Skill Tracer
Skills › Compound Engineering › ce-resolve-pr-feedback › full-mode.md

full-mode.md

337 lines · skills/ce-resolve-pr-feedback/references/full-mode.md at 3449230

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Full Mode
2
3Read this reference when Mode Detection (in SKILL.md) routes to **Full Mode** — no argument given, a PR number was provided, or a whole-PR URL (`.../pull/N` with no comment fragment) was provided. Full mode processes all unresolved threads on the PR. When the argument is a PR URL, parse the host, `OWNER/REPO`, and number from it — the host feeds the `GH_HOST` prefix below, and `OWNER/REPO` targets the correct repo for a fork→upstream PR.
4
5The shape: **fetch once, judge centrally, dispatch subagents only for the fixes.** You, the orchestrator, hold every thread from a single fetch, so you judge validity in your own context, where you can read each file once, spot a reviewer who is wrong across several threads, and weigh the author's design intent. Subagents are dispatched only to *implement* fixes you have already approved. Do not delegate the judgment: a subagent per thread pays per-agent overhead, re-reads the same files, and loses the cross-thread view, and you would pay that even for threads that turn out to be skips.
6

Full Mode

Read this reference when Mode Detection (in SKILL.md) routes to Full Mode — no argument given, a PR number was provided, or a whole-PR URL (.../pull/N with no comment fragment) was provided. Full mode processes all unresolved threads on the PR. When the argument is a PR URL, parse the host, OWNER/REPO, and number from it — the host feeds the GH_HOST prefix below, and OWNER/REPO targets the correct repo for a fork→upstream PR.

The shape: fetch once, judge centrally, dispatch subagents only for the fixes. You, the orchestrator, hold every thread from a single fetch, so you judge validity in your own context, where you can read each file once, spot a reviewer who is wrong across several threads, and weigh the author's design intent. Subagents are dispatched only to implement fixes you have already approved. Do not delegate the judgment: a subagent per thread pays per-agent overhead, re-reads the same files, and loses the cross-thread view, and you would pay that even for threads that turn out to be skips.

Raw lines 1 to 6
Starts an agent dispatch :5
Starts an agent subagents :5
Starts an agent Subagents :5
Starts an agent dispatched :5
Starts an agent subagent :5
7## 1. Fetch Unresolved Threads
8
9If no PR number was provided, detect from the current branch:
10```bash
11gh pr view --json number -q .number
12```
14Then fetch all feedback using the GraphQL script at [scripts/get-pr-comments](../scripts/get-pr-comments). Set `SKILL_DIR` to the absolute directory you loaded the ce-resolve-pr-feedback SKILL.md from — the Bash tool's CWD is the user's project, not the skill dir, and shell state does not persist between Bash calls, so set it inline in each block below that runs a bundled script. If the bundled script is missing on disk the call fails plainly; fall back to the `gh` commands shown after this block.
16**GitHub Enterprise host.** The bundled `gh api graphql` scripts hit `gh`'s default host unless told otherwise, so on a GHE PR they would wrongly target `github.com`. Derive the host: if the caller passed a full PR **URL**, take its host; otherwise read it from `gh repo view --json url -q .url`. Then — because shell state does **not** persist between separate Bash calls — pass the host as a `GH_HOST=<host>` **env prefix inline on every bundled-script call** (`gh api` honors `GH_HOST` as the request host). A single `export` in one block does **not** carry to the reply/resolve/verify blocks that run as later Bash calls, which is why each call below shows the prefix. On `github.com`, drop the `GH_HOST=<host> ` prefix entirely.
18```bash
19PR_HOST=$(printf '%s' "<pr-url-if-one-was-passed>" | sed -n 's#^https\?://\([^/]*\)/.*#\1#p');
20[ -z "$PR_HOST" ] && PR_HOST=$(gh repo view --json url -q .url 2>/dev/null | sed -n 's#^https\?://\([^/]*\)/.*#\1#p');
21echo "$PR_HOST" # github.com -> no prefix; any other host -> prefix GH_HOST=<host> on each script call below
22```
24```bash
25SKILL_DIR="<absolute path of the directory containing the ce-resolve-pr-feedback SKILL.md>";
26GH_HOST=<derived-host> bash "$SKILL_DIR/scripts/get-pr-comments" PR_NUMBER OWNER/REPO # omit GH_HOST=<derived-host> on github.com
27```
29**Pass the base `OWNER/REPO`** (parsed from the PR URL, when one was given) as the second arg. `get-pr-comments` otherwise falls back to `gh repo view` in the *current checkout* — so for a fork→upstream PR handed in as a URL, omitting it would fetch review feedback from the fork (or fail) instead of the upstream base repo. Every `get-pr-comments` call below (fetch and verify) takes the same `OWNER/REPO`.
31Returns a JSON object with these keys:
33| Key | Contents | Has file/line? | Resolvable? |
34|-----|----------|---------------|-------------|
35| `pending_review` | Node ID of your own unsubmitted (PENDING) review on this PR, or `null` | n/a | n/a |
36| `review_threads` | Unresolved inline code review threads (includes outdated); each wrapper carries `root_comment_id` for REST replies and each node carries its GraphQL thread ID for resolution | Yes | Yes (GraphQL) |
37| `pr_comments` | Top-level PR conversation comments | No | No |
38| `review_bodies` | Review submission bodies with non-empty text | No | No |
39| `pr_author` / `viewer` | The PR author's login and the acting account's login, for judging identity in step 2 | n/a | n/a |
41**All three kinds of feedback are in scope.** `review_threads`, `pr_comments`, and `review_bodies` are judged the same way in step 3; only the reply and resolve mechanics differ (step 7). The fetch excludes nothing based on who wrote it — a top-level comment from the PR author is the ordinary way a human asks for a change on an agent-opened PR, so it is feedback like any other.
43**Stop here if `pending_review` is non-null.** Thread replies posted while you hold an unsubmitted review are absorbed into that draft: the reply call returns a comment ID and URL as if it succeeded, but nothing is visible to the reviewer until the draft is submitted. Do not proceed into steps 2-8 — the fixes would land while every reply silently disappeared. Tell the user they have an unsubmitted review on the PR, that it must be submitted or discarded before this skill can reply, and stop. Do not submit or discard it yourself; a draft review is unsent human writing.
45If the script fails, fall back to:
46```bash
47gh pr view PR_NUMBER --json reviews,comments
48gh api repos/{owner}/{repo}/pulls/PR_NUMBER/comments
49```

1. Fetch Unresolved Threads

If no PR number was provided, detect from the current branch:

gh pr view --json number -q .number

Then fetch all feedback using the GraphQL script at scripts/get-pr-comments. Set SKILL_DIR to the absolute directory you loaded the ce-resolve-pr-feedback SKILL.md from — the Bash tool's CWD is the user's project, not the skill dir, and shell state does not persist between Bash calls, so set it inline in each block below that runs a bundled script. If the bundled script is missing on disk the call fails plainly; fall back to the gh commands shown after this block.

GitHub Enterprise host. The bundled gh api graphql scripts hit gh's default host unless told otherwise, so on a GHE PR they would wrongly target github.com. Derive the host: if the caller passed a full PR URL, take its host; otherwise read it from gh repo view --json url -q .url. Then — because shell state does not persist between separate Bash calls — pass the host as a GH_HOST=<host> env prefix inline on every bundled-script call (gh api honors GH_HOST as the request host). A single export in one block does not carry to the reply/resolve/verify blocks that run as later Bash calls, which is why each call below shows the prefix. On github.com, drop the GH_HOST=<host> prefix entirely.

PR_HOST=$(printf '%s' "<pr-url-if-one-was-passed>" | sed -n 's#^https\?://\([^/]*\)/.*#\1#p');
[ -z "$PR_HOST" ] && PR_HOST=$(gh repo view --json url -q .url 2>/dev/null | sed -n 's#^https\?://\([^/]*\)/.*#\1#p');
echo "$PR_HOST"   # github.com -> no prefix; any other host -> prefix GH_HOST=<host> on each script call below
SKILL_DIR="<absolute path of the directory containing the ce-resolve-pr-feedback SKILL.md>";
GH_HOST=<derived-host> bash "$SKILL_DIR/scripts/get-pr-comments" PR_NUMBER OWNER/REPO   # omit GH_HOST=<derived-host> on github.com

**Pass the base OWNER/REPO** (parsed from the PR URL, when one was given) as the second arg. get-pr-comments otherwise falls back to gh repo view in the current checkout — so for a fork→upstream PR handed in as a URL, omitting it would fetch review feedback from the fork (or fail) instead of the upstream base repo. Every get-pr-comments call below (fetch and verify) takes the same OWNER/REPO.

Returns a JSON object with these keys:

KeyContentsHas file/line?Resolvable?
pending_reviewNode ID of your own unsubmitted (PENDING) review on this PR, or nulln/an/a
review_threadsUnresolved inline code review threads (includes outdated); each wrapper carries root_comment_id for REST replies and each node carries its GraphQL thread ID for resolutionYesYes (GraphQL)
pr_commentsTop-level PR conversation commentsNoNo
review_bodiesReview submission bodies with non-empty textNoNo
pr_author / viewerThe PR author's login and the acting account's login, for judging identity in step 2n/an/a

All three kinds of feedback are in scope. review_threads, pr_comments, and review_bodies are judged the same way in step 3; only the reply and resolve mechanics differ (step 7). The fetch excludes nothing based on who wrote it — a top-level comment from the PR author is the ordinary way a human asks for a change on an agent-opened PR, so it is feedback like any other.

**Stop here if pending_review is non-null.** Thread replies posted while you hold an unsubmitted review are absorbed into that draft: the reply call returns a comment ID and URL as if it succeeded, but nothing is visible to the reviewer until the draft is submitted. Do not proceed into steps 2-8 — the fixes would land while every reply silently disappeared. Tell the user they have an unsubmitted review on the PR, that it must be submitted or discarded before this skill can reply, and stop. Do not submit or discard it yourself; a draft review is unsent human writing.

If the script fails, fall back to:

gh pr view PR_NUMBER --json reviews,comments
gh api repos/{owner}/{repo}/pulls/PR_NUMBER/comments
Raw lines 7 to 50
Runs code scripts/get-pr-comments :14
51## 2. Triage: Separate New from Pending
53Before processing, reconcile the reply and resolution state of each piece of feedback.
55**Review threads**: An ordinarily handled thread is complete only when it has both a visible, submitted substantive reply and authoritative thread resolution. Reconcile those conditions independently:
57- A reply that explicitly defers a human choice (e.g., "need to align on this", "going to think through this", or options without a decision) is a **pending decision**. Keep the thread open and do not re-process it.
58- A reply that records a completed fix or reply verdict while the thread is still open is **resolution-pending**. Do not repost the reply or reapply the fix; carry the existing visible reply to step 7 and complete only the missing resolution after pending-review state is empty.
59- A thread without either kind of substantive response is **new**.
61**PR comments and review bodies**: These have no resolve mechanism, so they reappear on every run. Apply two filters in order:
631. **Actionability**: An item is actionable when it is someone's open request to this PR: something to fix, answer, or decide. This filter is also what keeps the run from looping on its own output. A reply posted by this run or an earlier one is a record of handling, not a request, so it drops here, whether it reports a fix or carries a parked `needs-human` decision. That parked item is already tracked as itself; re-reading its own write-up as fresh feedback is how the loop would never settle. Who posted an item never decides this, including the account that opened the PR. Examples: review wrapper text ("Here are some automated review suggestions..."), approvals ("this looks great!"), status badges ("Validated"), CI summaries with no follow-up asks. If there's nothing to fix, answer, or decide, it's not actionable -- drop it from the count entirely.
642. **Already replied**: For actionable items, check the PR conversation for an existing reply that quotes and addresses the feedback. If a reply already exists, skip. If not, it's new.
66The distinction is about content, not who posted what. A deferral from a teammate, a previous skill run, or a manual reply all count. Similarly, actionability is about content -- bot feedback that requests a specific code change is actionable; a bot's boilerplate header wrapping those requests is not.
68**Silent drop.** Non-actionable items are dropped without narration. Do not announce, list, or count dropped items in conversation, the task list, or the step 9 summary. Review-bot wrappers from CodeRabbit, Codex, Gemini Code Assist, and Copilot (bodies like "Here are some automated review suggestions...") commonly appear here -- recognize them by their boilerplate content, drop silently. The fetch script filters out only blank bodies. Every author and every kind of feedback — the PR author, CI/status bots such as Codecov, review bots — goes through this content check, so a reused account or a changed format cannot silently hide actionable feedback.
70If there are no new or resolution-pending items across all feedback types, skip steps 3-8 and go straight to step 9. If only resolution-pending threads remain, skip steps 3-6 and go straight to step 7.

2. Triage: Separate New from Pending

Before processing, reconcile the reply and resolution state of each piece of feedback.

Review threads: An ordinarily handled thread is complete only when it has both a visible, submitted substantive reply and authoritative thread resolution. Reconcile those conditions independently:

  • A reply that explicitly defers a human choice (e.g., "need to align on this", "going to think through this", or options without a decision) is a pending decision. Keep the thread open and do not re-process it.
  • A reply that records a completed fix or reply verdict while the thread is still open is resolution-pending. Do not repost the reply or reapply the fix; carry the existing visible reply to step 7 and complete only the missing resolution after pending-review state is empty.
  • A thread without either kind of substantive response is new.

PR comments and review bodies: These have no resolve mechanism, so they reappear on every run. Apply two filters in order:

  1. Actionability: An item is actionable when it is someone's open request to this PR: something to fix, answer, or decide. This filter is also what keeps the run from looping on its own output. A reply posted by this run or an earlier one is a record of handling, not a request, so it drops here, whether it reports a fix or carries a parked needs-human decision. That parked item is already tracked as itself; re-reading its own write-up as fresh feedback is how the loop would never settle. Who posted an item never decides this, including the account that opened the PR. Examples: review wrapper text ("Here are some automated review suggestions..."), approvals ("this looks great!"), status badges ("Validated"), CI summaries with no follow-up asks. If there's nothing to fix, answer, or decide, it's not actionable -- drop it from the count entirely.
  2. Already replied: For actionable items, check the PR conversation for an existing reply that quotes and addresses the feedback. If a reply already exists, skip. If not, it's new.

The distinction is about content, not who posted what. A deferral from a teammate, a previous skill run, or a manual reply all count. Similarly, actionability is about content -- bot feedback that requests a specific code change is actionable; a bot's boilerplate header wrapping those requests is not.

Silent drop. Non-actionable items are dropped without narration. Do not announce, list, or count dropped items in conversation, the task list, or the step 9 summary. Review-bot wrappers from CodeRabbit, Codex, Gemini Code Assist, and Copilot (bodies like "Here are some automated review suggestions...") commonly appear here -- recognize them by their boilerplate content, drop silently. The fetch script filters out only blank bodies. Every author and every kind of feedback — the PR author, CI/status bots such as Codecov, review bots — goes through this content check, so a reused account or a changed format cannot silently hide actionable feedback.

If there are no new or resolution-pending items across all feedback types, skip steps 3-8 and go straight to step 9. If only resolution-pending threads remain, skip steps 3-6 and go straight to step 7.

Raw lines 51 to 71
72## 3. Consolidate & Decide (the legitimacy gate)
74This is where validity is decided. Judge every **new** item here, in your own context, before any fix is dispatched. Apply the rubric in [references/evaluation-rubric.md](evaluation-rubric.md) (read it now) across the whole batch at once. When the invocation carries a `trajectory`, apply the non-convergence test in [references/pipeline-mode.md](pipeline-mode.md) before dispatching anything — a demonstrated shared root is answered once, at the root, instead of fixing each instance.
76Working over the full set lets you do what a per-thread subagent can't:
77- **Dedup reads by file** — read a file once and judge all its threads together.
78- **Cross-item reasoning** — cluster findings by root assumption; a source (often a bot) that's wrong in one place is suspect across its siblings; converging requests from independent reviewers are a strong fix signal.
79- **Selective depth** — clear nits need only the comment plus the diff line; deep-read (callers, invariants, `git blame`/PR rationale for author intent) only where a finding is contestable or the code looks deliberate. That deep read on the contestable minority is what catches a confidently-wrong reviewer.
81Produce a verdict per item and sort into three lists:
83- **fix-list** — `fixed` / `fixed-differently`. These get dispatched to fixers in step 4. For each, note the file/location (and for outdated threads, the resolved location or anchor) and a one-line "what to change." **Class fix:** when the cross-item pass (rubric: "A validated finding can span sites this PR itself introduced") found equivalent same-invariant sites this PR touched, record them as **one** fix-list item that enumerates every concrete location (`file:line`) and lists every feedback ID it covers — one class item → one fixer (step 4), so the sites are edited coherently and every covered thread/comment is replied-to and resolved from that single result. Enumerate only sites whose treatment is unambiguous; a site needing its own judgment stays a separate item.
84- **reply-list** — `replied` / `not-addressing` / `declined`. No code change. Compose the reply text now per the rubric (you have the evidence) and carry it to step 7.
85- **human-list** — `needs-human`. Compose `decision_context` now and run the rubric's "Adjudicate before escalating" step on each judgment-bound item; an adjudicated verdict moves the item to the list it names, and the rest carry to steps 7 and 9.
87Create a task list of all new items (e.g., `TaskCreate` in Claude Code, `update_plan` in Codex) tagged with their verdict, so progress is visible.
89**At scale.** If the batch is large (many threads spanning many files) and judging them all inline would overflow your context, process the consolidation in groups (e.g., file-clustered groups of ~8-10 threads), emitting the three lists incrementally. Don't fan the judgment out to subagents to avoid this — batch it instead.
91If the fix-list is empty (all verdicts are reply/needs-human), skip steps 4-6 and go to step 7.

3. Consolidate & Decide (the legitimacy gate)

This is where validity is decided. Judge every new item here, in your own context, before any fix is dispatched. Apply the rubric in references/evaluation-rubric.md (read it now) across the whole batch at once. When the invocation carries a trajectory, apply the non-convergence test in references/pipeline-mode.md before dispatching anything — a demonstrated shared root is answered once, at the root, instead of fixing each instance.

Working over the full set lets you do what a per-thread subagent can't:

  • Dedup reads by file — read a file once and judge all its threads together.
  • Cross-item reasoning — cluster findings by root assumption; a source (often a bot) that's wrong in one place is suspect across its siblings; converging requests from independent reviewers are a strong fix signal.
  • Selective depth — clear nits need only the comment plus the diff line; deep-read (callers, invariants, git blame/PR rationale for author intent) only where a finding is contestable or the code looks deliberate. That deep read on the contestable minority is what catches a confidently-wrong reviewer.

Produce a verdict per item and sort into three lists:

  • fix-list — fixed / fixed-differently. These get dispatched to fixers in step 4. For each, note the file/location (and for outdated threads, the resolved location or anchor) and a one-line "what to change." Class fix: when the cross-item pass (rubric: "A validated finding can span sites this PR itself introduced") found equivalent same-invariant sites this PR touched, record them as one fix-list item that enumerates every concrete location (file:line) and lists every feedback ID it covers — one class item → one fixer (step 4), so the sites are edited coherently and every covered thread/comment is replied-to and resolved from that single result. Enumerate only sites whose treatment is unambiguous; a site needing its own judgment stays a separate item.
  • reply-list — replied / not-addressing / declined. No code change. Compose the reply text now per the rubric (you have the evidence) and carry it to step 7.
  • human-list — needs-human. Compose decision_context now and run the rubric's "Adjudicate before escalating" step on each judgment-bound item; an adjudicated verdict moves the item to the list it names, and the rest carry to steps 7 and 9.

Create a task list of all new items (e.g., TaskCreate in Claude Code, update_plan in Codex) tagged with their verdict, so progress is visible.

At scale. If the batch is large (many threads spanning many files) and judging them all inline would overflow your context, process the consolidation in groups (e.g., file-clustered groups of ~8-10 threads), emitting the three lists incrementally. Don't fan the judgment out to subagents to avoid this — batch it instead.

If the fix-list is empty (all verdicts are reply/needs-human), skip steps 4-6 and go to step 7.

Raw lines 72 to 92
Starts an agent dispatched :74
Starts an agent dispatching :74
Starts an agent subagent :76
Starts an agent subagents :89
93## 4. Fix (fix-list only)
95Dispatch fixers **only** for fix-list items. Reply-list and human-list items never reach a subagent.

4. Fix (fix-list only)

Dispatch fixers only for fix-list items. Reply-list and human-list items never reach a subagent.

Raw lines 93 to 96
Starts an agent Dispatch :95
Starts an agent subagent :95
97### Where each fix runs
99Step 3 already read the code behind every fix-list item. Dispatch fixers when the items form a real parallel batch (two or more items on disjoint files), or for an item whose fix reaches well beyond what you read (a rename across callers, a class fix over many sites). Apply every other item in this context, with the fixer prompt below as your own instructions.
101Every fix-list item ends with one **per-item result** in the return format below, whether a fixer produced it or you did. The **change set** for this run is the union of those results' `files_changed`. Steps 5-7 read only per-item results and the change set, never which path produced them.

Where each fix runs

Step 3 already read the code behind every fix-list item. Dispatch fixers when the items form a real parallel batch (two or more items on disjoint files), or for an item whose fix reaches well beyond what you read (a rename across callers, a class fix over many sites). Apply every other item in this context, with the fixer prompt below as your own instructions.

Every fix-list item ends with one per-item result in the return format below, whether a fixer produced it or you did. The change set for this run is the union of those results' files_changed. Steps 5-7 read only per-item results and the change set, never which path produced them.

Raw lines 97 to 102
Starts an agent Dispatch :99
103### Dispatch
105Read [references/agents/pr-comment-resolver.md](agents/pr-comment-resolver.md) and spawn a generic subagent seeded with that fixer prompt for each fix-list item you are delegating. Do not dispatch a standalone agent by type/name. The fixer only implements: the validity judgment is already done, so it implements and returns; it does not re-judge whether the fix is worthwhile.
107Each fixer receives:
108- The feedback_id (thread ID or comment ID) and feedback type.
109- The file path and location fields: `line`, `originalLine`, `startLine`, `originalStartLine` (for outdated threads, the resolved location/anchor from step 3).
110- The reviewer's comment text.
111- Your step-3 note: what to change and why it was judged valid.
112- The PR number.
114For `pr_comment` / `review_body` fix-list items (no file/line), the fixer identifies the relevant files from the comment text and the PR diff.
116**No subagent capability — apply the fixes yourself, sequentially.** When the harness exposes no way to dispatch (or a dispatch fails), work the fix-list in this context one item at a time, using the fixer prompt as your own instructions and producing the same per-item result. This is a supported path, not a shortfall to report as lost coverage: the decision about whether each item is valid already happened in step 3, and fixers only *implement* changes you approved, so running them here costs parallelism and context headroom — never correctness. Keep the dispatch path's discipline: one item at a time, re-read each file before editing it, and stop to re-evaluate if implementing reveals a contradiction (the `blocked` handling applies unchanged). Items you apply in this context by choice follow the same discipline.
118This skill therefore does not depend on agent-tool authorization to complete a review. That is deliberate: it runs unattended under `ce-babysit-pr`, where a permission prompt would stall the whole loop, so it needs few tools and can still fix without dispatch.

Dispatch

Read references/agents/pr-comment-resolver.md and spawn a generic subagent seeded with that fixer prompt for each fix-list item you are delegating. Do not dispatch a standalone agent by type/name. The fixer only implements: the validity judgment is already done, so it implements and returns; it does not re-judge whether the fix is worthwhile.

Each fixer receives:

  • The feedback_id (thread ID or comment ID) and feedback type.
  • The file path and location fields: line, originalLine, startLine, originalStartLine (for outdated threads, the resolved location/anchor from step 3).
  • The reviewer's comment text.
  • Your step-3 note: what to change and why it was judged valid.
  • The PR number.

For pr_comment / review_body fix-list items (no file/line), the fixer identifies the relevant files from the comment text and the PR diff.

No subagent capability — apply the fixes yourself, sequentially. When the harness exposes no way to dispatch (or a dispatch fails), work the fix-list in this context one item at a time, using the fixer prompt as your own instructions and producing the same per-item result. This is a supported path, not a shortfall to report as lost coverage: the decision about whether each item is valid already happened in step 3, and fixers only implement changes you approved, so running them here costs parallelism and context headroom — never correctness. Keep the dispatch path's discipline: one item at a time, re-read each file before editing it, and stop to re-evaluate if implementing reveals a contradiction (the blocked handling applies unchanged). Items you apply in this context by choice follow the same discipline.

This skill therefore does not depend on agent-tool authorization to complete a review. That is deliberate: it runs unattended under ce-babysit-pr, where a permission prompt would stall the whole loop, so it needs few tools and can still fix without dispatch.

Raw lines 103 to 119
Starts an agent Dispatch :103
Starts an agent spawn :105
Starts an agent subagent :105
Starts an agent dispatch :105
Names a skill ce-babysit-pr :118
120### Per-item result format (fixer or inline)
122- **verdict**: `fixed`, `fixed-differently`, or `blocked`
123- **feedback_id**, **feedback_type**
124- **reply_text**: markdown reply to post (quoting the relevant feedback) — omit for `blocked`
125- **files_changed**: list of files modified (empty for `blocked`)
126- **reason**: what was done, or the concrete contradiction for `blocked`
128**Handling `blocked`.** A fixer returns `blocked` only when implementing revealed a concrete contradiction that the fixer could see and you could not (the change breaks a caller/test it can see, or the code isn't what the finding described). Re-evaluate it yourself with that evidence: either re-dispatch with a corrected instruction, or move it to the reply-list (`not-addressing`/`declined`) or human-list. Don't silently drop it.

Per-item result format (fixer or inline)

  • verdict: fixed, fixed-differently, or blocked
  • feedback_id, feedback_type
  • reply_text: markdown reply to post (quoting the relevant feedback) — omit for blocked
  • files_changed: list of files modified (empty for blocked)
  • reason: what was done, or the concrete contradiction for blocked

**Handling blocked.** A fixer returns blocked only when implementing revealed a concrete contradiction that the fixer could see and you could not (the change breaks a caller/test it can see, or the code isn't what the finding described). Re-evaluate it yourself with that evidence: either re-dispatch with a corrected instruction, or move it to the reply-list (not-addressing/declined) or human-list. Don't silently drop it.

Raw lines 120 to 129
Starts an agent dispatch :128
130### Batching and conflict avoidance
132**Batching**: If 1-4 items are delegated, dispatch them all in parallel. For 5+, batch in groups of 4.
134**Conflict avoidance**: No two fixers that touch the same file run in parallel. You already know the target files from step 3 — serialize fixers that share a file (dispatch one, wait, then the next); non-overlapping items run in parallel. For a **class item**, feed the fixer its full enumerated location set and every covered feedback ID (not a single thread), and account for **all** of its sites in this check — a class fix touching files another fixer also touches must be serialized against every one of them. When one fixer handles multiple threads on the same file, it addresses them sequentially.
136**Sequential fallback**: Platforms that do not support parallel dispatch run fixers sequentially.
138Fixes can occasionally expand beyond their referenced file (e.g., renaming a method updates callers elsewhere). This is rare but can cause parallel fixers to collide. Step 5 (combined validation) catches test breakage; step 8 (verify) catches unresolved threads. If either reveals inconsistent changes, re-run the affected fixers sequentially.

Batching and conflict avoidance

Batching: If 1-4 items are delegated, dispatch them all in parallel. For 5+, batch in groups of 4.

Conflict avoidance: No two fixers that touch the same file run in parallel. You already know the target files from step 3 — serialize fixers that share a file (dispatch one, wait, then the next); non-overlapping items run in parallel. For a class item, feed the fixer its full enumerated location set and every covered feedback ID (not a single thread), and account for all of its sites in this check — a class fix touching files another fixer also touches must be serialized against every one of them. When one fixer handles multiple threads on the same file, it addresses them sequentially.

Sequential fallback: Platforms that do not support parallel dispatch run fixers sequentially.

Fixes can occasionally expand beyond their referenced file (e.g., renaming a method updates callers elsewhere). This is rare but can cause parallel fixers to collide. Step 5 (combined validation) catches test breakage; step 8 (verify) catches unresolved threads. If either reveals inconsistent changes, re-run the affected fixers sequentially.

Raw lines 130 to 139
Starts an agent dispatch :132
140## 5. Validate Combined State
142If the change set is empty, skip steps 5 and 6 and proceed to step 7.
144Each fix runs only targeted tests on its own change. This step runs the project's full validation **once** against the combined diff to catch interactions between fixes that targeted runs can't see.
1461. **Run the project's validation command** (test suite, type check, or whatever the project's active conventions specify). Run once, not per-agent.
1482. **Green** -> proceed to step 6.
1503. **Red, failures touch files in the change set** -> one inline diagnose-and-fix pass. Re-run validation. If still red, escalate with a `needs-human` item containing the test output; do **not** commit.
1524. **Red, failures touch only files outside the change set** -> treat as pre-existing. Proceed to step 6, but add a footer to the commit message: `Note: pre-existing failure in <test> not addressed by this PR.`
154Record the validation outcome (command run, pass/fail counts, any pre-existing failures noted) for the step 9 summary.

5. Validate Combined State

If the change set is empty, skip steps 5 and 6 and proceed to step 7.

Each fix runs only targeted tests on its own change. This step runs the project's full validation once against the combined diff to catch interactions between fixes that targeted runs can't see.

  1. Run the project's validation command (test suite, type check, or whatever the project's active conventions specify). Run once, not per-agent.
  1. Green -> proceed to step 6.
  1. Red, failures touch files in the change set -> one inline diagnose-and-fix pass. Re-run validation. If still red, escalate with a needs-human item containing the test output; do not commit.
  1. Red, failures touch only files outside the change set -> treat as pre-existing. Proceed to step 6, but add a footer to the commit message: Note: pre-existing failure in <test> not addressed by this PR.

Record the validation outcome (command run, pass/fail counts, any pre-existing failures noted) for the step 9 summary.

Raw lines 140 to 155
156## 6. Commit and Publication
158Commit only the change set, preserving unrelated work in the tree and index, with a message referencing the PR:
160```bash
161git add [files in the change set]
162git commit -m "Address PR review feedback (#PR_NUMBER)
164- [list changes from per-item results]" -- [files in the change set]
165```
167In `mode:return-to-caller`, capture the combined fix commit SHA and follow [references/return-to-caller.md](return-to-caller.md) to save every judged action and intended checklist tick. Return after saving; do not push or enter steps 7-8 for any part of this batch. A failed commit or save reports the actual local state and incomplete handoff, never completion.
169Ordinary and pipeline execution publish the commit before the remote tail:
170```bash
171git push
172```

6. Commit and Publication

Commit only the change set, preserving unrelated work in the tree and index, with a message referencing the PR:

git add [files in the change set]
git commit -m "Address PR review feedback (#PR_NUMBER)

- [list changes from per-item results]" -- [files in the change set]

In mode:return-to-caller, capture the combined fix commit SHA and follow references/return-to-caller.md to save every judged action and intended checklist tick. Return after saving; do not push or enter steps 7-8 for any part of this batch. A failed commit or save reports the actual local state and incomplete handoff, never completion.

Ordinary and pipeline execution publish the commit before the remote tail:

git push
Raw lines 156 to 173
174## 7. Reply and Resolve
176Enter the remote tail only when the batch's fix commit is published, or the batch created no code changes. Return-to-caller batches with a fix stop at step 6; their saved reply-only and human-list items remain deferred too. No-change return-to-caller batches use this existing protocol and save observed progress even when a write fails. Resume enters here only through the publication and reconciliation conditions in [references/resume.md](resume.md), uses the saved verdicts and exact reply bodies, and returns there after completing or stopping the remote tail. Apply eligible PR checklist ticks under the entrypoint's publication condition.
178The done condition for an ordinary review thread is one visible, submitted substantive reply plus authoritative resolution; satisfy each condition independently and never repeat a satisfied half. Post for every newly handled item: fix-list items use the `reply_text` from their per-item result; reply-list and human-list items use the reply text you composed in step 3. A **class item** carries multiple covered feedback IDs (`feedback_ids`/`feedback_types` from its fixer) — reply to and resolve *every* one, posting the shared `reply_text` on each thread, not just the first; a covered thread left unresolved shows up as new work again in the next `ce-babysit-pr` loop. The mechanism depends on the feedback type.

7. Reply and Resolve

Enter the remote tail only when the batch's fix commit is published, or the batch created no code changes. Return-to-caller batches with a fix stop at step 6; their saved reply-only and human-list items remain deferred too. No-change return-to-caller batches use this existing protocol and save observed progress even when a write fails. Resume enters here only through the publication and reconciliation conditions in references/resume.md, uses the saved verdicts and exact reply bodies, and returns there after completing or stopping the remote tail. Apply eligible PR checklist ticks under the entrypoint's publication condition.

The done condition for an ordinary review thread is one visible, submitted substantive reply plus authoritative resolution; satisfy each condition independently and never repeat a satisfied half. Post for every newly handled item: fix-list items use the reply_text from their per-item result; reply-list and human-list items use the reply text you composed in step 3. A class item carries multiple covered feedback IDs (feedback_ids/feedback_types from its fixer) — reply to and resolve every one, posting the shared reply_text on each thread, not just the first; a covered thread left unresolved shows up as new work again in the next ce-babysit-pr loop. The mechanism depends on the feedback type.

Raw lines 174 to 179
Names a skill ce-babysit-pr :178
180### Reply format
182All replies quote the relevant part of the original feedback for continuity — the specific sentence or passage, not the entire comment if it's long. The per-verdict templates are in [references/evaluation-rubric.md](evaluation-rubric.md) (skip verdicts) and [references/agents/pr-comment-resolver.md](agents/pr-comment-resolver.md) (`fixed` / `fixed-differently`).
184For `needs-human` verdicts, post the natural-sounding reply but do NOT resolve the thread. Leave it open for human input.

Reply format

All replies quote the relevant part of the original feedback for continuity — the specific sentence or passage, not the entire comment if it's long. The per-verdict templates are in references/evaluation-rubric.md (skip verdicts) and references/agents/pr-comment-resolver.md (fixed / fixed-differently).

For needs-human verdicts, post the natural-sounding reply but do NOT resolve the thread. Leave it open for human input.

Raw lines 180 to 185
186### Review threads
188For every calling mode, select the first unsatisfied completion condition before acting. A thread with no visible submitted substantive reply runs steps 0-4. A `resolution-pending` thread skips only step 1, uses its existing reply IDs for step 2, and runs steps 2-4; do not judge, fix, or post again. A `needs-human` thread stops after its visible submitted reply and remains unresolved.
190Current GitHub state decides independently of local progress. A POST may succeed before the helper's pending-review check fails or before a checkpoint is written. Reconcile the existing reply and its submitted visibility before retrying; adopt a verified reply instead of reposting it, and verify authoritative resolution separately.
1920. **Verify the thread ID** before replying. GitHub Enterprise can return inconsistent node IDs for the same thread depending on the query path. Always confirm the ID from `get-pr-comments` resolves to the correct thread using [scripts/get-thread-for-comment](../scripts/get-thread-for-comment) with the comment's numeric URL ID. Extract the numeric comment ID from the comment URL (e.g. `discussion_r2589700` → `2589700`) for the `gh api` call; if the bundled script is missing, use `gh api` to inspect the review thread instead:
193```bash
194SKILL_DIR="<absolute path of the directory containing the ce-resolve-pr-feedback SKILL.md>";
195GH_HOST=<derived-host> GH_REPO=OWNER/REPO gh api repos/{owner}/{repo}/pulls/comments/COMMENT_ID --jq .node_id
196GH_HOST=<derived-host> bash "$SKILL_DIR/scripts/get-thread-for-comment" PR_NUMBER COMMENT_NODE_ID OWNER/REPO
197```
198The returned `id` is the authoritative thread ID for resolution, and `root_comment_id` is the numeric ID of the thread's first comment for the REST reply. If the thread ID differs from what `get-pr-comments` returned, use the one from this script.
2001. **Reply directly to the root comment over REST** using [scripts/reply-to-pr-thread](../scripts/reply-to-pr-thread). If the bundled script is missing, use the same `POST repos/{owner}/{repo}/pulls/PR_NUMBER/comments/ROOT_COMMENT_ID/replies` endpoint. Do not substitute `addPullRequestReviewThreadReply`, `gh pr review`, or a `/reviews` POST: those operations go through review-submission state, so the reply can sit unsubmitted, while a successful reply must be immediately submitted and visible.
201Feed the body from a private OS scratch file. For a fresh reply, the quoted heredoc below writes multiline Markdown without shell expansion; never use `echo "..."` or `printf` to interpret escape sequences. For a saved reply, write its exact decoded `reply_body` bytes to that file with a tool instead of running the illustrative heredoc, which would add a terminal newline. Preserve all existing line breaks, including terminal ones:
202```bash
203SKILL_DIR="<absolute path of the directory containing the ce-resolve-pr-feedback SKILL.md>";
204REPLY_BODY_FILE="<absolute private OS scratch reply file>";
205cat > "$REPLY_BODY_FILE" <<'EOF'
206> the specific sentence being addressed from the reviewer's comment
208Fixed in abc1234 — the lookup now null-checks before dereferencing.
209EOF
210GH_HOST=<derived-host> bash "$SKILL_DIR/scripts/reply-to-pr-thread" PR_NUMBER ROOT_COMMENT_ID OWNER/REPO < "$REPLY_BODY_FILE"
211```
212The helper exits nonzero if a pending review is visible after the POST. Stop without resolving on that error; do not submit or discard the review. Check that the returned comment URL contains the correct `OWNER/REPO` and PR number before proceeding.
2142. **Verify the REST-created reply is visible and submitted** before resolving. Take its numeric ID from the returned URL fragment (`#discussion_r2589700` → `2589700`) and read back what GitHub stored:
215```bash
216GH_HOST=<derived-host> GH_REPO=OWNER/REPO gh api repos/{owner}/{repo}/pulls/comments/REPLY_COMMENT_ID --jq .body
217GH_HOST=<derived-host> GH_REPO=OWNER/REPO gh api repos/{owner}/{repo}/pulls/comments/REPLY_COMMENT_ID --jq '.pull_request_review_id // empty'
218```
219The first command prints the decoded body, which must show real line breaks. If instead it shows `\n` (or `\n\n`) as literal backslash-n characters inside one line, the body was posted escaped: **do not resolve the thread**. Fix it first by rewriting the body through a heredoc, then re-verify:
220```bash
221GH_HOST=<derived-host> GH_REPO=OWNER/REPO gh api --method PATCH repos/{owner}/{repo}/pulls/comments/REPLY_COMMENT_ID -f body="$(cat <<'EOF'
222> the specific sentence being addressed from the reviewer's comment
224Fixed in abc1234 — the lookup now null-checks before dereferencing.
225EOF
226)"
227```
228If the second command prints a review ID, fetch that review and require a state other than `PENDING`; a pending state means the reply is not submitted, regardless of the successful POST response:
229```bash
230GH_HOST=<derived-host> GH_REPO=OWNER/REPO gh api repos/{owner}/{repo}/pulls/PR_NUMBER/reviews/REVIEW_ID --jq .state
231```
2333. **Re-fetch pending-review state after posting.** This closes the race after the initial fetch and detects a draft created during the reply loop:
234```bash
235SKILL_DIR="<absolute path of the directory containing the ce-resolve-pr-feedback SKILL.md>";
236GH_HOST=<derived-host> bash "$SKILL_DIR/scripts/get-pr-comments" PR_NUMBER OWNER/REPO | jq -r '.pending_review // empty'
237```
238If this prints an ID, stop without resolving any thread from this reply pass. Report the pending review, but do not submit or discard it.
2404. **Resolve** using [scripts/resolve-pr-thread](../scripts/resolve-pr-thread) (if the bundled script is missing, resolve the thread with `gh api` if supported):
241```bash
242SKILL_DIR="<absolute path of the directory containing the ce-resolve-pr-feedback SKILL.md>";
243GH_HOST=<derived-host> bash "$SKILL_DIR/scripts/resolve-pr-thread" THREAD_ID
244```

Review threads

For every calling mode, select the first unsatisfied completion condition before acting. A thread with no visible submitted substantive reply runs steps 0-4. A resolution-pending thread skips only step 1, uses its existing reply IDs for step 2, and runs steps 2-4; do not judge, fix, or post again. A needs-human thread stops after its visible submitted reply and remains unresolved.

Current GitHub state decides independently of local progress. A POST may succeed before the helper's pending-review check fails or before a checkpoint is written. Reconcile the existing reply and its submitted visibility before retrying; adopt a verified reply instead of reposting it, and verify authoritative resolution separately.

  1. Verify the thread ID before replying. GitHub Enterprise can return inconsistent node IDs for the same thread depending on the query path. Always confirm the ID from get-pr-comments resolves to the correct thread using scripts/get-thread-for-comment with the comment's numeric URL ID. Extract the numeric comment ID from the comment URL (e.g. discussion_r2589700 → 2589700) for the gh api call; if the bundled script is missing, use gh api to inspect the review thread instead:
SKILL_DIR="<absolute path of the directory containing the ce-resolve-pr-feedback SKILL.md>";
GH_HOST=<derived-host> GH_REPO=OWNER/REPO gh api repos/{owner}/{repo}/pulls/comments/COMMENT_ID --jq .node_id
GH_HOST=<derived-host> bash "$SKILL_DIR/scripts/get-thread-for-comment" PR_NUMBER COMMENT_NODE_ID OWNER/REPO

The returned id is the authoritative thread ID for resolution, and root_comment_id is the numeric ID of the thread's first comment for the REST reply. If the thread ID differs from what get-pr-comments returned, use the one from this script.

  1. Reply directly to the root comment over REST using scripts/reply-to-pr-thread. If the bundled script is missing, use the same POST repos/{owner}/{repo}/pulls/PR_NUMBER/comments/ROOT_COMMENT_ID/replies endpoint. Do not substitute addPullRequestReviewThreadReply, gh pr review, or a /reviews POST: those operations go through review-submission state, so the reply can sit unsubmitted, while a successful reply must be immediately submitted and visible.

Feed the body from a private OS scratch file. For a fresh reply, the quoted heredoc below writes multiline Markdown without shell expansion; never use echo "..." or printf to interpret escape sequences. For a saved reply, write its exact decoded reply_body bytes to that file with a tool instead of running the illustrative heredoc, which would add a terminal newline. Preserve all existing line breaks, including terminal ones:

SKILL_DIR="<absolute path of the directory containing the ce-resolve-pr-feedback SKILL.md>";
REPLY_BODY_FILE="<absolute private OS scratch reply file>";
cat > "$REPLY_BODY_FILE" <<'EOF'
> the specific sentence being addressed from the reviewer's comment

Fixed in abc1234 — the lookup now null-checks before dereferencing.
EOF
GH_HOST=<derived-host> bash "$SKILL_DIR/scripts/reply-to-pr-thread" PR_NUMBER ROOT_COMMENT_ID OWNER/REPO < "$REPLY_BODY_FILE"

The helper exits nonzero if a pending review is visible after the POST. Stop without resolving on that error; do not submit or discard the review. Check that the returned comment URL contains the correct OWNER/REPO and PR number before proceeding.

  1. Verify the REST-created reply is visible and submitted before resolving. Take its numeric ID from the returned URL fragment (#discussion_r2589700 → 2589700) and read back what GitHub stored:
GH_HOST=<derived-host> GH_REPO=OWNER/REPO gh api repos/{owner}/{repo}/pulls/comments/REPLY_COMMENT_ID --jq .body
GH_HOST=<derived-host> GH_REPO=OWNER/REPO gh api repos/{owner}/{repo}/pulls/comments/REPLY_COMMENT_ID --jq '.pull_request_review_id // empty'

The first command prints the decoded body, which must show real line breaks. If instead it shows \n (or \n\n) as literal backslash-n characters inside one line, the body was posted escaped: do not resolve the thread. Fix it first by rewriting the body through a heredoc, then re-verify:

GH_HOST=<derived-host> GH_REPO=OWNER/REPO gh api --method PATCH repos/{owner}/{repo}/pulls/comments/REPLY_COMMENT_ID -f body="$(cat <<'EOF'
> the specific sentence being addressed from the reviewer's comment

Fixed in abc1234 — the lookup now null-checks before dereferencing.
EOF
)"

If the second command prints a review ID, fetch that review and require a state other than PENDING; a pending state means the reply is not submitted, regardless of the successful POST response:

GH_HOST=<derived-host> GH_REPO=OWNER/REPO gh api repos/{owner}/{repo}/pulls/PR_NUMBER/reviews/REVIEW_ID --jq .state
  1. Re-fetch pending-review state after posting. This closes the race after the initial fetch and detects a draft created during the reply loop:
SKILL_DIR="<absolute path of the directory containing the ce-resolve-pr-feedback SKILL.md>";
GH_HOST=<derived-host> bash "$SKILL_DIR/scripts/get-pr-comments" PR_NUMBER OWNER/REPO | jq -r '.pending_review // empty'

If this prints an ID, stop without resolving any thread from this reply pass. Report the pending review, but do not submit or discard it.

  1. Resolve using scripts/resolve-pr-thread (if the bundled script is missing, resolve the thread with gh api if supported):
SKILL_DIR="<absolute path of the directory containing the ce-resolve-pr-feedback SKILL.md>";
GH_HOST=<derived-host> bash "$SKILL_DIR/scripts/resolve-pr-thread" THREAD_ID
Raw lines 186 to 245
Runs code scripts/get-thread-for-comment :192
Runs code scripts/reply-to-pr-thread :200
Runs code scripts/get-pr-comments :236
Runs code scripts/resolve-pr-thread :240
246### PR comments and review bodies
248These cannot be resolved via GitHub's API. Reply with a top-level PR comment referencing the original (pass `-R OWNER/REPO` — the parsed base repo — so a fork→upstream reply posts on the watched upstream PR, not the fork namespace):
250```bash
251REPLY_BODY_FILE="<absolute private OS scratch reply file>";
252cat > "$REPLY_BODY_FILE" <<'EOF'
253> the specific sentence being addressed from the reviewer's comment
255Fixed in abc1234 — the lookup now null-checks before dereferencing.
256EOF
257GH_HOST=<derived-host> gh pr comment PR_NUMBER -R OWNER/REPO --body-file "$REPLY_BODY_FILE"
258```
260For a saved reply, populate the file with its exact decoded bytes instead of running the illustrative heredoc. `--body-file` preserves terminal newlines that command substitution would strip. Confirm the posted body matches the intended Markdown, including actual line breaks.
262Include enough quoted context in the reply so the reader can follow which comment is being addressed without scrolling.

PR comments and review bodies

These cannot be resolved via GitHub's API. Reply with a top-level PR comment referencing the original (pass -R OWNER/REPO — the parsed base repo — so a fork→upstream reply posts on the watched upstream PR, not the fork namespace):

REPLY_BODY_FILE="<absolute private OS scratch reply file>";
cat > "$REPLY_BODY_FILE" <<'EOF'
> the specific sentence being addressed from the reviewer's comment

Fixed in abc1234 — the lookup now null-checks before dereferencing.
EOF
GH_HOST=<derived-host> gh pr comment PR_NUMBER -R OWNER/REPO --body-file "$REPLY_BODY_FILE"

For a saved reply, populate the file with its exact decoded bytes instead of running the illustrative heredoc. --body-file preserves terminal newlines that command substitution would strip. Confirm the posted body matches the intended Markdown, including actual line breaks.

Include enough quoted context in the reply so the reader can follow which comment is being addressed without scrolling.

Raw lines 246 to 263
264## 8. Verify
266Re-fetch feedback to confirm resolution:
268```bash
269SKILL_DIR="<absolute path of the directory containing the ce-resolve-pr-feedback SKILL.md>";
270GH_HOST=<derived-host> bash "$SKILL_DIR/scripts/get-pr-comments" PR_NUMBER OWNER/REPO
271```
273The `review_threads` array should be empty (except `needs-human` items).
275In resume, verify only the saved actions and report new feedback through its caller result; return to [references/resume.md](resume.md) without entering another fix cycle.
277**For fresh-feedback modes, if new threads remain**, check the iteration count -- counting rounds **for this PR**, not just this invocation. An orchestrator such as `ce-babysit-pr` re-invokes this skill fresh each round, so a per-invocation counter never trips; count instead the earlier review-fix commits already on the branch (`git log <base>..HEAD` subjects that address review feedback) plus this run's own cycles.
279- **First or second fix-verify cycle**: Repeat from step 2 for the remaining threads.
281- **After the second fix-verify cycle** (3rd pass would begin): Stop looping. Show the remaining issues to the user with context about the recurring pattern: "Multiple rounds of feedback on [area/theme] suggest a deeper issue. Here's what we've fixed so far and what keeps appearing." Use the same `needs-human` escalation pattern -- leave threads open and present the pattern for the user to decide.
283PR comments and review bodies have no resolve mechanism, so they will still appear in the output. Verify they were replied to by checking the PR conversation.

8. Verify

Re-fetch feedback to confirm resolution:

SKILL_DIR="<absolute path of the directory containing the ce-resolve-pr-feedback SKILL.md>";
GH_HOST=<derived-host> bash "$SKILL_DIR/scripts/get-pr-comments" PR_NUMBER OWNER/REPO

The review_threads array should be empty (except needs-human items).

In resume, verify only the saved actions and report new feedback through its caller result; return to references/resume.md without entering another fix cycle.

For fresh-feedback modes, if new threads remain, check the iteration count -- counting rounds for this PR, not just this invocation. An orchestrator such as ce-babysit-pr re-invokes this skill fresh each round, so a per-invocation counter never trips; count instead the earlier review-fix commits already on the branch (git log <base>..HEAD subjects that address review feedback) plus this run's own cycles.

  • First or second fix-verify cycle: Repeat from step 2 for the remaining threads.
  • After the second fix-verify cycle (3rd pass would begin): Stop looping. Show the remaining issues to the user with context about the recurring pattern: "Multiple rounds of feedback on [area/theme] suggest a deeper issue. Here's what we've fixed so far and what keeps appearing." Use the same needs-human escalation pattern -- leave threads open and present the pattern for the user to decide.

PR comments and review bodies have no resolve mechanism, so they will still appear in the output. Verify they were replied to by checking the PR conversation.

Raw lines 264 to 284
Runs code scripts/get-pr-comments :270
Names a skill ce-babysit-pr :277
285## 9. Summary
287In `mode:return-to-caller`, emit the structured result in [references/return-to-caller.md](return-to-caller.md) instead of the interactive summary below. Save actual no-change completion and any incomplete remote tail before returning; human decisions stay open and retain their typed payloads.
289Present a concise summary of all work done. Group by verdict, one line per item describing *what was done* not just *where*. This is the primary output the user sees, and the place where your step 3 (Consolidate & Decide) judgments become visible: the user can see exactly what was fixed, what was skipped, and why.
291Format:
293```
294Resolved N of M new items on PR #NUMBER:
296Fixed (count): [brief description of each fix]
297Fixed differently (count): [what was changed and why the approach differed]
298Replied (count): [what questions were answered]
299Not addressing (count): [what was skipped and the evidence]
300Declined (count): [what was declined and the harm or scope reason cited; name out-of-scope items separately so the user can carry them forward]
302Validation: [one line -- e.g., "bun test passed (893/893)" or "bun test passed with pre-existing failure in X noted"; omit when no code changes were committed]
303Diff change: [`git diff --shortstat` from the head before this run's first fix commit to the head after its last, e.g., "+42 / -7 across 3 files"; omit when no code changes were committed]
304```
306If any item is `needs-human`, append a decisions section. These are rare but high-signal. Each carries the `needs-human` object composed in step 3: quoted feedback, investigation, the reason autonomous action is unsafe or ambiguous, concrete options with tradeoffs, a recommendation if any, and links to every still-open thread it covers.
308Present the `decision_context` directly -- it's already structured for the user to decide quickly:
310```
311## Needs your decision
3131. [decision_context.quoted_feedback]
314 - Investigated: [decision_context.investigation]
315 - Decision needed: [decision_context.decision_reason]
316 - Options: [decision_context.options, preserving each option and tradeoff]
317 - Recommendation: [decision_context.recommendation, when non-null]
318 - Open threads: [thread_urls]
319```
321The `needs-human` threads already have a natural-sounding acknowledgment reply posted and remain open on the PR.
323If there are **pending decisions from a previous run** (threads detected in step 2 (Triage) as already responded to but still unresolved), list them after the new work:
325```
326Still pending from a previous run (count):
3281. [Thread path:line] -- [brief description of what's pending]
329 Previous reply: [link to the existing reply]
330 [Re-present the decision options if available, or summarize what was asked]
331```
333If a blocking question tool is available, use it to ask about all pending decisions (both new `needs-human` and previous-run pending) together. If there are only pending decisions and no new work was done, the summary is just the pending items.
335Use the host's blocking question tool already in the current tool list (match by capability, not by a host-specific name). Presence in the current tool list is proof the tool exists; never call a user-facing question tool to discover whether it exists. If a matching tool is listed but unloaded, use the host's tool-discovery mechanism to load that capability — do not search for another host's tool name. Use it to present the decisions and wait for the user's response. After they decide, process the remaining items: fix the code, compose the reply, post it, and resolve the thread.
337Fall back to presenting the decisions in user-visible summary output and waiting in conversation only when no blocking tool exists in the harness or the call errors (e.g., Codex edit modes) — not because a schema load is required. Never silently skip. If the user doesn't respond, the items remain open on the PR for later handling.

9. Summary

In mode:return-to-caller, emit the structured result in references/return-to-caller.md instead of the interactive summary below. Save actual no-change completion and any incomplete remote tail before returning; human decisions stay open and retain their typed payloads.

Present a concise summary of all work done. Group by verdict, one line per item describing what was done not just where. This is the primary output the user sees, and the place where your step 3 (Consolidate & Decide) judgments become visible: the user can see exactly what was fixed, what was skipped, and why.

Format:

Resolved N of M new items on PR #NUMBER:

Fixed (count): [brief description of each fix]
Fixed differently (count): [what was changed and why the approach differed]
Replied (count): [what questions were answered]
Not addressing (count): [what was skipped and the evidence]
Declined (count): [what was declined and the harm or scope reason cited; name out-of-scope items separately so the user can carry them forward]

Validation: [one line -- e.g., "bun test passed (893/893)" or "bun test passed with pre-existing failure in X noted"; omit when no code changes were committed]
Diff change: [`git diff --shortstat` from the head before this run's first fix commit to the head after its last, e.g., "+42 / -7 across 3 files"; omit when no code changes were committed]

If any item is needs-human, append a decisions section. These are rare but high-signal. Each carries the needs-human object composed in step 3: quoted feedback, investigation, the reason autonomous action is unsafe or ambiguous, concrete options with tradeoffs, a recommendation if any, and links to every still-open thread it covers.

Present the decision_context directly -- it's already structured for the user to decide quickly:

## Needs your decision

1. [decision_context.quoted_feedback]
   - Investigated: [decision_context.investigation]
   - Decision needed: [decision_context.decision_reason]
   - Options: [decision_context.options, preserving each option and tradeoff]
   - Recommendation: [decision_context.recommendation, when non-null]
   - Open threads: [thread_urls]

The needs-human threads already have a natural-sounding acknowledgment reply posted and remain open on the PR.

If there are pending decisions from a previous run (threads detected in step 2 (Triage) as already responded to but still unresolved), list them after the new work:

Still pending from a previous run (count):

1. [Thread path:line] -- [brief description of what's pending]
   Previous reply: [link to the existing reply]
   [Re-present the decision options if available, or summarize what was asked]

If a blocking question tool is available, use it to ask about all pending decisions (both new needs-human and previous-run pending) together. If there are only pending decisions and no new work was done, the summary is just the pending items.

Use the host's blocking question tool already in the current tool list (match by capability, not by a host-specific name). Presence in the current tool list is proof the tool exists; never call a user-facing question tool to discover whether it exists. If a matching tool is listed but unloaded, use the host's tool-discovery mechanism to load that capability — do not search for another host's tool name. Use it to present the decisions and wait for the user's response. After they decide, process the remaining items: fix the code, compose the reply, post it, and resolve the thread.

Fall back to presenting the decisions in user-visible summary output and waiting in conversation only when no blocking tool exists in the harness or the call errors (e.g., Codex edit modes) — not because a schema load is required. Never silently skip. If the user doesn't respond, the items remain open on the PR for later handling.

Raw lines 285 to 337
Involves a person and wait :335