This doc explains the autonomous PR review/fix pipeline (the largest piece of the kit). For the smaller pieces (individual hooks, the commit gate, the defense-loop skills), the source code is the doc — each file's header comment is enough.
GitHub repo with open PRs
│
│ gh pr list
▼
┌────────────────────────────────────────────────────────┐
│ ONE tmux session per repo: <repo>-pr │
│ │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ window "review" │ │ window "orchestrator"│ │
│ │ /loop /pr-review-tick│ │ /loop /pr-orch-tick │ │
│ │ Agent A │ │ Agent B │ │
│ │ │ │ CLAUDE_ROLE=orch │ │
│ └──────────────────────┘ └──────────────────────┘ │
│ │ │ │
│ │ posts review comment │ reads comment │
│ │ writes notify_orch flag │ spawns worker │
│ ▼ ▼ │
└────────────────────────────────────────────────────────┘
│ │
▼ ▼
PR comment on GitHub /tmp/orch-<slug>-pr<N>/
("Agent A round @ <sha>") (worker worktree;
sub-agent does the fixes,
commits with [auto N/4],
pushes back to PR branch)
│
▼
GitHub PR head moves
→ Agent A sees new sha
→ next review round starts
Job: discover open PRs, dedup against (pr_number, head_sha) → review_id
state, and for each PR with new content run a three-angle review then post
a single aggregated comment.
Three angles, in parallel (one Bash + two Agent calls in one message):
- Cross-vendor adversarial —
codex reviewagainst the PR diff. This is genuinely non-Claude signal. The user's codex profile determines the backend model (gpt-5, gpt-4o, etc.). Catches Claude blind spots that Claude-only review can't. - General Opus review —
Agent(subagent_type="code-reviewer-opus", ...). The kit's user-level Opus reviewer, with a confidence ≥ 80 filter so it only surfaces high-conviction findings. - PR-level coherence —
Agent(subagent_type="general-purpose", model="opus", ...). A bespoke prompt covering things the other two miss: cross-commit consistency, scope creep, test completeness, CI status, breaking-change detection.
Output: one PR comment per round, formatted as:
## PR review pipeline — Agent A round N @ <short_sha>
### Critical (must fix)
- [angle/P0] file:line — what + why
### Important
- [angle/P1] ...
### Suggestions (advisory)
- [angle/P2] ...
### CI status at <short_sha>
- ...
---
*Posted by `pr-review-tick` daemon. Angles: codex (...), code-reviewer-opus (...), pr-coherence (...). cc Agent B for triage.*
Big-PR handling: codex degrades sharply above 5000 lines/call (10–20×
latency, token-counter retries). For PRs larger than that, the skill
synthetic-commit-splits the diff into bins of ≤5000 lines each
(first-fit-decreasing bin packing), commits each bin as a synthetic
commit on a temp worktree with [skip-review] in the message, and runs
codex review --commit <syn_sha> per bin. The [skip-review] marker
keeps the second-opinion-commit-gate hook from recursing.
Job: triage Agent A's findings, spawn a sub-agent to fix them, and gate auto-merge.
Tick logic:
- List PRs that have a new comment from Agent A since the last orch tick.
- For each: read the comment, parse into
[P0]/[P1]/[P2]findings. - Spawn a
general-purposeAgent in a fresh worktree at/tmp/orch-<slug>-pr<N>. The worker follows thepr-defense-looptriage discipline: a/b/c split (worth-fixing / wrong-analysis / not-worth-fixing), fix the a's, push back on b's with a comment. The worker is the only thing that writes code — Agent B itself never does. Theblock-orchestrator-writes.shhook enforces this. - Worker commits with
[auto N/4]suffix and pushes to the PR branch. Each commit triggers the second-opinion-commit-gate hook (since[auto N/4]is not[skip-review]); if the gate blocks, the worker loops on its owncommit-defense-loop. - After the worker reports "no more actionable findings" (or
max_rounds=4hits), Agent B runs the verdict gate:- If
dry_runflag exists: post a "would auto-merge" comment instead of merging. - If the PR author is an external contributor: refuse to auto-merge regardless of dry-run state; @-mention the user.
- Otherwise:
gh pr merge(squash by default).
- If
Concurrency: per-PR flock lock files prevent Agent A and Agent B
from racing on the same PR.
The orchestrator can spawn sub-agents that do anything (worker writes
code, commits, pushes; review writes comments). But the orchestrator
itself never directly invokes Edit, Write, git commit, etc.
The reason: an orchestrator that can both make decisions AND mutate code
will, under load, accidentally try to fix things directly instead of
delegating. We've seen it. The block-orchestrator-writes.sh hook
makes "delegate to a worker" the ONLY viable code-fix path. The
orchestrator that can't write code can't shortcut delegation.
The hook is gated on CLAUDE_ROLE=orchestrator (env var set by the
launcher) and bypasses when the PreToolUse payload has an agent_id
(meaning the call is coming from a sub-agent, not the orchestrator
itself). Sub-agents inherit the env var but are intended to write —
the agent_id field is how the hook distinguishes them.
Lives at ~/.local/state/claude-pr-pipeline/<owner>__<repo>/:
dry_run # presence = Agent B posts "would auto-merge" instead of merging
last_review_tick_at # ISO timestamp of last Agent A run
last_orch_tick_at # ISO timestamp of last Agent B run
notify_orch # touched by Agent A to wake Agent B early (if Monitor is set up)
pr-<N>/
head_sha # last reviewed sha for PR N
review_comment_id # last review-comment id (for dedup)
fix_round # how many auto-fix rounds happened (caps at 4)
The state directory is shared between Agent A and Agent B within a repo. Cross-repo state is fully isolated (different subdirs).
The skills set up two ways to wake on each tick:
- Cron
*/2 * * * *(mandatory, primary). Created by the skill's step 1.5 on first tick using Claude Code'sCronCreatetool. The skill DELETES + recreates if it finds a wrong interval. - Monitor on
notify_orchfile (optional, for orchestrator only). Watches for Agent A to touch the file, gives sub-minute wake latency. Not critical when cron is*/2— but useful if you dial cron up to*/10for some reason.
Cron + Monitor are both in-process in Claude Code (no external cron daemon). They survive session resume but not session kill.
tmux kill-session -t <repo>-pr # stop the daemons
# Optionally:
rm -rf ~/.local/state/claude-pr-pipeline/<owner>__<repo>/ # wipe state
# Per-PR worker worktrees clean themselves up after each tick, but
# leftovers at /tmp/orch-<slug>-pr<N>/ are safe to remove manually.The protect-state-from-rm.sh hook blocks rm -rf against the state
dir to prevent accidental wipes inside a Claude session. To bypass for
a legitimate cleanup, run the rm outside Claude or set
PR_PIPELINE_RM_OK=1 for that session.
- dry_run by default for ~7 days. The kit assumes you want to watch
Agent B's verdicts on real PRs for a while before letting it actually
merge. The first bring-up creates
dry_run; yourmit when you trust the verdicts. - External contributors are never auto-merged. Agent B refuses to
gh pr mergeif the PR author isn't in the repo's collaborator set, regardless of dry_run state. max_rounds=4per PR. If the worker can't close findings in 4 rounds, Agent B escalates to the operator instead of looping forever.- No support for monorepos with selective path triggers. The pipeline reviews the full PR diff every round. If you have a big monorepo with per-team CODEOWNERS, you'll want to add a path-filter step yourself.
- The cross-vendor adversarial angle requires a working codex profile. Without one, the skill falls back to 2 angles and notes the miss. The kit doesn't tell you which codex profile to use — any non-Claude reviewer model works.