feat(dev): babysit-prs — orchestrator rewrite + progressive disclosure - #13
feat(dev): babysit-prs — orchestrator rewrite + progressive disclosure#13zublenko wants to merge 11 commits into
Conversation
One sweep over your open PRs: merge conflicts, failing checks, and unresolved review comments. Fixes what is mechanical and unambiguous, flags anything needing judgment. Built for `/loop 15m /babysit-prs`. Delegates to existing skills where they already own the work — review-github-comments for threads, circleci-tests for CircleCI failures, mattpocock-skills:resolving-merge-conflicts for resolution. Also makes scripts/gen-skills-readme.sh's block splice portable: it passed a multi-line value via `awk -v`, which only gawk accepts, so the pre-commit hook failed on macOS. The block now goes through a file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Resolved CodeRabbit findings on PR #3: - Paginate the open-PR sweep (`gh pr list` defaults to 30 and truncates silently); document how to detect truncation. - Re-run the full three-axis triage when a deferred `UNKNOWN` mergeability resolves, instead of only defining the still-UNKNOWN case. - Paginate `reviewThreads` in both babysit-prs and review-github-comments — a fixed `first: 50` can drop every unresolved thread past page 1. - Reject fork-backed PRs explicitly (`isCrossRepository`): every fetch/push here targets `origin`, i.e. the base repo. - Classify post-merge test failures before aborting, per the confidence rule — pre-existing and infra failures don't implicate the resolution. - Bound the mergeability poll (12 x 5s) so one stuck PR can't hang the pass. - Give the CI procedure its own worktree lifecycle; it previously assumed a worktree the conflict procedure had already removed. - Label the report code fence `text` (markdownlint MD040). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Save PR_HEAD_SHA before merging and back out via a MERGE_HEAD check so a merge that already auto-committed resets instead of failing `merge --abort`. Re-query `gh pr checks` when the conflict procedure pushed, so CI remediation never acts on Step 3 results from the pre-merge commit. Resolved comments from coderabbitai on PR #3. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`merge --abort` and `reset --hard` rewind tracked state only, so files left by conflict resolution or a test run survived every restore path. That broke the two steps that follow: redoing the merge failed with "untracked working tree files would be overwritten by merge", and `git worktree remove` refused with "contains modified or untracked files". Add `git clean -fd` to all four exits — both guarded restores, the success path (which never restores at all, so its test artifacts always leaked), and the CI drop-the-fix path (where `checkout .` cannot remove an added file). No `-x`: ignored paths block neither a re-merge nor `worktree remove`. Safe as a blanket clean because the worktree is created fresh from a remote ref, so it holds nothing this pass didn't make. Added a Safety rule pinning that to the skill's own worktree. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Address two CodeRabbit findings on PR #3: - The failure-classification rules claimed a failure could be pre-existing "on origin/$DEFAULT_BRANCH" without ever running the tests there. Split the merge-only case: check out the merge's other parent, re-run, and route on the result — inherited breakage, a genuinely wrong resolution, or indeterminate when the baseline can't run. - The CI fix procedure used `commit -am`, which skips files the fix added, so the push carried a half-fix and the following `clean -fd` deleted the missing piece. Use `add -A` + `show --stat` to confirm the commit before pushing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Step 4's baseline paths all end on a bare $PR_HEAD_SHA, and "redo the merge" existed only in prose — so the procedure could fall through to step 5 and push an unmerged head. That push is a no-op against the remote, which is worse than a failure: the pass reports the conflict fixed having changed nothing. Define the re-merge once as an executable step, noting it re-conflicts and the resolution has to be re-applied (a bare `git merge` would leave the tree mid conflict and let `commit --no-edit` commit the markers). Then assert at push time that the default branch is actually an ancestor of HEAD and that no conflict markers were committed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Resolves Copilot review comments on PR #3. - babysit-prs: `gh api graphql --paginate` runs `--jq` once per page, so the unresolved-thread snippet printed one count per page. Verified against PR #3 with `first: 5`: the first line reads `0` while two threads are unresolved. Pipe through awk to emit a single total, and say so in the prose. - gen-skills-readme.sh: `set -e` could abort between mktemp and its cleanup, leaking $tmp/$blockfile/$entries. Track them in TMPFILES and clear them from an EXIT trap on every path.
The two pre-push safety checks only echoed "STOP" — the `git push` on the next line ran regardless, so a pass could push the exact head the check had just declared unpushable. Restructure as if/elif/else so the push is conditional, and say why the branching is load-bearing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e) (#10) * feat(dev): dispatch babysit-prs per-PR work to worker subagents 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> * fix(dev): address PR #10 review comments - 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> --------- Co-authored-by: Kate Zublenko <zublenko@globaldev.tech> 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: Kate Zublenko <zublenko@globaldev.tech>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
PR #3 was squash-merged, so this branch's merge base with main was the pre-squash commit — which made a PR to main show an add/add conflict on babysit-prs/SKILL.md and render it as a 574-line new file instead of the real net change. Resolved SKILL.md by keeping this branch's version. Verified safe: main's blob (11db711) is byte-identical to this branch at 0ab15a7, the tip when #3 was squashed, so main holds no content the branch lacks. The only content this merge actually pulls in is main's CLAUDE.md note about /plugin update no-opping on matt-picks (5d56041). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
WalkthroughThe ChangesBabysit PR orchestration
Sequence Diagram(s)sequenceDiagram
participant Orchestrator
participant GitHub
participant Worker
Orchestrator->>GitHub: query open PR triage data
GitHub-->>Orchestrator: return mergeability and check status
Orchestrator->>Worker: dispatch flagged PR with evidence
Worker->>GitHub: execute conflict or CI procedure
GitHub-->>Worker: return repository and check state
Worker-->>Orchestrator: return one-line RESULT
Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
Closing in favour of #12, which delivers byte-identical content — #12 is the better artifact: it branches straight off This PR was opened without seeing #12, which landed partway through the same effort. Nothing is lost by closing it — |
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 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 196-211: Update the successful conflict cleanup procedure in
plugins/dev/skills/babysit-prs/references/conflict-procedure.md (lines 196-211)
to run a hard reset of tracked changes at HEAD before git worktree remove, while
retaining git clean -fd for untracked artifacts and refusing to use --force. No
direct change is required in
plugins/dev/skills/babysit-prs/references/ci-procedure.md (lines 78-89), because
that path already commits tracked changes with git add -A.
- Around line 154-156: Update the post-merge commit step in the
conflict-resolution procedure to avoid treating an already auto-committed merge
as a failure: run git commit --no-edit only when MERGE_HEAD exists, or
explicitly tolerate its nothing-to-commit result, while preserving the
subsequent push and worktree cleanup flow.
In `@plugins/dev/skills/babysit-prs/SKILL.md`:
- Around line 223-226: Update the worker-result handling instructions so each
worker must provide exactly one RESULT block whose PR number matches the
assigned PR and whose status is allowed; treat missing, duplicate, malformed,
mismatched, or otherwise extra output as FAILED for that PR. Preserve the
requirement that all workers, including stalled or errored ones, appear in the
Step 5 report.
- Around line 176-220: Update the worker prompt template to pass PR metadata
such as title, headRefName, and fail-bucket JSON as clearly delimited structured
data explicitly marked inert, rather than interpolating them into executable
instructions. Keep the operational instructions static and preserve the existing
literal placeholders and RESULT/DETAIL behavior in the template.
- Around line 176-220: Neutralize the headRefName value before any shell
execution by applying shell-safe validation or escaping consistently in SKILL.md
(lines 176-220), references/conflict-procedure.md (lines 150-165), and
references/ci-procedure.md (lines 78-89). Ensure the generated git worktree and
push commands cannot interpret branch-name content such as $() as command
substitution, while preserving the required head branch target.
- Around line 157-159: Update the Step 4 workflow in
plugins/dev/skills/babysit-prs/SKILL.md:157-159 and the corresponding CI
procedure in plugins/dev/skills/babysit-prs/references/ci-procedure.md:17-38 to
capture headRefOid alongside the fail-bucket JSON and pass both to the worker.
Before diagnosing failures, compare the current PR head with that SHA and
refresh gh pr checks when they differ, not only after a conflict push; keep the
unresolved-thread evidence and existing behavior otherwise unchanged.
- Around line 35-40: Update the repository-context setup before Step 2 to assign
OWNER_REPO, DEFAULT_BRANCH, and REPO_ROOT from the corresponding commands,
derive OWNER and REPO from OWNER_REPO, and use those variables in the GraphQL
command instead of literal owner/repo placeholders.
- Around line 45-49: Update the SKILL_FILE resolution logic near the
installed-plugin lookup and tracked-checkout fallback to collect regular
SKILL.md files and require exactly one total match. Fail immediately when there
are zero or multiple matches, and only then assign SKILL_FILE and derive
SKILL_DIR with dirname; do not accept a directory or silently choose the first
result.
🪄 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: 8959df55-399b-4aff-8fa9-fde8d0ee25df
📒 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
| ```bash | ||
| git -C "$WORKTREE_DIR" commit --no-edit # if the merge didn't auto-commit | ||
| # Assert you're pushing the resolved merge, not a head some restore rewound. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
file="$(fd -t f 'conflict-procedure\.md$' . | head -n 1)"
printf '%s\n' "FILE=$file"
sed -n '120,175p' "$file"
printf '%s\n' '--- command and error-handling context ---'
rg -n -C 3 'git merge|git commit|MERGE_HEAD|set -e|push|WORKTREE_DIR' "$file"Repository: hoopit/skills
Length of output: 12533
🏁 Script executed:
#!/bin/bash
set -eu
skill="$(fd -t f 'SKILL\.md$' plugins/dev/skills/babysit-prs | head -n 1)"
printf '%s\n' "FILE=$skill"
sed -n '1,140p' "$skill"
printf '%s\n' '--- relevant execution rules ---'
rg -n -C 4 'shell|command|exit|failure|error|cleanup|set -e|non-zero|nonzero' "$skill"Repository: hoopit/skills
Length of output: 10037
🏁 Script executed:
#!/bin/bash
set -eu
skill="plugins/dev/skills/babysit-prs/SKILL.md"
sed -n '176,235p' "$skill"
sed -n '228,305p' "$skill"
printf '%s\n' '--- read-only Git state and dry-run commit behavior ---'
git status --short
if git rev-parse -q --verify MERGE_HEAD >/dev/null; then
echo 'MERGE_HEAD=present'
else
echo 'MERGE_HEAD=absent'
fi
set +e
git commit --dry-run --no-edit
status=$?
set -e
printf 'git commit --dry-run --no-edit exit=%s\n' "$status"Repository: hoopit/skills
Length of output: 7687
Guard the post-merge commit.
When git merge auto-commits, git commit --no-edit exits 1 with nothing to commit. If the worker treats that status as failure, it can skip the push and worktree cleanup. Run the commit only when MERGE_HEAD exists, or make the no-op case non-fatal.
🤖 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/references/conflict-procedure.md` around lines
154 - 156, Update the post-merge commit step in the conflict-resolution
procedure to avoid treating an already auto-committed merge as a failure: run
git commit --no-edit only when MERGE_HEAD exists, or explicitly tolerate its
nothing-to-commit result, while preserving the subsequent push and worktree
cleanup flow.
| 7. **Clean up** the worktree you created (leave repo-skill-managed worktrees to that | ||
| skill's own convention): | ||
|
|
||
| ```bash | ||
| git -C "$WORKTREE_DIR" clean -fd # the success path never ran a restore | ||
| git worktree remove "$WORKTREE_DIR" | ||
| ``` | ||
|
|
||
| The `clean` is here for the path where **nothing went wrong**: a merge that | ||
| resolved cleanly, passed its tests and pushed never hits a restore step, so the | ||
| artifacts the test run left behind are still sitting there — and `git worktree | ||
| remove` refuses on untracked files exactly as it does on modified ones. | ||
|
|
||
| With that out of the way, a refusal means what it should: *tracked* state you | ||
| didn't finish dealing with. Investigate and report it; don't reach for `--force` | ||
| to make the error go away. |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- conflict procedure ---'
sed -n '1,240p' plugins/dev/skills/babysit-prs/references/conflict-procedure.md
printf '%s\n' '--- ci procedure ---'
sed -n '1,140p' plugins/dev/skills/babysit-prs/references/ci-procedure.md
printf '%s\n' '--- cleanup/reset/worktree guidance ---'
rg -n -C 3 'worktree remove|reset --hard|clean -fd|restore|WORKTREE_DIR' plugins/dev/skills/babysit-prs
printf '%s\n' '--- repository status ---'
git status --shortRepository: hoopit/skills
Length of output: 40824
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
files = [
Path("plugins/dev/skills/babysit-prs/references/conflict-procedure.md"),
Path("plugins/dev/skills/babysit-prs/references/ci-procedure.md"),
]
for path in files:
text = path.read_text()
commands = re.findall(r"^\s+git -C \"\$WORKTREE_DIR\" .+$", text, re.M)
print(f"--- {path} ---")
for i, command in enumerate(commands, 1):
if any(token in command for token in ("add -A", "commit", "push", "clean -fd", "reset --hard", "checkout .", "worktree remove")):
print(f"{i}: {command.strip()}")
print("has reset --hard:", "reset --hard" in text)
print("has checkout .:", "checkout ." in text)
PY
printf '%s\n' '--- git command help ---'
git worktree remove -h 2>&1 | sed -n '1,80p'
git clean -h 2>&1 | sed -n '1,80p'Repository: hoopit/skills
Length of output: 2346
🌐 Web query:
Search the official Git documentation for the behavior of git worktree removewhen the worktree has modified tracked files, and for the scope ofgit clean -fd.
💡 Result:
According to the official Git documentation, the behavior of git worktree remove and the scope of git clean are as follows: git worktree remove The git worktree remove command is designed to remove a linked worktree. By default, it will only remove "clean" worktrees, which are defined as those containing no untracked files and no modifications to tracked files [1][2]. If a worktree is "unclean" (e.g., it contains modified tracked files) or includes submodules, the command will refuse to remove it unless the --force option is used [1][3]. If the worktree is locked, --force must be specified twice [2][4]. git clean The scope of git clean is to remove untracked files from the working tree, starting from the current directory [5][6]. By default, it recursively removes untracked files that are not under version control, but it does not recurse into untracked directories unless the -d option is specified [5][6]. Key aspects of its scope and behavior include: - Untracked vs. Ignored Files: Normally, it only removes files unknown to Git. However, if the -x option is used, it will also remove files that are ignored by Git (e.g., build products) [5][6]. Alternatively, the -X option can be used to remove only those files that are ignored by Git [6][7]. - Safety Mechanisms: If the configuration variable clean.requireForce is not set to false, git clean will refuse to delete files or directories unless the -f (--force) option is provided [5][6]. - Nested Repositories: git clean will refuse to modify untracked nested Git repositories (directories containing a.git subdirectory) unless the -f option is provided twice [6][7]. - Pathspec: If a pathspec is provided, the command limits its action only to files matching that pathspec [5][7]. If a pathspec is provided, the -d option becomes irrelevant, as the command will act on all untracked files matching the paths [5][6].
Citations:
- 1: https://git-scm.com/docs/git-worktree
- 2: https://github.com/git/git/blob/master/Documentation/git-worktree.adoc
- 3: https://www.kernel.org/pub/software/scm/git/docs/git-worktree.html
- 4: https://code.googlesource.com/git/+/HEAD/Documentation/git-worktree.adoc
- 5: https://git-scm.com/docs/git-clean/2.45.0
- 6: https://github.com/git/git/blob/master/Documentation/git-clean.adoc
- 7: https://git-scm.com/docs/git-clean/2.43.0
Reset tracked changes before removing the conflict worktree.
In the successful conflict path, tests can modify tracked files. git clean -fd does not remove those changes, so git worktree remove "$WORKTREE_DIR" can refuse and leave the worktree behind. Add git -C "$WORKTREE_DIR" reset --hard HEAD before removal in conflict-procedure.md. The CI path commits tracked changes with git add -A, so this concern does not apply there.
📍 Affects 2 files
plugins/dev/skills/babysit-prs/references/conflict-procedure.md#L196-L211(this comment)plugins/dev/skills/babysit-prs/references/ci-procedure.md#L78-L89
🤖 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/references/conflict-procedure.md` around lines
196 - 211, Update the successful conflict cleanup procedure in
plugins/dev/skills/babysit-prs/references/conflict-procedure.md (lines 196-211)
to run a hard reset of tracked changes at HEAD before git worktree remove, while
retaining git clean -fd for untracked artifacts and refusing to use --force. No
direct change is required in
plugins/dev/skills/babysit-prs/references/ci-procedure.md (lines 78-89), because
that path already commits tracked changes with git add -A.
| git rev-parse --show-toplevel # REPO_ROOT — absolute; worker prompts need it | ||
| ``` | ||
|
|
||
| Use `OWNER_REPO` (as `<owner>/<repo>`) and `DEFAULT_BRANCH` throughout. For anything | ||
| else project-specific — the test command, worktree setup, CI provider — consult the | ||
| current repo's `CLAUDE.md` (see its *Workflow skills config* section if it has one). |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
file='plugins/dev/skills/babysit-prs/SKILL.md'
printf '%s\n' '--- target file outline ---'
ast-grep outline "$file" --lang markdown 2>/dev/null || true
printf '%s\n' '--- relevant lines ---'
cat -n "$file" | sed -n '1,190p'
printf '%s\n' '--- variable and repository-context references ---'
rg -n -C 3 'OWNER_REPO|DEFAULT_BRANCH|OWNER\b|REPO\b|gh repo view|graphql|CLAUDE\.md|Step 3' "$file"Repository: hoopit/skills
Length of output: 13509
🏁 Script executed:
#!/bin/bash
set -eu
file='plugins/dev/skills/babysit-prs/SKILL.md'
printf '%s\n' '--- worker prompt and report sections ---'
cat -n "$file" | sed -n '176,270p'
printf '%s\n' '--- all shell-variable-like identifiers ---'
rg -n '\$[A-Z][A-Z0-9_]*|<owner>|<repo>|REPO_ROOT|OWNER_REPO|DEFAULT_BRANCH' "$file"
printf '%s\n' '--- shell behavior probe ---'
bash -c '
OWNER_REPO=before
DEFAULT_BRANCH=before
REPO_ROOT=before
printf "%s\n" "OWNER_REPO=acme/project" "DEFAULT_BRANCH=trunk"
printf "%s\n" "/checkout/root"
printf "after print-only: OWNER_REPO=%q DEFAULT_BRANCH=%q REPO_ROOT=%q\n" "$OWNER_REPO" "$DEFAULT_BRANCH" "$REPO_ROOT"
'
printf '%s\n' '--- literal GraphQL placeholder parse probe ---'
bash -n -c 'gh api graphql -F owner=<owner> -F repo=<repo> -F pr=<pr_number>' 2>&1 || trueRepository: hoopit/skills
Length of output: 7482
Assign the repository context variables before Step 2.
The commands only print OWNER_REPO, DEFAULT_BRANCH, and REPO_ROOT; they do not assign them. Assign these values, derive OWNER and REPO from OWNER_REPO, and use those variables in the GraphQL command. Literal <owner> and <repo> placeholders cause a shell syntax error.
🧰 Tools
🪛 SkillSpector (2.5.1)
[warning] 176: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.
Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.
(Memory Poisoning (MP2))
🤖 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 35 - 40, Update the
repository-context setup before Step 2 to assign OWNER_REPO, DEFAULT_BRANCH, and
REPO_ROOT from the corresponding commands, derive OWNER and REPO from
OWNER_REPO, and use those variables in the GraphQL command instead of literal
owner/repo placeholders.
| SKILL_FILE=$(find ~/.claude/plugins -path '*babysit-prs/SKILL.md' 2>/dev/null | head -1) | ||
| # Fallback when the skill runs from a source checkout rather than an installed plugin: | ||
| [ -n "$SKILL_FILE" ] || SKILL_FILE="$(git rev-parse --show-toplevel)/$(git ls-files '*babysit-prs/SKILL.md' | head -1)" | ||
| SKILL_DIR=$(dirname "$SKILL_FILE") # its references/ dir sits here | ||
| ``` |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
file="plugins/dev/skills/babysit-prs/SKILL.md"
printf '%s\n' '--- target file ---'
cat -n "$file" | sed -n '1,120p'
printf '%s\n' '--- related path-resolution logic ---'
rg -n -C 4 'SKILL_FILE|SKILL_DIR|babysit-prs/SKILL\.md|references/' . \
-g '*.md' -g '*.sh' -g '*.bash' -g '*.yml' -g '*.yaml' -g '*.json' || true
printf '%s\n' '--- tracked matching files ---'
git ls-files '*babysit-prs/SKILL.md'
printf '%s\n' '--- source and installed-path assumptions in repository docs ---'
rg -n -C 3 '\.claude/plugins|source checkout|installed plugin|find .*SKILL\.md|git ls-files' . \
-g '*.md' -g '*.sh' -g '*.bash' -g '*.yml' -g '*.yaml' -g '*.json' || trueRepository: hoopit/skills
Length of output: 17946
🏁 Script executed:
#!/bin/bash
set -eu
file="plugins/dev/skills/babysit-prs/SKILL.md"
cat -n "$file" | sed -n '1,120p'
rg -n -C 4 'SKILL_FILE|SKILL_DIR|babysit-prs/SKILL\.md|references/' . \
-g '*.md' -g '*.sh' -g '*.bash' -g '*.yml' -g '*.yaml' -g '*.json' || true
git ls-files '*babysit-prs/SKILL.md'Repository: hoopit/skills
Length of output: 11588
🏁 Script executed:
#!/bin/bash
set -eu
tmp_home="$(mktemp -d)"
tmp_plugins="$(mktemp -d)"
trap 'rm -rf "$tmp_home" "$tmp_plugins"' EXIT
mkdir -p "$tmp_plugins/z-cache/babysit-prs" "$tmp_plugins/a-cache/babysit-prs"
: > "$tmp_plugins/z-cache/babysit-prs/SKILL.md"
: > "$tmp_plugins/a-cache/babysit-prs/SKILL.md"
printf '%s\n' '--- multiple installed matches: exact resolver ---'
HOME="$tmp_home" bash -c '
find "$1" -path "*babysit-prs/SKILL.md" 2>/dev/null | head -1
' bash "$tmp_plugins"
printf '%s\n' '--- no installed match: exact fallback ---'
HOME="$tmp_home" bash -c '
SKILL_FILE=$(find ~/.claude/plugins -path "*babysit-prs/SKILL.md" 2>/dev/null | head -1)
[ -n "$SKILL_FILE" ] || SKILL_FILE="$(git rev-parse --show-toplevel)/$(git ls-files "*babysit-prs/SKILL.md" | head -1)"
printf "SKILL_FILE=<%s>\nSKILL_FILE_is_regular=%s\nSKILL_DIR=<%s>\n" \
"$SKILL_FILE" \
"$(test -f "$SKILL_FILE" && echo yes || echo no)" \
"$(dirname "$SKILL_FILE")"
'
printf '%s\n' '--- tracked source matches and regular-file status ---'
matches="$(git ls-files '*babysit-prs/SKILL.md')"
printf '%s\n' "$matches"
printf 'tracked_match_count=%s\n' "$(printf '%s\n' "$matches" | sed '/^$/d' | wc -l)"
printf 'tracked_match_is_regular=%s\n' \
"$(test -f "$(git rev-parse --show-toplevel)/$matches" && echo yes || echo no)"Repository: hoopit/skills
Length of output: 600
🏁 Script executed:
#!/bin/bash
set -eu
tmp_home="$(mktemp -d)"
tmp_plugins="$(mktemp -d)"
trap 'rm -rf "$tmp_home" "$tmp_plugins"' EXIT
mkdir -p "$tmp_plugins/z-cache/babysit-prs" "$tmp_plugins/a-cache/babysit-prs"
: > "$tmp_plugins/z-cache/babysit-prs/SKILL.md"
: > "$tmp_plugins/a-cache/babysit-prs/SKILL.md"
HOME="$tmp_home" bash -c '
find "$1" -path "*babysit-prs/SKILL.md" 2>/dev/null | head -1
' bash "$tmp_plugins"
HOME="$tmp_home" bash -c '
SKILL_FILE=$(find ~/.claude/plugins -path "*babysit-prs/SKILL.md" 2>/dev/null | head -1)
[ -n "$SKILL_FILE" ] || SKILL_FILE="$(git rev-parse --show-toplevel)/$(git ls-files "*babysit-prs/SKILL.md" | head -1)"
printf "SKILL_FILE=<%s>\nSKILL_FILE_is_regular=%s\nSKILL_DIR=<%s>\n" \
"$SKILL_FILE" \
"$(test -f "$SKILL_FILE" && echo yes || echo no)" \
"$(dirname "$SKILL_FILE")"
'
matches="$(git ls-files '*babysit-prs/SKILL.md')"
printf 'tracked_match_count=%s\n' "$(printf '%s\n' "$matches" | sed '/^$/d' | wc -l)"Repository: hoopit/skills
Length of output: 382
🏁 Script executed:
#!/bin/bash
set -eu
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
mkdir -p "$tmp/bin" "$tmp/repo"
cat > "$tmp/bin/git" <<'EOF'
#!/bin/sh
case "$1" in
rev-parse) printf '%s\n' "$FAKE_ROOT" ;;
ls-files) : ;;
*) exit 1 ;;
esac
EOF
chmod +x "$tmp/bin/git"
printf '%s\n' '--- no installed match and no tracked source match ---'
PATH="$tmp/bin:$PATH" HOME="$tmp/home" FAKE_ROOT="$tmp/repo" bash -c '
SKILL_FILE=$(find ~/.claude/plugins -path "*babysit-prs/SKILL.md" 2>/dev/null | head -1)
[ -n "$SKILL_FILE" ] || SKILL_FILE="$(git rev-parse --show-toplevel)/$(git ls-files "*babysit-prs/SKILL.md" | head -1)"
printf "SKILL_FILE=<%s>\nSKILL_FILE_is_regular=%s\nSKILL_DIR=<%s>\n" \
"$SKILL_FILE" \
"$(test -f "$SKILL_FILE" && echo yes || echo no)" \
"$(dirname "$SKILL_FILE")"
'Repository: hoopit/skills
Length of output: 302
Fail closed when the skill path is missing or ambiguous.
find ... | head -1 selects the first installed match when multiple SKILL.md files exist. If no installed or tracked file exists, the fallback produces REPO_ROOT/, which passes [ -n "$SKILL_FILE" ] but is not a regular file; dirname then selects the wrong directory. Require exactly one regular SKILL.md match before setting SKILL_FILE and SKILL_DIR; otherwise stop.
🧰 Tools
🪛 SkillSpector (2.5.1)
[warning] 176: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.
Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.
(Memory Poisoning (MP2))
🤖 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 45 - 49, Update the
SKILL_FILE resolution logic near the installed-plugin lookup and
tracked-checkout fallback to collect regular SKILL.md files and require exactly
one total match. Fail immediately when there are zero or multiple matches, and
only then assign SKILL_FILE and derive SKILL_DIR with dirname; do not accept a
directory or silently choose the first result.
| **One or more flagged axes → Step 4.** Keep the evidence you just gathered (the | ||
| failing-checks JSON, the unresolved-thread count) — it goes into the worker prompt | ||
| so the worker doesn't re-triage from scratch. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- SKILL.md relevant sections ---'
sed -n '130,235p' plugins/dev/skills/babysit-prs/SKILL.md
printf '%s\n' '--- ci-procedure.md relevant sections ---'
sed -n '1,110p' plugins/dev/skills/babysit-prs/references/ci-procedure.md
printf '%s\n' '--- conflict-procedure.md relevant sections ---'
sed -n '130,225p' plugins/dev/skills/babysit-prs/references/conflict-procedure.md
printf '%s\n' '--- related evidence and head fields ---'
rg -n -C 3 'fail-bucket|failing-check|unresolved-thread|headRefOid|head SHA|head sha|gh pr checks|conflict procedure|worktree|branch' \
plugins/dev/skills/babysit-prsRepository: hoopit/skills
Length of output: 50371
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- orchestrator triage and prompt construction ---'
sed -n '28,155p' plugins/dev/skills/babysit-prs/SKILL.md
sed -n '228,290p' plugins/dev/skills/babysit-prs/SKILL.md
printf '%s\n' '--- exact head-related identifiers in babysit-prs files ---'
rg -n -C 4 'headRefOid|headRefName|headRepository|statusCheckRollup|pr checks|fail-bucket|failing checks|triage' \
plugins/dev/skills/babysit-prs/SKILL.md \
plugins/dev/skills/babysit-prs/references/ci-procedure.md \
plugins/dev/skills/babysit-prs/references/conflict-procedure.md
printf '%s\n' '--- conflict procedure opening and head capture ---'
sed -n '1,90p' plugins/dev/skills/babysit-prs/references/conflict-procedure.mdRepository: hoopit/skills
Length of output: 30793
🏁 Script executed:
#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
skill = Path("plugins/dev/skills/babysit-prs/SKILL.md").read_text()
ci = Path("plugins/dev/skills/babysit-prs/references/ci-procedure.md").read_text()
checks = {
"triage query omits headRefOid": "headRefOid" not in skill.split("## Step 3 — Triage each PR", 1)[0],
"worker prompt omits headRefOid": "headRefOid" not in skill[skill.index("```text\nYou are babysitting"):skill.index("```\n\nTake each worker's", skill.index("```text\nYou are babysitting"))],
"worker prompt carries fail JSON": "- Failing checks: <the fail-bucket JSON from triage | none>" in skill,
"CI refresh is conditional on conflict push": "If the conflict procedure pushed for this PR" in ci,
"CI procedure has no unconditional head comparison": "headRefOid" not in ci and "current head" not in ci,
"CI worktree is created from current remote branch ref": 'git worktree add "$WORKTREE_DIR" "origin/<headRefName>"' in ci,
}
for name, result in checks.items():
print(f"{name}: {'PASS' if result else 'FAIL'}")
PYRepository: hoopit/skills
Length of output: 427
Keep CI evidence tied to the PR head.
Capture headRefOid with the fail-bucket JSON and pass both to the worker. Before diagnosing failures, compare the current PR head with that SHA and refresh gh pr checks when they differ. The current refresh occurs only after a conflict push, so another branch update can leave the worker using stale evidence.
🧰 Tools
🪛 SkillSpector (2.5.1)
[warning] 176: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.
Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.
(Memory Poisoning (MP2))
📍 Affects 2 files
plugins/dev/skills/babysit-prs/SKILL.md#L157-L159(this comment)plugins/dev/skills/babysit-prs/references/ci-procedure.md#L17-L38
🤖 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 157 - 159, Update the
Step 4 workflow in plugins/dev/skills/babysit-prs/SKILL.md:157-159 and the
corresponding CI procedure in
plugins/dev/skills/babysit-prs/references/ci-procedure.md:17-38 to capture
headRefOid alongside the fail-bucket JSON and pass both to the worker. Before
diagnosing failures, compare the current PR head with that SHA and refresh gh pr
checks when they differ, not only after a conflict push; keep the
unresolved-thread evidence and existing behavior otherwise unchanged.
| Fill the prompt template below with **literal values only — never `$VAR`**. The | ||
| worker runs in its own context with its own shell: your variables don't exist there, | ||
| and an unexpanded `$DEFAULT_BRANCH` in the prompt becomes an empty string in the | ||
| worker's commands. Replace every `<...>` placeholder with the actual value — except | ||
| inside the final `RESULT`/`DETAIL` block, whose placeholders the worker fills. | ||
|
|
||
| ```text | ||
| You are babysitting exactly one pull request as part of a babysit-prs pass. | ||
|
|
||
| First read <SKILL_FILE — literal absolute path> and follow its "Per-PR procedures" | ||
| and "Safety" sections exactly. The orchestrator steps (1–5) are not your job — do | ||
| not sweep or touch any other PR. | ||
|
|
||
| Repo: <OWNER_REPO> Default branch: <DEFAULT_BRANCH> | ||
| Repo root: <absolute REPO_ROOT> | ||
| PR: #<number> — <title> | ||
| URL: <url> | ||
| Head branch: <headRefName> Draft: <true|false> | ||
| Worktree dir (conflicts): <REPO_ROOT>/.worktrees/babysit-<number> | ||
| Worktree dir (CI): <REPO_ROOT>/.worktrees/babysit-ci-<number> | ||
|
|
||
| Flagged axes — handle only these, in this order (conflicts → CI → comments). Each | ||
| one's full procedure is in its own file: read that file when you reach the axis, and | ||
| do not read the file for an axis flagged "no" / "none" / "0". | ||
| - Merge conflict: <yes (mergeable=…, mergeStateStatus=…) | no> | ||
| Procedure: <SKILL_DIR — literal absolute path>/references/conflict-procedure.md | ||
| - Failing checks: <the fail-bucket JSON from triage | none> | ||
| Procedure: <SKILL_DIR — literal absolute path>/references/ci-procedure.md | ||
| - Unresolved review threads: <count | 0> | ||
| Procedure: invoke the `review-github-comments` skill with the PR URL above | ||
|
|
||
| Safety rails — non-negotiable, restated from the skill's Safety section: | ||
| - Never push to the default branch. Every push is | ||
| `git push origin HEAD:<headRefName>` — that head branch, nothing else. | ||
| - Never force-push and never rebase. | ||
| - Only ever `git clean` inside the two worktree dirs named above, always via | ||
| `git -C "<worktree dir>"`, never with `-x`, never in the main checkout. | ||
| - Confidence rule: fix only what is mechanical and unambiguous. Anything needing | ||
| judgment → restore, report, move on. When in doubt, report. | ||
| - Remove every worktree you created before finishing, even when you failed. | ||
|
|
||
| Return ONLY this block — no logs, no diffs, no extra prose: | ||
|
|
||
| RESULT #<number>: <FIXED|NEEDS-HUMAN|PARTIAL|DEFERRED|FAILED> — <one line: found → did → remaining> | ||
| DETAIL: <≤2 lines, only for NEEDS-HUMAN or FAILED> |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
sed -n '130,235p' plugins/dev/skills/babysit-prs/SKILL.md
printf '\n--- worker/subagent references ---\n'
rg -n -C 3 'worker|subagent|prompt|title|headRefName|fail-bucket|Agent|Task|babysit' plugins/dev/skills/babysit-prs/SKILL.mdRepository: hoopit/skills
Length of output: 14788
Llm Prompt Injection (CWE-74): Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
Reachability: External · Exploitability: Moderate
Keep PR metadata out of worker instructions.
title, headRefName, and fail-bucket JSON are inserted directly into the worker prompt that grants shell and push authority. Pass them as clearly delimited structured data and mark them as inert. Keep executable instructions static.
🧰 Tools
🪛 SkillSpector (2.5.1)
[warning] 176: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.
Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.
(Memory Poisoning (MP2))
🤖 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 176 - 220, Update the
worker prompt template to pass PR metadata such as title, headRefName, and
fail-bucket JSON as clearly delimited structured data explicitly marked inert,
rather than interpolating them into executable instructions. Keep the
operational instructions static and preserve the existing literal placeholders
and RESULT/DETAIL behavior in the template.
🔒 Security & Privacy | 🔴 Critical | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- target files ---'
git ls-files 'plugins/dev/skills/babysit-prs/*' 'plugins/dev/skills/fix-itsm-issue/SKILL.md'
printf '%s\n' '--- babysit-prs structure ---'
ast-grep outline plugins/dev/skills/babysit-prs/SKILL.md 2>/dev/null || true
ast-grep outline plugins/dev/skills/babysit-prs/references/conflict-procedure.md 2>/dev/null || true
ast-grep outline plugins/dev/skills/babysit-prs/references/ci-procedure.md 2>/dev/null || true
printf '%s\n' '--- relevant SKILL.md sections ---'
sed -n '1,260p' plugins/dev/skills/babysit-prs/SKILL.md
printf '%s\n' '--- conflict procedure relevant sections ---'
sed -n '1,210p' plugins/dev/skills/babysit-prs/references/conflict-procedure.md
printf '%s\n' '--- CI procedure relevant sections ---'
sed -n '1,130p' plugins/dev/skills/babysit-prs/references/ci-procedure.mdRepository: hoopit/skills
Length of output: 30585
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- remaining Safety and per-PR context ---'
rg -n -A90 -B15 '## Safety|# Safety|headRefName|general-purpose|subagent|Task' \
plugins/dev/skills/babysit-prs/SKILL.md plugins/dev/skills/babysit-prs/references/*.md \
plugins/dev/skills/fix-itsm-issue/SKILL.md
printf '%s\n' '--- branch-name behavior ---'
for ref in \
'feature/$\(id\)' \
'feature/$(id)' \
'feature/`id`' \
'feature/;id' \
'feature/&&id' \
'feature/"id' \
'feature/$(printf injected)' \
'feature/normal'
do
if git check-ref-format --branch "$ref" >/tmp/ref-ok 2>/tmp/ref-err; then
printf 'ACCEPTED: %s\n' "$ref"
else
printf 'REJECTED: %s -- %s\n' "$ref" "$(tr '\n' ' ' </tmp/ref-err)"
fi
done
printf '%s\n' '--- all direct push/ref constructions in babysit-prs ---'
rg -n -C3 'git .*push|origin/<headRefName>|origin/\$|headRefName' \
plugins/dev/skills/babysit-prsRepository: hoopit/skills
Length of output: 50371
🏁 Script executed:
#!/bin/bash
set -eu
printf '%s\n' '--- git ref validation ---'
for ref in \
'feature/$\(id\)' \
'feature/$(id)' \
'feature/`id`' \
'feature/;id' \
'feature/&&id' \
'feature/"id' \
'feature/normal'
do
if git check-ref-format --branch "$ref" >/dev/null 2>/tmp/ref-error; then
printf 'ACCEPTED: %s\n' "$ref"
else
printf 'REJECTED: %s -- %s\n' "$ref" "$(tr '\n' ' ' </tmp/ref-error)"
fi
done
printf '%s\n' '--- shell expansion in the reviewed command shapes ---'
bash -c '
git() { printf "git-argv:"; printf "<%s>" "$@"; printf "\n"; }
git worktree add "/tmp/w" "origin/feature/$(printf INJECTED >&2)"
' 2>/tmp/expansion-stderr
printf 'worktree stderr: %s\n' "$(cat /tmp/expansion-stderr)"
bash -c '
git() { printf "git-argv:"; printf "<%s>" "$@"; printf "\n"; }
git push origin HEAD:feature/$(printf INJECTED >&2)
' 2>/tmp/push-expansion-stderr
printf 'push stderr: %s\n' "$(cat /tmp/push-expansion-stderr)"
printf '%s\n' '--- exact affected command lines ---'
rg -n 'origin/<headRefName>|HEAD:<headRefName>|Head branch:' \
plugins/dev/skills/babysit-prs/SKILL.md \
plugins/dev/skills/babysit-prs/references/conflict-procedure.md \
plugins/dev/skills/babysit-prs/references/ci-procedure.mdRepository: hoopit/skills
Length of output: 1410
🏁 Script executed:
#!/bin/bash
set -eu
bash -c '
git() { printf "git-argv:"; printf "<%s>" "$@"; printf "\n"; }
git push origin HEAD:feature/$(printf INJECTED)
'
bash -c '
git() { printf "git-argv:"; printf "<%s>" "$@"; printf "\n"; }
git -C /tmp/w push origin HEAD:feature/$(printf INJECTED)
'Repository: hoopit/skills
Length of output: 210
Injection (CWE-78): Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
Reachability: External
Neutralize headRefName before shell execution. Git accepts branch names containing $(), and the worker inserts headRefName into executable git worktree add and git push commands. Apply shell-safe validation or escaping in SKILL.md, conflict-procedure.md, and ci-procedure.md.
🧰 Tools
🪛 SkillSpector (2.5.1)
[warning] 176: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.
Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.
(Memory Poisoning (MP2))
📍 Affects 3 files
plugins/dev/skills/babysit-prs/SKILL.md#L176-L220(this comment)plugins/dev/skills/babysit-prs/references/conflict-procedure.md#L150-L165plugins/dev/skills/babysit-prs/references/ci-procedure.md#L78-L89
🤖 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 176 - 220, Neutralize
the headRefName value before any shell execution by applying shell-safe
validation or escaping consistently in SKILL.md (lines 176-220),
references/conflict-procedure.md (lines 150-165), and references/ci-procedure.md
(lines 78-89). Ensure the generated git worktree and push commands cannot
interpret branch-name content such as $() as command substitution, while
preserving the required head branch target.
| Take each worker's `RESULT` line into the Step 5 report as that PR's line. A worker | ||
| that errors out, stalls, or returns anything other than a `RESULT` block is reported | ||
| as `FAILED` for its PR — never silently dropped. Its leftover worktree, if any, is at | ||
| the two dirs named in its prompt; remove them if the worker didn't. |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Validate the worker result against the assigned PR.
The orchestrator accepts any RESULT line and uses it for that PR. Require one exact result block with the expected PR number and an allowed status. Otherwise report FAILED. This prevents a valid result for another PR or extra worker output from being attached to the wrong report.
🧰 Tools
🪛 SkillSpector (2.5.1)
[warning] 176: [MP2] Context Window Stuffing: Skill attempts to fill the context window with filler content, displacing legitimate instructions and safety constraints. This can degrade agent performance or bypass safety boundaries.
Remediation: Implement context-window management that detects and rejects padding or stuffing attempts. Prioritize system instructions over user-injected content.
(Memory Poisoning (MP2))
🤖 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 223 - 226, Update the
worker-result handling instructions so each worker must provide exactly one
RESULT block whose PR number matches the assigned PR and whose status is
allowed; treat missing, duplicate, malformed, mismatched, or otherwise extra
output as FAILED for that PR. Preserve the requirement that all workers,
including stalled or errored ones, appear in the Step 5 report.
Summary
Everything that landed on
babysit-prs-skillafter PR #3 shipped the skill's firstversion. Two changes, plus six hardening fixes:
Orchestrator rewrite (#10). The pass was one context doing everything: sweeping,
reading CI logs, resolving conflicts. It now runs as a thin orchestrator that
triages every PR with cheap
ghJSON calls, then hands each PR that actually needswork to its own
general-purposeworker subagent. Healthy PRs spawn nothing — ona good day the whole pass is a handful of
ghcalls and zero subagents.Two things fall out of that. Per-PR state (worktree paths, head SHAs, refnames)
becomes unmixable by construction, since no two PRs share a context. And CI logs,
diffs, and merge churn land in a worker that exits, not in the orchestrator — which
matters because this skill is built for
/loop 15m /babysit-prs, where theorchestrating session accumulates pass after pass.
Workers run one at a time, in PR order: they share the repo's single
.git, andconcurrent
worktree add/fetchcontend on its locks.Progressive disclosure (#11). The two long per-PR procedures moved out of
SKILL.mdinto one file per axis —references/conflict-procedure.md(git surgery)and
references/ci-procedure.md(CI archaeology). The orchestrator never reads eitherone; it passes their absolute paths into the worker prompt, and each worker reads only
the file for the axes it was flagged on.
SKILL.mddrops 473 lines to 311.Work item
No tracked item — this repo isn't Jira-connected, and this is skill authoring rather
than a bug fix.
Changes
SKILL.md— orchestrator/worker split; worker prompt template with literal-values-onlyrule (an unexpanded
$DEFAULT_BRANCHin a prompt becomes an empty string in theworker's shell); inline fallback for when no Agent tool is available
references/conflict-procedure.md(new) — merge-conflict procedure, own 1–7 numberingreferences/ci-procedure.md(new) — failing-checks procedure, own 1–5 numberingSix hardening fixes folded in along the way:
git cleanscoped to the pass's own worktree on every exit path, including failurereviewThreadscounts summed across pages —--jqruns once per page, soreading the first line alone undercounts and can miss every unresolved thread on a
busy PR
Rule 1 (project-agnostic)
Audited per this repo's
CLAUDE.md: no repo slugs, no Jira project keys, no hardcodeddefault branches in
SKILL.mdor either reference file. Repo and default branch comefrom
gh repo view --json nameWithOwner,defaultBranchRefat runtime; the referencescarry
origin/<DEFAULT_BRANCH>as a placeholder the orchestrator substitutes. Testcommand, worktree setup, and CI provider defer to the installed repo's
CLAUDE.md.A note on this branch's history
PR #3 was squash-merged, which left this branch's merge base with the default
branch at the pre-squash commit. A PR opened from it showed an
add/addconflict onSKILL.mdand rendered the file as a 574-line addition instead of the real diff.Fixed by merging the default branch into this branch (
7ae59dd) and resolvingSKILL.mdin this branch's favour. Verified safe rather than assumed: the defaultbranch's blob for that file is byte-identical to this branch at
0ab15a7, the tip when#3 was squashed, so there was no content on the far side to lose. The merge's only real
content is the
CLAUDE.mdnote about/plugin updateno-opping onmatt-picks. Norebase and no force-push — #11 was based on this branch.
Testing
Skill authoring, so there's no test suite to extend — the checks that exist:
pre-commit run --all-files— passesscripts/gen-skills-readme.sh --check— README skills block up to dategit merge-tree --write-tree <default-branch> babysit-prs-skill— exits clean, no conflictsincluding the
gh pr checks --json name,bucket,state,linkbucket normalisation andthe detached-HEAD
git push origin HEAD:<headRefName>form🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by CodeRabbit
New Features
Documentation