babysit-pr について
babysit-pr は、GitHub の PR と GitLab の MR で、レビュー対応から未解決スレッドの解消までを進めるスキルです。指摘を検証し、阻害要因を修正してから変更を公開し、根拠を添えて各議論を閉じます。
主な機能
- 01インラインとトップレベルのレビューを収集
- 02コードに照らして指摘を検証
- 03阻害要因を修正してプッシュ
- 04スレッドに返信して解決
- 05コミット単位でレビューラウンドを追跡
活用シーン
- 01各プッシュ後のボット指摘を分類
- 02未回答のレビュー議論を解消
- 03レビュー返信前に修正を検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ amelnagdy/ review-skills --skill babysit-prインストール後、Claude Code で/babysit-prを入力して読み込まれたか確認します。
同梱ファイルscripts/threads.sh
詳細
PR を見守る
目標:プルリクエスト(GitHub)またはマージリクエスト(GitLab)を、「作成直後」から「未回答のものが何もない」状態まで進めます。その間、人間がページを更新し続ける必要はありません。以下では、どちらも「PR」と呼びます。
レビュー bot は差分に紐づくサンプラーです。プッシュするたびに新たなラウンドが始まり、ある箇所を修正すると、隣接する箇所にコメントが付くこともあります。放置すると、誰も解決しない未回答のスレッドが PR にたまり、3 ラウンド目の本当のバグが、1、2 ラウンド目の細かな指摘に埋もれてしまいます。あなたの役目は、すべての指摘を読み、実際に正しいかを判断し、ブロック要因を修正し、すべてのやり取りに文章で決着をつけることです。
gh(GitHub)、glab(GitLab)、および git の操作方法は理解しているものとします。以下では、このループに必要な判断と、間違えやすい少数の API 呼び出しだけを説明します。収集スクリプトは、カレントディレクトリの git origin から Forge を判別します。返されるデータはどちらでも同じ形式で、Forge が取得できない情報を示す capabilities ブロックが含まれます。
特に重要な 3 つのルール
信じる前に検証します。bot の重大度バッジは、何も実行せずに下した推測です。P1 を含むすべての指摘を、コードに照らして確認すべき主張として扱います。bot はよく正しいため(このループを実行する価値があるのはそのためです)、一方で自信たっぷりに間違えることも多く、提案を調べずに取り込むとバグを持ち込むことになります。賛成するにせよ反対するにせよ、実際のコードパスを読んでから判断してください。
すべてのスレッドに返信します。修正、却下、または保留した指摘は、そのスレッドでその旨を伝え、解決して初めてクローズとなります。何も言わないと、次に PR を開いた人には「無視された」と受け取られ、実際のバグが見落とされる原因になります。
返信する前に公開します。「修正済み」という返信が真実になるのは、リモートブランチに修正が反映されてからです。修正がローカルにしかない状態で、確認済みの返信を投稿したり、そのスレッドを解決したりしてはいけません。却下にプッシュは不要です。根拠を添えて返信し、すぐに解決します。
ラウンドの指摘を収集する
指摘は異なる 2 つの場所に届くため、片方だけを確認するラウンドでは、気づかないうちに半分を見落とします。見守りループで最もよくある失敗です。
- インラインレビューのスレッド。debate-review と Codex はここに指摘を投稿します(Codex は、定型的なレビュー本文に P1/P2 バッジ付きのインラインコメントを付けます。本文が空に見えても、何もないとは限りません)。各スレッドには、解決に使う
thread_idと、スレッド内への返信に使うreply_toが含まれます。GitHub では GraphQL のレビュースレッド、GitLab ではディスカッションです。 - トップレベルのレビュー本文。Greptile の要約、Codex が投稿する番号付きリスト、debate-review のラウンド概要はここに投稿されます。これらには解決するスレッドがないため、ラウンドごとに PR コメントを 1 件投稿して返信します。GitHub ではレビューオブジェクト、GitLab では通常のノートです。
同梱スクリプトは、相互に関連付け済みの両方を 1 回の呼び出しで返します(<skill-dir> はこの SKILL.md を含むフォルダーです)。
"<skill-dir>/scripts/threads.sh" <N> > /tmp/pr-<N>-round-<k>.json
フィルター適用後の件数は、フィルター適用前の件数と照合せずに信頼してはいけません。収集結果に jq フィルターを適用する前に、未加工の合計を出力し(jq '{threads: (.threads|length), reviews: (.reviews|length)}')、比較します。すべての項目が除外されるフィルターは、実際のスキーマに照らしてフィールド名を確認するまで、壊れているものとみなします(jq '.threads[0] | keys')。存在しないフィールド名を使った jq の選択は、エラーを出さず空の結果を返します。その結果「問題なし」と誤認して、P1 の上にマージゲートのコメントが投稿されることになります。実際に起きたことがあります。GitHub のツールはエラーを返さず、取得データを少なくすることで失敗します。これにはページネーションのルールも併せて適用してください。
取得していないオブジェクトについて説明してはいけません。特定の ID を指定したクエリが空の結果を返したら、それは停止の合図です。「確認できません」と伝え、別の方法(gh api .../reviews/<id>)で取得してください。内容を推測して説明してはいけません。関連する落とし穴として、インラインスレッドへの返信はすべて、0 バイトの COMMENTED レビューオブジェクトに包まれて届きます。そのため、ウォッチャーの「新しいレビュー」イベントは、新たなレビューラウンドではなく、返信を包むラッパーにすぎない場合があります。threads.sh の .reviews にはこれらのラッパーが含まれないため、イベントにあるレビュー ID が取得結果に見つからない場合は、「消失」ではなく「ラッパー」を意味します。
前のラウンドのファイルと差分を取り、実際に新しい内容を確認してください。スレッドの outdated: true は、その下の行が移動したことを意味します。指摘事項はすでに修正されている可能性があるため、そのラウンドを費やす前に、現在のコードと照合してください。すでに対応したスレッドの comment_count が増えていたら、ボットがそのスレッド内で返信したということです。
このレビュアーは現在のプッシュを確認していますか?sha を示すフィールドだけを信頼してください。GitHub では各レビューに commit_id があるため、head と比較します。どちらのフォージでも、debate-review のラウンド本文にある debate_head が、レビュー対象の sha です。GitLab では他のレビュアーのノートに sha がありません(capabilities. review_commit_id: false)。ノートのタイムスタンプがプッシュより後でも、そのプッシュをレビューした証拠にはなりません。推測せず、「カバレッジ不明」と伝えてください。
レビュアーに該当する作成者は 2 種類あります。1 つ目はボットです。取得結果で author_bot: true になっています。GitHub では API 自身の作成者タイプに基づいており、信頼できます(通常は chatgpt-codex-connector と greptile-apps ですが、許可リストをハードコードしないでください)。GitLab では API が示すのは一部の場合に限られるため、author_bot が null になることがあります。null は不明として扱い、スレッドを確認したうえで、レポートには確認できなかったことを記載してください。2 つ目は、最初のコメントに `` マーカーがあるスレッドです。debate-review はユーザー自身のアカウントから投稿されるため、作成者は PR の作成者(author_is_pr_author: true)ですが、そのスレッドはレビュアーのスレッドです。取得結果では、これらに debate_review: true が付けられ、マーカーから解析した debate_id、debate_status、debate_severity が含まれます。ラウンド本文は .reviews に表示され、レビュー対象の sha を示す debate_head と、debate_agreed/debate_contested が含まれます。これらは他のボットスレッドと同じように扱ってください。PR の作成者によるその他の内容、およびそのマーカーがない人間のコメントは、自律的な修正の対象にはなりません。代わりにユーザーへ知らせてください。
ボットの投稿はプッシュから 5~10 分後に届き、大きな差分ではさらに時間がかかります。頻繁に確認せず、待機をバックグラウンドで進めながら、その間に自分で差分をレビューしてください。想定しているすべてのレビュアーが、現在の head SHA に対する投稿を行うか、それぞれの待機時間の上限に達して利用不可と判断された時点で、ラウンドは「揃った」ことになります。利用不可のレビュアーがいても、投稿済みのレビュアーからの内容を取得したり、それに基づいて対応したりする妨げにはなりません。PR に問題がないと報告するのではなく、カバレッジの不足を開示してください。
バッジではなく、実際の影響で分類します
指摘を確認したら、ボットが付けたラベルではなく、結果に基づいて分類します。
ブロッキング:不具合を含んだままリリースされる、またはマージが止まるもの:
- 変更したコードに実際のバグ、誤った動作、または壊れたエッジケースがある
- セキュリティ、認可、データの整合性、またはデータ損失に関するリスクがある
- 変更自体が明示している契約、受け入れ基準、または仕様に違反している
- マイグレーションまたはスキーマに危険がある
- チェックが失敗する、または新たに不安定になる
非ブロッキング:実際の指摘ではあるものの、壊れたものはリリースされないもの:命名、構造、ドキュメント、テストの細かな指摘、わずかなパフォーマンス上の問題、「抽出を検討してください」といった提案、スタイルの好み。
指摘が本当に曖昧な場合は、降格するのに十分なコードを読むまでブロッキングとして扱います。この非対称性は意図的です。慎重すぎる修正にかかるのは数分ですが、見逃した P1 は本番環境のバグにつながります。
debate_status: contested の付いたレビュー議論スレッドは、2 つのモデルが調査して意見が分かれたことを意味します。メインのレビュアーは反論を受けても指摘を維持しており、コメントの最後の斜体の行に異議の内容が記載されています。これは既知の反論がある主張であり、弱い主張ではありません。同じように検証し、コードがどちらの見解を裏付けるか、またその理由を返信で述べてください。
ブロッカーを自律的に修正します
ブロッカーについて確認を求めて作業を止めないでください。検証し、修正し、プッシュし、引き続き状況を確認して、実施した内容を報告してください。
- 可能であれば、まず再現します。修正前に失敗し、修正後に成功する検証こそが、実際の修正ともっともらしいだけの編集を区別します。最初に指摘へ異議を唱えた場合は、とりわけ重要です。誤っていると大きな代償を伴うのは、まさにそうしたケースです。
- 指摘ごとではなく、ラウンドごとに 1 回プッシュします。プッシュするたびに新しいボットラウンドが始まるため、指摘ごとにプッシュすると、待つラウンド数が増えてしまいます。
- プッシュ前に、リポジトリ独自のゲートを実行します。修正によってテストスイートが壊れると、ラウンドが丸ごと 1 回余分に必要になります。
- 該当するガードスキル(guard-skills の clean-code-guard、test-guard、wp-guard、woo-guard)がインストールされている場合は、プッシュ前に修正へ実行します。こうしたガードは、レビューのプレッシャーの中で急いで修正した場合に起こりがちな失敗を検出します。
- 異議がある場合は、根拠を示します。指摘を退けるのは正当なことであり、よくあることですが、返信には根拠が必要です。コードパス、すでに対処しているガード、または動作を保証するテストを示してください。「問題ありません」だけでは、反論になりません。
公開し、返信してから解決する
指摘ごとではなく、ラウンド単位でまとめて対応します。すべてを確認し、可能であれば確認済みのブロッカーを再現し、すべて修正してゲートを実行したら、一度だけコミットしてプッシュし、リモートの SHA を確認します。その後にのみ、各スレッドを解決します。
- 確認済み:修正コミットを明記して返信し、その後に解決します。
- 却下:具体的な根拠を添えて返信し、その後に解決します。プッシュは不要です。いつでも解決できます。
- 保留:合意した issue を作成し、そのリンクを添えて返信した後に解決します。
ユーザーが承認したブロッカー以外の修正は、次回の統合プッシュに含めます。個別にプッシュしてはいけません。再レビュー免除のプッシュはありません。最終的なドキュメントのみ、または軽微な修正のみのプッシュも含め、すべてのプッシュについて、マージ前にマージゲートレビュー担当者から問題なしのラウンドレビューを受ける必要があります(「マージ前」を参照)。公開または検証に失敗した場合は、スレッドを開いたままにし、ブロッカーを報告します。
指摘があったスレッド内で返信します。新しいトップレベルコメントを投稿すると元のスレッドが開いたままになり、読者が手作業で関連付ける必要が生じます。収集データの reply_to を使って返信し、thread_id を使って解決します。GitHub ではこの2つは別の識別子(REST コメント ID、GraphQL スレッド ID)です。GitLab ではどちらもディスカッション ID です。
GitHub:
gh api --method POST "repos/<owner>/<repo>/pulls/<N>/comments/<reply_to>/replies" \
-f body="$(cat /tmp/reply.md)"
gh api graphql -f query='mutation($t:ID!){
resolveReviewThread(input:{threadId:$t}){ thread{ isResolved } } }' -F t="<thread_id>"
GitLab(<project> は URL エンコードされた group/path、--hostname は使用するインスタンスです):
glab api --hostname <host> --method POST "projects/<project>/merge_requests/<N>/discussions/<reply_to>/notes" \
--raw-field "body=$(cat /tmp/reply.md)"
glab api --hostname <host> --method PUT "projects/<project>/merge_requests/<N>/discussions/<thread_id>" \
-F resolved=true
GitLab の返信および解決の API 呼び出しは GitLab API ドキュメントに基づいていますが、このスキルから稼働中のインスタンスに対してまだ実行したことはありません。初めて使用する際はレスポンスを確認し、いずれかが失敗した場合は、別の形式を試さずに停止して報告してください。
投稿者の明示。人間が判断したのかどうかを読者が推測しなくて済むよう、すべての返信は、返信を作成するモデル名と、そのモデルが誰を代弁しているかを明記して始めます。自身のモデル名で署名してください。このスキルは特定のモデルに依存しません。代弁する相手は、その返信を投稿するアカウントの所有者です。セッションごとに一度だけ名前を取得し、GitHub では gh api user -q '.name // .login'、GitLab では glab api user --hostname <host> | jq -r '.name // .username' を実行して、その後は同じ名前を使います。
私は <model-slug> です。<user> を代弁して返信します。
続けて判定、その後に簡潔な根拠を示します。
I am <model-slug> writing on behalf of <user>.
Confirmed and fixed in `a1b2c3d`. You were right that `occurrence_time` was never
compared against `evidence.event_time`, so a mapping could bind proof from a
different occurrence. Reproduced with a failing test first
(`test_binds_proof_to_mapped_occurrence`), then fixed the composition check.
I am <model-slug> writing on behalf of <user>.
Declining this one. The nil case you describe is already unreachable. `resolve()`
returns early at `handlers.py:88` whenever the session is unset, which is the only
path that reaches this line. Leaving the behavior as-is.
実際に解決したものだけを解決します。修正してプッシュした指摘、根拠を添えて却下した指摘、または issue を作成して保留にした指摘です。回答していない質問のスレッドは解決しないでください。解決するということは対応が完了したと示すことです。誤った完了報告をするくらいなら、スレッドを開いたままにしてください。
ブロッカー以外:ラウンドごとに一度、まとめて確認する
指摘ごとに作業を中断せず、また黙って判断を下すことも避けます。ブロッカーへの対応後、ラウンドごとに一度、ブロッカー以外の指摘をそれぞれ推奨案(今すぐ修正、issue を作成、または却下)とあわせてリストにし、ユーザーの判断を仰ぎます。
PR #123 のラウンド 2 です。ブロッカー1件を修正してプッシュしました(
a1b2c3d)。ブロッカー以外の指摘が3件残っています。
- debate-review:
test_foo.pyに重複している fixture を切り出す。推奨:issue を作成。この変更範囲外のファイルにも影響します- Codex:
Counterの比較は==を直接使えます。推奨:今すぐ修正。1行です- Greptile:新しいヘルパーに docstring がありません。推奨:今すぐ修正。些細な変更です 2と3を次のプッシュで修正し、1は issue にしますか?
どのような判断であっても、各スレッドは他の指摘と同じ方法で解決します。保留にする指摘には、数か月後でも対応できるだけの情報を記した実際の issue を作成します。スレッドへのリンク、ファイル名、保留にした理由を含めてください。タイトルだけでは不十分です。
固定予算内で再レビューを依頼する
1 回の実行で行うのは、初回のレビューと、その後の修正をまとめて反映した最大 2 回のプッシュおよび 2 回の再レビューまでです。ユーザーから明示的に続行を求められない限り、これを超えて続けてはいけません。各プッシュの後は、自分で次のラウンドを開始します。レビュアーによって開始方法が異なります。レビュアーは次の 3 通りの方法で起動するためです。
-
debate-review はボットではなくローカルスクリプトで、どちらのフォージでも動作します。実行すると、待っている間にレビュー全体を行い、レビューが投稿されると終了します。通知もポーリングも不要です。
node "<debate-review skill-dir>/scripts/review-pr.mjs" <pr-url>(
<debate-review skill-dir>はスキルがインストールされている場所です。標準的なインストール先は~/.agents/skills/debate-reviewです。)バックグラウンドで実行し、作業を続けて、コマンドが終了したらすぐにレビュー結果を取得します。レビューの URL が出力されます。終了コード 3 は、この head がすでにレビュー済みであることを意味します。1 回の実行でレビューするのは 1 つの head sha だけなので、プッシュ後に実行すれば、必ず新しいラウンドが始まります。実行には 10~20 分かかります。 -
Codex は GitHub アプリです(GitLab に相当するものはありません)。PR コメントで
@codex reviewとメンションしてから待ちます。8~15 分後に、実行時点の最新 head に対して回答します。プッシュ内容が対象になっていることを確認してから判断してください。レビューのcommit_idを確認します。 -
Greptile などのボットは、各プッシュを自動で再レビューします。呼び出す必要はありません。指摘が届いたら対応します。
ボットのレビューを待つ場合、通常の所要時間を過ぎてから待つのは最大 10 分までです。反応がない場合やレート制限されている場合は、そのレビュアーを利用不可として扱います。クールダウンが終わるまで待ってはいけません。例外はマージゲートにおけるマージゲートレビュアーで、こちらにはタイムアウトがありません(「マージ前」を参照)。テストのみ、ドキュメントのみ、または軽微な修正のみの最終プッシュであっても、必ずレビューを受けます。最後のプッシュが未レビューのままでは、以下のマージゲートが意味をなしません。
修正をまとめてプッシュするたびに、リポジトリで必須とされているゲートを 1 回実行します。同じ SHA ですでに成功したゲートは再実行しません。ユーザーから「止めて」「もう十分」「あるものをそのままプッシュして」と言われたら、実行中のポーリングや時間のかかるゲートをキャンセルし、すぐに完了できる範囲で最小限の関連チェックを実行して、安全な作業を公開します。未完了のゲートがあればその旨を伝え、次のレビューラウンドは開始しません。
ラウンドを重ねるごとに、指摘は減っていくべきです。3 回目のラウンドで 1 回目と同じ規模の指摘があるなら、何か根本的な問題が起きています。ひたすら対応し続けるのではなく、そのことを伝えてください。同じ形の指摘が繰り返される場合は、原因ではなく症状に対処している可能性が高いため、その点を明らかにする価値があります。
予算の上限に達したら作業を止め、残っている指摘、未解決のスレッド、最後にレビューされた SHA、利用できなかったレビュアーを正確に引き継ぎます。未レビューの head を問題なしと説明してはいけません。
マージ前
マージゲートを通過するには、リポジトリの主要レビュアーから、マージ候補そのもの、つまり最終ヘッド SHA に対する明示的な問題なしのラウンドを得る必要があります。どのレビュアーが該当するかはリポジトリによって異なります。
Codex がインストールされている場合は、最後のプッシュ後に @codex review とメンションし、返信を待ちます。問題なしのラウンドとは、最終ヘッドに対して Codex が「指摘事項なし」「よくできています」といった明確な言葉でそう伝えることです。まだ返信がない状態は合格ではありません。Codex はプッシュから 8〜15 分後に回答するため、その時間内にマージすると、マージから数分後に実際の指摘が届くことになります。
debate-review がレビュアーの場合(GitLab では通常、これだけです)は、最終ヘッドに対して実行します。問題なしのラウンドと判断するには、次の 3 つすべてを満たす必要があります。.reviews にそのラウンドの本文があり、debate_head が最終ヘッド SHA と一致すること、debate_agreed と debate_contested がどちらも 0 であること、未解決のレビュアースレッドがないことです。本文がない場合(インラインコメントを投稿した後に実行が失敗することがあります)は、ゲートを通過していません。推測で判断せず、再実行してください。
どちらの場合も、指摘があれば新しいラウンドが必要であり、マージしてはいけません。通常の待機時間を大幅に過ぎても返答がない場合は、承認と見なすのではなく、ユーザーに報告してください。
マージを提案する前に、PR の最新コメントを再取得して読み直してください。監視が静かな状態で落ち着くと、遅れて届いたラウンドを見逃すことがあります。最後の確認後に投稿されたコメントこそ、その内容を見落としたままマージしてしまうものです。
その後、マージするかどうかをユーザーに尋ねてください。自分の判断でマージしてはいけません。実施したラウンド数、修正したブロッカーとその SHA、却下した指摘とその理由、起票した問題、残っている未解決スレッド(できれば 0)、CI の状態を報告してください。マージするかどうかはユーザーが決めます。それに至るまでの作業はすべて、あなたが行ったものです。
作業を止めて申し出るタイミング
次の状況では、無理に対応を続ける必要はありません。
- ボットの指摘が正しいものの、この PR の範囲を大きく超える変更を求めている場合。
- コード、テスト、明示された仕様を見ても結論を出せないのに、同じ行について 2 つのボットの意見が食い違っている場合。
- 再試行後も同じ指摘が繰り返される場合。最初の再発時には、根本原因を再検証したうえで、修正予算の範囲内でもう一度だけ試みます。2 回目の再発は、バグについての自分の理解が誤っていることを意味します。
- 人間のレビュアーからコメントがあった場合。例外はありません。
- コードではなくインフラの理由で CI が失敗している場合。
- 2 回の修正サイクルの予算を使い切った場合。
- ユーザーから、作業を止めること、現在の作業をプッシュすること、または見守りループを終了することを求められた場合。