エージェント・ソフトウェア・エンジニアリング #4|Agent がコードを書き終えた後、誰が「マージ OK」の判断を下すのか?

シリーズ記事:


エージェント・ソフトウェア・エンジニアリングの概念図


本シリーズの過去 2 回で、私たちは 2 つの課題を解体してきました。1 つ目は、Agent が 1 日に数十の PR を作成するようになった際、従来のコードレビューのプロセスが崩壊するという問題(#2)です。2 つ目は、複数の Agent が並行して作業を行う際、Git のメンタルモデルがボトルネックになるという問題(#3)です。

これら 2 つの問題が指し示しているのは、より根本的な空白地帯の存在です。それは「Agent によるコーディング完了後、メインブランチへのマージ前に、確定的かつ機械的に実行可能な品質ゲートが存在しない」という事実です。

従来のプロセスでは、このゲートキーパーは人間のレビュアーでした。レビュアーは PR を開き、数百行の diff を読み込み、頭の中でコードの動作をシミュレートし、「このコードは正しいか」と判断してから「Approve」をクリックします。このプロセスは人間の経験、注意力、時間という 3 つのリソースに依存していますが、これらはまさに Agent の時代においてスケールしないリソースなのです。

CI テストは機械的なゲートですが、これは「既存のテストがパスするか」のみをチェックするものであり、「Agent の実装が今回のタスクの意図を満たしているか」まではチェックしません。Agent は既存のテストをすべてパスさせつつも、完全に間違った機能を実装することがあります。なぜなら、CI に対して「今回のタスクの意図が何か」を伝える者がいないからです。

これこそが、agent-spec が解決しようとしている問題です。

agent-spec は「より優れたコードレビューツール」ではなく、異なるパラダイムです。これは審査の対象を「コード」から「契約(コントラクト)」へ移し、審査のタイミングを「コーディング後」から「コーディング前」へ移し、検証の実行者を「人間」から「機械」へと変えるものです。

一、審査ポイントのシフト

agent-spec[1] の中核となる理念は、一言で要約できます。「人間の審査ポイントを『コード写完後』から『コード書く前』へ移す」ことです。

従来のプロセスにおいて、人間の注意力がどのように配分されていたかを示すと以下のようになります。

Issue 作成 (10%) → Agent によるコーディング (0%) → コード diff の読み込み (80%) → Approve クリック (10%)

人間の作業時間の 80% が「コード diff の読み込み」に費やされていますが、これは非効率な活動です。レビュアーが diff の中で探している本質は、次の 2 点に集約されます。1 つ目は「Agent は正しく行ったか(機能の正確性)」、2 つ目は「Agent はやってはいけないことを行っていないか(権限逸脱行為)」です。前者にはビジネス意図の理解が、後者にはコード境界の理解が必要ですが、これらはいずれも Issue の自然言語記述の中に暗黙的に含まれており、形式化されていません。

agent-spec はこの配分を以下のように変えます。

コントラクト作成 (60%) → Agent によるコーディング (0%) → 要約説明(explain)の確認 (30%) → Approve クリック (10%)

人間の主たる作業は「コードを読むこと」から「コントラクトを書くこと」へと変化します。構造化された方法で、タスクの意図、技術的決定、ファイルの境界、受け入れ基準を定義するのです。これはより付加価値の高い活動です。あなたはコードの diff を見て「これは正しいのか?」と推測するのではなく、「何が正しいのか」を定義しているからです。

コードが完成した後、人間が目にするのは数百行の diff ではなく、コントラクトレベルの実行要約です。「コントラクトは何の意図を定義したか」「Agent はどのファイルを変更したか」「それは許可された範囲内か」「紐付けられたテストはすべてパスしたか」。これらすべてが「Yes」であれば、承認は 5 秒で完了する作業となります。

二、タスク・コントラクト:制御面の 4 要素

agent-spec の中核となる抽象概念はタスク・コントラクト(Task Contract)です。これは構造化されたタスク仕様書であり、4 つの要素で構成されます。

第 1 要素:Intent(意図)

これは曖昧な Issue のタイトルではなく、焦点を絞った説明文です。このタスクが何を行い、なぜそれを行い、どのような文脈で行うのかを記述します。意図は Agent に方向性を示すと同時に、最終的にレビュアーが「コントラクトの定義は正しいか」を判断する際の根拠となります。

## Intent
既存の auth モジュールにユーザー登録エンドポイントを追加する。
新規ユーザーはメールとパスワードで登録し、成功時に確認メールが送信される。
これはユーザーシステムの最初のステップである。

第 2 要素:Decisions(決定済み事項)

すでに確定済みの技術的選択です。「推奨」や「検討」ではなく、交渉の余地のない決定として記述します。Agent はこれに従って動作し、自ら技術方案を選択する必要はありません。これにより、Agent が最もバイアスを生み出しがちな工程である「技術選定」のズレを排除します。

## Decisions
- ルート:POST /api/v1/auth/register
- パスワードハッシュ:bcrypt、コストファクター=12
- 確認トークン:crypto.randomUUID()、DB 保存、有効期限 24 時間
- メール:既存の EmailService を使用し、新規作成しない

第 3 要素:Boundaries(境界)

Agent が変更してよいものと、してはならないものを定義します。パスレベルの境界は、agent-spec の BoundariesVerifier によって機械的に実行されます。Agent が Allowed Changes(許可された変更)リストにないファイルを変更した場合、検証は即座に失敗します。

## Boundaries
### Allowed Changes
- crates/api/src/auth/**
- crates/api/tests/auth/**
- migrations/
### Forbidden
- 新規依存関係の追加は禁止
- 既存のログインエンドポイントの変更は禁止

この設計の意義は、Agent の行動境界をプロンプト内の「他のファイルは変更しないでください」といった確率的な制約に頼らなくて済む点にあります。そのような制約は Agent が守ることもあれば守らないこともありますが、境界検証は確定的です。変更してはいけないファイルを変更すれば fail であり、グレーゾーンは存在しません。

第 4 要素:Completion Criteria(完了条件)

BDD(Behavior Driven Development)スタイルの受け入れシナリオであり、各シナリオは明示的に 1 つのテスト関数に紐付けられます。これは一般的な BDD とは異なります。一般的な BDD では自然言語をコードにマッピングするためのステップ定義レイヤーが必要ですが、agent-spec はこの中間層をスキップし、既存のテスト名に直接紐付けます。

## Completion Criteria
シナリオ:登録成功
  テスト:test_register_returns_201_for_new_user
  前提:メール "alice@example.com" のユーザーが存在しない
  操作:クライアントが登録リクエストを送信する
  結果:レスポンスステータスは 201 であるべき
シナリオ:重複メールの拒否
  テスト:test_register_rejects_duplicate_email
  前提:メール "alice@example.com" のユーザーが既に存在する
  操作:クライアントが同じメールで登録を試みる
  結果:レスポンスステータスは 409 であるべき

ここには重要な執筆原則があります。「例外パスのシナリオ数は、正常パス以上でなければならない」という原則です。上記の例で「登録成功で 201 を返す」というシナリオしか書かなかった場合、Agent は入力検証を全く行わない、重複メールを処理しない、パスワード強度をチェックしないといった実装も可能になってしまいます。なぜなら、これらの境界ケースがコントラクト上で受け入れ基準として定義されていないからです。

例外シナリオを 1 つ追加するごとに、Agent が見落としうる境界条件を 1 つカバーできます。コントラクトを書くというプロセス自体が、Agent を動かす前に処理すべきすべてのケースを考慮させる役割を果たします。

agent-spec の DSL(ドメイン固有言語)は、キーワードに日本語と英語の両方をサポートしています。

シナリオ:重複メールの拒否
 テスト:test_register_rejects_duplicate_email
 仮定 既にメール "alice@example.com" のユーザーが存在する
 時 クライアントが同一メールでの登録リクエストを送信する
 ならば レスポンスステータスは 409 である

これは単なる飾りの二言語対応ではなく、日本語圏のチームが母語でコントラクトを作成・閲覧できるようにし、仕様書(Spec)作成の認知的負荷を低減するためのものです。

三、7 ステップのワークフロー

コントラクトが作成された後のプロセスは明確なパイプラインであり、3 つの役割がそれぞれを担います。

Step 1:人間によるコントラクトの作成

agent-spec init --level task --lang en --name "User Registration"

テンプレートが生成されるので、人間が 4 要素を記入します。これがプロセス全体で最も人間の注意力を要する工程であり、作業時間の 60% がここに費やされます。

もちろん、ここを AI に補助させてコントラクトを作成させることも可能ですが、コントラクトの DSL は人間開発者にとって非常にレビューや修正がしやすい設計になっています。

Step 2:コントラクトの品質ゲート

agent-spec lint specs/user-registration.spec --min-score 0.7

コントラクトを Agent に渡す前に、コントラクト自体の品質をチェックします。agent-spec には 8 つのリンターが内蔵されており、曖昧な動詞(「処理する」「manage」など)、定量化されていない制約(「高速であること」ではなく「< 200ms」など)、機械的に検証不可能なアサーション(「画面は美しくあること」など)、不確実な表現(「約」「approximately」など)、テスト紐付けのないシナリオ、そして Agent の迎合(Sycophancy)を誘発する表現(「すべてのバグを見つけて」などの表現は、Agent に問題を作り出させてまでユーザーに迎合させる恐れがある)などを検出します。

品質スコアが閾値を下回る場合は、修正してから次に進みます。これが「審査ポイントの前方シフト」の第一歩です。Agent が手を付ける前に、コントラクト自体が高品質であることを保証します。

Step 3:Agent によるコントラクトの読み込みとコーディング

agent-spec contract specs/user-registration.spec

構造化されたプロンプト断片を出力します。Agent はコントラクトによる 3 重の制約を受けます。Decisions は「どう行うか」を、Boundaries は「何に触れてよいか」を、Completion Criteria は「どこまでできたら完了か」をそれぞれ伝えます。

Step 4:lifecycle 検証(自動リトライループ)

agent-spec lifecycle specs/user-registration.spec \
  --code . --change-scope worktree --format json

ここがプロセスの核心です。lifecycle は 4 層の検証を実行します。

L1 Structural Verifier(構造検証):コントラクトの Must Not 制約に対するコードパターンマッチングを行います。コントラクトで「.unwrap() の使用禁止」とされていれば、verifier は全ソースファイル内の .unwrap() 呼び出しをスキャンします。トークンコストゼロ、結果は確定的です。

L2 Boundaries Verifier(境界検証):Agent が実際に変更したファイルが、コントラクトの Allowed Changes 範囲内にあるかを確認します。パスの glob マッチングにより、トークンコストゼロ、結果は確定的です。

L3 Test Verifier(テスト検証):Completion Criteria に紐付けられたテストを実行します。各 Test: test_register_returns_201 が実際に実行されます。これが最も重要な層です。これは「Agent のコードがコントラクトで定義された受け入れ基準を満たしているか」という問いに直接答えます。

L4 AI Verifier(AI 検証):上記 3 層でカバーしきれないシナリオに対し、AI による分析を提供します(現在は stub モードと呼び出し元モードをサポート)。AI の判断は passfail ではなく uncertain であり、確実性を主張するものではなく、最終判断は人間に委ねられます。

lifecycle が失敗した場合、Agent は各失敗シナリオの原因と証拠が明記された構造化された failure_summary を受け取ります。Agent はこれに基づいてコードを修正し、lifecycle を再実行します。このリトライループは人間の介入なしに自動で行われます。

Code → lifecycle → FAIL (2/5) → failure_summary → 修正 → lifecycle → PASS (5/5) ✓

agent-spec の実行ログにはこの過程が記録され、「このコントラクトは 3 回目でパスした」といった履歴が残ります。

Step 5:guard ゲート

agent-spec guard --spec-dir specs --code . --change-scope staged

pre-commit フックまたは CI 検査として機能します。specs/ 以下の全 spec ファイルに対して lint と verify を実行します。1 つでも spec が通過しなければ、コミットはブロックされ、PR は失敗します。

CI によるガードの概念図

(本プロジェクトも agent-spec によるブートストラップを行っており、図は CI 失敗時のインターセプト例です)

Step 6:コントラクトの承認(Contract Acceptance)

agent-spec explain specs/user-registration.spec --format markdown

これが人間による最後の審査ポイントです。レビュアーが目にするのはコードの diff ではなく、コントラクトレベルの実行要約です。意図は何か、どのような決定がなされたか、どのファイルが変更されたか(それは許可範囲内か)、すべての受け入れ基準の合否状態はどうか、が示されます。

レビュアーが答えるべき質問は 2 つだけです。「コントラクトの定義は正しいか」「検証はすべて通過したか」。この 2 つが「Yes」であれば、承認します。

より多くのコンテキストが必要な場合は、実行履歴を確認できます。

agent-spec explain specs/user-registration.spec --history

「このタスクは Agent が 3 回試行して初めてパスした」という記録は、コントラクトの受け入れ基準が実際に機能していたことを示しています。

Step 7:stamp によるアーカイブ

agent-spec stamp specs/user-registration.spec --dry-run

Git コミットのトレーラー機能を用いて、コントラクトからコミットへのトレーサビリティチェーンを構築します。後日、「なぜこのコードはこのように書かれているのか」と問われた際、トレーラーからコントラクトを遡り、そこで完全な意図と決定を確認することができます。

四、4 つの評決、曖昧さゼロ

agent-spec の検証結果には、過不足なく 4 つの意味論のみが存在します。

pass:シナリオが確定的検証器または AI 検証器によって通過が確認された状態。

fail:シナリオが検証器によって具体的な違反を発見された状態。証拠(コード断片、テスト出力、パターンマッチ結果)が添付されます。

skip:どの検証器もこのシナリオをカバーしていない状態。これは通常、紐付けられたテストが存在しないか、セレクタの設定ミスなどを意味します。

uncertain:AI 検証器がコードを分析したが、確定的な判断を下せなかった状態。構造化された分析推論と信頼度が添付されます。

最も重要なルールは、skip ≠ pass です。検証されていないシナリオは、通過したシナリオとはみなされません。is_passing であるためには、failed == 0 かつ skipped == 0 かつ uncertain == 0 である必要があり、すべてのシナリオが確定的に pass と検証されて初めて、そのコントラクト全体が通過したとみなされます。

この 4 値論理は、多くのツールが採用する pass/fail の 2 値システムよりも誠実です。それは「確定的に検証できるものもあれば、確率的にしか判断できないもの、そして全くカバーできていないものもある」という現実を認めています。これら 3 つの状態を区別せず、すべてを「pass」に押し込めるのではなく、区別して明示することが、信頼構築の基礎となります。

五、AI Verifier:2 つのモード、1 つのプロトコル

4 層の検証ピラミッドのうち、上位 3 層(Structural、Boundaries、Test)は確定的です。トークンコストはゼロ、偽陰性もゼロです。しかし、競合状態、リソースリーク、隠れたセキュリティ脆弱性など、多くの品質次元はこの 3 層の範囲外にあります。

AI Verifier はこの空白を埋めますが、その設計哲学は従来の AI コードレビューツールとは異なります。確定的な判断ができるふりはしないのです。その出力は常に uncertain であり、構造化された分析と信頼度を添付します。最終判断は人間(またはより高次の検証システム)が下します。

agent-spec は 2 つの AI 検証モードをサポートしています。

Caller モード:呼び出し元の Agent(例:Claude Code)自身が AI 検証を行います。これはツールファーストなシナリオにおけるデフォルトの経路です。lifecycle が機械的検証を実行した後、未カバーのシナリオを構造化された AiRequest として生成し、.agent-spec/pending-ai-requests.json に書き出します。呼び出し元 Agent(Claude Code、Codex など)がこのリクエストを読み取り、自らの推論能力でコードを分析し、AiDecision を生成。resolve-ai コマンドを通じて最終レポートにマージします。

# Step 1: lifecycle が skip されたシナリオを発見し、AI リクエストを生成
agent-spec lifecycle specs/task.spec --code . --ai-mode caller
# Step 2: Agent がリクエストを読み取り、コードを分析して意思決定ファイルを生成
# Step 3: AI の意思決定を最終レポートにマージ
agent-spec resolve-ai specs/task.spec --decisions decisions.json

このモードでは、AI 検証の出力は自動化プロセスではなく人間へと流れます。Agent のリトライループは確定的な信号(テストの合否)に基づき、AI の分析結果は Contract Acceptance の段階で人間が判断するために残されます。

Backend モード:Rust API を介して独立した AI バックエンドを注入するモードです。Symphony のようなオーケストレーターが、異なるモデルを用いて独立した検証を行うのに適しています。ホストプログラムが AiBackend トレイトを実装し、spec-gateway に注入することで、agent-spec 内部で AI 検証が完結します。

let report = gw.verify_with_ai_backend(code, Arc::new(my_backend)).unwrap();

どちらのモードも、同一のデータ構造(AiRequest / AiDecision)を共有しており、agent-spec はプロバイダー非依存(provider-agnostic)を維持しています。

六、jj との連携:必須ではなくオプションの加速装置として

本シリーズ第 3 回で詳しく分析した jj(Jujutsu)の Agent 親和性の高い特性、すなわち「すべてがコミット(ステージングエリアという儀礼がない)」「stable change ID(amend を跨いでも不変)」「conflicts as data(rebase をブロックしない)」「operation log(アトムなロールバック)」について触れました。

agent-spec と jj の接点は自然なものですが、その設計原則は「jj は必須の依存関係ではなく、オプションの加速装置である」という点にあります。すべてのコア機能は、純粋な Git 環境下でも完全に動作します。

Change Scope:統一された変更検出

# Git 環境
agent-spec lifecycle specs/task.spec --code . --change-scope staged
agent-spec lifecycle specs/task.spec --code . --change-scope worktree
# jj 環境
agent-spec lifecycle specs/task.spec --code . --change-scope jj

Git 環境では、agent-spec は完全な変更ファイルリストを取得するために 3 つのコマンド(staged + unstaged + untracked)を必要とします。一方、jj であれば jj diff --name-only の 1 コマンドだけで済みます。jj にはステージングエリアの区別がないためです。

BoundariesVerifier はファイルリストがどこから来たかは気にしません。「これらの変更ファイルがすべてコントラクトの Allowed Changes 範囲内にあるか」のみをチェックします。

Stamp:stable change ID による追跡

jj 環境下では、stamp コマンドは追加で Spec-Change トレーラーを出力します。

Spec-Name: ユーザー登録 API
Spec-Passing: true
Spec-Summary: 4/4 passed
Spec-Change: kkmpptqz

kkmpptqz は jj の change ID であり、amend を跨いでも安定しています。Agent が後からこのコミットを修正(コードのフォーマット、タイプミスの修正など)しても、change ID は変わりません。これにより、コントラクトから変更への追跡チェーンが途切れることがありません。Git のコミットハッシュは amend すると変化してしまうため、この追跡チェーンは amend 後に無効になってしまいます。

Run History:実行間 diff

agent-spec explain specs/task.spec --history

2 回の lifecycle 実行間の run log 両方に jj operation ID が含まれている場合、agent-spec は jj op diff を呼び出し、2 回の実行の間で Agent がどのファイルを変更したかを示します。これはデバッグ時に非常に価値のある「前回は fail したが、今回は pass した。その間、Agent は一体何を変更したのか?」という問いに答えます。

設定ではなく検出

agent-spec は .jj/ ディレクトリの存在を自動検出します。あれば jj の機能を利用し、なければ Git にフォールバックします。ユーザーは設定ファイルで「jj を使っています」と宣言する必要はありません。colocated リポジトリ(.git/.jj/ が併存)の場合、agent-spec は jj を優先的に使用します。

すべての jj との対話は std::process::Command を介して jj CLI を呼び出す形で行われ、jj-lib にはリンクしません。これは Git との統合方法と完全に一致しており、ライブラリをリンクするのではなくコマンドを呼び出す形式です。将来的に他の Agent-Native VCS が登場しても、新しい検出ブランチを追加するだけで対応可能です。

七、コンポーザビリティ:agent-spec は全てを解決するものではない

これは正直に議論すべき境界線です。

agent-spec が保証するのは「コントラクトへの適合性」です。コードがコントラクトで定義された受け入れ基準を満たしているかどうかです。しかし「コードの品質」とは、適合性よりもはるかに広範な概念です。すべての受け入れ基準をパスしていても、競合状態、リソースリーク、不適切な抽象化レベル、あるいはチームのコーディングスタイルへの不適合などがあり得ます。

これは agent-spec の設計上の欠陥ではなく、意識的な境界選択です。agent-spec が契約の検証とコード品質のすべての次元を同時に解決しようとすれば、それは「何でもありだが、どれも深くない」巨大ツールになってしまいます。

agent-spec の位置づけはオーケストレーターです。これはフレームワークを提供し、他のツールの出力をコントラクトの受け入れ基準へと変換します。コード品質の向上は、組み合わせ(コンポジション)によって実現されます。

品質ルールを Spec レイヤーにエンコードする

多くのコード品質ルールは形式化可能です。

spec: project
name: "プロジェクトルール"
---
## Constraints
### Must NOT
- `.unwrap()` と `.expect()` の使用禁止
- `panic!` および `todo!` の使用禁止
- 金額処理への `f32` または `f64` の使用禁止

project.spec の制約は、すべての子 task spec に継承されます。agent-spec の StructuralVerifier は、その中のコードパターンを機械的に検出します。追加の lint ツールは不要で、agent-spec 自身が「ソースコード内に .unwrap() が存在するか」をチェックできます。

外部ツールを Completion Criteria に統合する

より強力な組み合わせ方は、clippy、カバレッジツール、セキュリティスキャナなどの既存ツールの出力を受け入れ基準に変えることです。

シナリオ:clippy strict チェックに合格
 テスト:test_clippy_passes_with_deny_warnings
 前提:実装が完了している
 操作:`cargo clippy -- -D warnings` を実行
 結果:終了コードは 0 であるべき
シナリオ:閾値以上のテストカバレッジ
 テスト:test_coverage_above_80_percent
 前提:実装が完了している
 操作:新規コードに対してカバレッジツールを実行
 結果:行カバレッジは 80% 以上であるべき

これにより、Agent は機能テストをパスさせるだけでなく、clippy をパスさせ、カバレッジ基準を満たす必要が出てきます。agent-spec はこれらのツールを代替するのではなく、それらに対して「基準を満たしているか」を判断する統一フレームワークを提供します。

AI Verifier による残存次元のカバー

機械的ツールでは検出できない次元(競合状態、設計の妥当性、セキュリティ脆弱性の推論)については、AI Verifier がヒューリスティックなチェックを行います。その出力は判決ではなく、人間への補足情報となる uncertain です。

これらを組み合わせると、project.spec が一般ルール(L0/L1 制約)をエンコードし、task spec がタスク固有の受け入れ基準(L2 criteria)を定義し、Completion Criteria が外部ツールの出力を統合し、AI Verifier が残りの確率的次元をカバーします。各工程で最も得意なツールを使用し、agent-spec がその組み合わせフレームワークを提供します。

八、3 層の Spec 継承

agent-spec は 3 層の Spec 継承をサポートしています。

org.spec → project.spec → task.spec

org.spec(組織レベル):プロジェクト横断的なセキュリティポリシーやコーディング標準を定義します。例:「認証情報のハードコーディング禁止」「すべてのユーザー入力は検証必須」「認証関連コードにはセキュリティテスト必須」。これらのルールは組織内の全プロジェクトに適用されます。

project.spec(プロジェクトレベル):プロジェクトの技術スタックの決定事項や規約を定義します。例:「PostgreSQL を使用」「すべての API は構造化されたエラーを返す」「thiserror を使用してエラータイプを統一」。これらのルールはプロジェクト内の全タスクに適用されます。

task.spec(タスクレベル):個々のタスクの意図、境界、受け入れ基準を定義します。これが Agent が直接消費するコントラクトです。

制約と決定事項は自動的に下位へ継承されます。task spec 内の Agent は org.spec や project.spec の存在を意識する必要がありません。Agent が見るコントラクトには、すでにすべての祖先レイヤーの制約がマージ済みです。しかし人間側は階層管理が可能です。セキュリティチームが org.spec を維持し、プロジェクトリードが project.spec を維持し、開発者が task spec を作成します。役割を分担し、機械的にマージします。

九、Skills:Agent にワークフローを教える

agent-spec は単なる CLI ツールではありません。Agent に自身の使い方を教える必要があります。それが Skills の役割です。

インストール

npx skills add ZhangHanDong/agent-spec

1 行のコマンドで、agent-spec の Skills をプロジェクトにインストールします。

2 つの Skill の役割分担

agent-spec-tool-first はデフォルトのワークフロー用 Skill です。これは Agent に 7 ステップのワークフロー全体を教えます。いつコントラクトを読み、いつ lifecycle を実行し、失敗時にどう failure_summary を読んで修正し、いつ人間のために explain を生成し、いつ stamp を実行するかです。また、重要な指針として「lifecycle 失敗後はコードを修正し、spec ファイルを変更してはならない」というルールを含んでいます。これは Agent が「賢く」验收基準を書き換えて検証をパスさせようとするのを防ぐためです。

agent-spec-authoring は Spec 作成用 Skill です。これは Agent に高品質なコントラクトの作成方法を教えます。4 要素の構造、二言語キーワード、テスト紐付けの形式、step table の構文、「例外パス≧正常パス」という原則などです。人間が Agent にコントラクト作成を手伝わせる際、この Skill によって Agent の生成する spec がベストプラクティスに準拠することが保証されます。

マルチ Agent サポート

Skills は Claude Code 専用ではありません。agent-spec プロジェクトには Codex 用の AGENTS.md、Cursor 用の .cursorrules、Aider 用の .aider.conf.yml も含まれています。これらのファイルは Claude Code 用 Skill よりも簡素ですが、中核となるコマンドリファレンスとワークフロー手順が含まれており、異なる Agent ツールでも agent-spec と連携して動作可能です。

agent-spec の設計原則は「CLI ファースト、エージェント・アグノスティック(Agent-agnostic)」です。中核機能は CLI コマンドとして公開されており、シェルコマンドを呼び出せるあらゆる Agent が利用可能です。Skill ファイルはアダプターレイヤーであり、CLI が共通レイヤーとなります。

十、本物のセルフホスティング・ループ

agent-spec は自分自身で自分を検証します。プロジェクトの specs/ ディレクトリ内には project.spec があり、agent-spec 自身の開発制約を定義しています。

spec: project
name: "agent-spec プロジェクトルール"
---
## Constraints
### Must
- 公開 CLI および gateway の動作には回帰テスト必須
- DSL 構文の変更時は AST、解析出力、回帰テストの同時更新必須
- 検証結果は pass、fail、skip、uncertain を区別すること
...

すべてのコミットは agent-spec guard によってチェックされます。新機能の開発にはすべて対応する task spec が存在します。specs/roadmap/ 以下には Phase 0 から Phase 6 までの完全なロードマップ spec があり、これら自体が agent-spec 形式のタスク・コントラクトです。

これは見せかけではなく、最良のテストです。agent-spec が自らの開発を管理できないのであれば、他プロジェクトを管理する資格などありません。

十一、現状と正直な境界線

現在、agent-spec が最も力を発揮するのは、以下の方法でコントラクトがチェック可能なシナリオです。

Completion Criteria から選択された明示的なテスト、StructuralVerifier によるコードパターンマッチング、BoundariesVerifier によるパス glob 検査、そして明示的またはステージング済み変更セットに対する境界検証です。

一方、現在の制限も明確です。

TestVerifier は Rust/Cargo 専用です(cargo test を経由して実行)。Rust 以外のプロジェクトでも agent-spec のコントラクト機能と境界機能は利用可能ですが、テストの実行にはカスタム拡張が必要です。

AI Verifier の真のバックエンドはまだ接続されていません(stub モードと呼び出し元モードは利用可能)。対立的なマルチ Agent 検証(Bug Finder / Skeptic / Referee による三者対戦)は --adversarial フラグの予約機能であり、実装は真の AI バックエンド接続後に予定されています。

Resolver は現在、Constraints と Decisions のみを継承し、Boundaries は継承しません。project.spec で Forbidden: tests/golden/** が定義されていても、task spec には自動的に継承されません。

品質スコアは 3 つの次元(決定論的度、テスト容易性、カバレッジ)のみを測定し、曖昧な動詞、定量化不足、迎合的表現などの lint 警告は反映されません。これらの警告は診断リストには表示されますが、数値スコアには影響しません。

これらの制限は既知であり、文書化され、明確な改善パスが存在します。これらは agent-spec が現状でも Rust プロジェクトに真の価値を提供することを妨げるものではありません。

十二、AI コーディングチームの協働モデル

複数の開発者、複数の AI Agent が同時に作業するチームにおいて、協働の核心的な課題はもはや「コードの競合」ではありません。jj や Git でファイルレベルのマージは処理可能です。真の課題は「意図の競合」です。2 つの Agent が各自のタスクを完了し、コードはコンパイルされ、テストもパスしているにもかかわらず、マージすると挙動が一致しないことがあります。システムに対する理解が同じ土俵にないためです。

従来のチームはコードレビューでこの問題を発見していました。経験豊富なレビュアーが 2 つの PR の diff を見て、頭の中でマージ後の挙動をシミュレートし、矛盾を発見します。しかし、PR の数が 1 日 5 件から 50 件に増えた場合、人間の脳によるクロスチェックはもはや成立しません。

agent-spec の 3 層 Spec 継承は、ここに構造化された調整メカニズムを提供します。

org.spec と project.spec はチームのコンセンサス・アンカー

AI コーディングチームにおいて、人間の第一の役割はコードを書くことでも、PR を 1 つずつレビューすることでもなく、Spec 階層の維持です。テックリードは project.spec を維持し、プロジェクトの技術スタックの決定、API 規約、エラー処理规范を定義します。セキュリティチームは org.spec を維持し、侵してはならないセキュリティの底线を定義します。これらのファイルはチーム全員の Agent に対する共通の制約です。どの Agent がどのタスクを実行していようとも、継承される project.spec の制約は同一です。

これはつまり、2 つの Agent が並行開発を行う際、技術選定で齟齬が生じることはありません(bcrypt を使うか argon2 を使うかは project.spec で決定済み)。API スタイルに不一致が生じることもありません(エラーコード形式は project.spec で定義済み)。セキュリティルールを侵すこともありません(org.spec の制約が機械的に実行されるため)。Spec 階層は「チームの合意」を、人間の脳内の暗黙知から、機械的に実行可能な明示的制約へと変換します。

タスク・コントラクトはタスクの分離境界

各 task spec の Boundaries 条項は、Agent が変更可能なファイル範囲を定義します。チームが agent-spec でタスクを割り当てる際、自然なプラクティスとして、異なるタスクの Allowed Changes が重複しないようにします。あるいは、重複が必須の場合、コントラクト内で共有領域の調整戦略を明示します。

agent-spec の lint --cross-check はこの衝突を検出できます。task-A の Allowed Changes と task-B の Allowed Changes に重複パスがある場合、cross-check は警告を出します。これは開発をブロックするものではありません(2 つのタスクが同一ファイルを変更する必要がある場合もあるため)が、2 つの PR がマージされるまで潜在的な並行競合に気づけないのではなく、タスク割り当ての段階でチームがそれを認識できるようにします。

典型的なチームの日常

4 名体制の AI コーディングチームの日常を想像してみてください。

午前中、テックリードが 30 分かけて project.spec のレビューと更新を行います。先週チームで構造化ログの使用を統一すると決定した場合、この決定を project.spec の Decisions 条項に記述します。これにより、今後すべての Agent がこの規約に従うようになります。

次にテックリードは 3 つの task spec を作成し、3 人の開発者に割り当てます。各 task spec には明確な意図、技術的決定(project.spec からの継承+タスク固有のもの)、ファイル境界(重複しない、あるいは意識的な重複)、そして 4〜6 の受け入れシナリオ(例外パスを含む)が定義されます。

3 人の開発者は各自の AI Agent(Claude Code、Codex、Cursor などのいずれでも可。agent-spec は問いません)を起動します。Agent はコントラクトを読み、Boundaries 内でコーディングし、lifecycle 検証を実行します。失敗すれば自動リトライします。開発者は Agent の作業中に他のことができます。次のタスクのコントラクト作成、前タスクの explain 出力のレビュー、あるいは project.spec の更新などです。

Agent が完了すると PR が作成されます。CI 内の guard が自動的に機械的検証を実行します。PR コメントには explain によるコントラクト要約が自動添付されます。テックリードは Contract Acceptance を行いますが、3 つの PR のコード diff(合計 1500 行に及ぶことも)を読む必要はありません。3 つの explain 要約(各 30 行程度)を見て、コントラクトの定義が正しいか、検証がすべて通過したかを判断するだけです。

3 つの PR すべてが Contract Acceptance を通過し、guard の cross-check で境界の競合が報告されていなければ、マージ可能です。このプロセス全体で、テックリードのレビュー時間は「1500 行の diff を読む」ことから「90 行のコントラクト要約を見る」ことに変わります。レビュー時間は約 80% 削減され、かつ各 PR が確定的な 4 層の検証を通過しているため、実際の品質保証は以前よりも強固になります。

Agent もまた貢献者である場合

オープンソースのシナリオでは、さらに興味深い状況が生まれます。外部のコントリビューターが AI Agent を直接使ってコードを貢献してくる場合です。ここでメンテナーは信頼という問題に直面します。その貢献者を知らず、その Agent がどのようなプロンプトを使い、何回の修正を経て、どのようなプロセスをたどったのかも分かりません。

agent-spec がここで提供するのは「信頼」ではなく「検証可能性」です。メンテナーは貢献者やその Agent を信頼する必要はありません。確認すべきは 2 点のみです。1 点は「コントラクトで定義された意図と境界が妥当か(これは人間が即座に判断可能)」、もう 1 点は「lifecycle のすべての確定的チェックが通過したか(これは機械が検証済み)」です。信頼の対象が「人」から「プロセス」へと移行します。コードが人間によって書かれたか AI によって書かれたかにかかわらず、同一の検証パイプラインを通過していれば、それがマージ可能な十分条件となります。

これが、agent-spec がコントリビューションガイドで「コントラクトの品質はコードの品質と同等に重要」と強調する理由です。外部コントリビューターが、意図が明確で、決定が明瞭で、例外パスが十分で、すべてのシナリオにテストが紐付けられた、非常によく書かれたコントラクトを提出してきたとします。そのコードスタイルがチームのそれと一致していなくても、そのコントリビューションは安全に受け入れ可能です。なぜなら、その正しさはレビュアーの主観的判断ではなく、コントラクトと検証パイプラインによって保証されているからです。

結び:より良いコードレビューではなく、異なるコードレビューへ

本シリーズの中核となる主張に戻りましょう。

第 2 回で述べたように、Agent 時代のコードレビューとは「人間がより多くの diff を読む」ことではなく、「人間が意図を定義し、機械が適合性を検証する」ことであるべきです。

第 3 回で述べたように、Agent 時代のバージョン管理とは「Agent に git add / git commit を学ばせる」ことではなく、「VCS が Agent の作業プロセスを自動的にキャプチャする」ことであるべきです。

本稿ではその具体的な実装を示しました。agent-spec は「より優れたコードレビューツール」ではなく、異なるパラダイムです。これは審査の対象を「コード」から「契約」へ移し、審査のタイミングを「コーディング後」から「コーディング前」へ移し、検証の実行者を「人間」から「機械」へと変えるものです。

人間の役割が消えたのではありません。アップグレードされたのです。「コードを読んでバグを探す」ことから「何が正しいのかを定義する」ことへ。これはより付加価値の高い活動であり、よりスケールする活動です。優れたコントラクトは無数の Agent によって実行・検証可能ですが、優れたレビュアーが 1 日に読める diff の数には限りがあるからです。

# あなたの最初のコントラクトを始めよう
cargo install agent-spec
agent-spec init --level task --name "my-first-task"

プロジェクトアドレス:github.com/ZhangHanDong/agent-spec[2]

参考資料

[1] agent-spec: https://github.com/ZhangHanDong/agent-spec

[2] github.com/ZhangHanDong/agent-spec: https://github.com/ZhangHanDong/agent-spec


分享網址
AINews·AI 新聞聚合平台
© 2026 AINews. All rights reserved.