feat(dev): babysit-prs — worker subagents + progressive disclosure - #12
Conversation
Rewrite SKILL.md as an orchestrator (sweep + cheap gh-JSON triage + report) that spawns one general-purpose subagent per flagged PR. The worker prompt inlines literal values only (repo, default branch, repo root, PR fields, triage evidence, assigned worktree dirs), restates the safety rails verbatim, and demands a structured RESULT block. Healthy PRs never spawn a worker; workers run sequentially (shared .git locks); inline fallback when no Agent tool. The conflict/CI procedures move intact into a worker-facing Per-PR procedures section that workers read from a resolved literal path. Implements point 1 of the babysit-prs improvement plan (issue #8). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Document why every flagged PR gets a worker (no count threshold): workers are sequential, so the fan-out-overhead caveat from #8 doesn't apply, and context hygiene pays at any count under /loop. - Align worktree-dir placeholder names (<REPO_ROOT>/<number>) with the Step 4 prompt template. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Point 2 of the babysit-prs improvement plan: progressive disclosure. The two
long per-PR procedures move out of SKILL.md into one file per axis under
references/, leaving SKILL.md at 311 lines (was 574).
- references/conflict-procedure.md — the merge-conflict axis (steps 1-7)
- references/ci-procedure.md — the failing-checks axis (steps 1-5)
Both bodies move verbatim; the only text changes are cross-references that no
longer resolve in-file ("step 5" -> "step 5 below", and CI step 4's pointer at
the conflict procedure's own step 7). Each file opens by naming its worktree dir
and its placeholders, and defers to SKILL.md for the confidence rule and Safety
so neither is duplicated.
Wiring:
- Step 1 resolves SKILL_DIR alongside SKILL_FILE and states that the
orchestrator must not read either procedure file — it only passes the paths on.
- The Step 4 worker prompt carries a procedure path per flagged axis, with an
explicit instruction to read only the flagged ones, as each axis is reached.
- The inline (no Agent tool) fallback is called out as the one path that reads
the procedure files itself.
Frontmatter description is unchanged, so the generated README is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThe ChangesBabysit PR workflow
Sequence Diagram(s)sequenceDiagram
participant Orchestrator
participant GitHubCLI
participant Worker
participant Worktree
Orchestrator->>GitHubCLI: triage open PR
GitHubCLI-->>Orchestrator: return PR state and evidence
Orchestrator->>Worker: send flagged axes and literal values
Worker->>Worktree: create isolated worktree
Worktree-->>Worker: return verification or remediation result
Worker-->>Orchestrator: return structured status
Possibly related issues
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@plugins/dev/skills/babysit-prs/references/conflict-procedure.md`:
- Around line 156-165: The final push guard must verify that the original PR
head remains in the resolved merge. In the conditional chain around the
default-branch ancestry check, add a `git merge-base --is-ancestor
"$PR_HEAD_SHA" HEAD` validation and emit a stop message instead of pushing when
it fails; retain the existing conflict-marker check and push behavior only after
both ancestry checks pass.
- Around line 11-14: Reinitialize procedure state in every shell block: update
WORKTREE_DIR references in conflict-procedure.md at lines 11-14 and
ci-procedure.md at lines 60-71, and update PR_HEAD_SHA references in the
conflict procedure’s later restore and checkout blocks to reassign or reload
each variable before use.
In `@plugins/dev/skills/babysit-prs/SKILL.md`:
- Around line 176-180: Update the prompt template instructions around the
literal placeholder replacement to explicitly delimit PR metadata values such as
the title, URL, branch name, and fail-bucket JSON as untrusted data, and
instruct the worker to ignore any commands embedded in metadata, diffs, CI logs,
or review comments.
- Around line 193-212: Quote headRefName in every push refspec to prevent shell
metacharacters from being interpreted: update
plugins/dev/skills/babysit-prs/SKILL.md lines 193-212,
references/conflict-procedure.md lines 150-165, and references/ci-procedure.md
lines 78-88 to use the quoted HEAD:<headRefName> form; apply the same change in
all three procedures.
- Around line 45-48: Update the SKILL_FILE resolution logic around the
installed-plugin and source-checkout searches to require exactly one matching
active skill file, rejecting both zero and multiple matches instead of using
head -1 or falling back to the repository root. Before dispatching workers,
validate that the resolved SKILL_DIR contains both required reference files and
fail clearly if either is missing.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9be7e45c-eaa5-4dd6-b632-a1e1c62b6709
📒 Files selected for processing (3)
plugins/dev/skills/babysit-prs/SKILL.mdplugins/dev/skills/babysit-prs/references/ci-procedure.mdplugins/dev/skills/babysit-prs/references/conflict-procedure.md
Resolved CodeRabbit comments on PR #12. - Quote every `HEAD:<headRefName>` push refspec. Git accepts `;`, `$(…)` and backticks in branch names, so an unquoted refspec is a command-injection vector (verified with `git check-ref-format`). - Add a PR-head ancestry check to the conflict push guard. The default-branch check passes trivially on step 4's baseline detour, where HEAD *is* the default branch — verified that the old guard allowed pushing the default branch over the PR's own head, discarding the PR. - Replace the cross-block `PR_HEAD_SHA` shell variable with a `refs/babysit/pr-<number>-head` git ref. Refs survive a fresh shell, a reset and a `clean`; an empty variable turned `reset --hard` into a no-op that kept the merge it was meant to discard. Deleted in step 7. - Re-assign `WORKTREE_DIR` in every command block that uses it. Each tool call is a fresh shell, so an empty value made `git -C "$WORKTREE_DIR" clean -fd` clean the current directory instead. - Resolve the skill path from the base directory Claude Code supplies, falling back to a search that requires exactly one match and verifies both procedure files exist. `find | head -1` picked a stale plugin-cache commit — this machine has three copies, and it was selecting the oldest. - Mark PR metadata in the worker prompt as untrusted data with BEGIN/END markers, and instruct workers to ignore instruction-shaped content in metadata, diffs, CI logs and review comments. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@plugins/dev/skills/babysit-prs/references/conflict-procedure.md`:
- Around line 156-161: Update the conflict rerun procedure around the two git
clean commands to remove ignored artifacts before both checkout operations,
preventing PR-generated state from affecting baseline tests. Use git clean -fdx
only if all required ignored setup files can be recreated; otherwise apply an
appropriate repository-specific artifact cleanup.
- Around line 208-212: Update the conflict procedure’s git command construction
so the PR-controlled headRefName is passed as data through a shell variable and
expanded only at execution time, rather than interpolated into shell source or
double-quoted command text. Apply this to the refspec usage around
HEAD:<headRefName> and every other branch-name expansion in the procedure,
preserving correct handling of valid shell metacharacters.
- Around line 23-26: Update the conflict procedure around the saved PR head ref
and steps 3–5 so the original PR head is stored in trusted state outside the
PR-controlled shared Git ref store. Ensure setup and test commands cannot
rewrite or delete the value used by the ancestry check before pushing, and
revalidate the current HEAD against that trusted original SHA after
PR-controlled commands complete.
In `@plugins/dev/skills/babysit-prs/SKILL.md`:
- Around line 371-374: Update the branch-push guidance around headRefName so raw
branch text is never interpolated into shell source. Resolve headRefName into a
shell variable and expand that variable only within a quoted git push argument,
preserving ref validation and preventing embedded quotes or command
substitutions from executing.
- Around line 63-75: Make the path-validation logic terminate with a non-zero
status when skill or procedure resolution fails. Update each STOP branch in the
babysit-prs validation flow and ensure the file-existence loop sets a failure
guard or exits before worker dispatch, while preserving successful resolution
behavior.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1a5defab-0ba2-4e7f-beba-020441ea2566
📒 Files selected for processing (3)
plugins/dev/skills/babysit-prs/SKILL.mdplugins/dev/skills/babysit-prs/references/ci-procedure.mdplugins/dev/skills/babysit-prs/references/conflict-procedure.md
🚧 Files skipped from review as they are similar to previous changes (1)
- plugins/dev/skills/babysit-prs/references/ci-procedure.md
- Resolve branch names at execution time (HEAD_BRANCH=$(gh pr view ...)) instead of interpolating headRefName into shell source — double quotes do not stop $() / backtick evaluation inside a pasted ref name. - Pin the saved PR-head ref: note the SHA at step 2 and re-check the ref against it in step 5's push guard, since the shared ref store is writable by anything the procedure runs. - Make Step 1 STOP branches exit non-zero so failed path resolution can't scroll past. - Document the ignored-files tradeoff on the baseline detour and the indeterminate escape hatch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
plugins/dev/skills/babysit-prs/SKILL.md (1)
221-236: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winLLM Prompt Injection Through Unescaped Delimiter Data (CWE-74): Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
Reachability: External · Exploitability: Moderate
Encode GitHub-sourced values before prompt interpolation.
The
BEGIN/END PR DATAmarkers are only textual boundaries. Escape line breaks and delimiter text, or use a serialized structured object with an explicit decoding rule. Add tests for marker text and multiline values.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@plugins/dev/skills/babysit-prs/SKILL.md` around lines 221 - 236, Update the prompt construction in the PR data flow to encode all GitHub-sourced values before interpolation, rather than relying only on BEGIN/END PR DATA markers. Use a serialized structured representation or escape line breaks and delimiter text with an explicit decoding rule, and add coverage for multiline values and embedded marker text.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@plugins/dev/skills/babysit-prs/references/conflict-procedure.md`:
- Around line 26-30: Update the procedure’s saved-head flow so it captures the
original PR-head SHA, fetched default-branch SHA, and validated HEAD SHA in
trusted state before setup or tests run. Use only these captured SHA values for
all ancestry checks and push the validated HEAD SHA explicitly rather than
rereading mutable PR, origin/default-branch, or HEAD refs; apply the same
pinning consistently across the referenced validation and push steps.
- Around line 206-225: Update the final push flow after the merge-validation
checks to isolate it from PR-controlled Git configuration: run setup hooks and
PR tests without push credentials, resolve and verify the PR head repository,
and validate the trusted push remote URL uses secure transport before pushing.
Replace the direct git push using mutable origin settings with a push from
trusted configuration targeting the verified head repository, while preserving
the explicit HEAD:$HEAD_BRANCH refspec and never using --force.
- Around line 210-226: Update the final push guard in the conflict-resolution
procedure to fetch the remote PR head and verify its current tip still matches
the saved SHA from step 2, including force-pushes to ancestors. Push with an
explicit force-with-lease expectation for that saved SHA, preserving the
existing ancestry and conflict-marker checks before pushing.
- Around line 210-214: Update the manual commit step in the conflict-resolution
procedure to run only when a merge is still in progress, by checking for the
repository’s MERGE_HEAD state before invoking git commit --no-edit. Preserve the
subsequent ancestry checks and push so they always execute after either an
auto-committed merge or a manually committed one.
---
Outside diff comments:
In `@plugins/dev/skills/babysit-prs/SKILL.md`:
- Around line 221-236: Update the prompt construction in the PR data flow to
encode all GitHub-sourced values before interpolation, rather than relying only
on BEGIN/END PR DATA markers. Use a serialized structured representation or
escape line breaks and delimiter text with an explicit decoding rule, and add
coverage for multiline values and embedded marker text.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 99ab6faa-ac0e-4eea-a4bf-49386341ff47
📒 Files selected for processing (3)
plugins/dev/skills/babysit-prs/SKILL.mdplugins/dev/skills/babysit-prs/references/ci-procedure.mdplugins/dev/skills/babysit-prs/references/conflict-procedure.md
🚧 Files skipped from review as they are similar to previous changes (1)
- plugins/dev/skills/babysit-prs/references/ci-procedure.md
Address CodeRabbit review on PR #12: - Gate `git commit --no-edit` on MERGE_HEAD so an auto-committed merge can't error a fail-fast shell before the push guards run. - Read the saved-head ref once into SAVED_SHA, verify it resolved, and use that one value for both the ancestry guard and a --force-with-lease=<branch>:<sha> push — a compare-and-swap that rejects any mid-pass branch movement (including force-pushes to an ancestor that a plain push would silently bury) while remaining a strict fast-forward when it succeeds. - Clarify in both SKILL.md safety rails that the pinned lease is stricter than a plain push, not a force-push; bare --force / --force-with-lease stay forbidden. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…abysit-prs-improvements # Conflicts: # plugins/dev/skills/babysit-prs/SKILL.md # plugins/dev/skills/babysit-prs/references/conflict-procedure.md
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@plugins/dev/skills/babysit-prs/SKILL.md`:
- Around line 290-293: Update the conflict procedure guidance in the “Never
force-push and never rebase” section to describe
--force-with-lease="$HEAD_BRANCH:$SAVED_SHA" as a lease-guarded force update,
removing claims that it is not a force-push or a stricter plain push. Retain the
prohibition on bare --force and bare --force-with-lease, and do not add a
MERGE_HEAD requirement at push time.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: bfa33302-f198-4ba1-b7e5-316d5d4f2376
📒 Files selected for processing (2)
plugins/dev/skills/babysit-prs/SKILL.mdplugins/dev/skills/babysit-prs/references/conflict-procedure.md
🚧 Files skipped from review as they are similar to previous changes (1)
- plugins/dev/skills/babysit-prs/references/conflict-procedure.md
--force-with-lease is force-capable even when pinned to an explicit SHA; what confines the conflict procedure's push to a fast-forward is the ancestry guard, not the flag. Say so instead of claiming the push is "not a force". Addresses coderabbitai review on PR #12. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Updates the babysit-prs dev skill to reduce orchestrator-context growth by (1) delegating per-PR work to sequential worker subagents and (2) progressively disclosing long, rarely-needed procedures via references/ files that workers load only when an axis is flagged.
Changes:
- Restructures
SKILL.mdinto an orchestrator flow (sweep/triage/dispatch/report) plus a worker-side contract (confidence + Safety). - Introduces sequential per-PR worker subagents with a strict
RESULT #<pr>return format and hardened “treat PR text as data” boundaries. - Extracts merge-conflict and CI remediation procedures into
references/conflict-procedure.mdandreferences/ci-procedure.md, with SKILL.md routing to them.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| plugins/dev/skills/babysit-prs/SKILL.md | Adds orchestrator→worker dispatch flow, progressive disclosure routing, and worker-side contract/Safety. |
| plugins/dev/skills/babysit-prs/references/conflict-procedure.md | New dedicated merge-conflict procedure referenced by workers when the conflict axis is flagged. |
| plugins/dev/skills/babysit-prs/references/ci-procedure.md | New dedicated failing-checks procedure referenced by workers when the CI axis is flagged. |
Suppressed comments (3)
plugins/dev/skills/babysit-prs/references/conflict-procedure.md:223
- This guard uses
"origin/<DEFAULT_BRANCH>"inside a double-quoted shell argument. That contradicts the Safety guidance about not interpolating branch names into shell source and can allow command substitution if the default branch name is malicious. DefineDEFAULT_BRANCHin this block and useorigin/$DEFAULT_BRANCH.
elif ! git -C "$WORKTREE_DIR" merge-base --is-ancestor "origin/<DEFAULT_BRANCH>" HEAD; then
plugins/dev/skills/babysit-prs/references/conflict-procedure.md:155
- This redo-merge step again interpolates
<DEFAULT_BRANCH>into a double-quoted ref ("origin/<DEFAULT_BRANCH>"), which can evaluate command substitutions in the branch name. Resolve the default branch in the block (likeHEAD_BRANCH) and reference it asorigin/$DEFAULT_BRANCH.
WORKTREE_DIR="<your assigned conflicts worktree dir>"
git -C "$WORKTREE_DIR" merge "origin/<DEFAULT_BRANCH>" # conflicts again, the same ones
# …re-apply the same resolution, then commit it:
git -C "$WORKTREE_DIR" commit --no-edit
plugins/dev/skills/babysit-prs/references/conflict-procedure.md:175
- The baseline detour checks out
"origin/<DEFAULT_BRANCH>"directly. Per the Safety section, avoid pasting branch names into shell source (double quotes still evaluate$()/backticks). Resolve the default branch at runtime and useorigin/$DEFAULT_BRANCH.
git -C "$WORKTREE_DIR" checkout --detach "origin/<DEFAULT_BRANCH>"
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Copilot review on PR #12: a literal <DEFAULT_BRANCH> pasted into a double-quoted shell argument can execute command substitutions embedded in a branch name. Resolve it per block via gh repo view, matching the file's own HEAD_BRANCH load-then-expand rule. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Brings
mainup to date with the babysit-prs improvement plan: point 1 (per-PR worker subagents) and point 2 (progressive disclosure intoreferences/).Both target
maindirectly. Point 1 was reviewed on #10 but that PR was merged into thebabysit-prs-skillfeature branch, which never landed onmain— so its commits are replayed here, unchanged, ahead of point 2. #11 (point 2 stacked on that branch) is closed in favour of this PR.Only three files change:
SKILL.mdand the two new reference files.Point 1 — per-PR worker subagents (
90e5e09,24f8a6a)SKILL.mdsplits into two halves:gh pr list, triages each PR with cheapghJSON calls, then spawns onegeneral-purposeworker per flagged PR. Healthy PRs get a report line and never spawn a worker; theUNKNOWN-mergeable recheck stays orchestrator-side. Workers run sequentially — they share one.git, and concurrentworktree add/fetchcontend on its locks. Inline fallback when no Agent tool is available.clean -fdreasoning.The worker prompt template inlines literal values only — never
$VAR(an unexpanded variable would reach the worker as an empty string), restates the safety rails verbatim since workers don't inherit skill text, and constrains the return to a structuredRESULT #<pr>block — capping main-context growth at ~1–3 lines per PR per pass.Point 2 — progressive disclosure (
69e314d)The two long per-PR procedures move out of
SKILL.mdinto one file per axis, taking it from 574 → 311 lines:references/conflict-procedure.md— merge-conflict axis, steps 1–7references/ci-procedure.md— failing-checks axis, steps 1–5Both bodies moved verbatim. The only text changes are the three cross-references that stopped resolving in-file:
"(step 5)"→"(step 5 below)","Step 5 asserts"→"Step 5 below asserts", and CI step 4's mention of the conflict procedure now naming the file and its own step 7. Verified mechanically by diffing the pre-split sections against the new files (164→164 and 77→78 non-blank lines, 3 hunks, all three being exactly those rewordings).Each reference file opens with a short header rather than duplicating shared rules: which axis it is, which
WORKTREE_DIRliteral it means, that<...>values come from the worker prompt, that its step numbers are its own (not the orchestrator's Steps 1–5), and a pointer back to../SKILL.mdfor the confidence rule and Safety. The conflict file hands off to the CI file when both axes are flagged.The disclosure is wired, not just filed:
SKILL_DIRbesideSKILL_FILE, tables the two procedure paths, and states that the orchestrator must not read them — it only passes the paths on. That's where the win lands: ~300 lines of git surgery and CI archaeology never enter a context that, under/loop, accumulates pass after pass.Procedure:path per flagged axis, with an instruction to read only the flagged ones and only on reaching that axis. A conflicts-only worker never loads the CI procedure.Verification
#conflict-procedure/#ci-procedureanchor links anywhere in the repo.grep -iE 'hoopit|BAC-|WEB-|FA-'clean across the skill dir — repo-agnostic per create-hoopit-skill Rule 1.descriptionunchanged;scripts/gen-skills-readme.shregeneratesREADME.mdwith no diff (pre-commitpasses).Not in this PR
Later points of the plan: flake retry, cross-pass state, stale-worktree sweep.
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by CodeRabbit