はじめに
「Issueを書いたら、AIが勝手にコードを書いて、自分でレビューして、ダメなら自分で直して、最後にPRを出してくる」
GitHub Actions + Claude Code + 3つの専用AIエージェントで、そんな仕組みを作ってみました。Planner(計画)→ Generator(実装)→ Evaluator(検証)のハーネス構造で、Evaluatorが不合格を出せばGeneratorに差し戻して修正させます。
公式ドキュメント:
ハーネスとは
公式ドキュメントではこう説明されています。
Claude Code は Claude の周りの agentic ハーネス として機能します。言語モデルを有能なコーディングエージェントに変えるツール、コンテキスト管理、実行環境を提供します。
つまりハーネスとは、AIモデルを「ただテキストを返すもの」から「実際にアクションを実行できるエージェント」に変えるための枠組みのことです。
公式ドキュメントでは、agenticループの3フェーズとして コンテキストの収集 → アクションの実行 → 結果の検証 を挙げています。今回の設計では、この3フェーズをさらに 専門化した3つのサブエージェント に分割しました。
| 公式の3フェーズ | 本設計のエージェント | 役割 |
|---|---|---|
| コンテキストの収集 | Planner | コードベースを調査し、実装計画をJSON出力 |
| アクションの実行 | Generator | 計画に基づき1ファイルずつコードを書く |
| 結果の検証 | Evaluator | 実装結果を検証し、pass/failを判定 |
なぜ3つに分けるのか
単一のAIエージェントにすべてを任せることもできますが、役割を分離することで以下のメリットが得られます。
-
責務の明確化: 計画・実装・検証が混ざると、AIは「自分が書いたコードを自分で甘く評価する」傾向があります。検証を別エージェントに分離することで、客観的な品質チェックが働きます。
-
リトライの制御: Evaluatorが不合格を出した場合、Generatorだけをリトライすればよく、計画からやり直す必要はありません。
-
デバッグの容易さ: どのエージェントが失敗したかがログから一目でわかります。Plannerの計画が悪いのか、Generatorの実装が悪いのか、Evaluatorが厳しすぎるのか。
-
再利用性: エージェント定義はMarkdownファイルなので、プロジェクトごとにカスタマイズして使い回せます。
対象プロジェクト
今回ハーネスを導入したのは、個人で開発している Datum Gallery — D3.jsベースのチャート作成・共有プラットフォームWebアプリです。
- Frontend: React 18 + TypeScript + Vite
- Backend: Hono on Cloudflare Pages Functions
- Storage: Supabase (認証・RLS) + Cloudflare KV
- デプロイ: Cloudflare Pages
ファイル構成
最終的に作成したファイルは以下の4つです。
.github/
workflows/
claude.yml # GitHub Actions ワークフロー(汎用)
.claude/
agents/
dev-planner-agent.md # 計画エージェント(読み取り専用)
dev-generator-agent.md # 実装エージェント(読み書き可能)
dev-evaluator-agent.md # 検証エージェント(読み取り専用)
それぞれの設計思想と実装を詳しく見ていきます。
GitHub Actions ワークフロー
設計方針: 汎用性を最優先
ワークフローのYAMLは他のリポジトリでも使い回したいので、プロジェクト固有のロジックは一切書きません。プロジェクト固有の知識は CLAUDE.md(リポジトリルートに置くプロジェクト説明ファイル)と .claude/agents/ のエージェント定義に閉じ込めます。
トリガー設計
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]
4種類のイベントをカバーしています。
| イベント | ユースケース |
|---|---|
issues: opened |
Issue作成時 → ハーネス全体が起動 |
issues: assigned |
Issue割り当て時 → 同上 |
issue_comment |
Issue/PRコメントで @claude → 質問対応・追加修正 |
pull_request_review_comment |
PRレビューコメントで @claude → コード修正 |
pull_request_review |
PRレビュー本文で @claude → レビュー対応 |
条件分岐: @claude メンションでのみ起動
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && contains(github.event.issue.body, '@claude')) ||
(github.event_name == 'issue_comment' && !github.event.issue.pull_request && contains(github.event.comment.body, '@claude'))
すべてのトリガーに @claude メンションの条件を付けています。これにより、AIに関係ないIssueやコメントでは起動しません。コスト面でも大事なポイントです。
claude-code-action の設定
- name: Run Claude Code Action
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
timeout_minutes: "60"
claude_args: |
--model claude-sonnet-4-6
--allowedTools "Agent,Read,Write,Edit,MultiEdit,Glob,Grep,Bash(npm run build:*),Bash(npx tsc:*)"
--append-system-prompt "日本語で回答してください。..."
--max-turns 30
--allowedTools に Agent を含めるのがポイントです。これがないとサブエージェントが呼べず、ハーネスが機能しません。
公式ドキュメントのツール一覧によると、Claude Codeの組み込みツールは ファイル操作、検索、実行、ウェブ、コードインテリジェンス の5カテゴリに分類されます。これに加えて、サブエージェントの生成やオーケストレーション用のツールも用意されています。Agent ツールはこのサブエージェント生成に該当し、ハーネス構造の要です。
custom_instructions: ハーネスのオーケストレーター
--append-system-prompt で渡すカスタム指示がハーネス全体の指揮者の役割を果たします。Claude Code本体がこの指示に従い、3つのエージェントを順番に呼び出します。
--append-system-prompt
日本語で回答してください。
CLAUDE.md を必ず読み、プロジェクトの規約に従ってください。
## Issue駆動開発モード (Planner → Generator → Evaluator ハーネス)
Issueが作成された場合、以下のループで開発を行ってください。
`.claude/agents/` にある専用エージェントを使います。
### Step 1: ブランチ作成
命名規則: `claude/issue-<番号>-<簡潔な説明>`
### Step 2: Planner(計画)— 初回のみ
`dev-planner-agent` を Agent ツールで呼び出す。
### Step 3: Generator → Evaluator ループ
1. `dev-generator-agent` で1ファイルを作成/修正
2. `dev-evaluator-agent` で結果を検証
3. fail → フィードバックを添えて再度 Generator
4. 最大3回リトライしても不合格 → 次のファイルへ
### Step 4: ビルド検証
### Step 5: コミット&PR作成
ポイントは、この指示自体は何も実装しない ことです。具体的な実装ロジックは各エージェントのMarkdownに閉じ込めています。ワークフローはオーケストレーション(順番と条件)だけを担当します。
サブエージェントの定義方法
各エージェントは .claude/agents/ に置くMarkdownファイルで定義します。YAMLフロントマターで設定、本文がシステムプロンプトになります。
サブエージェントは、特定の種類のタスクを処理する特化した AI アシスタントです。各サブエージェントは、カスタムシステムプロンプト、特定のツールアクセス、および独立した権限を備えた独自のコンテキストウィンドウで実行されます。
フロントマターの主なフィールドはこちらです。
| フィールド | 必須 | 説明 |
|---|---|---|
name |
はい | 小文字とハイフンの識別子 |
description |
はい | Claudeがこのエージェントに委譲するタイミングの判断に使う |
tools |
いいえ | 使えるツール。省略するとすべて継承 |
model |
いいえ |
sonnet, opus, haiku, inherit など |
ポイントは、各サブエージェントが 独自のコンテキストウィンドウ で動くことです。メインの会話とは分離されているので、大量の調査結果や実装の詳細でメインのコンテキストが埋まりません。完了後、要約だけがメインに返ります。
配置場所によってスコープが変わります。
| 場所 | スコープ |
|---|---|
.claude/agents/ |
現在のプロジェクト(チームで共有可能) |
~/.claude/agents/ |
すべてのプロジェクト(個人用) |
今回は .claude/agents/ にプロジェクトスコープで3つ作りました。
Planner エージェント — 計画を立てる
---
name: dev-planner-agent
description: Issueの内容からコードベースを調査し、実装計画をJSON形式で出力する
tools:
- Read
- Glob
- Grep
- Bash
---
Plannerの役割
Plannerは「何をどう変えるか」の計画書を作ります。Issue の要件を読み、コードベースを 自分で 調査し、以下を含むJSONを出力します。
-
implementation_order: ファイルの実装順序(依存関係を考慮) -
files_to_create: 新規作成ファイルの一覧と目的 -
files_to_modify: 修正ファイルの一覧と変更内容 -
type_changes: 型定義の変更 -
api_changes: APIの変更 -
risks: リスクと注意事項
なぜPlannerに Write/Edit 権限を与えないのか
Plannerのツールは Read, Glob, Grep, Bash のみで、ファイルの変更権限がありません。これは意図的な設計です。
計画と実装を同じエージェントがやると、「調査が不十分なまま書き始める」パターンに陥りやすくなります。Plannerはコードを読むことしかできないため、必然的に十分な調査を行ってから計画を立てることになります。制約が良い行動を引き出すわけです。
公式ドキュメントでも、agenticループの最初のフェーズは「コンテキストの収集」とされています。Plannerはこのフェーズに特化したエージェントです。
実装順序の設計指針
Plannerには 型定義 → ドメイン → インフラ → UI の順で実装するよう指示しています。これはTypeScriptプロジェクトでの定石で、依存の上流から順に変更することでコンパイルエラーを最小化できます。
Generator エージェント — コードを書く
---
name: dev-generator-agent
description: Plannerの計画に基づき、1ファイルずつコードを実装する
tools:
- Read
- Write
- Edit
- Glob
- Grep
- Bash
---
Generatorの役割
Generatorは計画書に従って実際にコードを書きます。最も重要なルールは 「1回の呼び出しで1ファイルのみ」 です。
なぜ1ファイルずつなのか?
- Evaluatorの検証粒度: 1ファイルずつ検証することで、問題の特定が容易になります
- リトライの効率: 10ファイルまとめて書いて1つだけNGだった場合、全部やり直しになります
- コンテキストの管理: 1ファイルに集中することで、AIの出力品質が上がります
リトライ時の振る舞い
Evaluatorから fail が返された場合、Generatorは以下を行います。
-
feedbackの内容を正確に理解する - 指摘された問題点 のみ を修正する(他を触らない)
- 修正後、変更箇所を報告する
「他を触らない」が重要です。リトライのたびに修正範囲が広がると、新しい問題が混入するリスクが高まります。人間のコードレビュー対応でも同じことが言えますね。
Evaluator エージェント — 検証して採点する
---
name: dev-evaluator-agent
description: Generatorの実装結果を検証し、合格/不合格を判定する
tools:
- Read
- Glob
- Grep
- Bash
---
Evaluatorの役割
EvaluatorはGeneratorの成果物を5つの観点で検証します。
- 実装の正確性: 計画通りに実装されているか
- 型の整合性: TypeScriptの型が壊れていないか
- プロジェクト規約: CLAUDE.mdの規約に従っているか
- 副作用: 他のファイルに悪影響がないか
- コードスタイル: 既存コードとの一貫性
Evaluatorにも Write/Edit 権限がない
PlannerとEvaluatorの共通点は、どちらもファイル変更権限を持たないことです。
Evaluatorが自分でコードを直し始めると、「GeneratorとEvaluatorの責務が曖昧になる」「修正の品質が検証されない」という問題が起きます。Evaluatorは問題を 指摘 するだけで、修正はGeneratorに委ねます。この分離がハーネスの健全性を保ちます。
判定基準のバランスが超重要
過度に厳しく判定しない(完璧主義は不要、実用的に問題なければ pass)
元のコードより明らかに良くなっていれば pass とする
この指示は地味に重要です。Evaluatorが厳しすぎると、リトライが永遠に終わりません。最大3回のリトライ制限と合わせて、「実用的な品質」で妥協するラインを設けています。完璧を求めてハングアップするくらいなら、8割の品質で前に進む方がいいです。
やってみた: 実際にIssueを作って動かしてみる
4ファイルをmainにプッシュし、テスト用のIssueを @claude 付きで作成しました。
gh issue create --title "招待メンバーがダッシュボードのウィジェットを閲覧できない" \
--body "@claude ..."
7分41秒で完了。ログからエージェントの呼び出しを確認してみると...
01:02:39 "subagent_type": "dev-planner-agent"
01:03:45 "subagent_type": "dev-generator-agent" ← 1回目の実装
01:04:17 "subagent_type": "dev-evaluator-agent" ← 検証
01:04:36 "subagent_type": "dev-generator-agent" ← 2回目(フィードバック後の修正)
3つとも動いています! タイムラインを整理すると:
- 01:02:39 — Planner がコードベースを調査し、実装計画を策定
-
01:03:45 — Generator が
useDashboards.tsを修正(1回目) - 01:04:17 — Evaluator が検証し、何らかの指摘を出した(fail)
- 01:04:36 — Generator がフィードバックに基づいて再修正(2回目)
Evaluatorが1回目の実装を差し戻し、Generatorが修正して再提出する流れが確認できました。
Issueに自動投稿されたコメント
Claude Codeは自動的にIssueにコメントを投稿し、進捗をリアルタイムで報告していました。
### 修正タスク
- [x] プロジェクト構成とCLAUDE.mdの確認
- [x] Issue駆動開発モード:Plannerエージェントで実装計画作成
- [x] 現在の実装 `useDashboardDetail` の調査
- [x] RLSアクセス制御ロジックの修正実装
- [x] ビルド検証(TypeScript)
- [x] コミット&PR作成
### 重要な発見
⚠️ CLAUDE.mdによるとプロジェクトはCloudflare KV使用、Supabase移行は未実装(Issue #2で予定)。
しかしIssue #4では「dashboard_widgetsテーブル」「RLS」について言及されている。
コードベースの実際の状況を調査中...
面白いのは、CLAUDE.md の記述と Issue の内容に矛盾があることをPlannerが自分で検出している ところです。CLAUDE.md にはCloudflare KV使用と書いてありましたが、実際のコードベースにはSupabaseのテーブルが存在します。Plannerはこの食い違いを検出し、コードベースの実態に基づいて計画を立てました。
最終的にブランチ claude/issue-4-20260406-0101 が作成され、PRリンクが生成されました。
学んだこと
1. エージェントの権限分離は効く
Planner(読み取りのみ)→ Generator(読み書き)→ Evaluator(読み取りのみ)という権限設計は、実際に機能します。
公式ドキュメントのツールカテゴリに沿って、各エージェントに必要最小限のツールだけを与えることで、役割の逸脱を防げます。特にEvaluatorが独立した視点でコードを検証するのは、単一エージェントではできない品質チェックを可能にします。人間の開発チームで「書いた人と別の人がレビューする」のと同じ原理です。
2. CLAUDE.md の充実度がエージェントの品質を決める
エージェントはプロジェクトの全体像を知らない状態で起動します。CLAUDE.md がプロジェクトの型定義、API仕様、コーディング規約、よくある罠などを記述しているおかげで、エージェントは的確な判断ができます。
公式ドキュメントでも CLAUDE.md は「プロジェクト固有の指示、規約、Claude が毎回のセッションで知っておくべきコンテキストを保存するマークダウンファイル」と説明されています。ハーネスを導入するなら、まず CLAUDE.md を充実させることが最優先です。
実際、今回のテストではPlannerが「CLAUDE.mdと実態が違う」という矛盾を自分で検出して適切に対応していました。CLAUDE.md が存在しなかったら、的外れな計画を立てていた可能性が高いです。
3. ログの確認は必須
Actions のワーニングやエージェント呼び出しログは、ハーネスが正しく動いているかの唯一の証拠です。「動いてるように見える」を信じず、必ず subagent_type のログエントリを確認してください。
他のリポジトリでも使ってみたい人へ
今回作ったYAMLは、他のリポジトリでも以下の手順で導入できます。
Step 1: CLAUDE.md を作る
リポジトリルートに CLAUDE.md を作成し、プロジェクトの概要・構造・規約を記述します。これがエージェントの共通知識になります。ここの品質が全体の品質を左右するので、手を抜かないでください。
Step 2: エージェント定義をコピー
.claude/agents/ に3つのエージェント定義をコピーし、プロジェクトに合わせてカスタマイズします。
例えばdbtプロジェクトなら、Evaluatorの検証項目に ref() / source() の使い方チェックを追加します。Reactプロジェクトなら、hooks のルール違反チェックを追加する、といった具合です。
Step 3: ワークフローをコピー
.github/workflows/claude.yml をそのままコピー。ハーネスの制御フロー(--append-system-prompt)のみプロジェクトに合わせて調整します。
Step 4: シークレットを設定
リポジトリの Settings → Secrets に認証情報を設定します。
-
直接API:
ANTHROPIC_API_KEY -
OAuth:
CLAUDE_CODE_OAUTH_TOKEN - AWS Bedrock / Google Vertex AI: それぞれの認証情報(公式ドキュメント参照)
Step 5: テスト
小さなバグ修正のIssueを @claude 付きで作成して、Actions が起動するか確認します。ログで subagent_type のエントリを見て、エージェントが呼ばれているか確認してください。
コスト
今回の実行コストです。
| 項目 | 値 |
|---|---|
| モデル | claude-sonnet-4 |
| 所要時間 | 7分41秒 |
| ターン数 | 109 |
| API コスト | 約$1.19 |
1つのバグ修正PRに約$1.19。人間のエンジニアが同じ作業を行う時間(調査 + 実装 + レビュー対応)と比較すれば、十分にペイする金額です。
ただし注意点として:
- 複雑なIssueではターン数が増え、コストも上がります
-
--max-turnsで上限を設定しておくとコスト暴走を防げます - GitHub Actions の実行時間分(ランナーコスト)も別途かかります
まとめ
今回やったのは Planner → Generator → Evaluator の3エージェント構成で、ハーネスエンジニアリングとしてはかなりシンプルな方だと思います。
私自身も試行錯誤中ですが、ここから色々いじれそうだなと思っています。たとえば、テスト専門やセキュリティレビュー専門のエージェントを足して分業を細かくしたり、Evaluatorにビルド結果やPlaywrightのブラウザ検証を食わせて検証精度を上げたり。Planner自体にレビュアーを付けて計画段階から品質を上げる多段ループとか、複数Issueを並列でさばく構成にするとかも面白そうです。
エージェント定義はただのMarkdownファイルなので、気軽にいじれます。興味がある方はこの基本形をベースに、自分のプロジェクトに合わせて色々試してみてください。