Claude CodeのカスタムスキルをAtomとRecipeに分けて運用する
毎回、進め方がブレる問題
Claude Codeにタスクを丸投げすると、進め方が毎回違う。あるときは丁寧に調査してから実装し、あるときはいきなりコードを書き始める。設計の確認なしに実装が終わっていて、方向性が違ったので全部やり直し、ということも起きる。
CLAUDE.mdに「必ず調査してから実装すること」のような手順を書いてみたのですが、手順が増えるほど守られなくなっていきました。そこでカスタムスキル(スラッシュコマンド)で開発の進め方そのものを構造化することにしました。
最初に作ったのは、調査から実装・PR作成までを1つに詰め込んだ巨大なワークフロースキルでした。これは失敗でした。タスクの種類が違うと手順の一部が合わなくなり、その都度スキル本体を書き換えるはめになります。途中でやり直したいときの分岐も表現しきれませんでした。
この反省から、いまはAtomとRecipeという2層にスキルを分けて運用しています。
- Atomスキル: 開発行為の最小要素を能力軸で切ったスキル(調査する・要件を整理する・設計する・実装計画を立てる・実行する…)
- Recipeスキル: タスク種別ごとに「どのAtomをどの順で実行するか」を定めたテンプレート
発想としてはUnixのパイプに近く、小さな単機能のコマンド(Atom)をつなぎ合わせて、目的に応じたパイプライン(Recipe)を組むイメージです。
スキルの全体像
AtomスキルやRecipeスキルには以下の表のようなスキルが含まれています。
| カテゴリ | スキル |
|---|---|
| Atom | atom-research, atom-goal-to-requirement, atom-spec, atom-impl-plan, atom-verify-plan, atom-execute, atom-check, atom-checkpoint, atom-message ほか |
| Recipe | recipe-normal(一般的な機能開発), recipe-bug-fix(バグ修正), recipe-big-task(大きな機能開発), recipe-spike(技術検証) |
Atomスキル:stdin / stdout を持つ最小単位
Atomスキルの設計で一番こだわったのが、すべてのAtomが共通のstdin/stdoutインターフェイスを持つことです。
- stdin:
ref_docs(先行Atomの出力ファイルへのパスの配列)+ Atom固有のパラメータ - stdout:
session-log/配下のMarkdownファイル
たとえば設計を担当する atom-spec の定義はこうなっています(抜粋)。
## stdin
- `resolution`: micro-service | infrastructure | app-logic
- `ref_docs`: goal-to-requirement.md, research.md(あれば)等
## stdout
session-log配下に `spec.md` として出力する。
**frontmatter:**
---
skill: atom-spec
resolution: <resolution>
version: <n>
ref_docs: [入力として参照したファイル群]
---
## Prohibitions
- 実装の詳細(コードレベル)に踏み込んではならない(それはimpl-planの責務)
ポイントは3つあります。
1つめは、出力が会話ではなくファイルであること。Claude Codeとの会話はコンテキストウィンドウとともに流れていくが、ファイルは残る。後続のAtomは ref_docs として先行Atomの出力ファイルを受け取るので、「atom-researchの調査結果を踏まえてatom-specが設計する」という受け渡しが、会話の記憶ではなくファイルで成立します。これがパイプです。
2つめは、frontmatterでトレーサビリティを持たせていること。各出力ファイルには「どのスキルが」「何を参照して」「何回目の改訂で」作ったかが記録されます。後から「この設計はどの調査に基づいているんだっけ」を辿れます。
3つめは、Prohibitionsで責務の境界を明示していること。atom-specは設計までで、コードレベルの詳細はatom-impl-planの責務。これを書いておかないと、Claudeは1つのAtomの中で先のステップまで進んでしまいがちになります。
レビューをファイル上で完結させる
Atomの出力に対するフィードバックにも決まりを作りました。ユーザーはstdoutのMarkdownファイルにHTMLコメントで直接フィードバックを書き込む。Claudeはコメントの内容から「このレビュー結果をどう取り扱うか」を判定して動きます。この取り扱い区分をdispositionと呼んでいます(処分・取り扱いの決定、という意味の英単語)。区分は次の4つ。
| disposition | 意味 | アクション |
|---|---|---|
| approved | OK。後続へ渡せる | 次のAtomへ進む |
| commented | 局所的修正指示 | 部分修正して再提示 |
| terminal-commented | 全体的方向性の指摘 | コメント範囲を書き直して再提示 |
| done | 完成。チェーン離脱 | 終了 |
チャット欄で「ここを直して」と言うかわりに、ファイルの該当箇所に <!-- この設計だとエラー時のフローが考慮されてない --> のように書き込みます。コードレビューでインラインコメントを書く感覚に近く、指摘の位置が曖昧になりません。修正されるとfrontmatterのversionが上がり、Change Logに改訂履歴が残ります。
Recipeスキル:Atomの実行順序テンプレート
RecipeはAtomの実行順序を定義したテンプレートで、タスクの種類ごとに用意しています。一番よく使う recipe-normal(一般的な機能開発・改善)の流れはこうです。
### 1. Phase 1: 調査・要件定義・設計
1. /atom-goal-to-requirement を提案する
2. /atom-spec を提案する
3. /atom-checkpoint を提案する(Phase境界の文脈要約)
### 2. Phase 2: 設計・実装
1. /atom-spec を提案する
2. /git-branch を提案する
3. /atom-impl-plan を提案する
4. /atom-verify-plan を提案する
5. /atom-execute を提案する
- ng の場合: /atom-spec resolution:app-logic に戻ることを提案する
- ok の場合: 必要に応じて /git-commit を提案する
6. /atom-checkpoint を提案する
### 3. Phase 3: 最終確認
1. /atom-check を提案する
2. /git-push, /gh-pr, /atom-message を提案する
全部の動詞が「提案する」になっているのが重要なところで、Claudeは次のAtomを提案するだけで、実行するのはユーザーが承認してからという原則にしています。Prohibitionsにも「Userの承認なしにスキルを実行してはならない」と明記しました。ユーザーはいつでもスキルの追加・スキップ・順序変更ができる。Recipeはレールであって、ベルトコンベアではない、という気持ちで運用しています。
recipe-state.md:進行状態の外部化
Recipeを開始すると、まず session-log/<task-name>/recipe-state.md というファイルが作られます。Recipeの全ステップをチェックリストとして展開したもので、Atomが完了するたびに [x] と成果物パスが記録されていきます。
これの何が嬉しいかというと、コンテキストが飛んでも続きから再開できることです。長いタスクでは会話の要約(compact)やセッションの切れ目を必ず跨ぐことになりますが、「いまどこまで進んでいて、次に何をするか」がファイルに外部化されていれば、新しいセッションでrecipe-state.mdを読むだけで現在位置を復元できます。
同じ目的のAtomが atom-checkpoint で、こちらはPhase境界で「ここまでの議論の要点」を圧縮したrunning logを出力します。状態はrecipe-state.mdに、文脈はcheckpointに、それぞれ永続化する分担です。
タスクが終わる頃、session-logにはこんなディレクトリができています。
session-log/
<task-name>/
recipe-state.md
checkpoint-01.md
goal-to-requirement.md
spec.md
impl-plan.md
verify-plan.md
execute.md
これがそのまま開発ログになります。「なぜこの設計にしたのか」が成果物として残るのは、巨大ワークフロースキル時代にはなかった副産物でした。
この記事もRecipeで書いている
実例をひとつ。この記事自体が recipe-normal で書かれています。執筆開始時点のrecipe-state.mdはこうでした。
# Recipe State: write-atom-recipe-skills-article
## Phase 1: 調査・要件定義・設計(スキップ)
- [-] /atom-goal-to-requirement — Userの指示によりスキップ
## Phase 2: 執筆
- [x] worktreeを作成 — ../blog-worktrees/write-atom-recipe-skills-article
- [x] /atom-impl-plan — session-log/.../impl-plan.md(version 2でapproved)
- [ ] /atom-execute(記事執筆)
- [ ] /git-commit
## Phase 3: 文体の調整
- [ ] /revise-article
- [ ] /git-commit
- [ ] /git-push
ブログ記事の執筆はコードを書く作業ではないですが、「計画を立てて成果物を作り、レビューを受けて改訂する」という構造は同じなので、そのままRecipeに乗ります。記事の構成案はatom-impl-planの出力としてレビューし、HTMLコメントで修正指示を受けて改訂しました。Phase 1を丸ごとスキップしているように、合わないステップは飛ばせばいい、という気軽さで使っています。
使ってみてどうか
よかったこと。
- 進め方が安定した。各ステップの成果物がファイルに外部化されているので、途中で方向転換しても文脈が失われない。方向転換自体もstateファイルを変えれば意図が明確に伝わるのでやりやすい
- レビューのタイミングが構造に組み込まれた。Atomごとに成果物の承認を挟むので、方向性のずれが早期に見つかる
- session-logが開発ログとして蓄積される。後から経緯を辿れる
- 記憶に残りやすかったり深く理解できている感覚がある(分析しきれてないので、なぜかはわからない)
一方で課題もある。
- Atomの粒度設計が難しい。細かすぎると承認の往復が増えてテンポが悪くなり、粗すぎると巨大スキルの二の舞になる
- 小さいタスクにはやはり重い。1行の修正にPhase 3つは要らない。いまはステップのスキップで対応しているが、もっと軽いRecipeがあってもいいかもしれない
- スキル群のメンテナンスコスト。共通インターフェイス(stdin/stdout/disposition)の規約を変えると全Atomに波及する
- 消費トークンが多い。Atomごとにスキル定義と先行成果物を読み直すので、丸投げするより明らかにトークンを食う
まとめ
- Claude Codeのカスタムスキルを、最小単位のAtomと実行順序テンプレートのRecipeの2層に分けた
- AtomはUnixコマンドのようにstdin/stdoutを持ち、ファイル経由で成果物を受け渡す
- レビューはstdoutファイルへのHTMLコメントで行い、dispositionの判定で次のアクションが決まる
- Recipeは「提案→承認→実行」のレールで、recipe-state.mdが進行状態を外部化する
巨大な1本のワークフローを書くより、小さな部品と組み合わせ方の定義に分けるほうが、修正にも例外にも強い。これが運用してみての実感です。Atomの粒度もRecipeの種類もまだ試行錯誤の途中なので、使いながら育てていきたいと思います。Claude Codeのスキル設計で悩んでいる人の参考になれば嬉しいです。