mcpField
A
afkkit

afkkit

github.com/mimukitエージェントワークフロー2271 回インストール今日更新
リポジトリ

afkkit について

afkkit は、人が事前に整えた GitHub Issue を実装、QA、PR 作成まで進めるスキルです。複数のスキルを連携させ、判断が必要な境界で人に引き継ぐエスカレーション方針を担います。

主な機能

  1. 01Issue から PR までの工程を連携
  2. 02Issue の ready ラベルを必須化
  3. 03実装と QA チェックの実行
  4. 04PR 作成と Issue 状態の更新
  5. 05停止条件に応じたエスカレーション

活用シーン

  1. 01ready Issue をオープン PR まで進行
  2. 02ready キューの Issue を一括処理
  3. 03停止した作業を人が引き継ぐ

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mimukit/skills --skill afkkit

インストール後、Claude Code で/afkkitを入力して読み込まれたか確認します。

詳細

afkkit

away-from-keyboard ランナーです。整備済みの ready issue を渡すと、分離された worktree からオープンなプルリクエストまで、開発ワークフローの中間工程を進めます。実装してコミットし、QA 計画を作成して実行し、issue に照らして結果を確認し、修正し、PR を開いて、issue を in-review に切り替えます。人間による確認が必要な工程は、判断が求められる箇所に残ります。計画と厳しい質問は事前に行われ(ready ラベルが開始条件です)、レビューとマージは事後に行われます。また、詳細なコードレビューも事後に行われます。PR が開かれると、PR レベルのレビューボットが差分を確認するため、afkkit が実行範囲内で行う受け入れチェックは 1 回だけです。

afkkit は、worktree、トラッカー、PR に関する独自の動作を一切追加しません。コンパニオンキット(最初に issuekit の start、続いて implementkit、commitkit、qakit、reviewkit、prkit)を順番に実行し、ほかのキットにはない 1 つの役割を担います。それは、各ステップで続行するか、問題を明確にして人間に引き継ぐかを判断するエスカレーションポリシーです。

契約

  • 入力: issue 番号、または all。afkkit はissuekit の start <n> を自ら呼び出します。issuekit は ready ラベルが付いていない issue を拒否し、gitkit から worktree を取得します(最新の解決済みベース参照を使用し、既存のものがあれば作り直さずに再利用します)。さらに、ready → in-progress に切り替え、gitkit の prepare を使ってリポジトリに宣言された worktree のセットアップを実行します。このガードが安全性を保証します。誰がコマンドを入力しても、この保証は変わりません。issue が ready になるのは、人間による厳しい確認を経た後だけであり、afkkit は issue を ready に昇格させることも、ready でない issue を開始することもできません。
  • 承認: issue を指定すること、または all キューで 1 回だけ OK を出すことは、各 issue に対して次の操作を行うユーザーの承認となります。issuekit の start による worktree の取得(リポジトリが宣言する worktree セットアップを含む)、issue 専用ブランチへのコミットの作成、PR の手順でのブランチの 1 回限りのプッシュ、prkit による PR の作成です。afkkit は、呼び出すすべてのコンパニオンキットとすべてのディスパッチプロンプトで、この承認内容を明示します。prkit はこれを、QA 計画のコミットと PR 作成に対するプレビュー OK として扱います。ラベルの書き込みは、呼び出し元を問わず、それを担当するスキルが承認不要としているため、承認は必要ありません。このリストにない操作には、引き続き同意が必要です。そのため、該当する操作があれば実行をエスカレーションします。たとえば、強制プッシュ、公開済みブランチのリベース、別のブランチへのプッシュ、マージです。このリストを広げる唯一の方法は、issue の本文に明記することです。本文で事前承認された外部操作(厳しい確認の際に「フォローアップ用の issue を作成してよい」などと記録されたもの)は、その issue に限ってリストに加わります。
  • 成功時の出力: ユーザーに代わって実行中に下した判断を前提の下にテキストで冒頭に記載し、未達の受け入れ条件と、自動化された結果を含むコミット済み QA 計画への参照を続けて記載した、オープンな PR と、in-review に移動した issue です。
  • **処理がブロックされた場合の出力:**PR は作成されません。 worktree とコミットはそのまま保持され、issue へのコメントで正確な停止状態が示され、対応が必要な担当者向けに issue にラベルが付けられます。バッチ処理の場合は、次の issue の処理が始まります。afkkit が不完全な作業を公開することはありません。PR の手順より前のすべてのコミットでは commitkit の no-push が使われるため、prkit が PR を開くときに限り、ブランチが origin に送られます。

これが実行されるタイミング

  • 1 件の issue。 「afkkit 42」、「#42 を無人で実行」、「issue 42 を自動操縦」、「#42 を PR にする」。
  • ready キュー全体。 「afkkit all」、「不在の間に ready issue に取り組んで」、「ready backlog を処理して」。

ユーザーが issue 番号も all も指定していない場合は、どちらかを尋ねてください。afkkit は計画、聞き取り、マージ、PR レビューへのフィードバック対応は行いません(対象外を参照)。

今いるセッションで、メインのチェックアウトから実行してください。 1 つのコマンドですべての工程を実行します。issuekit start が worktree を取得し、すべてのステップはパスを指定してその中で実行されます。worktree で開く別のセッションも、そこで入力するビルド用プロンプトもありません。新しい会話を worktree にひも付けられるホスト(T3 Code のスレッド起動など)では、その会話に実行内容が表示される場合がありますが、実行自体はそれに依存しません。

事前確認(呼び出しごとに 1 回)

gh --version && gh auth status                          # GitHub CLI installed + authenticated
gh repo view --json nameWithOwner -q .nameWithOwner     # inside a repo on GitHub
  • gh がない、または認証されていない場合は停止し、https://cli.github.com / gh auth login を案内してください。
  • コンパニオンキットの確認。 afkkit には implementkit、commitkit、qakit、reviewkit、prkit が必要です。ステップで必要なキットがない場合は、処理を独自に補わず、停止してキット名を伝えてください。(操作が単純な場合は、以下のステップに通常の gh による代替方法が記載されています。)
  • issuekit は必須で、代替手段はありません。 安全性を支える ready ガードは issuekit が管理しています。インストールされていない場合は、実行を拒否して、インストールするよう伝えてください。gh でガードを再実装してはいけません。ゲートを二重に持つと、片方だけが開いた状態になり得ます。無人ランナー内にある複製版は、状態のずれに誰も気付きません。
  • GitHub トラッカーも必須です。これは別途確認してください。 リポジトリで GitHub issue を使っていない場合は、その理由を明示して実行を拒否し、まず計画を登録するための issuekit create を案内してください。不足している依存関係としてではなく、理由を明確に伝えてください。
  • シェル/CLI が使えない場合は? その旨を伝えて停止してください。afkkit は実行ランナーであり、文章で推論することはありません。

完了条件: gh が認証済みで、すべてのコンパニオンキットがあり、リポジトリで GitHub issue を使用していること。そうでなければ、実行を停止し、不足しているものを明示します。

実行の流れ

1 つのウォームセッションで issue を処理します。 開始、仕様ゲート、実装、コミット、QA 計画、修正、PR をすべて 1 つのコンテキストで実行するため、前のステップがすでに読み取った内容を後のステップが再度導き出す必要はありません。エージェント間の引き継ぎは毎回コールドスタートと再調査のコストがかかり、ステップごとにコンテキストをエージェント間で移す実行では、そのコストを 5 回も支払うことになります。issue を指定した実行は、ユーザーが afkkit を呼び出したセッションで行います。バッチモードでは issue ごとに専用のセッションが使われます。

  • worktree のパスは実行状態として保持し、セッションの作業場所とは区別します。 issuekit が返すパスを保持し、すべてのコマンドをそのパスに対して実行してください。git -C <worktree> … を使うか、同じシェル呼び出し内で cd <worktree> && … を実行します。シェルの作業ディレクトリは呼び出しのたびにリセットされる場合があり、誤ってメインのチェックアウトでコマンドを実行すると、別のブランチに書き込んでしまいます。
  • implementkit が実装の分割タイミングを決めます。 implementkit 独自の指揮ルールでは、重いフェーズが複数あるビルド、または機械的な一括処理フェーズがあるビルドは、フェーズのグループごとに 1 つのサブエージェントに割り当てます。afkkit は別の分割ルールを追加しません。ディスパッチできないセッション(Claude 対応ホスト上のサブエージェント)では、implementkit の指示どおり、グループをインラインで構築します。
  • 実行で独自に行うディスパッチは 1 回だけです。受け入れチェックです。 このステップだけは、セッションのコンテキストを保持しないことに価値があります。
  • すべてのステップでセッションのモデルを使います。 デフォルトでは、他のモデルやファミリーにルーティングされるステップはありません。ユーザーがインラインでモデルを指定した場合(「afkkit 42、sonnet で受け入れチェック」など)は、アクティブなホストで利用可能か確認し、日付付きのスナップショットではなく、ホストのエイリアスを記述してください。
  • タスク追跡ツールは実行状態ではありません。 ハーネスのタスクリストは進捗表示として便利ですが、永続性はありません。記録として残るのは progress.md と issue のラベルおよびコメントです。
ディスパッチルール

これらのルールは、実行によって開始されるすべてのサブエージェントに適用されます。受け入れチェック、バッチ内の各課題を担当するエージェント、そして afkkit がインストールされている場合の implementkit のフェーズグループエージェントが対象です。

  • フォークではなく、新しいエージェントを起動します。 フォークしたエージェントはディスパッチャーのトランスクリプトを引き継ぐため、自分がディスパッチャーだと勘違いすることがあります。ある指揮役からフォークされたレビュアーが、自分は指揮役だと判断して自己レビューを行い、「ブロッカーなし」と記載して、PR まで自分で作成したことがありました。新しいエージェントには、ブリーフだけが渡されます。
  • ブリーフには役割と担当範囲を明記します。 エージェントが何者なのか(「課題 42 の受け入れチェッカーです」)、何を返すのか、どの作業は他の担当者に属するのか(「QA の実行、コミット、プッシュ、PR の作成はしないでください」)を伝えます。
  • ブリーフではパスを使って入力を渡します。 ワークツリーのパスと、読み込む実行ディレクトリ内のファイルを指定します。エージェントの最初のアクションは、そのパス内で作業することです。ペイロードはファイルに入れ、結果は合格か不合格に加えて、ディスパッチャーが必要とする識別子と1行の要約(B1 · 1280 px でサイドバーがない)を返します。
  • ブリーフには2つのコマンドルールを記載します。 サブエージェントは、前回の教訓を知らずに開始するためです。1つ目は、zsh と bash のどちらでも同じように動作するコマンドを書くことです。すべての glob 引数を引用符で囲み(--include='*.tsx')、ファイル一覧の反復には | while IFS= read -r f または xargs を使い、for f in $var は使いません。2つ目は、各ゲートコマンドをログファイルに1回だけ実行し、その後、終了コードと範囲を限定した末尾部分を表示することです。メッセージや合否を確認するために、同じコマンドを再実行してはいけません。

サブエージェントを利用できない場合は? 受け入れチェックをインラインでセルフチェックとして実行し、findings.md の先頭に self-check と記載して、PR の本文にその旨を書けるようにします。パイプラインの他の部分は変更ありません。

1回だけ実行する作業

計測した実行では、これらの作業がそれぞれ繰り返されましたが、繰り返しても何の効果もありませんでした。pnpm deps:check は9つのエージェントで計13回実行され、あるセッションでは開発サーバーが31回起動されました。

  • 1回の実行につき、開発サーバーは1つだけです。 リポジトリ独自のスクリプトで1回起動し、出力をログに、PID をファイルに記録します。起動と停止のコマンドを orientation.md に記録してください。その後のすべての手順で同じサーバーを再利用します。引き継ぎの前に停止し、ポートが解放されていることを確認します。
  • ベースブランチでゲートが失敗することは、1回だけ証明します。 ゲートが失敗し、セッションで main も失敗すると判断した場合は、その主張を orientation.md に記録します。コマンド、終了コード、失敗を示す行を記載してください。主張を再度証明するために、どの手順でも再実行しません。受け入れチェックでベースブランチに対して1回だけ検証します。
  • 各ゲートコマンドは、リビジョンごとに1回だけログに記録します。 同じコミットと同じ未コミット変更状態で2回目を実行しても、同じ結果が得られるだけで、コストがかかります。
  • ブラウザーを開くのは qakit だけです。 qakit がページをチェックし、スクリーンショットを取得します。他のすべての手順では、その結果を参照します。

実行ディレクトリ

各ステップでペイロードを一度だけ、ひとつの場所に書き込みます。これにより、実行を再開した場合も受け入れチェックの場合も、パスを再導出せずに読み取れます。

  • 場所。 worktree のルートにある .afkkit/。Git の対象外にすることで、その中の内容が PR の差分に含まれないようにします。リポジトリのプライベートな除外ファイルに登録します。

    git -C <worktree> rev-parse --git-path info/exclude    # resolve the real path first
    

    そのパスは Git に問い合わせて取得し、.git/info/exclude をハードコードしないでください。 リンクされた worktree では、.git はディレクトリではなくファイルです。.afkkit/ がまだ記載されていない場合にのみ追記してください。除外ファイルは worktree 間で共有されます。

  • 内容。

    ファイル書き込むもの読み取るもの
    assumptions.md仕様ゲート、その後、判断を行う各ステップPR を開く(PR 本文にテキストとしてコピー)、受け入れチェック
    checks.md仕様ゲートqakit、受け入れチェック
    orientation.md開発サーバーを起動するステップ、または既存の失敗を申告するステップ以降のすべてのステップ、受け入れチェック
    findings.md受け入れチェック修正
    progress.md作業を取り込む各ステップ。各ステップにつき 1 行中断した実行を再開する
  • assumptions.md は判断の一覧です。 実行中に、ユーザーに代わって妥当な選択肢からひとつを選ぶたび(ファイル名、ライブラリのバージョン固定、課題で未解決のまま残された境界ケース、回避策を講じた main の失敗テストなど)、選択した内容、代替案、理由を 1 行追記します。ゲートが最初の項目を書き込みます。実装、QA、修正の各ステップでも、最後に記憶を頼りに書くのではなく、発生した時点でそれぞれ追記します。ユーザーが PR で最初に読むのはこの一覧です。

  • checks.md は判定基準です。 受け入れ基準ごとに 1 行記載します。識別子、基準を確認できる観測可能な事象、そしてエージェントが確認できるか人間にしか確認できないかを示すフラグを記載します。たとえば、C3 · /dashboard の 1280 px でサイドバーが表示される · agent のようにします。フラグには qakit のテストを使ってください。合格条件をスクリプトでアサートできるチェックはエージェントが確認できます。また、マシンにブラウザードライバーがあれば、ページの表示内容も含めて確認できます。ここにはコマンドを記載しません。qakit が、実際に取り込まれた内容からコマンドを導き出します。

  • orientation.md には事実とその出典だけを記載し、結論は記載しません。 「pnpm lint は abc123 の main で終了コード 1 を返し、vendor/ に 12 件のエラーがある」は事実ですが、「lint はどうせ壊れている」は事実ではありません。簡潔に保ち、開発サーバーのコマンドと既存の失敗に関する申告だけを記載します。

  • progress.md の行。 implement <group> <phases> <sha>、qa <path> <sha>、check <n blockers>、fix <sha>、qa-refresh <sha>。取り込まれた各ステップの直後に、1 行追記します。

  • ファイルシステムに書き込めない場合。 各ペイロードをセッション内に保持して受け入れチェックの概要に貼り付け、その方法で進めることを伝えます。

中断した実行を再開する

ワークツリーを引き継いでも、どのステップが完了したかは分かりません。よくあるのは、使用制限に達して停止するケースです。長時間のビルドがセッションの時間枠に達し、次のセッションには何のコンテキストも引き継がれません。issue がすでに in-progress になっている場合、または issue-<n>- ブランチがすでに存在する場合は、作業を始める前に、1 回の呼び出しで最初に状態を確認してください。

git branch --list 'issue-<n>-*' && git worktree list --porcelain \
  && gh pr list --state all --json number,url,state,headRefName -q '.[] | select(.headRefName | startswith("issue-<n>-"))'

ワークツリーのパスが分かったら、2 回目の呼び出しに git -C <worktree> status --porcelain、git -C <worktree> ls-remote --heads origin <branch>、git -C <worktree> rev-parse HEAD、および cat <worktree>/.afkkit/progress.md を追加してください。その後、次の表で最初に該当する行を選びます。

確認された状態実行が停止した後のステップ再開位置
ブランチにオープンな PR があるPR の作成ラベルがまだ in-progress の場合に限り、in-review への移行のみ(prkit のラベルステップ、または gh issue edit <n> --remove-label in-progress --add-label in-review)。結果は opened です
ブランチにマージ済みまたはクローズ済みの PR があるスパン何もしません。PR を報告して停止してください。issuekit の close または人間が対応します
origin 上のブランチがローカルの HEAD と一致し、PR がないプッシュPR を開く
origin 上のブランチが別のコミットを指している不明in-progress のままエスカレーションし、両方のコミットを明記します
progress.md に記載された QA 計画以外の未コミット変更がある実行中のステップin-progress のままエスカレーションし、パスを列挙します。afkkit は変更の所有者を推測しません
qa-refresh の行、または check 0 の行がある最後の QA 書き込みPR を開く
fix の行があり、qa-refresh がない修正コミット修正にある qakit の更新
ブロッカーがある check の行があり、fix がない受け入れチェック修正。適用する前に、各ブロッカー ID をコードで確認してください
check がなく、qa の行があるQA 計画受け入れチェック
各フェーズグループに implement の行があり、qa がない最後のフェーズコミットQA 計画
一部のグループに implement の行があるフェーズコミット実装。行のない最初のグループから再開します
progress.md がないafkkit に記録なしパイプライン全体

progress.md に記載されたすべてのコミットは、ブランチ上に存在している必要があります(git merge-base --is-ancestor <sha> HEAD)。記載されたコミットが見つからない場合は、実行中に履歴が変更されています。その場合は in-progress のままエスカレーションしてください。ワークツリー内から再開するすべての行では、まず issuekit の start を実行してワークツリーを引き継いでください。また、issue が in-progress の状態で届き、assumptions.md と checks.md がすでに存在する場合は、仕様ゲートを省略してください。ready を経由して戻ってきた issue は、grill によって仕様が変更されているため、新たにゲートを実施します。

完了条件:作業を始める前に、該当する行と再開位置を 1 行で明示します。

パイプライン(issue ごと)

各 issue について、以下を順番に実行してください。進行できないステップがあれば、エスカレーションの契約に従い、そこで issue を正常に停止させ、PR は作成しません。

1. issue を開始する

issuekit の start <n> を呼び出し、実行は無人で行うと伝えます。afkkit は start に何も追加せず、その機能を再実装することもありません。issuekit は ready ラベルが付いていない issue をすべて拒否し、作業ツリーを gitkit に依頼します(ブランチは issue-<n>-<slug>。既存の作業ツリーがあれば、作り直さずに採用します)。そしてラベルを ready → in-progress に変更します。issuekit はすべての変更内容を事前に表示し、OK を待ちます。ただしラベルの書き込みは例外で、すべての呼び出し元に対して確認なしで実行されます。実行は無人だと伝えることで、後続のすべての手順に、プロンプトに答える人がいないことを知らせます。

issuekit は、パスとともに gitkit prepare の結果を返します。prepare の失敗は実行上の不足です。in-progress のままエスカレーションし、失敗したコマンド、その終了コード、出力末尾をコメントに記載します。依存関係やデータベースのない作業ツリーでビルドすると、後になって、原因からさらに離れた段階で失敗します。

issuekit のオープン PR チェックは、オープン PR の件数と番号を無人の呼び出し元に返します。3 件で警告しますが、拒否はしないため、いずれの場合も実行は続行します。件数は引き継ぎのために控えておきます。

次に、1 回のシェル呼び出しで戻り値を確認し、パスをこの issue の実行状態として保持します。

git -C <worktree> rev-parse --show-toplevel \
  && git -C <worktree> branch --show-current \
  && gh issue view <n> --json labels -q '.labels[].name'   # real worktree, right branch, label now in-progress

issuekit が拒否した場合、それは事前確認での停止であり、エスカレーションではありません。まだ何も実行されていないためです。issuekit が示した理由を一字一句そのまま報告し、バッチ処理中であれば次の issue に進みます。

  • needs-planning → 判断がまだ確定していません。まず人間による検討セッションが必要です。
  • blocked → Blocked by #N の前提 issue と、その状態を示します。
  • クローズ済み、またはライフサイクルラベルなし → どちらに該当するかを伝えます。分類するのは issuekit triage です。

すでに in-progress の issue は拒否ではありません。issuekit は引き継ぎ経路を取り、gitkit は既存の作業ツリーを返します。そして実行は、中断した実行を再開するで見つかった状態から続行します。これには、エスカレーション後の再実行、使用量制限で中断された実行、人間が手作業で用意した作業ツリーが含まれます。

完了条件:確認用の呼び出しで作業ツリーのルート、issue-<n>- ブランチ、in-progress ラベルが表示されるか、拒否理由が記録されていること。

2. 仕様ゲート

コードを作成する前に、セッション内で issue の本文と、変更対象のコードを一度読みます。issue の仕様と、実装に必要な内容との間にあるすべての不足を分類します。

  • 判断の不足。 人間が決める必要のあるプロダクト上の選択やトレードオフです。→ 計画上の不足としてエスカレーションします。コードを書く前に停止し、未解決の質問を(検討用の質問として)正確に issue にコメントし、in-progress → needs-planning に変更します。
  • 人が関与する作業。 人が必要となるフェーズです。issue に Attended: と記されているもの、デザインの選択やモックアップの承認など人間による選択が必要なもの、またはフォローアップ issue の作成など、この実行の承認範囲に含まれない外部向けの操作が該当します。→ 同じ方法で計画上の不足としてエスカレーションします。実行が停止する原因となる各選択や操作をコメントし、in-progress → needs-planning に変更します。実行の途中でこれに遭遇すると、作業が半端な状態で止まるため、ゲートで事前に見つけます。検討によって選択が確定するか、issue 本文で操作が事前承認されれば、解消されます。
  • 手順上の不足のみ。 ファイル名、軽微なエッジケース、命名、経験のある実装者が議論の余地なく補える曖昧さです。→ 続行し、それぞれの判断を assumptions.md に記録します。

ready の issue は、このゲートを通過するはずです。ready になるには検討が必要だからです。このゲートは、漏れてしまった判断に対する最後の防波堤です。まだ決まっていないことを前提に実装してはいけません。implementkit の仕様不足による差し戻しは、その後段のセーフティネットとして残ります。

ゲートでは checks.md も作成します。受け入れ基準ごとに 1 件ずつ記載します。コードが存在しない段階で実行するため、基準となるテスト対象は、コードが実際にどう動くかではなく、issue で求められた内容です。

完了条件:assumptions.md と checks.md が存在し、すべての受け入れ基準に checks.md の項目があり、分類が決定していること。または、実行がエスカレーションされていること。

3. 実装

課題仕様に対して、ワークツリーのパスと認証情報を指定して implementkit を呼び出します。implementkit は、ストレートスルー方式と TDD 方式のどちらで進めるかを自ら判断し、独自のルールに従って長いビルドをフェーズグループごとのサブエージェントに分割し、完了を報告する前にリポジトリ独自のテストとビルドのゲートを通過させます。失敗の形によって、対応は異なります。

  • implementkit が仕様を不十分として差し戻す場合 → ゲートで見逃された 判断 の不足です。具体的な不足点をコメントに記載して、needs-planning にエスカレーションします。
  • implementkit がゲートを通過できない場合 → 実行 の失敗です。失敗したゲートの出力をコメントに記載して、in-progress のままエスカレーションします。

各フェーズ境界でコミットします。 ## Phase N 見出しのある課題は、フェーズグループごとに一度、commitkit を使って no-push でコミットします(フォールバック:グループで変更したパスを指定して git add -- <paths the group changed> && git commit を実行し、課題タイトルに基づく conventional な件名を付けます。push はしません)。その直後に progress.md に implement <group> <phases> <sha> を追記します。implementkit 自体の契約にはコミットが含まれないため、afkkit がグループ間でコミットします。この境界によって使用制限に達した際の停止範囲が限定され、再実行時に失われるのは進行中のグループまでとなります。フェーズ見出しがない本文は、1 つのグループとして扱います。

この実行では、課題のフェーズチェックボックスを更新しません。 このパイプラインで許可されているのはラベルの書き込みのみで、チェックボックスの編集はラベルの書き込みには該当しません。実行中は、ブランチ上のコミットが記録となります。

完了条件: すべてのフェーズグループについて、該当するコミットがブランチ上にある implement 行が progress.md に記録され、ワークツリーがクリーンで、implementkit のゲートを通過していること。または、実行がエスカレーションされていること。

4. QA 計画

ブランチに対して qakit を呼び出し、受け入れ項目として checks.md を渡し、orientation.md に記録された開発サーバーを指定します。qakit は docs/qa/NNNN-qa-<slug>-YYYY-MM-DD.md を作成し、エージェントが確認可能なすべてのチェックを自ら実行し(ドライバーがある場合はヘッドレスブラウザーで実行)、人間の判断が必要な各画面のスクリーンショットを撮影し、各結果を実行したリビジョンを記録します。checks.md の人間のみが実施する項目は、手動テストケースになります。

例外として、ここでエスカレーションするケースが 1 つあります。 変更がまったく実行できない場合(アプリが起動しない、またはすべてのページチェックが同じ理由で失敗する場合)は、実行上の不足です。in-progress のままエスカレーションし、起動できないコードの受け入れチェックにコストをかけないでください。

QA ドキュメントはコミットせずに残します。prkit が PR の手順でコミットします。progress.md に qa <path> <sha> を追記します。

完了条件: QA 計画が存在し、checks.md のエージェント項目すべてに、特定のリビジョンでの ✅ または ❌ が記録され、progress.md に qa 行があること。

5. 受け入れ確認

この実行で行うレビューは1回、ディスパッチも1回です。ディスパッチルールに従い、新しいサブエージェントを起動します。モデルはセッションのものを使いますが、ユーザーが別のモデルを指定した場合はそれを使います。サブエージェントはビルドの内容を把握していません。それこそが独立したレビューの目的です。ビルダーとコンテキストを共有するレビュー担当者は、使用するモデルにかかわらず、ビルダーと同じ見落としをします。

依頼には、パスを指定して、ワークツリー、課題番号、ブランチの差分範囲(<base>...HEAD)、assumptions.md、checks.md、orientation.md、スクリーンショットのディレクトリを含むQAプランを記載します。エージェント自身が新しいレビュー担当者であることを明記し、各パスを再委任せず、自ら実行するよう伝えます。担当する作業は次の順です。

  1. orientation.mdに記載された、既存の失敗に関する主張をすべて検証します。指定された各コマンドを、ベースブランチの使い捨てワークツリー(git worktree add --detach <tmp> <base>。検証後に削除)で1回ずつ実行し、confirmedまたはbelongs to this branchと記録します。このブランチに起因する失敗はブロッカーです。無人実行が出荷済みのリグレッションにつながるのを防ぐ唯一の確認なので、変更を実装したエージェント自身に評価させてはいけません。
  2. 差分範囲に対して、reviewkitの要件充足性と正確性のパスだけを実行します。明示された意図として課題を、判定基準としてchecks.mdを使います。qakitの❌の結果とスクリーンショットは証拠として確認します。スクリーンショットが基準に反している場合(「デザインAを選んだのに、ページにはBが表示されている」「サイドバーがない」など)は、差分に問題がないように見えてもブロッカーです。スクリーンショットがない場合(マシンにブラウザードライバーがない場合)は、差分だけをレビューし、その旨をfindings.mdに記載します。
  3. assumptions.mdを課題と照らし合わせて確認します。課題に反する前提や、課題で人の判断に委ねられていることを決めてしまう前提はブロッカーです。
  4. findings.mdを作成し、ブロッカーだけを記載します。それぞれに安定したID(B1、B2)、ファイルと行番号またはチェックID、証拠を含めます。スタイル、命名、好みはブロッカーではありません。それらはPRレビューbotと人間のレビュアーが担当します。

依頼の最後に、エージェントが行わないことを明記します。コードを編集せず、ブラウザーを起動せず、QA、コミット、プッシュ、PRの作成も行いません。ブロッカー数と、ブロッカーIDごとに1行を返します。progress.mdにcheck <n>を追記します。

完了条件:既存の失敗に関するすべての主張が記録され、checks.mdのすべてのエージェント基準がQA結果と照合され、ブロッカーリストの有無にかかわらずfindings.mdが存在すること。

6. 修正

findings.mdにブロッカーがなければ、PRを開くに進みます。

それ以外の場合は、セッション内でimplementkitの修正ラウンドを通じて、ブロッカーをIDごとにすべて修正します。このラウンドではリポジトリのゲートが実行されます。ブロッカーを修正できない場合、またはゲートを通過できない場合は、in-progressの状態を維持して該当IDを明記し、エスカレーションします。既知のブロッカーを残したままPRを開いてはいけません。既存の失敗と確認されたものはブロッカーではありません。ただし、それによってリポジトリの状態から受け入れ基準を満たせない場合は、未達成の基準としてPR本文に記載します。

no-pushを指定してcommitkitでコミットし、fix <sha>を追記します。その後、同じQAプランでqakitを再実行します。qakitは新しいリビジョンを指定している結果のみを再利用するため、修正コミットによって無効になったチェックを再実行します。afkkitはこのルールを緩和しません。qa-refresh <sha>を追記します。

完了条件:ブロッカーIDが残っておらず、修正コミットがブランチ上にあり、QAプランが新しいリビジョンを指定していること。または、該当IDを示して実行がエスカレーションされていること。

7. PR を開く

prkit を実行の認可とともに呼び出し、assumptions.md、QA 計画のパス、未達成の受け入れ基準があればその項目、受け入れチェックを自己チェックとして実行した場合はfindings.mdのパスを渡します。assumptions.mdの項目を本文にテキストとしてコピーしてAssumptions見出しの下に置き、そのセクションを要約より上の先頭に置くよう、prkit に伝えます。これらは実行がユーザーに代わって下した判断であり、レビュー担当者は何よりも先にそれを確認するためです。ファイルには決してリンクしないでください。.afkkit/は git の対象外であり、レビュー担当者が開けないためです。prkit は実際のコミットと差分に基づいてタイトルと本文を作成し、QA 計画をコミットして初めてブランチをプッシュし、PR を開いて、issue をin-reviewに進めます。認可には QA 計画のコミット、プッシュ、PR が含まれるため、どれもプレビューで止まりません。このステータス変更は、prkit 独自のラベル例外により、プロンプトなしで実行されます。prkit がない場合に限り、手動で PR を開いた後、実行はgh issue edit <n> --remove-label in-progress --add-label in-reviewにフォールバックします。

このステップは機械的な処理です。入力は実行ディレクトリ内のファイルと差分であり、コードを調査することはありません。

ここが正常終了地点です。PR が開かれ、QA 計画がコミットされ、issue がin-reviewになっています。

完了条件: PR の URL が存在し、QA 計画が PR のコミットに含まれ、本文の冒頭に仮定事項がテキストとして記載され、issue がin-reviewになっていること。

8. 引き継ぐ

このセクションは手順の形式で記述します。1文につき1つの指示とし、能動態、現在形を使い、比喩は使いません。

この実行を見守っていた人はいないため、レポートが引き継ぎ資料になります。まず開発サーバーを停止し、そのポートが解放されていることを確認します。

変更内容。 issue の結果を1行で示します。opened(PR のリンク)、escalated(ラベル、1行の理由、issue のリンク)、またはskipped(issuekit が拒否した理由と、何も変更されていない事実)です。次に、assumptions.mdの全項目を1行ずつ列挙します。これらは実行がユーザーに代わって下した判断です。開始時に未クローズの PR が3件以上あった場合は、件数と PR 番号を1行追加し、レビュー待ちの列が増えたことをユーザーに示します。バッチ処理では、バッチの概要に結果の行を集約します。

作業場所。 worktree のパスとブランチを示します。エスカレーション時には、コミットがディスク上に実在する作業であるため、この情報は不可欠です。スキップされた issue には worktree がありません。その旨を明記します。

次の手順。 結果に応じて振り分けます。兄弟キットの名前を挙げるのは、それがインストールされている場合に限り、それ以外はアクションを具体的に記述します。

  • opened → PR には人間のレビュー担当者が必要です。mergekit start <n> を実行すると、PR が作成された worktree に取り込まれます。コミット済み QA 計画にある手動テスト項目は、手作業で実行します。
  • escalated to needs-planning → issue に残された疑問点について、grillkit でグリルセッションを実施します。その後、issuekit のtriageで issue を再度昇格させます。グリルセッションの後、あなたの指示でneeds-planning → readyに切り替え、afkkit を再実行します。
  • escalated, still in-progress → 実行が行き詰まっています。コメントされたゲート出力または残存するブロッカーを示します。既存の worktree で手作業により再開します。

バッチ処理の後でも、次のアクションを1つだけ決めます。通常は最も古い未クローズの PR を選びます。振り分けるだけにとどめ、起動はしません。afkkit 自身が mergekit や grillkit を呼び出すことはありません。

完了条件: 各 issue に結果の行が1つあり、worktree のパスまたは worktree がない旨が記載され、すべての仮定が列挙され、実行が開始したプロセスがすべて停止し、レポートに次のアクションが1つだけ記載されていること。

メトリクスは要求された場合のみ出力します。 呼び出しで「afkkit 42 with metrics」のように要求された場合は、issue ごとに表を1つ出力します。各ステップを1行とし、グループ単位の実装ディスパッチではフェーズを示します。時間、ツールの使用回数、トークン数、キャッシュの読み取り/書き込み列は、ハーネスが実際に報告する場合に限り含めます。数値を推定してはいけません。この表は実行同士の比較に使います。メトリクスはレポートにのみ記載し、それ以外には記載しません。afkkit は実行レポートの成果物を書き出しません。

エスカレーションの契約

afkkit が所有する唯一のポリシーです。ステップを進められない場合は、先に進むのではなく、エスカレーションします。

既存の失敗の申告は、申告者以外の誰かが検証します。 ゲートが赤だが以前から壊れていると報告するステップは、無人実行とリグレッションを含むリリースの間にある唯一のチェックを免除するよう求めています。また、作業ツリー内からは、自分が引き起こした失敗と引き継いだ失敗を見分けられません。セッションは申告を orientation.md に記録して作業を続け、受け入れチェックでベースブランチ上の状態を再実行します。

  • ベースはグリーンです。 失敗はこのブランチに起因します。これはブロッカーであり、Fix が対処します。
  • ベースもレッドです。 申告は正しく、実行は続行します。ただし、その失敗によりリポジトリの状態から受け入れ基準を満たせない場合は、未達の基準として PR 本文に明記します。未達と判断する前に、QA 計画でその基準の結果を確認してください。ゲートの失敗から未達だと推測してはいけません。

同意が必要なステップで、確認できる相手がいない場合はエスカレーションします。 実行の権限の範囲外の操作でプレビューと確認のゲートに達したステップは、「はい」と決めつけずに停止します。in-progress のままにしようとしていた操作についてコメントを残し、次に進みます。プロンプトなしで実行できる変更は 2 種類あります。1 つ目は、権限に明記されており、ユーザーが実行開始時に承認した操作です。2 つ目は、呼び出し元を問わず、担当スキルが例外として認めている変更です。issuekit の start における ready → in-progress の変更と、prkit の in-review への進行は、どちらもプロンプトなしで実行されます。afkkit は担当スキルがすでに定めている例外に従い、例外の範囲を広げることはありません。また、権限をそのリストの範囲外まで拡大することもありません。

以降、エスカレーションは常に次の 5 つを意味します。

  1. PR を作成しません。
  2. 作業を保持します。 作業ツリーとすべてのコミットをそのまま残し、開発サーバーを停止します。
  3. 停止状態を issue に正確にコメントします。計画の不足なら未解決の質問、実行の不足なら失敗したゲートの出力、レビューの不足なら解消されずに残ったブロッカー ID を記載します。複数フェーズの issue では、コミットしたフェーズと停止したフェーズを明記します。
  4. 原因に応じてラベルを設定します。 計画の不足(仕様ゲートまたは implementkit における、決定事項の不足)→ in-progress → needs-planning に変更します。人間の確認待ちキューに戻します。実行の不足(テストがグリーンにならない、または修正後もブロッカーが残る)→ in-progress のままにします。 仕様に問題はありません。
  5. バッチを続行します。

完了条件: issue に停止状態のコメントと原因に応じたラベルが付いており、作業ツリーにすべてのコミットが残っていることです。

バッチモード:all

afkkit all は gh issue list --label ready --json number,title,labels,updatedAt からキューを取得し、順番に処理します。順次実行にしているのは意図的です。実装が経過時間の大半を占め、根本的に直列処理だからです。1 つのベースから並列ブランチを作るとマージコンフリクトが予測しにくくなり、並列セッションは使用量の予算を共有して互いのセッション制限到達を招きます。

呼び出し元のセッションは薄い指揮役となり、各 issue には新しいエージェントが割り当てられます。 issue N のコンテキストが issue N+1 のターンの使用量に計上されてはいけません。そのため、指揮役が保持するのはキューと各 issue の 1 行の結果だけです。issue ごとに次のように処理します。

  1. ディスパッチのルールに従って、課題エージェントをディスパッチします。課題番号、承認、およびこのスキルを概要として渡します。課題の開始からQA 計画までのパイプラインを実行し、ワークツリーのパス、オープン PR 数、現時点までの結果、およびprogress.mdの末尾部分を返すよう指示します。
  2. 指揮役から受け入れチェックをディスパッチします。 Claude 対応ホストでは、サブエージェントは独自に別のサブエージェントを起動できないため、課題エージェントはこのディスパッチを行えません。指揮役なら実行でき、チェッカーは変更を作成したエージェントから独立した状態を保てます。
  3. ブロッカー数とfindings.mdのパスを、ホストのエージェントへのメッセージ送信ツール(Claude 対応ホストではSendMessage、Codex ではsend_input)を使って課題エージェントに伝え、修正、PR のオープン、引き継ぎまで、ウォームコンテキストを保ったまま作業を続けさせます。エージェントを続行できないホストでは、再開テーブルの該当行から新しいエージェントをディスパッチします。

指揮役はワークツリーに書き込みません。ディスパッチを行い、progress.mdとラベルを読んで申告内容を確認し、次のアクションを決めます。ディスパッチの合間には、何をしているかを一行で伝えます。

  • キューを優先度順に並べます。 issuekit の優先度ラベルは同じlabels配列に、優先度の高い順、同じレベルでは更新日時の古い順、未評価の項目は最後に返されます。優先度が付いた課題がない場合は古い順にし、プレビューでその旨を伝えます。ユーザーが明示した順序は、どちらよりも優先されます。優先度でキューの順序は決まりますが、要件が緩和されることはありません。criticalの課題にもreadyが必要であり、仕様ゲートを通過しなければならず、推測せずエスカレーションします。
  • 確認は最初に一度だけ行います。 キューを(番号、優先度、タイトル、実行順で)表示し、何かを始める前に一度だけ OK を待ちます。キューの前に、ユーザーがすでにオープンしている機能 PR の数も表示します(issuekit のオープン PR チェックをここで一度だけ実行します)。キュー内の課題ごとに PR が一つ増えるため、3 件以上の場合はその旨も伝えます。OK があれば、課題ごとの質問はせず、その後の課題を開始します。OK 後は、何が起きても追加の確認を求めず、自動で実行します。単一課題の実行では、番号を指定すること自体が意思表示となるため、確認は不要です。
  • キューは OK を得た時点で固定され、各課題の開始前に再読み込みしません。 実行中にラベルが変更されるため、再読み込みすると、承認されていない課題までキューから取り除かれてしまいます。
  • 課題は必要になった時点で開始します。それぞれの課題は独自のパイプライン実行の冒頭で開始され、ワークツリーは最新のベースをフェッチしてから分岐します。途中で終了したバッチでは、まだ到達していない課題はreadyのまま変更されません。
  • allはreadyだけを処理します。 すでにin-progressの課題は、ワークツリーで人間が作業している可能性があるため、バッチではスキップします。含めるには明示的に(afkkit 42のように)指定してください。stackedの課題もスキップします。下位レイヤーの問題が上位レイヤーすべてに影響するため、バッチで安全に連鎖させることはできません。両方の種類を優先度とともに事前プレビューに表示し、スキップする理由を伝えてください。何も言わないと「処理不能」と受け取られますが、実際にはこのランナーが処理しないだけです。

最後に、バッチの概要を表示します。オープンした PR(リンク付き)、状態ごとのエスカレーション(リンクと一行の理由付き)、スキップした課題とその理由、オープンした各 PR に付随する前提を記載し、キューの処理が完了していない場合は、未着手の課題とその優先度も記載します。その後、引き継ぎにある、次に行うべき唯一のアクションを提示します。この概要と GitHub 自体の通知が、すべてのシグナルとなります。

非目標

  • 計画や詰問は行いません。 仕様が不十分な場合は、needs-planning として人間のキューに戻します。plankit と grillkit は引き続き対話形式で動作します。
  • 実行範囲内での2回目のレビューや、スタイルレビューは行いません。 実行中に issue に照らして一度だけチェックします。より詳細なレビューは、PR レベルのレビューボットと、PR 作成後の人間のレビュアーが担当します。
  • PR フィードバックループ、マージ、後片付けは行いません。 実行範囲は PR の作成時点で終了します。issuekit の close はマージ後に実行され、実行範囲外です。
  • 並列バッチやプッシュ通知は行いません。 ブラウザーのチェックは qakit 内でのみ行います。通知手段は GitHub とセッションの要約のみです。
  • スタックの連鎖処理は行いません。 all は stacked の issue をスキップし、その旨を伝えます。名前を指定した stacked の issue は他の issue と同様に実行されます。issuekit のガードが前提となる issue の PR 自体を確認するためです。
  • 新たなワークツリー、トラッカー、PR のロジックは追加しません。 ワークツリーのライフサイクルは gitkit が管理し、トラッカーの用語と ready ガードは issuekit が管理し、PR は prkit が管理します。afkkit はこれらを順序立てて実行し、エスカレーションポリシーを管理します。ゲートを呼び出すことと、ゲートを所有することは別です。afkkit が issue を処理可能かどうかを判断しなければならない時点で、その処理は実行範囲外になります。
  • 設定ファイルはありません。 すべてのステップはセッションのモデルで実行し、ルーティング方法は口頭で指定するインラインの上書きのみです。

備考

  • エスカレーションは失敗ではなく成功です。 壁に突き当たった時点で、PR を作成せず、作業を保持し、原因に応じて issue にラベルを付けて正常に停止することが、afkkit の役割です。
  • issue ごとに冪等です。 作業用ワークツリーが存在する issue に対して afkkit を再実行すると、issuekit の start を通じてそのワークツリーを引き継ぎ、中断した実行を再開するに従って、現在の状態から再開します。
  • ここにあるデフォルトよりリポジトリの方針を優先してください。 リポジトリに独自のレビューの深さ、QA の場所、PR テンプレートがある場合、関連キットはすでにそれらを尊重します。afkkit がそれらを上書きすることはありません。

コメント