Claude CodeのAgent Teams実験機能でlead+複数teammate構成を組んでいて、teammateが手すきになる前にハンドオフや追加タスクを差し込みたい人向け
lead 1人 + 役割別teammate 数人でチームを組んで作業させているとき、片方のteammateが先に手すきになるタイミングで、もう片方の進捗を見て手伝わせたい場合や、合計コストが上限を超えたらチーム全体を止めたい場合に、settings.jsonにTeammateIdleフックを書いて自前スクリプトを呼ばせる
Claude Codeの実験機能「Agent Teams」では、リーダー役の lead と、複数の作業担当 teammate がチームで動きます。TeammateIdle は、その teammate のうち1人が「もう次にやることが無い」と判断して手すきモードに入る直前に、こちらが用意した自前スクリプトを割り込ませて呼んでもらえるフックです。
普通に放っておくと teammate は idle に落ちて、次の lead からの指示を待つだけになります。でも実際のチームワークだと「片方が暇になったら、まだ詰まってる相方を手伝う」みたいな動きが欲しい。TeammateIdle はその「手すき直前の差し込み」の口を開けるための仕掛けです。
噛み砕くと
会社のチーム作業をイメージしてもらえると早いです。フロント担当とバック担当がペアで動いていて、フロント担当が自分の分を片付けた瞬間に「上がりまーす」と席を立とうとする。TeammateIdle は、その「席を立つ直前」で肩を叩いて「待って、相方まだ詰まってるよ。ヘルプ入れる?」と引き止める係です。
引き止め方は2段階あります。「席を立たせない」と「もうチーム全体終わり」の2つを、フックの返し方で切り替えられる作りになっています。
大事な前提:実験機能なので、起動時の設定値を立てないと存在自体が無い
このフックは Agent Teams という実験機能に紐づいています。普通にClaude Codeを入れただけでは teammate も lead も出てこないし、TeammateIdle の出番もありません。
有効化に必要なのは下記の2点です。
- Claude Code v2.1.32 以降
- 起動時の設定値
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1を立てた状態で起動
この前提が崩れていると、設定ファイルに TeammateIdle を書いても無視されます。「動かない」と思ったらまずここを疑ってください。
「lead + frontend teammate + backend teammate の3人チーム」を例に、実際の手順を見る
料理レシピサイトの開発を、lead 1人 + frontend担当 teammate + backend担当 teammate の3人でやらせる、という想定で動かしてみます。
ステップ1: Agent Teams を有効にして起動する
まず Claude Code を実験用の設定値付きで立ち上げます。
$ CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 claude
このコマンドの前半は「この起動だけこの設定値を立てる」という書き方です。= の後に 1 を入れて、その後にスペースを開けて claude 本体を呼ぶ形。
ステップ2: チーム構成と TeammateIdle フックを設定ファイルに書く
プロジェクトの .claude/settings.json に次のように書きます。これは Claude Code がプロジェクトごとの設定をまとめておくファイルです。
{
"hooks": {
"TeammateIdle": [
{
"type": "command",
"command": "./scripts/check-busy-mates.sh"
}
]
}
}
注意点として、TeammateIdle は matcher 欄を持ちません。frontend担当だけ・backend担当だけ、みたいに役割で絞り込むことはできない仕様です。matcher を書いても黙って無視されます。
ステップ3: 呼ばれるスクリプト本体を書く
scripts/check-busy-mates.sh はこんな感じになります。
#!/bin/bash
# backend担当の進捗ファイルを覗いて、まだ未完了タスクが残っていれば idle を阻止
if [ -f ".team-status/backend-pending" ] && [ -s ".team-status/backend-pending" ]; then
echo "Backend teammate still busy. Pick up the API tests next." >&2
exit 2
fi
exit 0
ポイントは2行目の exit 2。これが「idle に入らせないで、teammate に作業を続けさせろ」のサインです。echo でエラーメッセージ用の出力に流した文字が、そのまま teammate への次の指示として渡されます。
ステップ4: 実際にチームを動かす
lead に「3人で料理レシピサイトを作って」と指示すると、lead が frontend担当には「画面側を組んで」、backend担当には「APIとデータベースを組んで」と振り分けます。frontend担当が画面を組み終えると、idle に落ちようとした瞬間に check-busy-mates.sh が呼ばれます。
ステップ5: backend担当がまだ作業中なら frontend担当を引き止める
backend担当の進捗ファイルに「未完了」が残っていれば、スクリプトは exit 2 を返します。すると frontend担当の idle はキャンセルされ、メッセージで指示された「APIのテスト書き」を新しいタスクとして続行します。ここで初心者がやりがちな勘違いがありますが、exit 2 は「セッション全体を止める」ではなくて、あくまで「その teammate を idle にさせない」だけです。
ステップ6: 両方の作業が終わったら素直に idle に落とす
backend担当も画面側も全部終わると、進捗ファイルが空になります。次に TeammateIdle が呼ばれた時はスクリプトが exit 0 を返して、teammate はめでたく idle に入ります。lead は両者の結果を統合して最終レポートを返す、という流れです。
つまり TeammateIdle は何をしてくれるのか
- やってくれる: teammate が idle に入る直前で自前スクリプトを呼んで、idle を中止させて新しいタスクを差し込める。
continue: falseを返せばチーム全体をその場で停止もできる - やってくれない: 役割ごとの絞り込み。frontend担当だけ・backend担当だけと指定することはできず、全 teammate の idle で必ず発火する。フィルタしたいならスクリプト側で teammate を見分けて分岐させる必要がある
- 意味が薄い場面: 1人 teammate しか立てていない構成、または lead だけで完結する作業。lead 本体が idle になる場合は
Stopフック側が発火するので、TeammateIdleは呼ばれない
使いどころ3シナリオ(具体題材で再現)
シナリオ1: 料理レシピサイトを3人チームで作っていて、frontend担当を遊ばせたくないとき
frontend担当が画面を組み終えてもbackend担当はまだAPI設計で詰まっている。普通だとfrontend担当はそのまま idle に落ちて待機になります。TeammateIdle でbackend側の進捗ファイルを見にいって、未完了が残ってればfrontend担当に「APIモックの仮データを書いて」と差し込む。実質ペアプロのフォロー入れ替えが自動化されます。
シナリオ2: 家計簿アプリのテストを4人チームで分担していて、1日の合計コストに上限を設けたいとき
テスト担当4人で API利用料が膨らみすぎないように、合計コストが一定額を超えたら全員その場で止めたい。TeammateIdle 内でコスト集計ファイルを覗き、上限超過なら {"continue": false, "stopReason": "Daily budget reached, stopping team."} を返す。これは「この teammate だけ」じゃなくチーム全体を即座に停止させる強い停止です。
シナリオ3: OSSのドキュメント整備チームで、毎回 idle に入る前に進捗ログを書き出したいとき
3人 teammate がそれぞれ別ファイルを書き換えていて、誰がどこまで進めたか後で追いかけたい。TeammateIdle で exit 0 を返しつつ、その手前で進捗ログを logs/ フォルダにappendするだけのフックを書いておく。idle 自体は止めないので作業の流れは変えず、記録だけ自動で残せます。
初心者が踏みやすい落とし穴
- lead が idle になる時には呼ばれない。
TeammateIdleは lead 以外の teammate 専用です。lead 本体の終了直前に何か挟みたいならStopフック側を使ってください - matcher で teammate を絞り込めない。frontend担当だけ呼びたい、というのは設定ファイル側ではできない。スクリプト内で
session_idや transcript を見て自前で分岐するのが現実解です - 常に
exit 2を返すと無限ループになる。teammate は永遠に idle に落ちず、タスクキューが空でも何か仕事をやらされ続けます。必ず「もう全部終わってるならexit 0」の条件分岐をスクリプト内に書くこと continue: falseは teammate 1人だけじゃなくチーム全体が止まる。「この teammate だけ idle させたくない」のつもりでcontinue: falseを返すと、lead もろとも全員その場で停止します。1人だけ引き止めたいならexit 2+ エラーメッセージ用の出力にメッセージを書く形を使う- エラーメッセージ用の出力に書いたメッセージが teammate の次の指示になる。普通の
echo(標準出力)に書いても無視されます。echo "..." >&2の形で書く必要がある - 起動時の設定値を立て忘れると黙って無視される。
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1が無いと、設定ファイルに書いたTeammateIdleのブロックごと無効になります。エラーメッセージも特に出ないので気づきにくい - Stop / SubagentStop と混同しない。
StopはメインのClaude応答が終わる時、SubagentStopは Task ツールで呼ばれた subagent が終わる時、TeammateIdleは Agent Team の teammate が idle に入る直前。3つは別物で発火タイミングが違います
書き方
// .claude/settings.json
{
"hooks": {
"TeammateIdle": [
{
"type": "command",
"command": "./scripts/check-busy-mates.sh"
}
]
}
}
// matcher欄は持たない(書いても無視される)
// 全teammateのidle直前で必ず発火
やってみるとこうなる
入力
# Claude Codeを実験用の起動設定付きで立ち上げる
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 claude
# settings.jsonに上記フック設定を書いた状態で、
# lead経由でfrontend担当teammateとbackend担当teammateにタスクを振る。
# frontend担当が先に作業を終え、idleに入ろうとした瞬間に
# scripts/check-busy-mates.sh が呼ばれる。
# スクリプトに渡されるJSON:
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/recipe-site/transcript.jsonl",
"cwd": "~/projects/recipe-site",
"permission_mode": "default",
"hook_event_name": "TeammateIdle"
}
出力例
# scripts/check-busy-mates.sh の中身
#!/bin/bash
if [ -f ".team-status/backend-pending" ] && [ -s ".team-status/backend-pending" ]; then
echo "Backend teammate still busy. Pick up the API tests next." >&2
exit 2
fi
exit 0
# backend担当がまだ作業中の場合:
# → exit 2 が返り、frontend担当のidleがキャンセルされる
# → エラーメッセージ用出力のメッセージがそのまま次の指示文として
# frontend担当に渡される(「APIテストを書いて」と続行)
# 両者の作業が全部終わっている場合:
# → exit 0 が返り、frontend担当は素直にidleに入る
# チーム全体を止めたいときは JSON で返す:
# {"continue": false, "stopReason": "Daily budget reached, stopping team."}
# → teammate 1人だけでなく lead もろとも全員その場で停止
このページに出てきた言葉
- Agent Teams
- Claude Codeの実験機能。1セッション内にlead 1人とteammate数人を立てて役割分担させる構成。<code>CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1</code>で有効化
- lead
- チームの司令塔役。タスクを分けてteammateに振り、結果を受け取ってまとめる側
- teammate
- 実作業を担当するチーム員。lead以外のメンバー。frontend担当・backend担当のように役割を分けて立てる
- idle
- 「もう次にやることが無い」状態。teammateが自分の担当タスクを終えて次の指示待ちに入る瞬間
- フック
- Claude Codeが特定タイミングで自動で呼んでくれる外部スクリプト。<code>.claude/settings.json</code>にイベント名と呼び先を書いて登録する
- exit code(終了コード)
- スクリプトが終わる時に成功か失敗かを数字で返す仕組み。TeammateIdleでは0が「OK、idleに入っていい」、2が「idle阻止、teammateに作業継続させる」
- エラーメッセージ用の出力
- スクリプトが普通の結果とは別に流すメッセージ用の出力経路。<code>echo "..." >&2</code>の形で書く。TeammateIdleではここの文字がそのままteammateへの次の指示文として渡される
- matcher
- フック設定で「どの対象に対して発火させるか」を絞り込む欄。TeammateIdleは非対応で、書いても黙って無視される
- continue: false
- フックがJSONで返す停止指示。TeammateIdleで返すとteammate 1人だけでなくチーム全体(leadも含む)がその場で停止する