pr-shepherd 0.57.0 → 0.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +150 -297
  4. package/bin/classify/standard/codex-notices.d.mts +3 -2
  5. package/bin/classify/standard/codex-notices.mjs +4 -6
  6. package/bin/classify/standard/gemini-notices.d.mts +1 -1
  7. package/bin/classify/standard/gemini-notices.mjs +2 -2
  8. package/bin/classify/standard/index.d.mts +4 -1
  9. package/bin/classify/standard/index.mjs +4 -5
  10. package/bin/classify/standard/kilo-no-issues.d.mts +1 -1
  11. package/bin/classify/standard/kilo-no-issues.mjs +2 -2
  12. package/bin/classify/standard/sourcery-notices.d.mts +1 -1
  13. package/bin/classify/standard/sourcery-notices.mjs +2 -2
  14. package/bin/commands/iterate/index.mjs +31 -12
  15. package/bin/github/captured-proxy-agent.d.mts +3 -0
  16. package/bin/github/captured-proxy-agent.mjs +8 -0
  17. package/bin/github/github-fetch.mjs +19 -6
  18. package/bin/github/legacy-dispatcher.d.mts +6 -0
  19. package/bin/github/legacy-dispatcher.mjs +44 -0
  20. package/bin/github/poll-summary-readiness.d.mts +6 -1
  21. package/bin/github/poll-summary-readiness.mjs +9 -3
  22. package/bin/github/poll-summary-review.mjs +13 -10
  23. package/package.json +3 -3
  24. package/plugins/pr-shepherd/.claude-plugin/plugin.json +15 -0
  25. package/plugins/pr-shepherd/.codex-plugin/plugin.json +1 -1
  26. package/plugins/pr-shepherd/.codex.mcp.json +1 -1
  27. package/plugins/pr-shepherd/.mcp.json +1 -1
  28. package/plugins/pr-shepherd/skills/mark-files-as-viewed/SKILL.md +1 -1
  29. package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +1 -1
  30. package/plugins/pr-shepherd/skills/reduce-pr-noise/SKILL.md +1 -1
  31. package/plugins/pr-shepherd/skills/reduce-pr-noise/references/classifiers.md +2 -2
  32. package/bin/classify/standard/coderabbit-review-summary.d.mts +0 -8
  33. package/bin/classify/standard/coderabbit-review-summary.mjs +0 -37
  34. package/bin/classify/standard/codex-review-summary.d.mts +0 -7
  35. package/bin/classify/standard/codex-review-summary.mjs +0 -20
@@ -10,7 +10,7 @@
10
10
  {
11
11
  "name": "pr-shepherd",
12
12
  "description": "Autonomous PR CI monitor and review-comment resolver",
13
- "source": "./",
13
+ "source": "./plugins/pr-shepherd",
14
14
  "category": "productivity",
15
15
  "homepage": "https://github.com/jonathanong/pr-shepherd"
16
16
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pr-shepherd",
3
3
  "description": "Autonomous PR CI monitor and review-comment resolver for agentic coding tools",
4
- "version": "0.57.0",
4
+ "version": "0.58.0",
5
5
  "author": {
6
6
  "name": "Jonathan Ong",
7
7
  "email": "jonathanrichardong@gmail.com"
package/README.md CHANGED
@@ -1,375 +1,228 @@
1
1
  # pr-shepherd
2
2
 
3
- Autonomous PR CI monitor and review-comment resolver for agentic coding tools, including Claude Code and Codex.
3
+ Drive a pull request to merge-ready with a coding agent. It works with Claude Code, Codex, Grok, and any stdio MCP client.
4
4
 
5
- **[jongleberry.com/pr-shepherd](https://jongleberry.com/pr-shepherd/)** — the why and the principles behind the design, for humans and agents.
5
+ **Estimated per PR session: −42% cost and −19% turns vs. `gh`, −77% cost vs. the GitHub MCP server. While waiting on CI: ~60 GraphQL points an hour vs. ~360 for `gh pr checks --watch`.**
6
6
 
7
- ## Why
7
+ ## Outcomes
8
8
 
9
- An agent finishing a PR should think about code, not reconstruct GitHub state or invent a next-step policy each tick. Without Shepherd it fans out across GitHub MCP, `gh`, and GraphQL, then guesses what to do with the result.
9
+ | Outcome | Headline | Evidence |
10
+ | ----------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
11
+ | [Context and correctness](#context-and-correctness) | 60 GitHub edge cases cataloged, backed by 147 scenario fixtures; on 8 of them, evals show the agent does worse without the plugin | [Handled cases](docs/handled-cases.md) |
12
+ | [Fewer tokens, lower cost](#fewer-tokens-and-lower-cost) | Cost −42% vs. `gh` and −77% vs. MCP per PR session; turns −19% / −70% (estimates) | [Token bench](evals/tokens/README.md) |
13
+ | [Clearer agent direction](#clearer-agent-direction) | GitHub gotchas (cancelled runs, merge queues, stacks): eval score 0.82 → 0.94, about two-thirds fewer misses | [Behavior evals](evals/README.md) |
14
+ | [Lower GitHub API quota use](#lower-github-api-quota-use) | ~60 GraphQL points per CI-wait hour vs. ~360 for `gh`; ~4 when idle. REST core per PR session 4.8 vs. 9 (`gh`), 78.3 (MCP) | [GitHub API](docs/github-api.md), [GraphQL usage](docs/graphql-usage.md) |
15
+ | [Safe by construction](#safe-by-construction) | 0 git mutations; human handoff limited to 10 escalation triggers for a single PR | [Escalations](docs/escalations.md) |
16
+ | [Works across agents and stacks](#works-across-agents-and-environments) | 3 agent plugins plus any stdio MCP client; GraphQL and REST transports; native stacked PRs | [MCP](docs/mcp.md), [cloud](docs/cloud.md) |
17
+
18
+ **[jongleberry.com/pr-shepherd](https://jongleberry.com/pr-shepherd/)** covers the why and the design principles.
10
19
 
11
20
  ## What it does
12
21
 
13
- 1. **Gather all context for a PR** in one invocation: review threads, comments, replies, summaries, CI, mergeability, merge requirements, first-look / outdated / edited items, and author provenance.
14
- 2. **Provide deterministic actions for the agent**: exactly one of `WAIT`, `MARK_READY`, `FIX_CODE`, `MERGE`, `CANCEL`, or `ESCALATE`, plus numbered `## Instructions` and explicit commands. The agent still decides whether a comment or CI failure needs a code change. Shepherd does not classify signal vs noise and does not mutate git.
22
+ - Gathers the PR's review items, CI failures, and merge requirements in one call.
23
+ - Returns one action with numbered instructions and exact commands. `CANCEL` ends the loop and carries none.
24
+ - Never mutates git. The agent edits, commits, pushes, and decides what each comment deserves.
15
25
 
16
- Highlights:
26
+ ```mermaid
27
+ flowchart LR
28
+ A[Agent] -->|iterate PR| S[pr-shepherd]
29
+ S -->|batched, conditional reads| G[(GitHub)]
30
+ G --> S
31
+ S -->|one action + numbered instructions| A
32
+ A -->|fix, push, run the printed commands| G
33
+ ```
17
34
 
18
- - GraphQL by default, with a supported REST transport for Claude Code cloud sessions and narrowly defined automatic fallback. REST may expose less context; missing fields remain unknown. MCP `iterate` is one tick and the client owns recurrence; `--debounce` is a poll-dispatcher settle window, not an MCP tool.
19
- - CI summaries include failed checks, and the failed job/step plus a log excerpt when triage can fetch them. Job and log details are omitted for `STARTUP_FAILURE` and `CANCELLED`; agents may still inspect logs.
20
- - Handles GitHub comment types (comments, threads, replies) and their states, including first-look, outdated, resolved, minimized, and edited.
21
- - `apply` batches resolve / reply / minimize / dismiss. `build_suggestion_patches` validates and returns ordered diffs without mutating git.
22
- - `BEHIND` is mergeability information, not a rebase or a guarantee that the next push is at the default-branch tip. The agent can update the branch before pushing.
35
+ Without Shepherd, an agent fans out across `gh`, the GitHub MCP server, and GraphQL to rebuild PR state, then guesses the next step. Details for each outcome follow; more features are in [docs/features.md](docs/features.md).
23
36
 
24
- Full reference: [docs/README.md](docs/README.md). Feature matrix: [docs/features.md](docs/features.md).
37
+ ## Outcome details
25
38
 
26
- ## How It Works
39
+ ### Context and correctness
27
40
 
28
- `pr-shepherd` moves deterministic PR orchestration into a local MCP server, with a CLI for shells and CI. Both interfaces fetch the same GitHub state, emit raw-enough context, and return a numbered plan for the calling agent to follow.
41
+ One `iterate` call returns everything the agent needs about the PR:
29
42
 
30
- The MCP server exposes `iterate`, `apply`, `build_suggestion_patches`, `extract_journal`, and `get_journal`. `apply` accepts ordered review mutations, file-view mutations, and journal entries; the deprecated singular suggestion tool remains temporarily as an adapter. PR-targeted MCP calls require a repository-qualified `pr`: a GitHub PR URL or `owner/repo#N`; the explicit repository is the target for GitHub I/O, even when it differs from the local checkout. `extract_journal` takes a Markdown body string and performs no I/O. The CLI and programmatic API also retain bare-number and current-branch PR discovery. The shipped skills are thin dispatchers for those tools.
43
+ - review threads with replies, PR comments, and review summaries;
44
+ - each CI failure, with its failed step and a log excerpt when triage can fetch them;
45
+ - mergeability and the actual merge requirements;
46
+ - first-look, outdated, and edited items, and stack topology.
31
47
 
32
- Each tick returns exactly one action:
48
+ One exception: a `COMMENTED` review that was already minimized before the first tick is not fetched.
33
49
 
34
- - `WAIT` — no immediate action; continue with the next poll.
35
- - `MARK_READY` — the CLI converted an eligible draft PR to ready; continue polling.
36
- - `FIX_CODE` — agent work is required; complete it, push when needed, then continue polling. Push access to the PR head branch is a usage precondition.
37
- - `MERGE` — run the emitted head-pinned merge or queue command for the selected transport. GitHub is authoritative for the result and reports any authorization failure. Queue operations can use REST.
38
- - `CANCEL` — stop polling this pull request because it merged, closed, or completed its ready-delay. It prints no instructions; continue any remaining pull requests or issues from the original request.
39
- - `ESCALATE` — stop polling until a human provides direction. Native stacks reach this only after their autonomous one-PR sessions are exhausted.
50
+ The agent reasons less and misses less. [docs/handled-cases.md](docs/handled-cases.md) catalogs the GitHub edge cases this covers. These are the gotchas where the [behavior evals](evals/README.md) measured the agent going wrong without the plugin (score with vs. without):
40
51
 
41
- Native-stack summaries additionally use stack-level `SHEPHERD`: run the listed one-PR sessions,
42
- then recheck the stack. It is not a per-PR `FIX_CODE` action.
52
+ | GitHub gotcha | With | Without |
53
+ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---: | ------: |
54
+ | On a stack layer, the latest run of a required check was cancelled while an older run passed. GitHub still blocks the merge ([#567](https://github.com/jonathanong/pr-shepherd/pull/567), [gh-stack#466](https://github.com/github/gh-stack/issues/466)) | 1.00 | 0.44 |
55
+ | A bot `CHANGES_REQUESTED` review and a human thread arrive together | 0.89 | 0.33 |
56
+ | A cancelled run needs a rerun, not a code fix | 1.00 | 0.50 |
57
+ | Every stack layer is merged, so the loop must stop | 1.00 | 0.50 |
58
+ | GitHub denied a reply: skip it once instead of retrying | 0.72 | 0.33 |
59
+ | A maintainer removed the PR from the merge queue | 1.00 | 0.67 |
60
+ | A required run was cancelled in the merge queue: escalate, don't requeue | 0.75 | 0.42 |
61
+ | The REST transport cannot run the queue recovery | 1.00 | 0.83 |
43
62
 
44
- Example shape:
63
+ ### Fewer tokens and lower cost
45
64
 
46
- ```text
47
- > pr-shepherd 123
65
+ Batching, noise filtering, fingerprint skips, seen markers, and lean output cut tokens and agent turns. Estimated cost per session from the [token bench](evals/tokens/README.md) ([report](evals/tokens/REPORT.md)):
48
66
 
49
- # PR #123 [FIX_CODE]
67
+ | Session | Cost vs. `gh` | Cost vs. GitHub MCP |
68
+ | --------- | ------------: | ------------------: |
69
+ | Single PR | **−42%** | **−77%** |
70
+ | PR stack | **−45%** | **−63%** |
50
71
 
51
- **status** `UNRESOLVED_COMMENTS` · **repo** `owner/repo`
52
- **summary** 3 passing
72
+ These are offline estimates at 3.5 characters per token over recorded sessions, not measured billing. Two cases do not save money:
53
73
 
54
- ## Review threads
74
+ - A single fresh read-and-reply tick is roughly even with `gh`.
75
+ - Confirming an already-merged PR costs about 5% more ([report](evals/tokens/REPORT.md)).
55
76
 
56
- ### `threadId=PRRT_kwDOSGizTs58XB1L` — `src/commands/iterate/index.mts:42` (@alice · MEMBER)
77
+ ### Clearer agent direction
57
78
 
58
- > The variable name is misleading.
79
+ For a single PR, each tick returns exactly one action: `WAIT`, `READY`, `MARK_READY`, `FIX_CODE`, `MERGE`, `CANCEL`, or `ESCALATE`. A `--stack` poll can also return `SHEPHERD`, which starts one-PR sessions for owned layers. Every action except `CANCEL` comes with numbered `## Instructions` and exact commands, so the agent does not invent policy. In the [behavior evals](evals/README.md), Sonnet 5.5 at low effort scores **0.94** with the plugin and **0.82** without it on the 36 GitHub-gotcha cases, so it misses about two-thirds fewer graded checks (0.18 → 0.06). On the eight gotchas listed under [Context and correctness](#context-and-correctness) it goes from 0.50 to 0.92. Weighted toward those gotchas, the mean Δ over all 52 cases is **+0.14**, and no case has a regression whose interval excludes 0. See [docs/actions.md](docs/actions.md) for the output contract.
59
80
 
60
- ## Failing checks
81
+ ### Lower GitHub API quota use
61
82
 
62
- - `24697658766` — `CI › lint / typecheck / test (22.x)` [conclusion: FAILURE]
63
- > oxfmt
83
+ GitHub meters two tiers ([details](docs/github-api.md#github-metering)):
64
84
 
65
- ## Instructions
85
+ - Primary hourly budgets: GraphQL points and REST `core` requests.
86
+ - Secondary limits: per-minute points, where each GraphQL query or REST `GET` costs 1 and each mutation costs 5, plus concurrency and content-creation limits.
66
87
 
67
- 1. Fix each warranted item.
68
- 2. Triage `## Failing checks`. Playbook: "CI failure triage".
69
- 3. Commit and push any changes.
70
- 4. Journal key decisions or rejections with URLs or IDs: `pr-shepherd apply journal 123 '- <decision>'`
71
- 5. `$DISMISS_MESSAGE`: one sentence on what changed. Run even if no code changed: `pr-shepherd apply review 123 --reply-thread-ids PRRT_kwDOSGizTs58XB1L --message "$DISMISS_MESSAGE" --require-sha HEAD`
72
- 6. Rerun Shepherd now.
73
- ```
88
+ Waiting is where most quota goes, and where Shepherd saves the most. By default `gh pr checks --watch` refreshes every 10 seconds, at 1 GraphQL point per refresh. That is about 360 points an hour for each watched PR, so a few agents waiting on CI can drain the shared 5,000-point hourly budget. Shepherd polls every 60 seconds by default:
74
89
 
75
- See [docs/actions.md](docs/actions.md) for the complete output contract and [docs/escalations.md](docs/escalations.md) for the exact finite human-handoff boundary. Iterate/poll PR outcomes use exit codes `0` and `10`–`16`; command and GitHub failures use `sysexits.h` codes — [docs/exit-codes.md](docs/exit-codes.md).
90
+ - A typical tick is one batched GraphQL query (1 point). Large or paginated PRs add supplement queries. When nothing changed, the fingerprint skip returns the stored report from that same query.
91
+ - While CI runs, that is about 60 points an hour for a typical PR, against about 360 for `gh pr checks --watch` at its default interval. The token bench models `gh` refreshing every 60 seconds, which ties Shepherd at 60 ([report](evals/tokens/REPORT.md)).
92
+ - When no check is running, conditional REST change detectors run first. A `304` consumes no primary quota. An hour of unchanged idle waiting costs about 4 GraphQL points instead of 60 ([graphql-usage.md](docs/graphql-usage.md)). That holds only when the stored report is eligible for the detectors. Native-stack layers, `READY` reports, incomplete snapshots, and detector failures still run the batched query each tick ([graphql.md](docs/graphql.md#idle-wait-change-detectors)).
76
93
 
77
- ## Workflow Assumptions
94
+ Fewer requests help on both tiers. The GitHub MCP server issues one or more REST requests per tool call, so unbatched calls drain `core` and the per-minute pool faster.
78
95
 
79
- This system is opinionated and works best with PRs that use required status checks and conversation resolution.
96
+ Per session, assumed and deterministic, from the [token bench](evals/tokens/README.md):
80
97
 
81
- - A human inline thread whose original comment has `viewerDidAuthor: true` is replied to and resolved when its latest comment is unmarked. Bot/non-human threads use the same reply-and-resolve pairing. An unmarked other-human inline thread remains reply-only unless `iterate.resolveOtherHumanThreads` is `outdated` or `always`. Human items are never minimized.
82
- - Detected bots, configured `botUsernames`, and viewer-authored human review threads are returned until resolved when the required mutation is authorized. Reply and resolve mutations use the thread ID, so they still run when GitHub has cleared the source line. Unauthorized threads are surfaced once and then marker-gated until edited. Bot/non-human threads, PR comments, and review summaries can be resolved or minimized when eligible. Review summaries are not minimized while known inline child threads from that review remain unresolved.
83
- - Shepherd identifies its own latest reply only when that comment begins `<!-- pr-shepherd -->`, not from author equality. A marked viewer-authored thread can be resolved without another reply as a retry.
84
- - Every review thread/comment/review summary is surfaced at least once, even if already outdated, resolved, or minimized; edited items re-surface through seen markers.
85
- - Draft PRs can be marked ready automatically when clean; disable with `actions.autoMarkReady: false` or `--no-auto-mark-ready`.
86
- - With `--merge`, actionable review threads/comments/reviews/summaries are held back (`WAIT`, with raw deferred-work counts) while a PR sits in the merge queue, since a Shepherd-initiated push would eject it; set `actions.workWhileQueued: true` to act on them immediately instead. Failing checks and merge conflicts are never deferred.
87
- - The CLI never performs git mutations itself — it only emits commit/push instructions for the agent to run. Push access to the PR head is a usage precondition; GitHub viewer fields do not create a separate push-authorization handoff.
88
- - Generated iterate mutations use capability fields when the transport supplies them. With REST, capability is unknown and otherwise eligible mutations are attempted; GitHub's response is authoritative. Explicit `apply` operations forward the caller's requested IDs and surface GitHub's result.
89
- - `build_suggestion_patches` turns one or more ordered GitHub suggestion threads into checked patches and commit metadata, but never edits the working tree or git history. Local HEAD may be ahead when the live PR head is its ancestor.
98
+ | Session | GraphQL points: Shepherd / `gh` / MCP | REST core: Shepherd / `gh` / MCP |
99
+ | --------- | ------------------------------------: | -------------------------------: |
100
+ | Single PR | 30.8 / 36.5 / 12 | 4.8 / 9 / 78.3 |
101
+ | PR stack | 11 / 27 / 12 | 2 / 6 / 74 |
90
102
 
91
- ## Usage
103
+ - On the default GraphQL transport, Shepherd spends fewer GraphQL points than `gh`. It makes fewer REST requests than `gh` and far fewer than MCP.
104
+ - On a single PR, MCP spends fewer GraphQL points but about 16× the REST requests.
105
+ - The REST transport used in cloud sessions spends no GraphQL points. It does spend more `core` requests than `gh` or MCP (175 single PR, 432 stack).
92
106
 
93
- ### Iterate A PR
107
+ See [docs/graphql-usage.md](docs/graphql-usage.md) and [docs/rest-usage.md](docs/rest-usage.md).
94
108
 
95
- Claude Code:
109
+ ### Safe by construction
96
110
 
97
- ```text
98
- /goal /pr-shepherd:pr-shepherd # infer PR from current branch
99
- /goal /pr-shepherd:pr-shepherd 42
100
- ```
111
+ - The CLI runs read-only git only. It emits patches and commit commands for the agent to run ([AGENTS.md](AGENTS.md#git-operations)).
112
+ - Shepherd never merges by itself. With `--merge`, it emits a merge or queue command for the agent to run. The command is head-pinned for a single PR and guarded by READY receipts for a stack.
113
+ - Human handoff is a [finite escalation list](docs/escalations.md).
114
+ - The shipped skill tells the agent to treat review titles, comments, and CI logs as untrusted data. Shell and other MCP callers must apply that rule themselves.
115
+ - A denied reply or resolve is a one-look skip, not a retry loop.
101
116
 
102
- Codex:
117
+ ### Works across agents and environments
103
118
 
104
- ```text
105
- /goal $pr-shepherd # infer PR from current branch
106
- /goal $pr-shepherd 42
107
- ```
119
+ - The plugin ships [skills](docs/skills.md) for Claude Code, Codex, and Grok.
120
+ - Cursor and other stdio clients use the [MCP server](docs/mcp.md).
121
+ - Shell and CI use the [CLI](docs/cli-usage.md).
122
+ - In Claude Code cloud sessions, Shepherd switches to the [REST transport](docs/rest.md) and [event mode](docs/cloud.md).
123
+ - `--stack` reports every layer of a native GitHub stacked PR and shepherds the layers you own.
108
124
 
109
- Grok:
125
+ ## Use cases
110
126
 
111
- ```text
112
- /pr-shepherd # infer PR from current branch
113
- /pr-shepherd 42
114
- ```
115
-
116
- MCP clients call `iterate` once per tick, then use `apply` for review/file/journal mutations and validated queue-removal acknowledgments and `build_suggestion_patches` for anchored suggestions. To read journal entries, call `extract_journal` with a body already in hand or `get_journal` with a repository-qualified PR reference. `iterate` returns the same structured action data as the CLI, including its review mutation arguments. The client owns recurrence, so this works consistently in Codex, Claude Code, Grok, and any other stdio MCP client.
117
-
118
- The CLI remains useful for shell workflows. Its canonical polling form is:
119
-
120
- ```sh
121
- pr-shepherd 42 # poll until non-WAIT or timeout
122
- pr-shepherd 42 --interval 60s --timeout 270s
123
- pr-shepherd 42 --quiet-status # print only changed WAIT status snapshots
124
- pr-shepherd 42 --until-terminal # continue through WAIT/MARK_READY until work or terminal state
125
- pr-shepherd 42 --debounce 5m # wait 5m after first FIX_CODE or stack SHEPHERD, then return one batched tick
126
- pr-shepherd 42 --ready-delay 15m
127
- pr-shepherd 42 --merge # request head-pinned auto-merge/queue; GitHub reports the result
128
- pr-shepherd iterate 42 # single tick
129
- pr-shepherd 42 --instructions playbook # fold invariant fix_code steps into a playbook pointer (default: inline)
130
- pr-shepherd 42 --poll-mode event # one tick, no sleeping; prints nextCheck (default under CLAUDE_CODE_REMOTE=true)
131
- pr-shepherd playbook "Fix-code loop" # print a bundled skill playbook (no name lists them)
132
- pr-shepherd owner/repo#42 # poll a PR in an explicit repository
133
- pr-shepherd https://github.com/owner/repo/pull/42
134
- pr-shepherd 42 43 44 # summarize an explicit same-repository set
135
- pr-shepherd --stack 43 # summarize every PR in a native GitHub stack
136
- ```
137
-
138
- A user-supplied `--merge` authorizes the agent to run the emitted merge/enqueue commands for the
139
- selected PRs or stack without another conversational confirmation. Host permission checks still apply.
140
-
141
- Multi-PR and `--stack` polling use compact, read-only summaries from the selected transport.
142
- GraphQL mode uses GraphQL summaries; REST mode preserves unavailable fields as unknown. They return when work is
143
- needed, every selected PR is complete, the bounded timeout expires, or `--until-terminal` crosses a
144
- configured GraphQL quota-warning band. Explicit PR sets give each actionable row an exact single-PR
145
- `pollCommand`, so independent rows can proceed before the next aggregate poll.
146
-
147
- Native-stack rows are ordered bottom-to-top. `--stack` never performs a mutation itself. Every
148
- row marks ownership by comparing its author with the authenticated viewer; REST reads `/user`
149
- for that identity without inferring viewer permissions. Sessions act only on rows marked `owned`. Every
150
- owned layer that still has work gets its own one-PR session on the same tick, including a clean draft
151
- whose session marks it ready. Layers do not wait for a lower layer's READY receipt, so their
152
- ready-delays overlap. With automatic mark-ready disabled, the instructions ask the agent to mark
153
- a clean draft ready after its probe. A queued stack, or one whose remaining layers can only wait,
154
- returns `WAIT`; an idle `WAIT` that stays unchanged past the stall timeout returns `ESCALATE` with
155
- `stall-timeout`. A terminal READY or fully merged stack returns `CANCEL`. Closed or unverified
156
- topology returns `ESCALATE` for human direction after any other shepherdable PRs are handled;
157
- until then, `SHEPHERD` remains the immediate action and lists the human blockers too.
158
-
159
- With `--stack --merge`, the highest open layer whose open lower layers all have current READY
160
- receipts, and whose bottom open layer GitHub has retargeted onto the stack base, returns `MERGE`
161
- with the transport-specific stack merge command and allowed method. GraphQL mode uses
162
- `gh stack merge <that PR number> --yes`; REST mode uses the SHA-pinned
163
- `pr-shepherd apply merge` command, using the trunk's known queue policy even when the named layer
164
- targets its parent branch. The command binds the observed stack, trunk, and ordered prefix with
165
- `--expected-stack` and rejects a changed stack before submission. Unknown REST queue policy uses
166
- `default` without a merge method. Known queue requests omit the configured direct merge method.
167
- That lands the named layer and every
168
- unmerged layer below it. When the base uses a merge queue, the same command queues the prefix
169
- together and GitHub evaluates each layer from the bottom; a failure ejects that layer and those
170
- above it. For a `failed_checks` removal on the layer's first ejection, the one-PR session emits a head-, queue-commit-, and timestamp-pinned local acknowledgment command; run it only when the failure does not reproduce after updating from the latest base, the head did not change, and no source changes or other blockers remain. Fresh source checks and a new READY receipt then let the aggregate selector recover the eligible prefix. Manual or stale removals cannot use this path. Layers above the prefix keep their one-PR sessions. After the merge, GitHub retargets
171
- the next layer, so the rerun continues until the stack returns `CANCEL`. API and MCP aggregate
172
- calls perform one summary tick and leave recurrence to the caller.
173
-
174
- Polling defaults can be set under `poll` in `.pr-shepherdrc.yml`: `intervalSeconds` (built-in 60 for one PR), `stackIntervalFactor` (built-in 2, so `--stack` and multi-PR polls wait 120s), `timeoutSeconds`, `debounceSeconds`, `quietStatus`, and `reconcileSeconds` (built-in 900; the longest an idle GraphQL wait replays its last snapshot while REST change detectors are unchanged). Explicit `--interval` overrides either period for that invocation and is not multiplied. Other explicit flags override configuration, including `--no-quiet-status` when a shared config enables quiet output. Quiet status remains off by default. Quota-warning bands stay multiples of `intervalSeconds`; the dispatcher sleeps the slower of the effective interval and the active band, so a default stack waits 120s until a tighter band is slower than that.
175
-
176
- ### Apply Review And Journal Changes, Or Select Files
177
-
178
- Use `apply` with ordered operations to reply/resolve/minimize/dismiss review items, mark selected changed files as viewed, append an idempotent Shepherd Journal item, or record a validated native-stack CI queue-removal acknowledgment. Explicit operations are attempted and surface GitHub's per-operation results; generated iterate guidance remains capability-filtered. Use `build_suggestion_patches` to turn ordered review suggestions into checked patches and commit metadata; it never changes the worktree or git history.
179
-
180
- ### Extract Shepherd Journal Entries
181
-
182
- The pure `pr-shepherd/journal` entry point can extract one validated journal without GitHub access:
183
-
184
- ```ts
185
- import { extractShepherdJournal } from "pr-shepherd/journal";
186
-
187
- const result = extractShepherdJournal(prBody);
188
- if (!result.ok) throw new Error(result.error);
189
-
190
- for (const entry of result.journal?.entries ?? []) console.log(entry);
191
- ```
127
+ - **Autonomous agents.** An agent opens a PR and drives it to merge-ready, or merged when you allow it. Nobody has to watch CI and reviews.
128
+ - **Exhaustive AI code review.** Some PRs get many bot reviews (CodeRabbit, Codex, Copilot, and others). Shepherd shows every thread and comment once and tracks first-look, edited, and outdated items. It batches the replies, resolves, and minimizes.
192
129
 
193
- The result identifies canonical `details` versus historical `legacy` H2 journals and returns each
194
- complete Markdown list item with LF line endings. It fails closed for malformed or ambiguous
195
- containers and ignores journal-shaped examples hidden in Markdown constructs. The full journal API,
196
- including append and reconciliation helpers, is documented in [docs/api.md](docs/api.md).
130
+ ## How to use
197
131
 
198
- MCP clients can call `extract_journal({ body: prBody })` for the same pure result without writing a
199
- file, or `get_journal({ pr: "owner/repo#123" })` to fetch a PR body through the selected
200
- transport and extract it.
201
- Both return the typed extraction JSON in `structuredContent` and `content`; neither mutates the PR.
132
+ 1. **Install the MCP server and the CLI.** See [Install](#install) below.
133
+ 2. **Write your policy into a skill or agent instruction.** Examples: "skip non-blocking review comments", "reply instead of fixing nits", "never merge". Shepherd reports state and the next action. Your instructions decide how the agent treats each comment. The shipped `pr-shepherd` skill is a thin dispatcher you can wrap ([docs/skills.md](docs/skills.md)).
134
+ 3. **Configure Shepherd.** In `.pr-shepherdrc.yml`, turn on the bundled classification rules. They drop known bot noise before it reaches the agent, which saves more tokens and tool calls. With the default `actions.autoMinimizeSuppressed: true`, several rules also minimize matching comments on GitHub and log a Shepherd Journal entry; set it to `false` to keep comments untouched. See [docs/configuration.md](docs/configuration.md#classifystandard--default-).
202
135
 
203
- For shell automation that already has a PR body, use the equivalent local-only command:
204
-
205
- ```sh
206
- pr-shepherd journal extract --body-file pr-body.md
207
- ```
208
-
209
- It writes one JSON line containing the typed extraction result. It never reads GitHub credentials,
210
- configuration, or Shepherd logs. On POSIX, its final body-file path entry must be a readable regular
211
- file in a trusted parent directory; symlinks, FIFOs, and devices are rejected with exit code 66.
212
- Unsupported platforms fail closed with that same exit code.
213
-
214
- ### Clean Local State
215
-
216
- In Claude Code cloud sessions, [event mode](docs/cloud.md) runs one tick per event or wake-up instead of sleeping, and the default state directory moves into the repository's common directory.
217
-
218
- `pr-shepherd` stores seen markers, fix-attempt counters, stall fingerprints, ready-delay markers, and logs under `$PR_SHEPHERD_STATE_DIR` (default: `pr-shepherd-state` in the per-user temp dir; see [configuration](docs/configuration.md#environment-variables)).
219
-
220
- ```sh
221
- pr-shepherd admin clean current
222
- pr-shepherd admin clean repo
223
- pr-shepherd admin clean all --dry-run
224
- pr-shepherd admin log-file
225
- ```
136
+ ```yaml
137
+ classify:
138
+ standard:
139
+ all: true
140
+ ```
226
141
 
227
142
  ## Install
228
143
 
229
- The plugin launches the version-matched `pr-shepherd-mcp` binary from the `pr-shepherd` npm package automatically. Install the `pr-shepherd` CLI separately only when you want the shell interface.
230
-
231
- To register the MCP server without the plugin, or to wire a local checkout, see [docs/mcp.md](docs/mcp.md).
232
-
233
- ### Claude Code
144
+ The plugin starts the version-matched `pr-shepherd-mcp` server automatically.
234
145
 
235
146
  ```bash
147
+ # Claude Code
236
148
  claude /plugin marketplace add jonathanong/pr-shepherd
237
149
  claude /plugin install pr-shepherd
238
- ```
239
-
240
- ### Codex
241
150
 
242
- ```bash
151
+ # Codex (then enable the pr-shepherd plugin)
243
152
  codex plugin marketplace add jonathanong/pr-shepherd
244
- ```
245
-
246
- Or pin a ref:
247
-
248
- ```bash
249
- codex plugin marketplace add jonathanong/pr-shepherd --ref main
250
- ```
251
-
252
- For local development:
253
-
254
- ```bash
255
- git clone https://github.com/jonathanong/pr-shepherd ~/.codex/plugin-sources/pr-shepherd
256
- codex plugin marketplace add ~/.codex/plugin-sources/pr-shepherd
257
- ```
258
-
259
- After adding the marketplace, install/enable the `pr-shepherd` plugin from Codex. The marketplace root must contain `.agents/plugins/marketplace.json` and `plugins/pr-shepherd/`.
260
-
261
- ### Grok
262
153
 
263
- ```bash
154
+ # Grok
264
155
  grok plugin marketplace add jonathanong/pr-shepherd
265
156
  grok plugin install pr-shepherd --trust
266
- ```
267
-
268
- Grok starts a plugin's MCP server only after the plugin is trusted. Confirm with `grok mcp list` or `/mcps`.
269
-
270
- ### MCP server only
271
-
272
- Any stdio MCP client can run the published binary without installing the plugin:
273
-
274
- ```bash
275
- claude mcp add --transport stdio --scope user pr-shepherd -- \
276
- npx --yes --package pr-shepherd@<version> pr-shepherd-mcp
277
- codex mcp add pr-shepherd -- \
278
- npx --yes --package pr-shepherd@<version> pr-shepherd-mcp
279
- grok mcp add pr-shepherd -- \
280
- npx --yes --package pr-shepherd@<version> pr-shepherd-mcp
281
- ```
282
157
 
283
- Replace `<version>` with a published version. Full config-file examples, tool schemas, and local-checkout wiring are in [docs/mcp.md](docs/mcp.md).
284
-
285
- ## Configuration
286
-
287
- Create `.pr-shepherdrc.yml` in your project root, an ancestor directory, or `$HOME`. Every file on the walk is deep-merged; closer directories override farther ones.
288
-
289
- ```yaml
290
- cliCommand: [pnpm, exec, pr-shepherd] # launcher for emitted commands; defaults to [pr-shepherd]
291
- ignoreChecks:
292
- - "Kilo Code Review"
293
- iterate:
294
- fixAttemptsPerThread: 5
295
- stallTimeoutMinutes: 60
296
- minimizeApprovals: false
297
- minimizeComments: all # all | bots | none
298
- checks:
299
- ciTriggerEvents:
300
- - pull_request
301
- - pull_request_target
302
- merge:
303
- method: squash
304
- commandArgs:
305
- - --delete-branch
306
- actions:
307
- autoMinimizeSuppressed: true
308
- autoMarkReady: false
158
+ # CLI, for shells and CI
159
+ npm install -g pr-shepherd
309
160
  ```
310
161
 
311
- Environment variables:
312
-
313
- - `GH_TOKEN` / `GITHUB_TOKEN` / `GITHUB_PERSONAL_ACCESS_TOKEN` for auth; `gh auth token` is used as a fallback. See [GitHub authentication and token access](docs/authentication.md) for required PAT permissions.
314
- - `PR_SHEPHERD_STATE_DIR` to override state and log location.
315
- - `PR_SHEPHERD_LOG_DISABLED=1` to disable per-worktree debug logging.
162
+ For the MCP server without the plugin, or a local checkout, see [docs/mcp.md](docs/mcp.md).
316
163
 
317
- See [docs/configuration.md](docs/configuration.md) for the full reference.
164
+ Requirements:
318
165
 
319
- For guided noise reduction, use the plugin's `reduce-pr-noise` skill. It loads focused guidance for bot-comment classifiers or settings only when relevant; see [docs/skills.md](docs/skills.md).
320
-
321
- ### Classification rules
166
+ - Node.js >= 22.19.0, Bun, or Deno
167
+ - `git`
168
+ - A GitHub token or an authenticated `gh` CLI with [the required access](docs/authentication.md)
322
169
 
323
- For common vendor bot noise (CodeRabbit and Gemini rate-limit notices, Codex usage-limit and review boilerplate, Codecov reports, and more), enable the bundled rules instead of writing your own:
170
+ ## Quick start
324
171
 
325
- ```yaml
326
- # .pr-shepherdrc.yml
327
- classify:
328
- standard:
329
- all: true
172
+ ```text
173
+ /goal /pr-shepherd:pr-shepherd 42 # Claude Code
174
+ /goal $pr-shepherd 42 # Codex
175
+ /pr-shepherd 42 # Grok
330
176
  ```
331
177
 
332
- See [`classify.standard`](docs/configuration.md#classifystandard--default-) for the rule list and per-rule overrides. Write custom rules for repository-specific policy.
333
-
334
- Drop `.ts` / `.mts` / `.mjs` / `.js` files under `.pr-shepherd/classification/` to suppress and/or auto-resolve specific bot comments — useful for silencing repetitive noise like rate-limit notices from `gemini-code-assist` or "Reviews paused" from `coderabbitai`.
178
+ ```sh
179
+ pr-shepherd 42 # shell: poll for work (270s cap; --until-terminal removes it)
180
+ ```
335
181
 
336
- ```ts
337
- // .pr-shepherd/classification/gemini-quota.mts
338
- import type { ClassifyRule } from "pr-shepherd/classify";
182
+ Leave out the PR number to use the current branch. Example `FIX_CODE` output:
339
183
 
340
- const rule: ClassifyRule = (item) => {
341
- if (item.author !== "gemini-code-assist") return null;
342
- if (!/You have reached your daily quota limit/i.test(item.body)) return null;
343
- return { suppress: true, autoResolve: true };
344
- };
345
- export default rule;
346
- ```
184
+ ```text
185
+ # PR #123 [FIX_CODE]
347
186
 
348
- `suppress: true` hides the item from agent output. `autoResolve: true` queues it for the minimize/resolve mutation. `reason` is an optional note. When both flags apply together and `actions.autoMinimizeSuppressed` is `true` (the default), Shepherd attempts supported operations and relies on GitHub's response when capability is unknown. Confirmed successes are recorded on `threads.autoResolved` and `comments.autoMinimized`, printed once as `## Classification auto-resolve` before `## Instructions` (the same `ruleAutoResolve` object in JSON), and appended as one Shepherd Journal list item attributed to the token login. Distinct rule reasons are included. Failed IDs stay on the generated `apply review` command, and each failure is an extra bullet in that section. A journal write failure is reported the same way and does not undo the GitHub resolve or minimize. `actions.autoMinimizeSuppressed: false` leaves the IDs on that command and does not mutate, journal, or print the line. Denied review mutations are surfaced once then skipped; REST comment minimization is unsupported and is surfaced as a one-look skip. See [transport behavior](docs/rest.md).
187
+ **status** `UNRESOLVED_COMMENTS` · **repo** `owner/repo`
188
+ **summary** 3 passing
349
189
 
350
- TypeScript rules are loaded by the runtime's native TypeScript support; keep them to erasable syntax such as type annotations and `import type`. Runtime TypeScript features that need transpilation, such as enums, namespaces, parameter properties, and decorators, are not supported. Use `.mts` for portable ESM rules across Node, Bun, and Deno.
190
+ ## Review threads
351
191
 
352
- Ready-to-use examples for common patterns are in [`examples/classification/`](examples/classification/).
192
+ ### `threadId=PRRT_kwDOSGizTs58XB1L` — `src/commands/iterate/index.mts:42` (@alice · MEMBER)
353
193
 
354
- ## CLI aliases
194
+ > The variable name is misleading.
355
195
 
356
- `poll`, `resolve`, `build-suggestion-patch`, `commit-suggestion`, `mark-files-as-viewed`, `journal`, `clean`, and `log-file` are CLI aliases or deprecated adapters. Prefer default polling/`iterate` in a shell and the MCP `iterate`, `apply`, and `build_suggestion_patches` tools in an agent client.
196
+ ## Failing checks
357
197
 
358
- ## Requirements
198
+ - `24697658766` — `CI › lint / typecheck / test (22.x)` [conclusion: FAILURE]
199
+ > oxfmt
359
200
 
360
- - Node.js >= 22.18.0, Bun, or Deno
361
- - A GitHub token or authenticated `gh` CLI with the [required repository access](docs/authentication.md). A classic PAT needs the `repo` scope for complete operation.
362
- - `git`
201
+ ## Instructions
363
202
 
364
- ## Docs
203
+ 1. Fix each warranted item.
204
+ 2. Triage `## Failing checks`. Playbook: "CI failure triage".
205
+ 3. Commit and push any changes.
206
+ 4. Journal key decisions or rejections with URLs or IDs: `pr-shepherd apply journal 123 '- <decision>'`
207
+ 5. `$DISMISS_MESSAGE`: one sentence on what changed. Run even if no code changed: `pr-shepherd apply review 123 --reply-thread-ids PRRT_kwDOSGizTs58XB1L --message "$DISMISS_MESSAGE" --require-sha HEAD`
208
+ 6. Rerun Shepherd now.
209
+ ```
365
210
 
366
- Full reference, grouped by the two jobs (gather context / emit actions): [docs/README.md](docs/README.md).
211
+ ## Documentation
367
212
 
368
- ## Harness Ecosystem
213
+ | Topic | Doc |
214
+ | -------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
215
+ | Index of every doc | [docs/README.md](docs/README.md) |
216
+ | Features, workflow assumptions, limits | [docs/features.md](docs/features.md) |
217
+ | Commands, flags, stacks, polling | [docs/cli-usage.md](docs/cli-usage.md) |
218
+ | Actions and exit codes | [docs/actions.md](docs/actions.md), [docs/exit-codes.md](docs/exit-codes.md) |
219
+ | Configuration and classification rules | [docs/configuration.md](docs/configuration.md), [examples/classification/](examples/classification/) |
220
+ | Journal, library API | [docs/api.md](docs/api.md) |
221
+ | Compared with Cursor, Copilot, CodeRabbit, … | [docs/comparison.md](docs/comparison.md) |
369
222
 
370
- This is part of the following harness ecosystem:
223
+ ## Harness ecosystem
371
224
 
372
- - [auto-harness](https://github.com/jonathanong/auto-harness) - non-interactive agent CLI orchestration across sandboxes
373
- - [agent-blackboard](https://github.com/jonathanong/agent-blackboard) - session-scoped telemetry for autonomous agents
374
- - [pr-shepherd](https://github.com/jonathanong/pr-shepherd) - autonomous pull request shepherd
375
- - [no-mistakes](https://github.com/jonathanong/no-mistakes) - deterministic AST-based codebase intelligence, test selection, and linting for agents
225
+ - [auto-harness](https://github.com/jonathanong/auto-harness): non-interactive agent CLI orchestration across sandboxes
226
+ - [agent-blackboard](https://github.com/jonathanong/agent-blackboard): session-scoped telemetry for autonomous agents
227
+ - [pr-shepherd](https://github.com/jonathanong/pr-shepherd): autonomous pull request shepherd
228
+ - [no-mistakes](https://github.com/jonathanong/no-mistakes): deterministic AST-based codebase intelligence, test selection, and linting for agents
@@ -1,7 +1,8 @@
1
1
  import type { ClassifyRule } from "../types.mts";
2
2
  /**
3
- * Codex quota notices, the review-activity status table, and no-findings notices. Each pattern
4
- * matches the whole comment, so a notice with any appended finding stays visible.
3
+ * Codex quota notices, the review-activity status table, and no-findings notices on conversation
4
+ * comments. Each pattern matches the whole comment, so a notice with any appended finding stays
5
+ * visible. Review summaries and inline comments are left for the normal review path.
5
6
  */
6
7
  declare const rule: ClassifyRule;
7
8
  export default rule;
@@ -10,19 +10,17 @@ const ACTIVITY_SUMMARY = /^<!-- codex-pull-request-review-summary -->\n(?:<!-- c
10
10
  const CLEAN_REVIEW = /^Codex Review: Didn't find any major issues\. (?:Bravo\.|Breezy!|Hooray!|:\+1:)\n\n\*\*Reviewed commit:\*\* `[a-f0-9]+`$/;
11
11
  const CLEAN_SECURITY = /^### 🛡️ Codex Security Review(?: · _Automatically triggered_)?\n\nSecurity review completed\. No security issues were found in this pull request\.\n\n\*\*Reviewed commit:\*\* `[a-f0-9]+`\n\n\[View security finding report\]\(https:\/\/chatgpt.com\/codex\/cloud\/tasks\/[a-zA-Z0-9_]+\)\n\n_Only the user who started this review can view the report in Codex\._$/;
12
12
  /**
13
- * Codex quota notices, the review-activity status table, and no-findings notices. Each pattern
14
- * matches the whole comment, so a notice with any appended finding stays visible.
13
+ * Codex quota notices, the review-activity status table, and no-findings notices on conversation
14
+ * comments. Each pattern matches the whole comment, so a notice with any appended finding stays
15
+ * visible. Review summaries and inline comments are left for the normal review path.
15
16
  */
16
17
  const rule = (item) => {
17
- if (!isBotItem(item, ["chatgpt-codex-connector"], ["pr-comment", "review-summary"])) {
18
+ if (!isBotItem(item, ["chatgpt-codex-connector"], ["pr-comment"]))
18
19
  return null;
19
- }
20
20
  const body = item.body.trim();
21
21
  if (QUOTA_NOTICES.some((notice) => notice.test(body))) {
22
22
  return { autoResolve: true, suppress: true, reason: "Codex usage-limit notice" };
23
23
  }
24
- if (item.kind !== "pr-comment")
25
- return null;
26
24
  // Strip only the trailing About block; extra findings after it stay visible.
27
25
  const content = body.replace(ABOUT_BLOCK, "").trim();
28
26
  if (ACTIVITY_SUMMARY.test(content)) {
@@ -1,4 +1,4 @@
1
1
  import type { ClassifyRule } from "../types.mts";
2
- /** Gemini Code Assist daily-quota and review-limit notices. A heading means a real review. */
2
+ /** Gemini Code Assist daily-quota and review-limit notices on conversation comments. A heading means a real review. */
3
3
  declare const rule: ClassifyRule;
4
4
  export default rule;