docs(source-control): correct the bare-name wrapper PATH and allow-rule rationale - #1399
Conversation
`safety.md` asserted the bundled wrappers' bare names "are not on the
Bash tool's PATH", and the two bin/ wrapper headers presented their
bare-command allow-rule rationale as operative fact. Both were wrong, in
opposite directions.
A shell-snapshot corpus on the reporting machine shows plugin bin/
directories reaching the Bash tool's PATH in 35 of 112 sessions, 4 of
them carrying this plugin's own bin/. The feature is delivered, then
intermittently lost: a plugin's bin/ arrives only via the session shell
snapshot's final `export PATH=` line, and when that line does not land
every enabled plugin's bin/ goes with it. The "Windows/Git-Bash never
delivers it" reading was a sampling artifact — every reproduction on the
issue fell inside one degraded window.
Operational guidance is unchanged and was already correct: the
${CLAUDE_PLUGIN_ROOT}/bin/ path form stays canonical because it works in
both states. Only the justification changed, and it mattered — a reader
who tested on a healthy-snapshot session found the doc contradicting
their own shell, and the documented reason to keep the path form
evaporated exactly when it looked safe to drop.
The wrapper headers point at safety.md rather than restating the
analysis; the upstream reference lives in the markdown, which the
comment-hygiene tracker-ref policy does not scan.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…dy narrative Independent review caught two overclaims in the first pass. The wrapper headers called the bare-name allow-rule match "opportunistic", implying it sometimes fires. It cannot fire at all for this skill's calls. Claude Code strips only a fixed wrapper set before matching Bash rules (timeout, time, nice, nohup, stdbuf, command, builtin, noglob, bare xargs -- verified against the live permissions page); `bash` is not among them, so `bash ".../bin/source-control-babysit-merge"` matches as a bash command and never satisfies Bash(source-control-babysit-merge:*). The benefit is not intermittent, it is unrealized -- which is exactly the residual the tracking issue records, and it means a per-call prompt on these invocations is expected rather than a misconfiguration. safety.md now carries both halves (unreliable delivery, non-matching form) with their sources; the headers point there instead of characterizing it. The CHANGELOG claimed every reproduction "fell inside one degraded window". The upstream issue's own log shows healthy and degraded sessions interleaving minutes apart, and that issue is macOS/zsh only -- it supplies the mechanism, not the Windows/Git-Bash evidence. The entry now separates the two sources instead of merging them into one tidy story, and drops precise session counts that no future reader can reproduce from this repo. Also caveats the bin/ row in PLUGIN-PHILOSOPHY.md, the table a future plugin author reads before making a bare name load-bearing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…per-bare-name-rationale # Conflicts: # plugins/source-control/.claude-plugin/plugin.json # plugins/source-control/CHANGELOG.md
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 201ebcc032
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
This was generated by AI during autonomous execution. Conflict status: mechanical version-bump race, not a content conflict. This branch was integrated with The conflict is confined to exactly two files, and never to the substance of this PR:
The four files carrying this PR's actual change — both Resolution recipe (mechanical, no judgement needed): take Verified green on the merged tree before the last push: Not merging is this lane's boundary, so the final integration belongs to whoever merges. |
…per-bare-name-rationale # Conflicts: # plugins/source-control/CHANGELOG.md
|
Claude finished @kyle-sexton's task in 1m 52s —— View job PR Review
SummaryThis is a documentation-only correction. No guard logic, operational behavior, or invocation forms change — the diff touches only comments, prose, and a version bump. The two factual corrections are sound and the evidence trail is solid. CorrectnessCorrection 1 — PATH delivery is unreliable, not absent. Correction 2 — path-form invocation cannot satisfy a bare-name allow rule. Wrapper script headers.
CHANGELOG. SecurityNo security surface changes. The authorization layer (wrapper guards, CLAUDE.md Alignment
Observations (non-blocking)Codex review finding is spurious. The Codex comment references
VerdictClean documentation correction. Claims are accurate, evidence is attributed, guidance is unchanged, guards are untouched. No blocking issues. |
|
Claude finished @kyle-sexton's task in 1m 25s —— View job Security Review — PR #1399
FindingsNo security issues found. Scope of changesAll six changed files are either documentation/prose updates or a version bump. The security-relevant executable code in both
Analysis of each changed file
Security model impactThe
No changes to GitHub Actions workflows, permissions, secrets handling, MCP server configuration, or any other supply-chain surface. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a29376413f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
# Conflicts: # plugins/source-control/.claude-plugin/plugin.json # plugins/source-control/CHANGELOG.md
In auto mode an uncovered Bash call gets no permission prompt: the classifier decides, and can deny silently. Claiming a per-call prompt leaves an operator waiting for one that never arrives.
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 95f513b433
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Plan mode prompts for shell commands only when the auto-mode classifier is not reviewing them; useAutoModeDuringPlan is on by default.
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5864ca78c6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The marketplace-wide convention still stated categorical non-delivery and a classifier-on-every-invocation rule, so a plugin author following the declared source of truth got the reading this PR corrects downstream.
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
# Conflicts: # plugins/source-control/CHANGELOG.md
|
Claude finished @kyle-sexton's task in 1m 25s —— View job Security Review — PR #1399
No security issues found. Scope of changesAll eight changed files are documentation/prose corrections, a version bump, or comment-only edits to shell scripts. Security-relevant executable code in both Shell script analysis
The existing argument-guard loop uses Documentation analysis
Security model impactThe No GitHub Actions workflow changes. No permission-widening. No action-pin or dependency-pin changes. No secret or credential handling anywhere in the diff. |
|
Claude finished @kyle-sexton's task in 1m 38s —— View job PR Review — #1399
SummaryDocumentation-only correction across 8 files — no guard logic, no invocation forms, no operational behavior changes. Both factual corrections are accurate and well-attributed. No blocking issues. CorrectnessCorrection 1 — PATH delivery is unreliable, not absent. All three prose destinations ( Correction 2 — path-form invocation cannot satisfy a bare-name allow rule. The categorical claim is correct:
The plan-mode qualifier at Wrapper script headers — pointer-not-copy. Executable logic in both wrappers (from
The "pointer-not-copy" pattern (pointing headers at CHANGELOG entries. Both the Convention drift — closed. The Codex finding at 2026-07-26T01:35 about SecurityThe authorization layer is untouched:
The documentation now more accurately describes why per-call prompts appear in prompting modes and why they don't appear in auto mode — a security-adjacent clarification, not a relaxation. Operators who expected the bare-name allow rule to suppress auto-mode prompts were wrong; the corrected docs prevent that false assumption from being acted on. CLAUDE.md Alignment
VerdictClean documentation correction. Both factual claims are accurate and attributed, guidance is unchanged, all guards are untouched, and the Codex findings about classifier wording and convention drift were addressed in the subsequent commits ( |
No related issue: #843 stays open deliberately — see "Why #843 stays open" below.
Summary
safety.mdasserted that the bundled babysit wrappers' bare names "are not on the Bash tool'sPATH", and the twobin/wrapper headers presented their bare-command allow-rule rationale asoperative fact. Both are wrong, in opposite directions. This corrects the justification; the
operational guidance is unchanged.
What the evidence actually shows
Correction 1 — bare-name resolution is unreliable, not absent. Plugin
bin/reaches the Bashtool's
PATHonly via the per-session shell snapshot's finalexport PATH=line. Sweeping thelocal snapshot corpus (112 snapshots, 06-26 -> 07-25) found that line present-with-plugin-bins in
35, present-without in 5, and absent entirely in 72 — with four snapshots carrying this
plugin's own
bin/. So the documented feature is delivered on this Windows/Git-Bash machine,then intermittently lost; when the line does not land, every enabled plugin's
bin/goes with it.anthropics/claude-code#68066 supplies the
mechanism and root cause — note it is a macOS/zsh report, so it is the mechanism source, not the
Windows evidence, and its own log shows healthy and degraded sessions interleaving minutes apart.
The prior "never delivers it here" reading came from sampling only degraded sessions: #843 was filed
07-21, and every reproduction on it landed after the 07-18 healthy runs.
Correction 2 — the path form cannot match a bare-name allow rule (this one is categorical).
Before matching Bash rules, Claude Code strips only a fixed wrapper set:
timeout,time,nice,nohup,stdbuf,command,builtin,noglob, and barexargs(permissions, verified live this session).
bashis not among them. So
bash "…/bin/source-control-babysit-merge" …matches as abashcommandand can never satisfy a pre-approved
Bash(source-control-babysit-merge:*)— not"opportunistically", but for every call this skill issues. A per-call prompt on these invocations is
therefore expected behavior, not a misconfiguration, which is worth stating plainly since the
operator pre-approved those bare names specifically to avoid it. This is residual #1 on #843, now
with a verified mechanism.
Changes
skills/babysit-prs/reference/safety.md— "Guarded Mutation Wrappers" now carries both factsabove, each with its source, replacing the flat "not on
PATH" claim.bin/source-control-babysit-merge,bin/source-control-babysit-resolve-thread— headers statethe bare-name rationale as currently unrealized and point at
safety.mdrather thanrestating the analysis (pointer-not-copy). The upstream
owner/repo#Nreference deliberatelylives only in markdown: the
comment-hygieneCI policy bans tracker-refs in code comments —verified by running that action's own
comment-hygiene-patterns.shagainst both wrappers, with apositive control confirming the scanner does flag the pattern.
docs/PLUGIN-PHILOSOPHY.md— thebin/stance row gains the caveat. This is the table a futureplugin author reads before making a bare name load-bearing, so leaving it asserting
unconditional PATH delivery would reproduce this exact defect. Row's
Verifieddate left at2026-07-17: the caveat cites its own sources and is not a re-verification of that row's linked
page.
0.26.4->0.26.5+ CHANGELOG entry.No engine, CLI, flag, or guard behavior changes.
Test plan
Run against the branch worktree; all green:
layer, so they were exercised rather than assumed):
source-control-babysit-merge … --allow-unpinned-head→ refused, exit2source-control-babysit-mergewithout--allowed-owners→ fail-closed JSON, exit3source-control-babysit-resolve-threadwithout--allowed-owners→ fail-closed JSON, exit3shellcheckon both wrappers — clean.markdownlint-cli2on both changed markdown files — 0 errors.typos --config _typos.tomlon the changed files — clean.editorconfig-checkeron the diff — clean.comment-hygiene-patterns.sh(fetched from the pinnedci-workflowsaction) on both wrappers —clean; positive control confirms it flags
owner/repo#N.pr-issue-linkagevalidator regexes (closing-keyword +## Relatedextraction) before opening — this caught an accidental closing keyword in an earlierdraft heading that would have auto-closed the tracking issue on merge.
100755on both wrappers); no CRLF introduced.plugin.jsonparses; version bumped.Fresh-docs check per
CLAUDE.md: the plugins reference was re-fetched this session(https://code.claude.com/docs/en/plugins-reference). The File locations row still reads
"Executables added to the Bash tool's
PATH. Files here are invokable as bare commands in any Bashtool call while the plugin is enabled", with no Windows/Git-Bash caveat — so upstream still
promises the behavior, which is why this PR corrects our justification rather than our guidance.
Related
and the corrected classification.
${CLAUDE_PLUGIN_ROOT}/bin/path form this PR keeps.mechanism and root cause. Closed
NOT_PLANNEDon 2026-07-25.Why #843 stays open
The dispatching lane's default is a closing keyword; this deviates deliberately, for operator
override. #843's own body designates it the tracker for the upstream dependency, and its two
residuals — the lost bare-name allow-rule match, and the wrappers' unrealized design intent —
cannot be closed downstream. Closing it on a docs correction would strand a live upstream
regression that now has an unexplained second signature (below).
Operator decisions parked here
non-delivery" report would now be factually wrong, and #68066 already carries the mechanism.
The live question is different: upstream declined #68066 as
NOT_PLANNED— do we want toargue it? The corpus here (clean 07-18-works / 07-19-onward-fails break, 64% session failure
rate over 112 snapshots) is materially stronger than what #68066 carried. This lane filed
nothing upstream and is not authorized to.
export PATH=line carrying zero plugin bins — three of them today. That is not truncation,so either #68066's mechanism does not fully account for this or there is a second failure mode.
The prose says "consistent with #68066's signature", never "caused by".
IMPORTANT findings were adopted, not argued: the "opportunistic" mischaracterization above, and
an over-tidy "one degraded window" narrative in the CHANGELOG that the cited upstream issue does
not support. Both are fixed in the second commit; precise session counts were dropped from the
CHANGELOG because no future reader can reproduce them from this repo (the methodology lives on
source-control:babysit-prs: plugin bin/ not on Bash-tool PATH — guarded wrapper bare names unresolvable (blocks narrow allow-rule match) #843).
docs/topics/babysit-prs-migration/design/phase-2-engine-modules.md:35andPLAN.md:478stilldescribe bare names as the pinned invocation. They are completed-migration records that were
already superseded by source-control:babysit-prs: 'source-control-babysit-resolve-thread' bare wrapper not on PATH (command not found), worker must fall back to raw GraphQL #484, not by this change; rewriting them would falsify what was decided
at the time. Flagged, deliberately out of scope.
🤖 Generated with Claude Code