MarkdownでAIエージェントの作業を自動化するときに押さえること

 ・ 6分

photo by niko photos(https://unsplash.com/@niko_photos?utm_source=templater_proxy&utm_medium=referral) on Unsplash

Claude Code、Codex、Gemini CLIのようなAIコーディングエージェントが増えてくると、一度はこんなことを考えますよね。「ノートにやることを書いておくだけで、エージェントたちが勝手に開発して、テストして、結果だけ持ってきてくれたらいいのに」と。

私も実際にそういう仕組みを作ってみました。Markdownノートを作業依頼書として使い、ファイル監視がノートを読んでエージェントを実行し、実行結果をまたドキュメントとして残す方式です。先に結論を言うと、人がノートを書くだけで残りがすべて自動で回る姿は、思ったほどうまくいきませんでした。それでも、作る過程で整理した設計原則の中には、ほかの自動化にもそのまま使えるものがけっこうありました。今回はその部分だけを抜き出してみます。

人が関わるのは最初と最後だけにします#

全体の流れは三つの段階に分けました。

  1. 種をまく — 人がノートにアイデアや要件を書きます。Markdown一枚がそのまま作業依頼です
  2. 育てる — エージェントが役割ごとに作業を進めます
  3. 収穫する — テストを通過した成果物を人がレビューし、承認したら完了にします

ポイントは、人が関わる地点を最初と最後の二か所に固定することです。途中で人が何度も割り込むと自動化の意味が薄れますし、逆に最後に承認ステップがないと、検証されていない成果物がそのまま流れてしまうからです。

役割はこんなふうに分けられます。

役割 やること
PM ノートを分析して要件ドキュメントに構造化し、作業を分割します
開発 要件をもとにコードとユニットテストを書きます
QA テストを実行し、結果レポートを残します
デプロイ ビルドしてストア申請までつなげます

QAで失敗したら、結果をまた開発段階に戻すループを入れておくのがおすすめです。一度で通るケースは思ったより少ないんですよね。

実行条件はfrontmatterで絞り込みます#

ファイル監視がノートを見た瞬間にエージェントを実行すると困ったことになります。書きかけのノートやメモ用のノートまで、すべて作業として扱われてしまうからです。そこで、frontmatterの条件をすべて満たしたときだけ実行するようにしました。

---
type: task # 作業ドキュメントかどうか
status: APPROVED # 人が承認したかどうか
dispatch: true # 今実行してよいかどうか
---

三つの条件をすべて満たしたときだけエージェントに渡されます。status: APPROVEDは人の承認ゲートの役割を果たし、dispatch: trueは「承認はしたけど、まだ実行しないで」を表現できるようにしてくれます。承認と実行のタイミングを分けておくと、思った以上に役立ちます。

同じドキュメントが二回実行されないようにします#

ファイル監視は保存するたびにイベントが発生します。ノートを少し直しただけでも、同じ作業がまた実行されかねません。そのため、実行履歴をDBに残し、実行済みの作業はスキップする重複実行防止が欠かせません。

私はSQLiteにこのくらいのテーブルを置きました。

  1. tasks — ノートから作られた作業と現在の状態
  2. agent_runs — どのエージェントがいつ実行され、結果がどうだったか
  3. events — ファイル変更、作業作成、エージェントの開始・終了、QA通過といった全活動のログ

特にeventsテーブルのようにすべての活動を時系列で残しておくと、何かおかしな動きをしたときに、どこでこじれたのかをさかのぼりやすくなります。

失敗もドキュメントとして残します#

エージェントの実行が失敗したら、ログだけ残して終わりにせず、QAドキュメントを自動で作ってdocs/qa/のようなフォルダに残すようにしました。失敗がまた一つの作業ドキュメントになるわけです。

同じやり方で、Sentryのようなエラー監視サービスのwebhookを受けて、QAドキュメントやホットフィックスのドキュメントを自動作成する分岐も入れられます。こうすると、人が書いた依頼も、失敗も、運用中のエラーも、すべて同じ形式のドキュメントとして入ってくるようになります。処理する側は、入力がどこから来たかを気にする必要がなくなりますよね。

コアはCLI、画面は読み取り専用ビューアに分けます#

カンバンボードや実行ログを見たくてダッシュボードを付けたくなりますが、そのときは構成をこう分けました。

  • CLIがコア — ファイル監視、エージェント実行、DBへの書き込みといったロジックはすべてCLIに置きます
  • ダッシュボードは読み取り専用 — CLIが作ったSQLiteファイルを読んで表示するだけです
  • 単独で動作 — ダッシュボードがなくても、CLIだけで完全に動きます

こう分けておけば、ダッシュボードが壊れても自動化は動き続けます。画面側のコードがコアロジックに触れることもありません。両者が同じDBファイルを共有するので、別途APIサーバーを作る必要もありません。

コマンドも流れに合わせてシンプルにしました。

tool seed <ノートのパス>     # ノートを作業として登録
tool grow <task-id>          # エージェントを実行
tool status                  # 全作業の状況
tool harvest <task-id>       # 結果を承認
tool harvest --reject <id>   # 却下すると実行段階へ戻る
tool watch <Vaultのパス>     # Vaultを監視して自動登録

完全自動化がうまくいかなかった理由#

設計原則は使えるものでしたが、ノートを書くだけで終わる姿は最後まで実現しませんでした。理由は大きく三つありました。

  1. 成果物の品質 — ノート一枚に込めた文脈だけでは、エージェントが望む結果を出すのは難しかったです。結局、人が成果物を何度も直す必要があり、「最後だけ関わる」という前提が崩れてしまいました
  2. 管理の負担 — frontmatterの状態を切り替えたり、自動で作られたQAドキュメントを整理したりする作業が、むしろ増えました。作業を減らすために作った仕組みが、新しい作業を生んだわけです
  3. パイプラインの保守 — ファイル監視、DB、ダッシュボードのような自動化ツールそのものを管理するコストが、思った以上に大きかったです。本来作りたかったプロダクトより、パイプラインの手入れに時間がかかることもありました

そのため、これらの原則は「すべてを自動化」よりも、途中で人が確認することを前提にした小さな自動化に組み込むほうが合っています。

まとめ#

MarkdownノートでAIエージェントの作業を自動化するときに押さえることは、次のようにまとめられます。

  • 人が関わる地点を最初と最後の二か所に固定します
  • 実行条件はfrontmatterで絞り込み、承認と実行のタイミングを分けます
  • 実行履歴を残して、同じ作業が二回動かないようにします
  • 失敗や運用エラーも同じ形式のドキュメントとして戻します
  • ロジックはCLIに、画面は読み取り専用ビューアに分けます

完全自動のパイプラインは期待どおりには回りませんでしたが、これらの原則は小さな自動化にもそのまま当てはまります。ノートを起点に何かを自動化しているなら、まずは実行条件と重複実行防止から見直してみてください。


Don't ruin the present with the ruined past.

— Ellen Gilchrist


他の投稿
テスト文書1つで自動化のエンドツーエンドを検証する 커버 이미지
 ・ 4分

テスト文書1つで自動化のエンドツーエンドを検証する

ObsidianのノートをAIエージェントの作業指示書として使う 커버 이미지
 ・ 4分

ObsidianのノートをAIエージェントの作業指示書として使う

もっともらしいのに失敗し続けるアイデア、タールピット 커버 이미지
 ・ 5分

もっともらしいのに失敗し続けるアイデア、タールピット