タスクを別のエージェントCLIに委譲する
外部エージェントCLIで1つのタスクをバックグラウンドで実行し、正規化された結果を返します。
ドライバー: delegate.mjs(このスキル自身のディレクトリ内、Node ≥ 18、依存関係なし)
動作はcontracts/内の3つのコントラクトによって定義されています—ドライバーを変更する前にそれらを読んでください。
startは即座にrun_idを返し、collectで結果を取得します。何もブロックしません。
最初にドライバーと実行ディレクトリを解決する
このスキルがインストールされている場所によってdelegate.mjsの位置が決まり、実行アーティファクトはデフォルトでドライバーの隣に置かれます。セッションごとに両方を一度設定し、以下のすべてのコマンドで$DELEGATEを使用します:
# Claude Code プラグインインストール (agent-tools@sanduq)
DELEGATE="$CLAUDE_PLUGIN_ROOT/skills/delegate-task/delegate.mjs"
# npx skills install、またはリポジトリにコミットされたコピー
DELEGATE=".claude/skills/delegate-task/delegate.mjs"
# 実行アーティファクトをドライバーの隣ではなく、作業中のプロジェクト内に保存する
export DELEGATE_RUNS_DIR="$PWD/.delegate/runs"
DELEGATE_RUNS_DIRはプラグインインストールでは必須です: 設定しないと、すべてのプロジェクトのアーティファクトが共有プラグインディレクトリ内に蓄積され、タスクテキストやハーネスの生の出力が含まれます。.delegate/をプロジェクトの.gitignoreに追加してください。実行に触れるすべてのコマンド(start、status、collect、list、prune)は同じ値を見なければなりません。
まず利用可能なものを確認する
node "$DELEGATE" doctor
doctorは各CLIのバージョンをプローブするため、未インストールとインストール済みだが壊れているを区別し、--sandboxが各CLIに実際に何を要求するかを表示します。
| ハーネス | ID | ティア | 再開 | --sandboxの要求 |
|---|---|---|---|---|
| Claude Code | claude | 検証済み | 検証済み | --permission-mode plan |
| OpenAI Codex | codex | 検証済み | 検証済み | -s read-only (CLI強制) |
| OpenCode | opencode | 検証済み | 検証済み | --agent plan |
| GitHub Copilot | copilot | 実験的 | 実験的 | --mode plan |
| Pi | pi | 実験的 | 実験的 | --no-approve --tools read,grep,find,ls |
claude、codex、またはopencodeを優先的に使用してください。
委譲を実行する
node "$DELEGATE" start \
--harness codex \
--cwd /path/to/workspace \
--timeout 600 \
--task "parse_config() に入力バリデーションを追加し、不正な入力パスをカバーするテストを追加する。"
{"run_id": "codex-…", "state": "running", ...}を出力して戻ります。その後:
node "$DELEGATE" collect codex-… --wait 300
--wait Nは最大N秒間ポーリングします。これがない場合、collectは実行がまだ進行中であれば終了コード3で終了します。
その他のコマンド:
node "$DELEGATE" status <run_id> # starting|running|stalled|adrift|lost|done
node "$DELEGATE" collect <run_id> --json # 機械可読な結果 — これをパースする
node "$DELEGATE" list # すべての実行、最も古いものから順に
node "$DELEGATE" prune --keep 20 --yes # 古い実行アーティファクトを削除する
node "$DELEGATE" contract # フラグ、フィールド、終了コードの機械可読な定義
結果の読み方
ステータス SUCCESSFUL
理由 harness_telemetry
変更
測定 greeting.txt
主張 greeting.txt
権限 要求=bypass 適用=codex: --dangerously-bypass-approvals-and-sandbox
3つのフィールドがほとんどの意味を持ちます:
status—successful/failed/abandoned。status_provenance.primary— そのステータスの理由を一言で:timeout、spawn_error、signal、exit_code、parse_error、telemetry_incomplete、harness_telemetry、self_report、head_moved、index_moved、relay_aborted、supervisor_lost、legacy。 どの理由によるものかを知らずにステータスを報告しないでください。evidenceは、採用されたものだけでなく、真だったすべての観測結果をリストします。dirty_paths_changed— 委譲先が言ったfiles_claimedとは対照的に、gitが測定した変更です。files_mismatchは不一致を示します。
権限
デフォルトは完全バイパスです。 委譲先は無人で任意のコマンドを実行します。
--sandboxは各CLIの実際の読み取り専用モード(上の表)を要求し、トリップワイヤーを有効にします:
read_only_violationはtrue / false / null。nullは不明を意味します—gitが利用できないか、フィンガープリントのカバレッジが不完全でした。falseに丸められることはありません。
falseは「書き込みが発生しなかった」ことを意味しません。 これは、カバーされた最終状態のデルタが検出されなかったことを意味します。書き込み後に元に戻す操作、gitignoreされたもの、またはリポジトリ外への書き込みは検出できません。
trueは委譲先がそれを実行したことを意味しません — 同じワークツリーでの同時編集は同一に見えます。
エンベロープは委譲先にコミットしないよう指示しますが、それはポリシーであり、強制ではありません。強制するのは測定です: 実行ウィンドウ中にHEADが移動した場合、結果はレビュー必須(head_moved)に強制されます。ただし--allow-commitを渡した場合は除きます。
実行の継続
node "$DELEGATE" start --harness codex --cwd <同じディレクトリ> --resume <run_id> \
--task "修正自体は正しいですが、モックの代わりに実際のフィクスチャを使用してください。"
差分のみを送信します。Resumeは新しいrun_idをparent_run_idが設定された状態で取得し、ハーネス、作業ディレクトリ、または親のセッションIDが一致しない場合は拒否します。
Resumeされたディスパッチは、親セッションが依然としてポリシーを尊重していると仮定するのではなく、すべてのポリシールールを再適用します。
フラグ
| フラグ | 用途 |
|---|---|
--cwd DIR | 作業ディレクトリ — 常に明示的に設定してください |
--model M | モデルを上書きする |
--timeout SEC | デフォルト1800; 事前に検証; 期限が切れるとツリーが強制終了される → abandoned |
--deliverable TEXT | 返すべきもの(「統一された差分、コミットしないでください」) |
--constraint TEXT | 繰り返し可能な追加ルール |
--sandbox | ハーネスの読み取り専用モードを要求する |
--allow-commit | コミットを許可し、HEADの移動をレビュー必須として扱わない |
--resume <run_id> | 完了した実行のセッションを差分タスクで継続する |
--clean-env / --keep-env N | CLIにランタイムの基本のみを渡す; 認証に必要な変数ごとに--keep-envを繰り返す |
--raw | タスクをそのまま送信する(ステータス/サマリーを失う; --resumeと互換性なし) |
注意点
- 終了コード0はタスクが完了したことを意味しません — そしてこのリファクタリングまで、ゼロ以外の終了コードは失敗を意味しませんでした。アダプターは終了コードを受け取っていましたが、それを読むものはなかったため、成功形のイベントと終了コード1が
successfulとして公開されていました。修正済み;test/run.mjsのケースREPAIR-D1で固定。常にstatus_provenanceを読み、決してexit_codeだけを読まないでください。 - トークンフィールドはハーネスごとに異なる意味を持ちます。 Claudeの
input_tokens/cache_creation/cache_readは互いに素です — それらを合計してください(あるプローブでは、実際に58,065トークンを送信したリクエストに対してinput_tokens: 2と報告されました)。Codexのinput_tokensはcached_input_tokensを含みます — 新しいカウントを得るには減算してください。input_total/input_freshを使用してください;usage_rawは監査用にハーネス自身の数値を保持しますが、合計として表示されることはありません。 - 合計はハーネス間で比較できません。 OpenCodeはステップごとに1つの
step_finishを発行し、ドライバーがそれらを合計するため、各ステップで再送信されたコンテキストが毎回カウントされます。同一の簡単なタスク: 66,341 (codex)、117,014 (claude)、426,523 (opencode)。効率のランキングではありません。 claudeへの委譲には約58kトークンの下限があります。claude -pはタスクを読む前にCLAUDE.mdと発見されたすべてのスキルをロードします。- CodexはあなたのMCPサーバーを継承します。 codexが遅いと感じたら、
runs/<run_id>/stderr.logを読んでください — 遅延の原因は通常モデルではなくMCPです。 - Codexは成功した実行でも
item.type: "error"イベントを発行します。 カウントされるのはturn.failedまたは欠落したturn.completedのみです。 - 完全なバイパスは本当にサンドボックス化されていません。 あるOpenCodeの委譲先は、かつてその
--cwd外にファイルを書き込みました。--sandboxを使用するか、使い捨てのディレクトリを使用してください。 - すべてのハーネスがすべてのフィールドを報告するわけではありません。 Copilotはトークンカウントをまったく発行しません(
fidelity: "unavailable"— ゼロは不明を意味し、無料ではありません)。CodexはJSONLのどこにもコストもモデルも発行しないため、cost_usdとmodelは本質的にnullであり、パースエラーによるものではありません —cost_reported/model_reportedがどれかを示し、印刷された結果は「このハーネスでは報告されていません」と読みます。Claudeは両方を報告します; OpenCodeはコストを報告します。 - タスクテキストがシェルに到達することはありません。 各CLIは実際の実行可能ファイルに解決され、
shell:falseで生成されます。 piは独自のストアにセッションを保持します。--no-sessionは意図的に渡されません — セッションがなければ再開するものもありません。セッションは~/.pi/agent/sessions/<cwd-slug>/に、作業ディレクトリをキーとして保存されます;pruneはそれらに触れません。Piの認証はファイルベースです(~/.pi/agent/auth.json)ので、--clean-envはそれを壊しません。- スーパーバイザーが強制終了された実行は
lostであり、スタックではありません。collectはジャーナルとログから終端結果を合成します。そのgitデルタはnullです: 実行開始時のベースラインが生存しておらず、falseを報告することは何も測定されなかったという保証になります。 - 実行IDは検証されます。 それらは
<ハーネス>-<14桁>-<6桁の16進数>に一致しなければならず、実行ディレクトリの直下にある必要があります。呼び出し元から提供されたIDがそこから外に出ることはできません。 - ハーネスがまだ生きているのにスーパーバイザーが死んだ実行は
lostではなくadriftです。collectは公開を拒否します。なぜなら、その時点で書き込まれた結果は依然として進行中の実行のスナップショットになるからです。子プロセスを待つか、statusが示すpidを強制終了してください。pruneもadrift状態の実行は削除しません。 DELEGATE_BIN_<HARNESS>はバイナリが見つかる場所を上書きします — 例:DELEGATE_BIN_CODEX=/opt/codex/bin/codex。これはテストスイートがトークンを消費せずに偽のハーネスをエンドツーエンドで駆動する方法でもあります。
トラブルシューティング
| 症状 | 原因 / 修正方法 |
|---|---|
<bin> not found on PATH | そのCLIがインストールされていません; doctorを実行してください |
found <path> but could not resolve what it launches | CLIがこのドライバーがデコードできない非npmの.cmdシムの背後にインストールされています |
doctorがBROKEN: probe timed outを表示 | 通常はコールドスタート; 何かを結論付ける前にdoctorを再実行してください |
supervisor failed to start (終了コード5) | 切り離されたスーパーバイザーが応答しませんでした; runs/<id>/journal.jsonlを確認してください。実行はcontainment_evidence: "the harness never launched"とともにfailedとして確定されます; ジャーナルがcreatedとterminalのみを保持し、スーパーバイザーのpidが消えている場合、エージェントは実行されていません |
run <id> still executing (終了コード3) | --wait <秒>を追加してください |
Refusing to publish … still running (終了コード6) | 実行はadriftです: スーパーバイザーは死にましたが、ハーネスは生きています。待つか、それが示すpidを強制終了してください |
another process is finalising this run (終了コード7) | ライブライターがクレームを保持しています; 少し待ってから再試行してください |
written by a different driver (終了コード8) | 結果が未知のスキーマを持っています; このビルドはそれを推測しません |
ステータス abandoned、由来 supervisor_lost | スーパーバイザーが強制終了されました; 再ディスパッチする前に作業ツリーを検査してください |
ステータス failed、由来 head_moved / index_moved | 実行中に何かがコミットまたはステージングされました; ツリーは保存されています、レビューしてください |
サマリーが(no summary produced)と表示 | 委譲先が結果ブロックを発行しませんでした; runs/<run_id>/stdout.logを読んでください |
ファイル
実行アーティファクトは$DELEGATE_RUNS_DIR/<run_id>/に保存されます(prompt.txt、meta.json、journal.jsonl、stdout.log、stderr.log、result.json)。設定されていない場合、DELEGATE_RUNS_DIRはデフォルトでドライバーの隣のruns/になります — プラグインインストールでは共有プラグインディレクトリになるため、設定してください。DELEGATE_MAX_LOG_BYTESでログサイズを制限し(デフォルト1ストリームあたり32 MB)、DELEGATE_LOG_TAIL_BYTESで制限後の保持ウィンドウを設定します(デフォルト512 KB)。
制限を超えると、ドライバーはバイトサフィックスではなく完全な解析済みレコードを保持するため、テレメトリは依然として解析可能です。ウィンドウが保持できないレコードは**records_dropped**にカウントされます — ゼロ以外の値はステータスは依然として有効ですが、委譲先自身の最終回答は不完全である可能性があることを意味します。
⚠️ アーティファクトにはタスクテキスト、完全なプロンプト、ハーネスの生の出力が含まれます — 機密情報として扱ってください。 最終化により、stdout.logとstderr.log内のトークン形状と資格情報のように見えるNAME=valueペアがマスクされます(result.jsonではマスクされません)。POSIXでは実行ディレクトリはchmod 0700になります; Windowsでは権限は継承され、このドライバーはそれらを制限できません。成功したcollectは、DELEGATE_PRUNE_DAYS日(デフォルト30; 0で無効)より古い完了した実行を削除します; pruneでより早くクリーンアップしてください。
さらに詳しく
-
既知のローカルCLIチェックのバッチについては、ネイティブチェックランナーコントラクトを読んでください。 JSON argvプラン、不変の試行、制限付きコレクション、PowerShell呼び出しをカバーしています。
collect --summary、ハートビートのみの診断、オプトインの起動期限にも同じリファレンスを使用してください。 -
contracts/status-precedence.md— ステータスがどのように決定されるか、およびテストするべきクロスプロダクト -
contracts/git-fields.md— トリップワイヤーが測定するものとそれに見えないもの -
contracts/result-schema-v2.md— 結果の形状、v1の後方読み取り、ジャーナル、シングルライター -
references/writing-the-brief.md— 委譲先がブラインドで実行できるタスクの書き方 -
references/reviewing-the-result.md— 返ってきた結果をレビューする方法(スイープを含む) -
references/task-queues.md— スレッドを失わずに複数の依存タスクを実行する方法
テスト: node test/run.mjs(このスキルのディレクトリから)
実行リグレッション: node --test test/execution.test.mjs(Node/Python CLIフィクスチャ)