| name | symphony |
| description | GitHub Project をポーリングして Issue を Agent に dispatch するオーケストレーションを、Agent 自身の中で実行する。Use when ユーザーが「symphony を回して」「Issue を自動で消化して」「ポーリングして dispatch して」のような依頼をしたとき。外部から Claude Code を操作するのではなく、この Agent の subagent 起動で workflow を実行し、状態はローカルファイルで管理する。 |
symphony
GitHub Project をトラッカーとして、Ready / In progress な Issue を 1 サイクルずつ拾って subagent に実行させるオーケストレーター。外部プロセスのオーケストレータを動かす代わりに、この Agent の中で Skill として 1 サイクルを回す。継続実行は /loop で行う。
前提
bun, gh(project スコープ認証済み)が必要。
- 作業ディレクトリにこの Skill 一式(
scripts/, workflows/)がある前提。スクリプトは Skill のベースディレクトリからの絶対パスで実行すること(相対パスで No such file or directory を避ける)。
- 状態は
.symphony/state.json、実行ログは .symphony/AGENTLOGS.local.md。state.json を直接編集しない。必ず scripts/state.ts のサブコマンド経由で操作する。
- workflow パスは Skill の引数で受け取る(例:
/symphony path/to/your-workflow.md)。workflows/DEV.md はサンプルなので、実運用では自分の Project / repository に合わせた workflow を用意して渡す。
- 引数の先頭が
init の場合は workflow path として扱わず、workflow ファイル作成モードを実行する。
init: workflow ファイルを作成
引数の先頭が init の場合は通常の dispatch サイクルを実行しない。
$SKILL_DIR/references/init-workflow.md を読む。
- まず「おすすめプリセットを使うか、1 から設定するか」をユーザーに確認する。
- おすすめプリセットでは Implement (DEV) → Verify (TEST) の 2 workflow を提案する。
- GitHub Project は既存を使うか、新規作成するか確認する。新規作成する場合は必要項目を聞き、作成できるなら作成して owner / number を workflow に反映する。
- Status、repository 解決方法、branch テンプレート、Model、保存先をヒアリングする。
- ヒアリング結果から workflow Markdown を作成する。
- 既存ファイルがある場合は勝手に上書きしない。
- 作成後、次回は
/symphony <workflow path> を実行するよう案内する。
TEST workflow で ACTION REQUIRED が出力された場合は、追加対応が必要な状態として report.ts の outcome を failure にする。これにより failure_state(プリセットでは Ready)へ戻る。
1 サイクルの手順
以下を $SKILL_DIR を Skill のベースディレクトリ、$WORKFLOW を引数で受け取った workflow パスとして実行する。
0. workflow を決める
引数の先頭が init なら init: workflow ファイルを作成 に従う。そうでなければ、引数で workflow パスが渡されていればそれを $WORKFLOW とする。渡されていなければユーザーにどの workflow を使うか確認する(サンプルを試すだけなら $SKILL_DIR/workflows/DEV.md)。
1. dispatch 候補を取得
bun $SKILL_DIR/scripts/poll.ts --workflow $WORKFLOW --state .symphony/state.json
dispatchable な Issue の配列(TrackerItem[])が JSON で返る。空配列ならこのサイクルは何もせず終了(次の /loop を待つ)。poll は実行中(claimed/running)と retry 待ちを自動で除外し、max_concurrent_agents の空きスロット分だけ返す。
2. 各 Issue を claim → render → 実行 → report
候補ごとに順に(または空きスロット内で並行に):
重要(パラメータは都度スクリプトから取る): branch / model / agent 名 / 各 state などの派生値を Agent が記憶して持ち回らない。各フェーズで毎回スクリプトを叩き、--workflow $WORKFLOW と --issue '<TrackerItem JSON>'(poll の出力をそのまま)を渡して、スクリプト側がフロントマターを解析して解決する。Agent が渡すのは identifier と issue JSON だけ。
重要(Issue 実行は必ず subagent): claim / workspace / render / report はこの Agent が行うが、render 後の Issue 実行本体は必ず Agent ツール(Task)の subagent に委譲する。この Agent 自身が Issue の実装・計画・検証を直接進めてはいけない。
(a) claim(重複実行防止。失敗したら他で処理中なのでスキップ)
bun $SKILL_DIR/scripts/state.ts claim "<identifier>" --workflow DEV --state .symphony/state.json
--agent は省略してよい(<identifier>-DEV-<ts> を自動生成して {"claimed":true,"agent":...} を返す)。exit code が 0 のときだけ次へ進む。
(b) running に遷移
bun $SKILL_DIR/scripts/state.ts mark-running "<identifier>" --state .symphony/state.json
(c) workspace(worktree)を用意
worktree の repository / branch / createBranch は workspace.ts が workflow + issue から解決するので、Agent は branch を組み立てない。
bun $SKILL_DIR/scripts/workspace.ts ensure --workflow $WORKFLOW --issue '<TrackerItem JSON>'
{"cwd":"<worktree path>","created":true|false} を返す。冪等で、既存 worktree があれば再利用する。subagent はこの cwd で動かす(isolation: "worktree" は使わない — それは現リポジトリの fork であって対象リポジトリではないため)。対象リポジトリは ghq 配下($(ghq root)/github.com/<owner>/<repo>)にチェックアウト済みであること。workflow に workspace が無ければ何もせず exit 0(単一リポジトリ運用)。
(d) prompt と model を取得して subagent を起動
bun $SKILL_DIR/scripts/render-workflow.ts --workflow $WORKFLOW --issue '<TrackerItem JSON>' --attempt <n>
返る prompt / config.runner / config.model をこの場で使う。config.runner == "subagent"(既定)のとき、Agent ツール(Task)で subagent を起動し、prompt をそのまま渡す。Issue の実行本体は必ずこの subagent にやらせる。作業ディレクトリは (c) の cwd、model は config.model。ポーリングや完了検出は不要 — subagent の最終メッセージが返った時点で workflow 実行は完了する。
- subagent の最終メッセージが返った場合は、成功・未達のどちらでも必ず (e) report を実行する。
- PR 作成・計画提出・検証 OK など workflow の達成なら outcome=success。
ACTION REQUIRED、追加対応あり、レビュー指摘未対応、PR 作成に至らないなど workflow の未達なら outcome=failure。
- subagent 起動失敗、workspace/render/state/report コマンド失敗、例外、timeout などの実行エラーは outcome にしない。この場合は error として扱い、完了 report は実行しない。
将来: config.runner == "agmsg" の場合は別 CLI エージェントへ agmsg spawn/send で委譲し、inbox で結果を受け取る(段階2)。
(e) report(内部 state と AGENTLOGS を確定)
failure は完了した workflow 実行の結果なので、success と同じく必ず report.ts を呼ぶ。error は完了結果ではないため report.ts を呼ばない。
bun $SKILL_DIR/scripts/report.ts --workflow $WORKFLOW --id "<identifier>" --outcome <success|failure> --report '<subagentの戻り値>' --state .symphony/state.json --log .symphony/AGENTLOGS.local.md
reporter に tracker が含まれる場合、report.ts が Project の Status フィールドを自動で移動する(success_state / failure_state へ)。内部で gh project view / field-list と Issue の projectItems GraphQL から project-id / field-id / option-id / item-id を解決し gh project item-edit を実行する。gh project item-list --format json は Project field 名を camelCase 化するため使わない。Status フィールド名が Status でなければ --status-field <name> を渡す。移動を抑止したいときは --no-tracker。stdout に {"tracker_status":"Testing","moved":true} を返す。
3. サイクル終了
全候補を処理したらサイクル終了。
継続実行(/loop)
ポーリング間隔($WORKFLOW の polling.interval_ms、既定 60s)で本 Skill を繰り返したい場合は /loop を使う:
/loop 1m symphony を 1 サイクル回す
/loop を使わず手動で 1 サイクルだけ回すこともできる。
状態管理(state.json)
scripts/state.ts <subcommand> --state .symphony/state.json:
| サブコマンド | 用途 |
|---|
list-active | claimed/running の identifier 一覧 |
claim <id> --agent <name> --workflow <wf> | 原子的 claim(既に active なら exit 1) |
mark-running <id> / mark-done <id> / mark-failed <id> --error <msg> --retry-at <iso> | 状態遷移 |
set-tracker-status <id> <status> | tracker に書いた Status を記録 |
due-retries | retry 期限切れの failed id 一覧 |
get <id> | 1 件の状態を JSON 表示 |
書き込みは一時ファイル + rename の atomic write、zod でスキーマ検証してから保存するため JSON は壊れない。--now <iso> で時刻を差し込める(テスト・再現用)。
tracker 単体操作
Status 移動だけ手動で行いたいとき:
bun $SKILL_DIR/scripts/tracker.ts move-status --workflow $WORKFLOW --id "<identifier>" --status "Testing"
テスト
cd $SKILL_DIR && bun test