| name | vibeflow-execute-issue |
| description | Execute a single GitHub Issue through the full 11-Step workflow. Iris handles everything — Issue Review, TDD, implementation, QA judgment, PR, cross-review, merge, close. |
Issue 実行 — 11-Step ワークフロー
使い方
/execute-issue <Issue番号>
Iris が 1 つの Issue を 11 Step で完遂します。ユーザーは needs_human の場合のみ確認を求められます。
Step 1: Issue Review(Iris)
gh issue view <NUMBER> --json number,title,body,labels
- Issue の内容を読み、要件を整理する
- DoR チェック(Definition of Ready):
import json, subprocess, sys
sys.path.insert(0, '.vibe/runtime')
from dor_gate import check_dor
issue = json.loads(subprocess.run(
['gh', 'issue', 'view', '<NUMBER>', '--json', 'title,body,labels'],
capture_output=True, text=True).stdout)
result = check_dor(issue)
- UI task 判定: 以下に該当するか確認
- 変更対象に UI ファイル (
.tsx, .jsx, .vue, .svelte, .html, .css, .scss) を含む
- Issue タイトル/本文に UI キーワード(画面、表示、UI、デザイン、コンポーネント等)がある
- ラベル確認:
risk:low/medium/high, qa:auto/manual, type:dev/fix/patch
- UI task の場合:
qa:manual ラベルを付与(未付与なら)
gh issue edit <NUMBER> --add-label "qa:manual"
Step 2: Task Breakdown + To-Be 確認(Iris)
- Acceptance Criteria を明確化
- Issue の「## Spec 変更」欄を読み、To-Be spec 差分案(どの Story の
invariant / どの Contract をどう変えるか)を具体化する
- 曖昧性の解消(実装前 clarify): 複数解釈できる点・未定義の入力域・
不明確な完了条件があれば、AskUserQuestion で PO に質問する(最大 3-5 問)。
回答は Issue 本文の「## Clarifications」セクションに追記して記録する
— 手戻りは実装後検出より実装前検出のほうが圧倒的に安い
- Go 確認: spec 変更がある場合のみ、「この Issue でできるようになる
こと / 変わること」を日本語 3-5 行で提示して PO の Go を得てから Step 3 へ。
スキップ条件: 「spec 変更なし(コードのみ)」かつ曖昧点なしの場合は
確認不要で進む(バグ分類 (i) の autonomy を保つ)
- 必要なファイル・テストを洗い出し、実装方針を決定
Step 3: Branch Creation
git checkout -b vf/issue-<NUMBER>
── Coding part の委譲(Issue ごとに fresh context)──
Step 3.5〜6(spec 編集・TDD・実装・リファクタ)は、Iris 本体の
コンテキストで直接やらず、サブエージェントに委譲する。
これは iris-core.md「必ず Coding Agent に dispatch する」の実行であり、
2 つの効果がある:
- コンテキスト隔離 — テストログ・diff 全文などの重い出力を
サブエージェント側に閉じ込め、Iris 本体のコンテキスト劣化を防ぐ
(Ralph ループの「イテレーション毎にコンテキストをリセットし、
ファイルだけを共有状態にする」原則)
- ロール分離 — サブエージェントが Coding Agent として動く
委譲手段(どちらか):
- Agent tool のサブエージェント(推奨。worktree 分離も可能)に
Issue 番号・AC・To-Be spec を渡し、Step 3.5〜6 を実行させる
- headless
claude -p(.vibe/runtime/claude_code_wrapper.py 経由)
委譲先がワークフロー状態を更新する(3 ストア同時):
python3 -c "import sys; sys.path.insert(0,'.vibe/runtime'); import state; \
state.update_workflow_state('.', role='Coding Agent (Claude Code / Codex)', step='4_test_writing', issue=<NUMBER>)"
これにより validate_access.py が src/*, tests/*, .vibe/spec/** への書き込みを許可します。
Step 3.5: To-Be Spec 編集(Coding Agent)
Issue = Spec 差分。 Issue の「## Spec 変更」欄に従い、.vibe/spec/ の
Story / Contract をこの Issue ブランチ上で編集してコミットする
(As-Is = base ブランチの spec、To-Be = このブランチの spec。spec-loop.md)。
- Issue が「spec 変更なし(コードのみ)」(バグ分類 (i) 等)の場合は省略
- バグ分類 (iii)(spec に invariant が書かれていなかった)の場合は、
対応する Story に invariant を追加し、Step 4 でその test を書く
- 機能追加なら Story の invariants / source_files、境界を渡る型の変更なら
Contract を更新する
- コミット:
spec: update To-Be for #<NUMBER>
Step 4: Test Writing — TDD Red(Coding Agent)
テストを先に書く。実装は書かない。
- acceptance criteria からテストケースを作成
- ユニットテスト:
tests/ または src/**/__tests__/
- UI task の場合: Playwright E2E テスト (
tests/e2e/) も作成
- テスト実行 → 全て失敗することを確認 (Red)
npm test || pytest || bash tests/run_tests.sh
- コミット:
test: add failing tests for #<NUMBER>
Step 5: Implementation — TDD Green(Coding Agent)
- テストをパスする最小限の実装を書く
- テスト実行 → 全て通ることを確認 (Green)
- テストは変更しない
- コミット:
feat: implement #<NUMBER>
スコープ予算ガード(暴走防止)
実装後、diff が予算内かを確認する(patch_loop と同水準):
python3 .vibe/runtime/loop_control.py 2>/dev/null; \
git diff --shortstat main...HEAD
1 試行でのスコープ爆発(43 コミット級)を、qa_judge の事後判定を待たずに止める。
Step 6: Refactoring(Coding Agent)
- コード品質の改善(重複排除、命名改善等)
- テスト実行 → GREEN を維持
- 必要な場合のみコミット:
refactor: improve #<NUMBER>
── ロール切替: Coding Agent → Iris ──
python3 -c "import sys; sys.path.insert(0,'.vibe/runtime'); import state; \
state.update_workflow_state('.', role='Iris', step='7_acceptance_test', issue=<NUMBER>)"
Step 7: QA 判定(Iris)— 暫定トリアージ
確定判定は Step 9.5(クロスレビュー後)で行う。 Step 7 は「テストが
本当に通っているか」と「人間確認が必要な種類の変更か」のトリアージ。
7-0. spec 整合検証
vibeflow spec-verify
ERRORS 0(exit 0)を確認する。 FAIL の場合は spec とコードが乖離して
いる — Step 3.5(spec の修正)または Step 4-5(コードの修正)に差し戻す。
7-1. テスト全実行 — 証拠を残す
テスト出力と exit code をファイルに保存する(qa_judge はこの証拠
ファイルを検証する。会話内の「通りました」という主張は証拠にならない):
mkdir -p .vibe/reports/<NUMBER>
(npm test || pytest || bash tests/run_tests.sh) 2>&1 | tee .vibe/reports/<NUMBER>/test.log
echo "${PIPESTATUS[0]}" > .vibe/reports/<NUMBER>/test.exit
7-1b. invariant テスト実行(spec を使うプロジェクト)
python3 .vibe/runtime/spec_verify.py .vibe/spec . --run-tests --json \
> .vibe/reports/<NUMBER>/invariants.json
stats.invariants_violated の値を 7-3 / 9.5 の context に渡す。
violated > 0 = 既存の保証が破られている — qa_judge が hard fail させる。
7-2. UI task の場合: Playwright 実行
bash scripts/playwright_smoke.sh
7-3. qa_judge で暫定判定
以下の情報を集めて qa_judge.judge() を呼ぶ:
import sys, json
sys.path.insert(0, '.vibe/runtime')
from qa_judge import judge, is_ui_task
context = {
'labels': ['type:dev', 'risk:low', 'qa:auto'],
'tests_passed': True,
'review_verdict': 'pending',
'files_changed': 5,
'lines_changed': 120,
'has_ui_changes': False,
'playwright_passed': None,
'has_playwright_artifact': False,
'evidence': {
'test_log': '.vibe/reports/<NUMBER>/test.log',
'test_exit': '.vibe/reports/<NUMBER>/test.exit',
},
'invariants_violated': 0,
}
result = judge(context)
値の取得方法:
labels: gh issue view <NUMBER> --json labels --jq '[.labels[].name]'
files_changed: git diff --stat main...HEAD | tail -1 からファイル数を抽出
lines_changed: git diff --shortstat main...HEAD から行数を抽出
has_ui_changes: 変更ファイルに .tsx, .jsx, .vue, .css 等が含まれるか
playwright_passed: UI task なら scripts/playwright_smoke.sh の exit code
has_playwright_artifact: tests/e2e/ や .vibe/artifacts/ にファイルがあるか
判定結果による分岐(暫定)
review_verdict='pending' のため、この時点で auto_pass は出ない(仕様)。
| 結果 | アクション |
|---|
fail | → Step 4 に戻ってリトライ(最大 3 回) |
needs_human(理由が「review not executed」のみ) | → レビュー待ちの正常状態。Step 8 へ進む |
needs_human(UI / risk:high / qa:manual / 大 diff 等を含む) | → Step 7a を先に通してから Step 8 へ |
Step 7a: Human Checkpoint(必要な場合のみ)
needs_human の場合、Checkpoint Packet を作って PO の確認を求める。
PO はコードを読まない — packet が PO の判断材料のすべてになる。
まず current_step を 7a に進める(PO が席を外していてもアラートが鳴る):
python3 -c "import sys; sys.path.insert(0,'.vibe/runtime'); import state; \
state.update_workflow_state('.', role='Iris', step='7a_human_checkpoint', issue=<NUMBER>)"
1. Checkpoint Packet を作成
.vibe/checkpoints/<NUMBER>-packet.md に以下を 1 枚にまとめる
(packet がない人間承認は hook がブロックする):
# Checkpoint Packet — Issue #<NUMBER>: <タイトル>
## AC チェックリスト
- [x] AC-1: <内容> → テスト: <対応テスト名>
- [x] AC-2: <内容> → テスト: <対応テスト名>
## Spec 差分の要約(spec 変更がある場合)
<「できるようになること / 変わること / なくなること」を平易な日本語 3-5 行>
(生の差分: git diff main...HEAD -- .vibe/spec/)
## 証拠
- テスト: <test.exit の値> — <test.log 末尾のサマリ行>(.vibe/reports/<NUMBER>/test.log)
- invariant: verified N / violated 0 / pending N
- レビュー: <review.md の verdict>
- UI task の場合: スクリーンショットのパス
## スコープ外変更
<git diff のファイル一覧のうち、AC / Spec 変更に対応しないもの。なければ「なし」>
## invariant 接触リスト(best-effort)
<変更ファイル ∩ invariants[].source_ref で当たった invariant の story/id>
注意: packet に独自スキーマ・インデックス・履歴集約を作らない。
ただの 1 markdown ファイルであること。
2. packet 全文をチャットに提示して PO の OK を待つ
📋 Checkpoint Packet — Issue #<NUMBER>
(packet.md の内容をそのまま表示)
確認をお願いします。OK / NG を教えてください。
3. 承認は PO が端末から行う
エージェントは checkpoint を自分で作らない(自己承認の禁止)。
PO に次を依頼する:
vibeflow approve <NUMBER>
これが .vibe/checkpoints/<NUMBER>-qa-approved を作成する。
echo > .vibe/checkpoints/... での自作は BashGuard がブロックする。
4. NG の場合: フィードバックを反映して Step 4 に戻る
注意: アルゴリズム変更やデータ構造作成など、目視確認が不可能な場合は qa:auto ラベルが付いているはずなので、このステップはスキップされます。
Step 8: PR Creation
gh pr create \
--title "feat: <Issue タイトルの要約>" \
--body "Closes #<NUMBER>
## Summary
- <変更内容>
## Test Plan
- [x] Unit tests
- [x] Integration tests$(# UI task なら)
- [x] Playwright E2E tests"
validate_step7a.py が checkpoint をチェックし、未承認なら PR 作成をブロックします。
Step 9: Cross-Review(Iris がサブエージェントに依頼)
DIFF=$(git diff main...HEAD)
Iris は Agent tool を使ってクロスレビュー用サブエージェントを起動:
Agent tool で code-reviewer サブエージェントを起動:
- diff を渡す
- acceptance criteria を渡す
- verdict: pass / warn / fail を返してもらう
レビュー結果は必ず .vibe/reports/<NUMBER>/review.md に保存する
(verdict と指摘一覧を含める)。Step 9.5 と Step 10 がこのファイルを参照する。
失敗時の扱い(fail-closed):
- verdict
fail → Step 4 に戻ってリトライ(最大 3 回)
- verdict
warn → 各指摘に「修正」または「対応不要の技術的理由」を
review.md に記録してから Step 9.5 へ(記録なしの warn は auto_pass 不可)
- サブエージェントの実行失敗・verdict 抽出不能 → レビューをリトライ。
リトライ上限に達したら
needs_human として PO にエスカレーション
(壊れているのはコードではなくレビュー基盤なので、再実装はしない)
Step 9.5: 確定判定(Iris)
クロスレビューの実際の verdict で qa_judge を再実行し、確定 verdict を得る。
auto_pass はこの確定判定でのみ成立する。
import sys
sys.path.insert(0, '.vibe/runtime')
from qa_judge import judge
context = {
'review_verdict': 'pass',
'warn_responses_recorded': True,
}
result = judge(context)
| 確定 verdict | アクション |
|---|
auto_pass | → Step 10 へ |
needs_human | → Step 7a(未承認なら)→ 承認後 Step 10 へ |
fail | → Step 4 に戻ってリトライ(最大 3 回) |
Step 10: Merge(Iris)
gh pr merge --squash --delete-branch
Step 11: Close & Report(Iris)
gh issue close <NUMBER>
ワークフロー状態を idle に戻す:
python3 -c "import sys; sys.path.insert(0,'.vibe/runtime'); import state; \
state.update_workflow_state('.', role='Iris', step='idle', issue=None)"
ユーザーに完了報告。チェックマークだけの主張は禁止 — 証拠を添える:
✅ Issue #<NUMBER> 完了
━━━━━━━━━━━━━━━━━━━━━
Agent: Claude Code
PR: #<PR_NUMBER>
テスト: <test.exit の値> — 実行コマンド: <Step 7-1 で使ったコマンド>
<test.log の末尾サマリ(例: "All 42 tests passed")>
ログ: .vibe/reports/<NUMBER>/test.log
レビュー: <review.md の verdict>(指摘 N 件 / 対応記録あり)
レビュー: .vibe/reports/<NUMBER>/review.md
リトライポリシー — loop_control が機械的に判定する
テスト失敗(Step 7)/ レビュー fail(Step 9)の分岐では、散文で「3 回まで」
と数えるのではなく、必ず loop_control を実行して結果の action に従う:
python3 .vibe/runtime/loop_control.py record-attempt <NUMBER> <step> fail "<fingerprint>" 2>/dev/null \
|| python3 -c "import sys; sys.path.insert(0,'.vibe/runtime'); import loop_control as lc; lc.record_attempt('.', <NUMBER>, '<step>', 'fail', '<fingerprint>')"
python3 .vibe/runtime/loop_control.py should-retry <NUMBER>
| action | 意味 | 対応 |
|---|
retry | まだ試行回数内 | 同じ agent (claude_code) で Step 4 に戻る |
switch_agent (codex) | claude_code が 2 回失敗 | agent を Codex に切り替えて再試行 |
escalate | 3 回失敗 | qa_judge verdict を needs_human に強制し、PO に報告して停止。再実装しない |
成功(Step 7 pass)時は record-attempt <NUMBER> <step> pass を記録して
カウンタをリセットする。これにより夜間・長時間ループでも「同じ失敗を無限に
繰り返す」「失敗 Issue を勝手に成功扱いで先へ進む」が機械的に防がれる。
エラーハンドリング
- ブランチ競合 →
git rebase main で解決を試みる
- テストが不安定 → 2 回実行して確認
- 予期しないエラー → ユーザーに状況を報告して判断を仰ぐ