AIエージェントは、どんな開発者よりも速くコードを書くことができます。しかし、多くのチームでは、フィードバックループがそのペースに追いついていません。エージェントがコードを生成し、CIにプッシュすると、数分後に完全なパイプライン実行で、単純なlintエラーや失敗したユニットテストが検出されます。その頃には、エージェントは別の作業に移っています。動作する状態に戻すには、コンテキストをゼロから再構築し、本来出荷されるべきではなかったものを修正するためにトークンを消費することになります。

Chunk sidecarsは、失敗がCIに到達する前にキャッチすることで、そのループを短絡します。サイドカーはCI環境をミラーリングする軽量なLinuxマイクロVMで、テストスイートを数秒で実行し、単純なエラーをエージェント自身のワークフロー内で修正できるようにします。これにより、パイプラインは本来の目的である統合とデプロイメント作業のために確保されます。

5分で最初のマイクロビルドを実行するでは、サイドカーをセットアップし、chunk validateで手動で検証プロセスをトリガーする方法を学びました。このチュートリアルでは、Chunkのエージェントフックが同じ検証を自動的に、エージェントのワークフローの適切なタイミングで、手動プロンプトなしでトリガーする方法を見ていきます。

エージェントフックによる検証ステップの自動化

エージェントフックは、エージェントがツール呼び出し前やターンの終了時など、ループ内の固定チェックポイントで実行するスクリプトです。これらを使用して、リンター、フォーマッター、テストスイートなどのカスタム自動コマンドを接続し、これらのイベントが発生するたびに自動的に実行されるようにできます。

Chunkサイドカーはフックを使用して、すべてのgitコミット時に高速なローカルテストゲートを接続し、エージェントが作業を完了しようとする直前に環境全体の検証を行います。これにより、エージェントは自身の内部ループ内で小さな失敗をキャッチして修正できます。

マイクロビルドチュートリアルでは、Chunk CLIをインストールし、サンプルプロジェクトをクローンし、chunk auth set circlecichunk initを実行してワークスペースをセットアップしました。このプロセスは、コアサイドカー環境を処理するための.chunk/config.jsonを作成しただけでなく、すでに2つのフックが配線された.claude/settings.jsonも生成しました:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "cmd=$(jq -r '.tool_input.command // empty'); case \"$cmd\" in \"git commit\"*|*\" git commit\"*) cd ${CLAUDE_PROJECT_DIR:-.} && { CI=true npm test; } || exit 2 ;; esac",
            "timeout": 300
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "chunk validate",
            "timeout": 330
          }
        ]
      }
    ]
  }
}

各フックが発火したときに何が起こるかを見てみましょう。

2つのフックの役割

How Chunk Sidecar hooks work diagram

Chunkのエージェントフックは、エージェントの内部ループを制御するための明確なチェックポイントを確立します。

コミットゲート(PreToolUse)。このフックは、エージェントがツールを実行する直前にトリガーされます。すべてのBash呼び出しにマッチし、コマンドがgit commitかどうかを確認し、そうであればまずローカルでテストスイートを実行します。テストが失敗した場合、フックはexit 2ステータスを返し、コミットをブロックして出力をエージェントに返します。フィードバックは即時で、エージェントは既存のコンテキストを維持したまま作業を継続できます。

フィニッシュゲート(Stop)。エージェントがターンを終了する準備ができたとき、Stopフックが介入します。chunk validateコマンドを実行し、エージェントの未コミットの作業ツリーをリモートサイドカーに同期し、本番CI環境を完全にミラーリングするクリーンなLinuxマイクロVM内でテストスイート全体を実行します。検証テストが失敗した場合、フックはコード2で終了し、エージェントのターンを開いたままにして、ミスを修正するもう一度の機会を与えます。この自動リトライループは、.chunk/config.jsonstopHook MaxAttempts設定によって安全に制限されます(デフォルトは3回)。

これら2つを組み合わせることで、2つのチェックポイントが配置されます。エージェントがコミットするときの高速なローカルチェックと、終了が許可される前のサイドカーでのCIグレードの検証です。

動作を確認する

これらのゲートがどのように動作するか見てみましょう。エージェントに基本的なタスクを与えるとします。長いカードタイトルを管理するためのtruncate(text, maxLength)というクイックテキストヘルパー関数を追加する、というものです。

Prompting Claude Code CLI with a task that will trigger Chunk hooks and sidecars

リポジトリのテスト仕様src/utils/truncate.test.jsは、...の省略記号がmaxLengthにカウントされることを明示的に定めており、最終的な文字列がその制限を超えてはならないことを意味します。

エージェントの最初の試行では、文字数を数える際に省略記号を無視します:

export function truncate(text, maxLength) {
  if (text.length <= maxLength) return text;
  return text.slice(0, maxLength) + '...';
}

このバージョンでtruncate(‘hello world’, 8)を呼び出すと‘hello wo…’が返され、11文字になります。仕様では出力が8を超えてはならないとされています。

次に起こることは、エージェントがコードをどのように配信しようとするかによって異なります。フックが高速なローカルチェックと分離されたマイクロVMチェックの間で作業を分割するため、エージェントのパスに応じてループの異なるポイントでエラーをキャッチします。

パスA:エージェントがコミットする場合

エージェントがこの欠陥のあるコードを書き、すぐに変更をステージングしてコミットしようとする場合、ローカルチェックが介入します。

$ git add src/utils/truncate.js && git commit -m "Add truncate helper"

コミットゲートはコミットが実行される前にPreToolUseフックを発火させます。ツール呼び出しからコマンドを抽出し、git commitであることを確認し、まずローカルでテストを実行します:

Full output from PreToolUse hook wired by CircleCI Chunk agent into Claude Code

PreToolUseフックでのexit 2はツール呼び出しを完全にブロックします。Claude Codeはこれを「フックエラー」として表示しますが、コミットは実行されず、出力はエージェントに戻されます。エージェントは失敗を読み取り、スライスをslice(0, maxLength - 3)に修正し、再びコミットします。今度はテストが通り、壊れたバージョンはgit履歴に到達しません。

パスB:エージェントがターンを終了しようとする場合

ローカルチェックはロジックエラーを即座にキャッチしますが、2つの制限があります。OS固有のバグを見逃す可能性があり、エージェントがコミットコマンドを実行せずにターンをユーザーに返そうとした場合は発火しません。ここでストップフックとChunkサイドカーが内部ループを完成させます。

エージェントが同じ欠陥のあるコードを書き、コミットせずにターンを終了しようとした場合、Stopフックが発火し、chunk validateを実行します。これによりサイドカーが起動し、未コミットのファイルを同期し、リモート環境で完全なテストスイートを実行します:

[chunk validate]: No active sidecar found, creating a new sandbox...
✓ Created sandbox (72fca210)
  Synchronising local → remote: ./workspace/circleci-demo-javascript-react-app … ✓ Synced
  running on sidecar: test  →  CI=true npm test

FAIL src/utils/truncate.test.js
  ● truncate › counts the ellipsis toward the limit when truncating
      Expected: "hello..."
      Received: "hello wo..."
  ● truncate › never returns a string longer than the limit
      Expected: "he..."
      Received: "hello..."

Tests: 2 failed, 3 passed, 5 total

再びexit 2です。エージェントはサイドカーの出力を読み、同じslice(0, maxLength - 3)修正を適用し、chunk validateを再実行します:5 of 5 green。これでようやくターンを終了できます。

Chunk Sidecar successfully running tests in Linux microVM

実際には、この2つのゲートはしばしば連続して動作します。エージェントがコードを書き、コミットを試み、ローカルチェックが構文エラーや失敗したテストをキャッチします。それを修正してコミットに成功します。次にターンが終了するとき、サイドカーがローカル環境が見逃したものをキャッチします。Linuxで異なる動作をする依存関係や、キャッシュされたnode_modulesなしのクリーンインストールでのみ失敗するテストです。エージェントはそのフィードバックも受け取り、ターンが閉じる前に修正します。

CIパイプラインは引き続き独自の統合テスト、セキュリティスキャン、その他設定したものをすべて実行します。違いは、基本的なユニットテストに失敗するようなコードに対してそれらのサイクルを無駄にしないことです。

他のエージェントでのChunkサイドカーフックの使用

すべてのエージェントには独自の設定ファイルとイベントがあります。Claude Codeは.claude/settings.json、Cursorは.cursor/hooks.json、Codexは.codex/hooks.jsonを使用し、それぞれイベント名が異なります。

しかし良いニュースは、chunk validateが単なるプレーンなCLIコマンドであることです。chunk initはClaude Codeに自動的にフックしますが、このワークフローを他のエージェントに簡単にコピー&ペーストできます。特定のエージェントのpre-commitフックまたはstopフックをchunk validateに向けるだけです。サイドカーはどのエージェントがトリガーしたかに関係なく同じように動作します。

実際のプロジェクトで試す

エージェントとCIパイプラインの間のフィードバックループがボトルネックになる必要はありません。2つのフックとサイドカーにより、基本的な失敗はマシンを出る前にキャッチされ、パイプラインはより難しいチェックの準備ができたコードのみを受け取ります。セットアップは1回のchunk initコマンドで完了し、マイクロビルドはすべてのCircleCIプランで完全に無料です。

無料アカウントを作成し、フックを配線して、壊れたコードをCIにプッシュするのをやめましょう。