| name | pr-poller |
| description | ローカル Claude Code 内でポーリング起動し、gh CLI で merged/closed PR を取得 →
未処理 PR があれば pr-retrospective を起動、Renovate ラベル PR があれば
dependency-upgrade を起動するハーネスループ起点 Skill。3 系統の起動経路 (起動時 +
CronCreate + ScheduleWakeup) に対応するため .claude/locks/pr-poller.lock で排他制御し、
pending-fetch 項目の再走査と harness-meta 自動起動の閾値判定も担当する。
|
| status | active |
| phase | A4 |
| last_updated | "2026-05-19T00:00:00.000Z" |
| related_plan | docs/harness/plan.md §5.3 / §5.4 / §6.2 A3 / §6.2 A4 |
| related_rules | [".claude/rules/pr-poller.md",".claude/rules/harness-meta-criteria.md",".claude/rules/retrospective-format.md",".claude/rules/mcp-usage.md",".claude/rules/pii.md",".claude/rules/secrets.md",".claude/rules/roadmap.md"] |
| related_adrs | ["ADR-0017","ADR-0024","ADR-0026"] |
pr-poller
5 行以内 summary: ローカル Claude Code 内でポーリング起動し、gh CLI で merged/closed PR を
取得 → 未処理 PR があれば pr-retrospective を起動、labels:renovate 系 open PR があれば
dependency-upgrade を起動する Skill。3 系統の起動経路 (起動時 / CronCreate / ScheduleWakeup)
を .claude/locks/pr-poller.lock の mkdir 方式で排他制御し、harness-meta 自動起動閾値判定と
roadmap-tracker pending-fetch 再走査も同 Phase 内で実施する (R-11 / R-12 / R-35、ADR-0017)。
役割
- ハーネスループ起点: Spec Gen → Implementation → Evaluation → Merge → Retrospection → Meta の Retrospection 入口を担い、後続 Skill (
pr-retrospective / dependency-upgrade / harness-meta) を起動する責務単位
- 未処理 PR 検出 + pr-retrospective 起動:
gh pr list --state merged,closed の取得結果に対し docs/harness/learnings/*.md の存在で dedup → 未処理 PR があれば 1 件ずつ pr-retrospective Skill を起動 (R-12 ロスト対策の learning 生成 + push を後続 Skill が担当)
- Renovate ラベル open PR 検出 + dependency-upgrade 起動:
gh pr list --state open --label renovate 等で Renovate 系 PR を取得 → 各 PR の number を dependency-upgrade Skill に渡す (R-37 / ADR-0017)
- harness-meta 自動起動閾値判定: 未処理 learning 件数 (デフォルト 10 件) / 前回
harness-meta 実行からの経過 (デフォルト 7 日) を harness-meta-criteria.md §pr-poller 起動閾値 から読込み、超過時に harness-meta を起動
- roadmap-tracker pending-fetch 再走査:
docs/harness/roadmap.md / docs/epics/<id>/roadmap.md の <!-- evidence:pending-fetch --> コメント有項目を再 gh pr view、成功時は完了根拠を埋める (R-35)
- GitHub Actions では呼ばれない (ADR-0017): 起動経路はローカル Claude Code 内のみ、CI 上での Claude API 呼び出しは禁止
責務境界: 本 Skill 自身は learning ファイル / PR コメント / Plan / Epic を 生成しない (後続 Skill 担当)。本 Skill は「対象 PR を見つける + 排他制御 + 後続 Skill を呼ぶ + 起動結果を集計報告する」だけに専念する。
入力
- 起動経路 (auto-detect): 3 系統のいずれか
- manual (起動時): ローカル Claude Code 起動直後 / 人間 prompt 「pr-poller 走らせて」「未処理 PR を回収して」等
- cron (CronCreate): Claude Code routine の日次 09:00 JST 起動 (A4 で導入予定、本 Skill 側は経路識別子を受け取って動作差分)
- wakeup (ScheduleWakeup):
/loop Skill 等から前回処理 N 時間後の自動再起動 (A4 導入予定、pending-fetch 再走査を優先実行)
- 起動経路は引数 (
route=manual|cron|wakeup) で渡される、未指定なら manual と扱う
- lookback 期間 (default
24h): gh pr list --search "merged:>$LAST_RUN" の検索範囲。$LAST_RUN は .claude/locks/pr-poller.last-run に記録、ファイル不在時は lookback から逆算 (now - 7d をフォールバック上限)
- dry-run flag (default
false): true なら gh pr list のみ実行、後続 Skill 呼び出し + learning push + harness-meta 起動を skip + 標準出力に「起動予定 Skill リスト + 対象 PR#」を出す
- harness-meta 起動閾値 (引数 or
harness-meta-criteria.md 由来):
unprocessed_learnings_threshold (default 10 件)
harness_meta_interval_days (default 7 日)
harness_meta_min_interval_hours (default 24 時間)
- lock 設定: stale 判定閾値 (default 30 分)、PID file
.claude/locks/pr-poller.lock 配下
出力
フェーズ別動作 (5 Phase)
Phase 1: Lock 取得
Phase 2: 対象 PR 取得 (gh CLI)
$LAST_RUN を .claude/locks/pr-poller.last-run から読み込み (不在時は now - 7d)。lookback 引数で上書き可。gh CLI は 手動 git grep より優先 / GitHub MCP より優先 (ADR-0024)。
- merged/closed PR (Retrospection 対象):
gh pr list --state merged --search "merged:>$LAST_RUN" --limit 50 \
--json number,title,mergedAt,labels,author,baseRefName,headRefName
gh pr list --state closed --search "closed:>$LAST_RUN" --limit 20 \
--json number,title,closedAt,labels,author,baseRefName,headRefName
closed は merged で取得できない (人間が close した未マージ PR) 分の取りこぼし対策、件数は少なめに絞る
- Renovate ラベル open PR (dependency-upgrade 対象):
gh pr list --state open --label renovate --limit 30 \
--json number,title,labels,author,headRefName
gh pr list --state open --label dependencies --limit 30 --json number,title,labels,author,headRefName
gh pr list --state open --label renovate-bot --limit 10 --json number,title,labels,author,headRefName
- 3 ラベルのいずれか付与で対象 (
.claude/rules/pr-poller.md Phase 2 検出ロジック準拠)、UNION して dedup
- gh CLI 失敗時のリトライ: 指数バックオフ (1s → 2s → 4s)、最大 3 回。3 回失敗したら当該クエリを次回再試行に回し warning ログ + 連続 5 件失敗で本 Skill を緊急停止 + orchestrator 通知 (R-11)
Phase 3: ラベル / 未処理判定 + dedup
- merged/closed PR の未処理判定:
docs/harness/learnings/*.md を ls → frontmatter related_pr: NNN または ファイル名 YYYY-MM-DD-pr-<N>.md の <N> を抽出して処理済 set を構築
.claude/locks/pr-poller.processed-cache も参照 (直近 30 日分、ファイル列挙のショートカット)
- Phase 2 で取得した PR# から処理済 set を差し引いて未処理リスト確定
- Renovate ラベル PR の判定:
author.login == "renovate[bot]" または app/renovate の場合は確実に Renovate PR
- 人間が手動で
renovate ラベルを付けた PR (Renovate 化途中) は author が異なるため、dependency-upgrade 側で再確認させる (本 Skill では「Renovate ラベルがあれば dispatch する」だけに留め、誤検出は下流が判断)
- キャッチアップ動作 (R-11):
$LAST_RUN が 3 日以上前 なら「最後の処理から経過した PR」を最優先で FIFO 処理。件数が 30 件超なら orchestrator に warning 通知 + 古い順から 10 件ずつ batch (本 Phase 内では並べ替えのみ、Phase 4 で dispatch)
Phase 4: 後続 Skill dispatch
dispatch は順次 / 直列 (並列起動は Phase 4 内では行わない、各 Skill の touch ファイル衝突 / lock 衝突を予防):
- 未処理 merged/closed PR 1 件ごとに
pr-retrospective 起動: 引数 pr_number=<N> を渡す。各 Skill の終了を待ち、learning ファイル生成 + harness/learnings-batch-YYYY-WW ブランチ push の成否を確認 (失敗時は次回再試行に回す)
- Renovate open PR 1 件ごとに
dependency-upgrade 起動: 引数 pr_number=<N> を渡す。各 Skill が gh pr comment + Plan / Epic 起票で完結する (本 Skill は完了報告だけ集約)
- pending-fetch 再走査 (
roadmap-tracker の <!-- evidence:pending-fetch -->):
docs/harness/roadmap.md と docs/epics/*/roadmap.md を grep → pending PR# を抽出
- 各 PR# に対し
gh pr view <N> --json mergedAt,state を再試行
- 成功時 (state=MERGED かつ mergedAt あり) は
roadmap-tracker を起動して完了根拠を埋める / コメント削除 (R-35)
- harness-meta 自動起動閾値判定:
- 本セッションで生成された未処理 learning 件数 + 既存未処理 learning 件数を
harness-meta-criteria.md §pr-poller 起動閾値 と比較
- 未処理 learning >= 10 件 または 前回
harness-meta 実行から >= 7 日 かつ 最小実行間隔 24 時間を超えていれば harness-meta を起動
- 起動時は
.claude/locks/harness-meta.lock 排他制御 (harness-meta 側で実装、二重起動防止)
- dry-run mode の場合: dispatch を全て skip + handoff サマリだけ出力 (Skill 起動なし、副作用なし)
Phase 5: Lock 解放 + last-run 更新
.claude/locks/pr-poller.last-run に 現在時刻 (ISO8601) を上書き (lock 解放前に書くことで、次回起動時のキャッチアップ起点が確実に更新される)
.claude/locks/pr-poller.processed-cache に本 Phase で処理した PR# を追記 (直近 30 日超の行は trim)
rm -rf .claude/locks/pr-poller.lock で lock 解放
- handoff サマリを §出力 のフォーマットで標準出力に出す
- 異常終了時 (Phase 1-4 のいずれかで unrecoverable error): lock を解放してから orchestrator 通知 + 当該 PR を次回再試行に回す (lock 残留は次回 stale 判定で自動回収されるため強制不要)
実運用稼働手順 (A4 本格化)
3 系統起動経路の具体的 setup と初回 dogfood 手順。.claude/rules/pr-poller.md §3 系統の起動経路 + harness-meta-criteria.md §pr-poller 起動閾値 と整合。
経路 1: SessionStart hook (起動時 auto-invoke)
.claude/settings.json の hooks.SessionStart で Bash command を登録し、Claude Code セッション開始時に 「pr-poller 起動候補」のヒントを context に注入 する (.claude/rules/pr-poller.md §3 系統 / .claude/rules/harness-meta-criteria.md §pr-poller 起動閾値 参照)。
{
"hooks": {
"SessionStart": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "test -d .claude/locks/pr-poller.lock 2>/dev/null && echo '[pr-poller] lock active - skip auto-invoke' || echo '[pr-poller] no active lock - 候補: /pr-poller を起動して未処理 PR の有無を確認 (R-15 / R-37、SessionStart hint)'"
}
]
}
]
}
}
- hook の責務は context 注入のみ: Skill の自動起動は Claude が判断 (R-15 人間 approve の代替として、Claude が「起動候補」を提示する形)
- lock 既存時は skip:
mkdir が EEXIST で失敗する経路と整合、二重起動防止 (Phase 1 §stale 判定)
- PII / Secrets 漏洩経路なし: hook の stdout は固定文字列、
gh pr / git log などの外部コマンドを 呼ばない (PR# / 著者名等が context に乗らない、R-26)
経路 2: CronCreate (日次まとめ)
ローカル Claude Code routine を CronCreate で登録し、日次まとめ起動。harness-meta-criteria.md §pr-poller 起動閾値 (7 日経過、10 件閾値) と組合せて週単位の取りこぼし防止。
# 例: 毎日 22:00 JST (= 13:00 UTC) に pr-poller を起動
/schedule "0 13 * * *" /pr-poller route=cron
- cron 式は UTC で記述 (CronCreate の慣行)、JST 換算は手元計算で確認
- route=cron を渡す: Skill 側で経路識別 (Phase 1 lock 内
route 平文ファイルへ記録)
- 環境ロードのタイミング: Claude Code routine は起動時に
.claude/mcp.json / .claude/settings.json を再ロードするが、shell 環境変数は親プロセス継承前提なので gh auth status を最初に走らせて token 有効性を確認 (失敗時は Phase 2 連続失敗 5 件で緊急停止経路に乗る)
- 22:00 JST 採用理由: 日中の人間活動 (PR merge / コードレビュー) が一巡した後に retro 集約、翌日 09:00 JST までに learning が揃う想定
経路 3: ScheduleWakeup (継続ループ短時間追従)
/loop skill 経由で dynamic 間隔の wakeup を予約。merge tide が来ているタイミング (例: 並列 implementation PR が複数 merge された直後) の追従に使う。
# 例: 自己 pace で 20-30 分間隔の継続起動
/loop /pr-poller route=wakeup
- delaySeconds 推奨: 1200-1800s (20-30 分)、ScheduleWakeup の cache TTL 5 分超え前提で長め設定
- CronCreate との重複時: 09:00 JST の cron 起動と wakeup loop が同 lookback で重なる可能性 →
.claude/locks/pr-poller.lock の mkdir 排他で後発側が 30 分 no-op (.claude/rules/pr-poller.md §3 系統 二重起動防止)
- 明示停止: wakeup loop を止めるときは
/loop の停止指示で次サイクルから自動終了 (lock は正常終了で解放済)
初回 dogfood 手順
A4 PR merge 直後の本 Skill 実運用稼働を以下の手順で確認:
- lock 取得確認:
mkdir .claude/locks/pr-poller.lock で原子取得、配下に pid / acquired_at / route=manual 配置 (Phase 1)
- 対象 PR 検出:
gh pr list --state merged --search "merged:>2026-05-12" --limit 50 --json number,title,mergedAt で直近 7 日の merge PR 列挙 (Phase 2)
- dedup:
docs/harness/learnings/YYYY-MM-DD-pr-<N>.md を ls して処理済 set を構築、Phase 2 結果から差し引いて未処理リスト確定 (Phase 3)
- dispatch: 未処理 PR 1 件ごとに
pr-retrospective Skill 起動 (Phase 4)
- harness-meta 自動起動閾値判定: 未処理 learning 件数 + 前回 harness-meta 実行経過日数を
harness-meta-criteria.md §実行時パラメータ と比較、閾値超過なら harness-meta 起動 (Phase 4)
- lock 解放:
.claude/locks/pr-poller.last-run 更新 → rm -rf .claude/locks/pr-poller.lock (Phase 5)
- handoff サマリ: 標準出力に §出力 のフォーマットで起動経路 / 検出件数 / dispatch 件数 / harness-meta 起動有無を出力
A4 dogfood 期待値 (PR #180 直後タイミング)
PR #180 (4 件 retro 同時 merge: #174 / #175 / #176 / #177) の merge 直後で本 Skill を稼働させた場合の期待観測値 (実測は A4 PR merge 後の手動 dogfood で記録):
| 項目 | 期待値 | 観測手順 |
|---|
| 未処理 learning 件数 (本 Skill 起動時点) | 0-2 件 | `ls docs/harness/learnings/2026-05-*.md |
| 未処理 merged PR (直近 7 日) | 0-3 件 | gh pr list --state merged --search "merged:>2026-05-12" の件数 - 処理済 set |
| 前回 harness-meta 実行からの経過日数 | 7 日未満 (PR #156 から 5 月 13-15 日経過) | git log -- .claude/rules/harness-meta-criteria.md の最新更新日 |
| harness-meta 自動起動 | 起動しない見込み | 未処理 learning < 10 件 + 経過日数 < 7 日 (harness-meta-criteria.md §実行時パラメータ デフォルト) |
| Renovate open PR | 0-2 件 | gh pr list --state open --label renovate --limit 30 |
dogfood 結果は本 Skill PR merge 後の retro (docs/harness/learnings/YYYY-MM-DD-pr-<A4 PR#>.md) に「§指標」表として記録、.claude/rules/harness-meta-criteria.md §実行時パラメータ §dogfood 観測値 に転載する。
Gotchas
- 3 系統起動経路の二重起動防止:
.claude/locks/pr-poller.lock mkdir 排他で防御。CronCreate の 09:00 起動と ScheduleWakeup の前回 +N 時間起動が偶発的に重なる場合があり、後発側は 30 分以内 no-op で skip + 次サイクルに回す。stale 30 分は経験値で、長時間 dispatch を想定する場合は引数で延長可
- Lock 取得失敗時のフォールバック:
mkdir が EACCES (権限) で失敗するケース (worktree 移動直後 / .claude/locks/ 未作成) では handoff 「lock 取得不能、.claude/locks/ の存在 + 書込権限を確認」を出力して即時終了。retry 無限ループ禁止
- CronCreate と ScheduleWakeup の責務分離: cron は「日次まとめて」、wakeup は「短時間の追従」。同 lookback で重複 dispatch しないよう
.claude/locks/pr-poller.last-run で前進判定 (mergedAt > LAST_RUN を必ず通す)
- Renovate ラベル PR の commit author 判定:
renovate[bot] (= App) と「人間が Renovate ラベルを手動付与したケース」が混在する。本 Skill は ラベル付与のみで dispatch を決め、author 確認 / 妥当性判定は dependency-upgrade 側に委ねる (本 Skill が誤検出を判断しない、責務境界を狭める)
- PII / Secrets redaction を必ず通す (R-26 /
.claude/rules/pii.md / .claude/rules/secrets.md): handoff サマリ + processed-cache + last-run には PR title / author display name を含めない (PR# + メタ情報のみ)。gh pr view --json の body フィールドは本 Skill で直接扱わず後続 Skill に渡す (redaction 責務を pr-retrospective / dependency-upgrade 側に集約)
.claude/locks/*.last-run / *.processed-cache を絶対 commit しない: .gitignore で除外 (.claude/locks/README.md 参照)。lock ディレクトリ自体は .gitkeep で空コミット維持し、配下ファイルは ignore
- gh CLI 失敗時の連鎖停止: 連続 5 件 (
gh pr list 自体の不調) で本 Skill を緊急停止 + orchestrator 通知 (R-11)。retry 無限ループは資源浪費 + classifier 誤検知の原因
- キャッチアップ動作中の新規 PR: $LAST_RUN が 3 日以上前のキャッチアップ batch 処理中に、新たな merged PR が発生しても優先順位を変えず FIFO で処理 (古い PR の learning が後回しになると R-12 の趣旨 = レトロ取りこぼし防止 と矛盾)。batch 完走後の次サイクルで新規分を処理
- GitHub Actions では呼ばない (ADR-0017): 本 Skill 起動経路はローカル Claude Code 内のみ。
.github/workflows/pr-poller.yml 等の workflow は作らない (Claude API コスト回避 + PII 漏洩経路集約、§5.4 / R-37)
- harness-meta との二重起動防止: 本 Skill が
harness-meta を自動起動した直後に人間が手動起動するケースがある → .claude/locks/harness-meta.lock の排他制御を harness-meta Skill 側で担う。本 Skill では「閾値超過したら起動を試みる」だけで成否は問わない
- dry-run と本走の取り違え防止: dry-run flag が true でも
.claude/locks/pr-poller.lock は取る (二重 dry-run も防ぐ)。ただし .claude/locks/pr-poller.last-run は 更新しない (次回本走時の lookback を壊さない)
harness-evolution は本 Skill から起動しない (ADR-0026): 外部研究駆動は手動起動のみ。本 Skill から自動起動すると内部 KPT (harness-meta) と外部研究の責務境界が曖昧化する
- classifier 迂回 NG 表現の回避 (
.claude/rules/harness-meta-criteria.md §classifier ブロック対応): handoff サマリ / commit message / PR description に「auto-merge」「self-merge」「force-merge」を書かない、「人間 approve 待ち」「orchestrator 委任」等の中立表現を使う
関連
- ADR-0017 (ローカル Claude Code ポーリング駆動、GitHub Actions で Claude API を呼ばない原則)
- ADR-0024 (
gh CLI 採用、GitHub MCP 不採用、PR 操作の SoT)
- ADR-0026 (
harness-evolution は手動起動のみ、本 Skill から自動起動しない根拠)
docs/harness/plan.md §5.3 (Skill 責務一覧) / §5.4 (ハーネスループ Retrospection 入口) / §6.2 A3 / §6.2 A4 (本格化フェーズ)
.claude/rules/pr-poller.md (3 系統起動経路 + 排他制御 + 検出ロジック SoT)
.claude/rules/harness-meta-criteria.md §pr-poller 起動閾値 (10 件 / 7 日 / 24h の上書き可)
.claude/rules/retrospective-format.md (pr-retrospective 生成フォーマット、本 Skill が dispatch する先)
.claude/rules/mcp-usage.md (gh CLI 優位、Context7 / JetBrains MCP の使い分け)
.claude/rules/{pii,secrets}.md (handoff / cache の redaction)
.claude/rules/roadmap.md (pending-fetch 再走査の対象、R-35)
.claude/skills/pr-retrospective/SKILL.md (dispatch 対象、A3-10 で本格化)
.claude/skills/dependency-upgrade/SKILL.md (dispatch 対象、A3-7 完了)
.claude/skills/harness-meta/SKILL.md (閾値超過時の自動起動先)
.claude/skills/roadmap-tracker/SKILL.md (pending-fetch 再走査時に起動)
.claude/skills/implementation-workflow/SKILL.md (Phase 8 で本 Skill を即時起動する上位フロー)
.claude/locks/README.md (lock ディレクトリ運用ルール)