AIエージェントにzennで記事を書いてもらいたい

モチベーション
今まで学習した内容を定着させるためのアウトプットとしてや日本語の情報がそんなにないものを中心に定期的にzennで記事を書いてきた。
学習した内容を知識として定着させたり、あれなんだったっけみたいな時にメモとして見返したり、自分の活動アピールとしてだったり記事を各理由はいろいろあるけど、いろいろ試行錯誤して執筆して書いた記事にリアクションをもらえると素直にうれしい。
まあ、なので定期的に記事を書くことを続けていきたいのだけど本業で普通に仕事しているとその時間がなかなか取れなくなってきた。
特に子供が産まれてからプログラミングに割ける時間がかなり制限されてきてしまったなと感じ、ますますzennで記事を書く時間が確保できなくなってきている。
しかし、今は大AI時代。AIエージェントを駆使して開発することがいずれ当たり前になることでしょう。
上記のzenn記事を読んで今まで書いてきたzenn記事を使って新しく記事を書いてもらうというAIエージェントの使い方にかなり可能性を感じました。
AIエージェントで記事を書くことで執筆にかける時間を大幅に削減できることを期待しています。あとはAIエージェントを使う練習にもなるかなという期待もこめて
この記事のようなことを試したい

Roo Codeをインストール
ClineとRoo Codeの比較や導入記事はもう山程でてそうだから詳細は省略。
とりあえず、拡張機能でRoo Codeをインストール。インストールできたらAPI keyをセットする必要がある。Roo CodeがOpenRouterを推奨していたのでとりあえずアカウント作って10$課金してみた。
API keyをセットできたら、Roo Codeを使う準備は完了。

Cline素振りその1
ローカルの開発環境いろいろ見直したのでその記事を書いてみた
とりあえず、自分の今まで書いた記事を読んでもらって人格とか文体を抽出してもらう
私はGoが得意な日本のサーバーサイドエンジニアです。このリポジトリはzennという技術記事投稿サイトの投稿記事を管理するためのリポジトリです。
articles/* 以下は自分が zenn に書いた記事です。
AIが書いたとバレない範囲で、ブログの記述を自動化したいです。
記事一覧から私の技術の方向性を抽出し、そこからランダムに読んでください。最低限、10記事は読んでください。
そこから私の人格と文体を抽出して、それを docs/writing-style.md に抽出してください。
最終的には、それをベースに記事を執筆してもらいます。
抽出してもらった分析結果
抽出してもらった人格と文体
# 文体と人格の分析
## 技術的背景と専門分野
- **主な専門分野**: Goによるバックエンド開発、gRPC、テスト、クリーンアーキテクチャやDDDといったアーキテクチャ
- **副次的な専門分野**: Java、Kotlin、Spring Boot、関数型プログラミング、テスト手法(特にプロパティベーステスト)
- **興味のある技術**: Buf、Cloud Functions、EKS、Docker、testcontainers
## 文体の特徴
### 全体的な文体
- **簡潔で直接的**: 無駄な装飾を避け、技術的な内容を直接的に伝える文体
- **親しみやすさ**: 堅苦しくなく、「〜です」「〜ます」調の丁寧語を基本としつつも親しみやすい
- **謙虚さ**: 自分の知識に自信を持ちつつも、「初学者です」「間違っていたらコメントください」など謙虚な姿勢を示す
- **絵文字の使用**: 🐼、🙇♂️、😓などの絵文字を適度に使用して文章に親しみやすさを加える
- **カジュアルな口調**: 「〜だ」「〜である」よりも「〜です」「〜ます」や「〜だよ」「〜かな」などのカジュアルな表現を好む
- **一人称の使用**: 「私は」という表現はあまり使わず、主語を省略することが多い
- **体験に基づいた記述**: 「〜してみた」「〜と思った」など、実際の体験に基づいた表現が多い
- **率直な感想**: 「心折れた」「面倒だな」など、率直な感想や主観を交えた表現が多い
### 特徴的な表現パターン
- **「〜だなと思います」**: 個人的な見解を述べる際によく使用
- **「備忘録です」**: 多くの記事で自身の学習や実装の記録として位置づけている
- **「ハマったところ」**: 実装中に苦労した点を共有するセクションをよく設ける
- **「今回は以上です」**: 記事の締めくくりによく使用する表現
- **「🐼」**: 記事の最後に使用することが多い、著者のアイコン的な絵文字
- **「〜っぽい」**: 「〜っぽいな」「〜っぽいので」など、曖昧さを含む表現をよく使用する
- **「〜と思う」**: 「〜と思った」「〜と思います」など、自分の考えを示す際によく使用する
- **「〜かな」「〜かも」**: 断定を避け、可能性を示す表現をよく使用する
- **「とりあえず」**: 暫定的な解決策や方針を示す際によく使用する
- **「〜だけど」**: 逆接の接続詞をよく使用し、複数の視点から物事を見る傾向がある
- **「〜してみる」**: 試行錯誤の姿勢を示す表現をよく使用する
### 記事構成
- **明確な目的提示**: 冒頭で記事の目的や背景を簡潔に説明
- **対象読者の明示**: 多くの記事で「対象読者」セクションを設け、記事の想定読者を明確にする
- **ステップバイステップの説明**: 複雑な技術的手順を順序立てて説明
- **コードと説明のバランス**: コードブロックと説明文のバランスが良く、読者が理解しやすい構成
- **まとめセクション**: 記事の最後に「まとめ」や「おわりに」のセクションを設け、内容を振り返る
- **見出しの使い方**: 簡潔で具体的な見出しを使用する傾向がある
- **箇条書きの活用**: 要点を箇条書きでまとめることが多い
- **コードブロックの活用**: コマンドや設定ファイルの内容をコードブロックで示すことが多い
- **段階的な説明**: 手順を段階的に説明することが多い
- **個人的な感想のセクション**: 記事の最後に個人的な感想や今後の展望を述べることが多い
## 技術的な内容の伝え方
- **コマンド例の提示**: 具体的なコマンド例を示して説明することが多い
- **設定ファイルの内容の共有**: 実際の設定ファイルの内容を示して説明することが多い
- **トラブルシューティングの共有**: 遭遇した問題とその解決方法を共有することが多い
- **選択肢の提示**: 複数の選択肢を示し、それぞれのメリット・デメリットを説明することが多い
- **個人的な選択の理由**: なぜその選択をしたのかという個人的な理由を説明することが多い
- **実践的な例**: 理論だけでなく実際に動く例を提供
- **図表の活用**: 複雑な概念を図表で説明することがある
- **参考リンク**: 関連する記事や公式ドキュメントへのリンクを提供
- **成果物の共有**: GitHub等で実装コードを公開
- **ハマりポイントの共有**: 自身が苦労した点を共有し、読者の時間節約を意識
## 人格的特徴
### 技術に対する姿勢
- **実践的**: 理論よりも実際に動くコードや実装方法を重視
- **探究心**: 新しい技術や手法に積極的に取り組む姿勢
- **体系的な学習**: 単に使い方を学ぶだけでなく、背景や原理の理解を重視
- **比較検討**: 複数の技術や手法を比較し、メリット・デメリットを分析する傾向
- **実用性重視**: 「使えるかどうか」「便利かどうか」を重視する傾向がある
- **効率性の追求**: 作業の効率化や自動化を重視する傾向がある
- **試行錯誤の姿勢**: 新しいツールや方法を試してみる姿勢がある
- **現実的な判断**: 理想よりも現実的な解決策を重視する傾向がある
### コミュニケーションスタイル
- **読者への配慮**: 初心者にもわかりやすいように説明を心がける
- **謙虚さと自己開示**: 自身の知識の限界を認め、学習過程を共有する
- **フィードバック歓迎**: 読者からの指摘や改善点を積極的に求める
- **実用性重視**: 読者が実際に使える情報提供を心がける
- **自己分析的**: 自分の作業スタイルや好みを分析し、それに合わせたツール選びをする傾向がある
### 個人的特徴
- **自己学習の記録**: 自分の学習過程を記録し共有することを重視
- **問題解決志向**: 技術的な課題に対して複数のアプローチを検討し解決する
- **継続的な学習**: 新しい技術や概念に対して継続的に学習し、理解を深める姿勢
- **コミュニティ貢献**: 自分の知識や経験を共有することでコミュニティに貢献する意識
## 記事作成のパターン
1. **問題提起**: 技術的な課題や学習のきっかけを提示
2. **背景説明**: 技術の背景や基本概念の説明
3. **実装手順**: ステップバイステップでの実装方法の解説
4. **コード例**: 実際のコードと詳細な説明
5. **ハマりポイント**: 実装中に苦労した点や注意点の共有
6. **まとめ**: 学んだことや今後の展望の整理
## 好んで使用する技術スタック
- **言語**: Go、Kotlin
- **フレームワーク/ライブラリ**: gRPC、Connect、Buf、testcontainers、Arrow
- **インフラ**: Kubernetes、EKS、Cloud Functions
- **テスト**: プロパティベーステスト、dockertest、runn
- **開発環境**: ghostty(ターミナル)、SKK(日本語入力)、Raycast(ランチャー)
- **その他**: ブロックチェーン、Google Analytics API
技術スタックとかが読んでもらった記事に引っ張られてる気もするがだいたい良さそうな感じがする。
次にこのmarkdownと以下のスクラップを読んでもらって、章構成を作ってもらってmarkdownで出力してもらう。
# 🛠️ エンジニアの開発体験を向上させる環境構築とツール導入ガイド
## 記事の概要
この記事では、日々の開発作業を効率化し、快適にするための環境構築とツール導入について解説します。ターミナル環境からテキスト入力、アプリケーション起動までをカバーし、筆者が実際に使用している設定やカスタマイズ方法を紹介します。各ツールの導入手順だけでなく、実際に使用する中で「ハマったポイント」や「こだわりポイント」も共有します。
## 対象読者
- 開発環境をより効率的にしたいエンジニア
- ターミナルやシェル環境をカスタマイズしたい方
- macOSでの開発環境構築に興味がある方
- キーボード操作を重視する効率化が好きな方
## 章構成
### 1. はじめに
- 開発環境カスタマイズの重要性
- 本記事で紹介するツールと設定の全体像
- 筆者の開発環境へのこだわり
### 2. モダンなターミナル環境の構築 - ghostty導入
- ghosttyとは何か
- インストール方法
- 基本設定と最適化
- ハマりポイントと解決方法
- 実際の使用感
### 3. シェル環境の最適化
- zshの設定とプラグイン
- starshipによるプロンプトのカスタマイズ
- エイリアスと関数の設定
- 環境変数の管理方法
- シェルスクリプトによる作業の自動化
### 4. 効率的な日本語入力 - SKKの導入
- SKKとは何か
- macOSでのSKKのセットアップ
- 基本的な使い方と学習曲線
- プログラミング時の日本語入力の効率化
- 実際の使用感と工夫点
### 5. ランチャーアプリによる作業効率化 - Raycast
- Raycastの特徴と機能
- インストールと初期設定
- 便利な拡張機能と使い方
- キーボードショートカットの設定
- 日常的な使用シーンと効率化のポイント
### 6. Gitワークフローの効率化
- Gitの基本設定
- エイリアスの設定
- 便利なGitツールの紹介
- GitHub連携の効率化
- コミットメッセージのテンプレート
### 7. 統合的な開発環境の構築
- 各ツールの連携方法
- ワークフローの例
- 設定ファイルの管理(dotfiles)
- 新しいマシンへの環境移行方法
### 8. まとめ
- 紹介したツールと設定のおさらい
- 継続的な環境改善のコツ
- 読者へのアドバイス
## 特徴的な要素
- **実践的なコード例**: 各設定ファイルの具体的な記述例
- **スクリーンショット**: 設定画面や使用イメージの視覚的な説明
- **トラブルシューティング**: 実際にハマったポイントとその解決方法
- **パフォーマンス考察**: 導入による作業効率の変化
- **参考リンク**: 公式ドキュメントや役立つリソースへのリンク
## 執筆方針
- 実際に使用している設定や経験に基づいた信頼性の高い情報提供
- 初心者にもわかりやすいステップバイステップの説明
- スクラップで検証した内容に忠実な情報提供
- 読者が自分の環境に合わせてカスタマイズできるような汎用的なアドバイス
- 「なぜそうするのか」という理由の説明を含める
あとはこの章構成を元に記事を書いてもらった
反省点
- 章構成が微妙
- 記事を作成するにあたって章構成がだいぶ大事になってくると思うのでもう少しやりとり多くして精度上げればよかった
- zennのスクラップを全て読めてなかったので不完全な情報抽出で章構成をしてしまった
- 手探りで
.clinerules
作ってみたもののあんまり機能してなかった- zennのサービス紹介
- zennでの記事、本の書き方
- スクラップに書いてないことを記事にけっこう書いてくるのでスクラップで検証したこと以外書かないようにルール化したい
- スクラップの読み込みが表示されている領域だけで下までスクロールしてくれなかった
- スクロールしてねって毎回指示出すの面倒くさかったのでruleとかに書いておきたい
- もしくは、MCPサーバーを使ってzennのスクラップの内容をmarkdownとかで抽出しておいたほうがいいのかもしれない
- 高い
- 気づいたら$42持ってかれてた
- スクラップのコンテキストが大きいのでこれを毎回送ってるのが高かったのか?
- 繰り返しスクラップの読み込みファイルの編集を行っていたのが費用につながってそう
- 編集行が多すぎる
- 一回で記事を書こうとしてしまったので約700行くらいを書こうとして、エラー吐くことが多かった
- これ1章ごとに書いてもらったほうがいいのかもしれない

素振りその2
Haskellで学習用のプログラムを書いたので(ほとんどAIに書いてもらったけど)、AIエージェントを使った記事の作成の練習として記事を書いてみる。
前回の反省を活かして今回は以下を試してみる
- Firecrawl MCPを使ってみる
- Cursor Agent(Composer)でやってみる
- .clinerules(.cursorrules)をちゃんと書いてみる
- 章構成は自分で書く
まず、前回zennのスクラップの内容が多すぎて、clineのコンテキストに収まらなかったり、読み込み試行錯誤で無駄にコストがかかったりなどがあった。これはコンテキスト維持ができないために毎回zennのスクラップを見に行くのもばからしいのでFirecrawl MCPを使ってスクラップの分析内容をmarkdownなどに出力しておいてそれを読み込むようにすればコンテキストの節約になるかなと思ったのでやってみようと思う。
もはや最初の目的からズレるが記事を書くだけならClineでなくともCursorで十分なんじゃないかと思ったので試してみる。というか、今回の題材のHaskellの練習でClineとCursor Agent両方使ったけどCursor Agentそんなに悪い感じもしなかったので使ってみようかなと。
ruleは前回の反省を活かしてちゃんと書く。
章構成に関してはAIに章構成とzennのスクラップの内容を元に記事を書くように指示をだすため当然なのだがだいぶ章構成に記事の内容が引っ張られる。章にないことは書かれないし、章にあれば書いてないことも書かれる。記事のクオリティーが章の構成次第のような気がするので章構成は今回自分で書いてみる。
Firecrawl MCPを使ってみる
上記記事に丸投げ。とりあえず、無料プランで500クレジット分(500ページのスクロール?)は使えるそうなので無料で使えそう。
アカウント作成して、APIキーを作成する。
一応紹介リンク貼っておくのでよかったらここからどうぞ(クレジットもらえるっぽい)
MCPサーバーのリポジトリはこちら
Cursorに移ってMCPの設定からなんやかんやで~/.cursor/mcp.json
に以下を記載してみた。
{
"mcpServers": {
"mcp-server-firecrawl": {
"command": "npx",
"args": ["-y", "firecrawl-mcp"],
"env": {
"FIRECRAWL_API_KEY": "YOUR_API_KEY_HERE"
}
}
}
}
素直に聞いてみた
以下のURLはzennという技術投稿サイトでHaskellについてまとめたスクラップURLです。スクラップの内容をできる限りそのまま抽出してAIがコンテキストとして扱いやすいファイル形式でreferences配下に保存してください。
@https://zenn.dev/jy8752/scraps/6df200e1548c54
何回かやりとりしたものの以下2つのmarkdownファイルを生成してくれた。
references/haskell-janken.md
# Haskellでじゃんけんゲームを作る
Haskellに入門したのでせっかくなので何か作ってみる。
Haskellで何かアプリケーションを作りたいというよりは純粋にHaskellによる関数型プログラミングでのシステムの作り方を学びたいというのがモチベーションなのでAPIとかDBとかの知識はいらない。
原点に戻ってじゃんけんゲームを作ってみることにした。

## プロジェクトの作成
```bash
stack new janken-app
cd janken-app && stack build
stack run
stackなのかCabalなのかどっちを使うのがいいのかよくわからなかったけど、今ならどっちでもいいみたいな感じだったと思うので感覚でstackにした。
メインコード
src/Lib.hs
module Lib
( playJanken,
Hand (..),
Result (..),
handToStr,
strToHand,
judgeJanken,
)
where
import Control.Monad (when)
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import qualified System.IO as IO
import System.Random (randomRIO)
-- じゃんけんの手を表す型
data Hand = Rock | Scissors | Paper
deriving (Eq, Show, Read)
-- 勝敗の結果を表す型
data Result = Draw | Win | Lose
deriving (Eq, Show)
-- 日本語表記への変換
handToStr :: Hand -> String
handToStr Rock = "グー"
handToStr Scissors = "チョキ"
handToStr Paper = "パー"
-- 結果の日本語表記への変換
resultToStr :: Result -> String
resultToStr Draw = "あいこです"
resultToStr Win = "あなたの勝ちです"
resultToStr Lose = "あなたの負けです"
-- 日本語入力からHandへの変換
strToHand :: String -> Maybe Hand
strToHand "グー" = Just Rock
strToHand "チョキ" = Just Scissors
strToHand "パー" = Just Paper
strToHand _ = Nothing
-- ランダムな手を生成
randomHand :: IO Hand
randomHand = do
n <- randomRIO (0, 2) :: IO Int
return $ case n of
0 -> Rock
1 -> Scissors
_ -> Paper
-- 勝敗判定
judgeJanken :: Hand -> Hand -> Result
judgeJanken player computer
| player == computer = Draw
| (player == Rock && computer == Scissors)
|| (player == Scissors && computer == Paper)
|| (player == Paper && computer == Rock) =
Win
| otherwise = Lose
-- じゃんけんゲームを実行
playJanken :: IO ()
playJanken = do
IO.hSetEncoding IO.stdin IO.utf8
IO.hSetEncoding IO.stdout IO.utf8
putStrLn "じゃんけんをしましょう!"
putStrLn "「グー」、「チョキ」、「パー」のいずれかを入力してください:"
input <- TIO.getLine
case strToHand (T.unpack input) of
Nothing -> do
putStrLn "入力が正しくありません。「グー」、「チョキ」、「パー」のいずれかを入力してください。"
playJanken
Just playerHand -> do
computerHand <- randomHand
putStrLn $ "あなた: " ++ handToStr playerHand
putStrLn $ "コンピュータ: " ++ handToStr computerHand
let result = judgeJanken playerHand computerHand
putStrLn $ resultToStr result
when (result == Draw) $ do
putStrLn "もう一度じゃんけんをしましょう!"
playJanken
app/Main.hs
module Main (main) where
import Lib
main :: IO ()
main = playJanken
references/haskell-janken-test.md
# Haskellじゃんけんゲームのテストコード
せっかくなのでテストを書いてみた。
## HUnitテスト
### test/LibUnitTest.hs
```haskell
module LibUnitTest (unitTests) where
import Test.HUnit
import Lib
unitTests :: Test
unitTests = TestList
[ "handToStr tests" ~: TestList
[ "グー" ~: "グー" ~=? handToStr Rock
, "チョキ" ~: "チョキ" ~=? handToStr Scissors
, "パー" ~: "パー" ~=? handToStr Paper
]
, "strToHand tests" ~: TestList
[ "グー" ~: Just Rock ~=? strToHand "グー"
, "チョキ" ~: Just Scissors ~=? strToHand "チョキ"
, "パー" ~: Just Paper ~=? strToHand "パー"
, "不正な入力" ~: Nothing ~=? strToHand "不正な入力"
]
, "judgeJanken tests" ~: TestList
[ "同じ手はあいこ" ~: Draw ~=? judgeJanken Rock Rock
, "グーはチョキに勝つ" ~: Win ~=? judgeJanken Rock Scissors
, "チョキはパーに勝つ" ~: Win ~=? judgeJanken Scissors Paper
, "パーはグーに勝つ" ~: Win ~=? judgeJanken Paper Rock
, "グーはパーに負ける" ~: Lose ~=? judgeJanken Rock Paper
, "チョキはグーに負ける" ~: Lose ~=? judgeJanken Scissors Rock
, "パーはチョキに負ける" ~: Lose ~=? judgeJanken Paper Scissors
]
]
QuickCheckテスト
test/LibPropertyTest.hs
module LibPropertyTest (main, prop_sameHandIsDraw, prop_strToHandInverse, prop_judgeJankenSymmetric) where
import Test.QuickCheck
import Lib
newtype TestHand = TestHand { unTestHand :: Hand }
deriving (Show)
instance Arbitrary TestHand where
arbitrary = TestHand <$> elements [Rock, Scissors, Paper]
-- 同じ手を出したら必ず引き分けになる
prop_sameHandIsDraw :: TestHand -> Bool
prop_sameHandIsDraw (TestHand h) = judgeJanken h h == Draw
-- strToHandとhandToStrは互いに逆関数
prop_strToHandInverse :: TestHand -> Bool
prop_strToHandInverse (TestHand h) = strToHand (handToStr h) == Just h
-- じゃんけんの判定は対称的
prop_judgeJankenSymmetric :: TestHand -> TestHand -> Bool
prop_judgeJankenSymmetric (TestHand h1) (TestHand h2) =
case judgeJanken h1 h2 of
Draw -> judgeJanken h2 h1 == Draw
Win -> judgeJanken h2 h1 == Lose
Lose -> judgeJanken h2 h1 == Win
main :: IO ()
main = do
putStrLn "\nRunning QuickCheck tests..."
quickCheck prop_sameHandIsDraw
quickCheck prop_strToHandInverse
quickCheck prop_judgeJankenSymmetric
Property based testを実行するのにHandの値を生成するArbitraryの定義が必要なのだがHandと別のモジュールで定義しようとすると警告がでるのでnewtypeでラップしてねとコンパイラに言われたのでとりあえずそれっぽくしてみた。
やってから気づいたけどスクラップ単一ページのコンテンツ抽出にfirecrawlを使うのはやりすぎだったかもしれない。以下の記事にまとまってるがfetch MCPとかで十分だったかもしれない。

zennのスクラップのコンテンツ抽出はできたので次にruleを作っていく。
調べたら.cursorrulesが非推奨になっていてProject Rulesなるものを作ったほうがいいっぽい

とりあえず、zennについてAIに教えといたほうがいのかなと思い、以下のルールを作成した。
zenn-rules.mdc
このリポジトリについてと Zenn サービスについて
本リポジトリは技術投稿サイトZennの投稿記事を管理するためのリポジトリです。以下は技術投稿サイトのZennについての詳細を記したものです。
Zennとは
Zennとは日本の技術投稿webサービスである。主にプログラミングに関する技術のことであれば自由に投稿することができる。Zennには後述する基本の記事と本、スクラップの3種類の投稿手段がある。
Zennのarticles(記事)について
Zennの基本的な技術投稿手段。zenn CLIを使うことでmarkdown形式で技術記事を執筆、投稿することが可能となっている。技術記事の先頭には必ず以下の形式でタイトルなどを記載する。
---
title: "Astro + zenn-markdown-htmlで始める個人ブログ"
emoji: "🐕"
type: "tech" # tech: 技術記事 / idea: アイデア
topics: ["Astro", "TypeScript", "zenn", "markdown"]
published: true
---
- title: 技術記事のタイトル
- emoji: zennの特徴的な部分。技術記事には何かしらの絵文字を1つ紐づけて表示する。
- type: zennには投稿の種別がtechとideaの2種類ある。基本的にはtechで問題ないが思想や意見のみの投稿の場合はideaを使う。
- topics: 最大5つまで記事に関係する技術ワードを紐づけられる。
- published: true or false。trueの状態でGitHubリポジトリにpushすると投稿されるようなワークフローが組まれている。投稿時は手動でtrueに変えるので基本はfalseで問題ない。
この形式の技術記事はarticles配下に任意のファイル名で保存される。
Zennのbooks(本)について
zennはいくつかのmarkdownファイルをまとめて技術本形式で投稿できるようになっている。以下はzenn本の特徴とルールである。
- books配下に任意のディレクトリ名で作成される。
- config.yaml, cover.png, <任意のファイル名>.mdが配置される。
- markdown1ファイルが本の1ページに相当し、markdownには先頭に以下のようなtitleが必須。
---
title: "はじめに"
---
- cover.pngはその本の表紙となる画像ファイルである。
- config.yamlには本の構成を記載する。以下は記載例。
title: "[protovalidate徹底ガイド] より安全でドキュメント性の高いスキーマ駆動開発"
summary: "Protobufのスキーマをバリデーションするのに長らくprotoc-gen-validate(PGV)が使われてきました。しかし、PGVはすでにその役目を終えprotovalidateが完全な後継としてその役目を引き継ぐこととなりました。protovalidateはGoogleが開発した式言語であるCEL(Common Expression Language)を採用しており、より柔軟な制約を可能としましたがCELの情報はまだ少なくprotovalidateに難しさを感じた人もいるかもしれません。
本書籍ではprotovalidateの使い方と全ての制約ルールを解説、紹介するだけでなくCELを使った基本的な評価式の読み書きについて解説することでprotovalidate採用の手助けとなることを目的としています。"
topics: ["protovalidate", "Buf", "Protocolbuffers", "Go", "CEL"]
published: true
price: 0 # 有料の場合200〜5000
# 本に含めるチャプターを順番に並べましょう
chapters:
- "1" # はじめに
- "2" # protovalidateについて
- "3" # protovalidateを使ってみる
- "4" # message / oneofのバリデーション
- "5" # stringのバリデーション
- "6" # bool / bytesのバリデーション
- "7" # 数値のバリデーション
- "8" # enumのバリデーション
- "9" # map / repeatedのバリデーション
- "10" # Well-Known Typesのバリデーション
- "11" # FieldConstratinsのその他の値について
- "12" # CELについてより詳しく知る
- "13" # (おまけ)protovalidateへのコントリビュート
- "14" # おわりに
Zennのスクラップについて
Zennにはスクラップ形式で投稿することも可能です。スクラップはmarkdownで管理することはできません。
Zennのmarkdownルール
@https://zenn.dev/zenn/articles/markdown-guide
上記サイトを参照。基本的なmarkdown形式に加えzenn独自の記法が存在します。
記事執筆に関してのルール
.cursor/article-rules.mdc
技術記事および本を作成する際に参照するルール
- @writing-style.md を参照し筆者の文体、人格を保ちつつ記事を執筆してください。
- 指定のreferenceがあればその内容を元に記事を執筆してください。一般的に事実として知られているようなことなど以外はreferenceに記載のないことを記載しないでください。感想や意見などを追加して執筆することはかまいません。
- 指定のGitHub リポジトリがあれば適切にそのコード内容を使ってかまいません。
- 参考にしたGitHubリポジトリやブログURLが存在するときはそのままリンクURLを記載することを徹底してください。
一応、スクラップからmarkdownに内容を抽出する際のルールも
.cursor/fetch-scrap.mdc
zennスクラップから内容を抽出する際のルール
- zennのスクラップURLが提供されたらそのページから内容を抽出し、referencesディレクトリ配下にmarkdownファイルとして保存してください。
- スクラップに記載の文章は正確にそのまま全て抽出してください。
- リンクURLがあった場合もそのまま抽出してください。
- 画像URLがあった場合はそのまま画像URLを抽出して記載してください。

章構成
---
title: "Haskellに入門したのでじゃんけんゲームを作ってみた"
emoji: "" # 記事の内容をもとに適当な絵文字を 入れて
type: "tech" # tech: 技術記事 / idea: アイデア
topics: ["haskell"]
published: false
---
## はじめに
## 対象読者
## Haskellプロジェクトの作成
## Haskellでじゃんけんゲームを実装してみる
## テストを書く
## おわりに

書いてもらった記事
感想とか思想みたいなことを語っているところは自分で書いた。はじめとおわりも自分で書き直した。
記事のボリュームは前よりは落ちるのでそこまで大変ではなかった。
章構成を自分で書くのとzennのスクラップをmarkdownで出力するのはけっこうありかもしれない。
以下、感想
- Project Ruleがあんまり機能してない気がする
- スクラップの抽出は1回じゃいい感じにできなかったので何回かやり取りが必要だったがまあそこまで大変ではなかった気がする
- 記事は抽出したスクラップの内容と章構成とProject RuleとサンプルのGitHub リポジトリを見て書いてもらった
- けっこうあっさり記事は書けた
- ただ、書いてほしいコードが抜けてたり微妙に抜けてるところがあったりした
- 章構成はもう少し細かく設定したほうがいいかもしれない
- 参考リンクや画像をスクラップに乗せたやつそのままzennの記事にも反映してほしいけど、やってくれなかった
あとは当然といえば当然なのだけど記事の内容について自分がどう感じたかとかどういった思想があってそう思ってるかとかそういう気持ち的なものがない記事になったなと感じた。
これはスクラップにそれを書けば反映してくれるかもしれないし、まあ、そのくらいは自分で書くのがいいのかなと思った。
特にそのお気持ちが出るのが記事のはじめとおわりな気がするのでここも章構成に加えて事前にこっちで考えて入力として与えちゃっても良い気がする。いずれにせよ、そこはAIでなくて自分で書いたほうが良い気がする。導入と結びがAIっぽいと面白みなくなりそうだし。
あともう少しzennのmarkdownルールとか使ってほしいのだけどProject Ruleについてもう少し試行錯誤が必要なきがした。
GitHubリポジトリのURLを与えてるけどそもそもそれだけどコード全部把握できるのかな?ここもあんまりわかってない。
ClineからCursorにしたけど記事を書く分にはあんまり不満はなかった。次もCursorでやってみる。