refactor(claude-permissions): align allow floor with auto-mode built-ins - #267
Conversation
Trim the 45 read-only allow entries auto mode already handles promptless (read-only git/gh inspection, read-only lint tooling, claude plugin inspection), keep the 45 deterministic grants it does not (non-destructive working verbs, write-capable gh verbs, babysit-lane gate tooling incl. the 10 interim interpreter+script-path rules), and promote 6 operator runtime keepers with observed-usage evidence (git pull, pytest forms). Allow floor 90 -> 51; deny/ask untouched per dotfiles#309 G1. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TJn7ZVyCCHQfVDmVNjJxBj
|
Claude finished @kyle-sexton's task in 3m 44s —— View job PR Review
Scope: Math and disposition auditEntry count reconciles cleanly:
90 − 45 (trim) + 6 (promote) = 51. ✓ Consistent with the PR body's stated "Allow floor 90 → 51." The TRIM set (45 entries) is all read-only git/gh inspection, read-only lint tooling, and The PROMOTE justification (observed-usage evidence from dotfiles#309 P2 keep set) meets the change discipline stated in the README. 🟡 Nit — bare
|
Add gh issue close/reopen and gh pr edit — the same metadata-write class as the floor's incumbent issue/PR verbs, closing an arbitrary gap in an otherwise-consistent posture — and gh run rerun, which re-executes already-merged workflow code and is needed by the loop lanes for flaky CI. No PowerShell parity rows: write verbs carry no mirrors. Allow floor 90 -> 55. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H6gcbtrPYdtMMwx2M8PfEu
|
Claude finished @kyle-sexton's task in 3m 16s —— View job PR Review
Scope: Entry count auditThe second commit (
The second commit message correctly says "Allow floor 90 → 55." ✓ The JSON (55 entries) and commit message are consistent. 🟡 Nit — PR body count is staleThe PR body's "Allow floor 90 → 51" and the per-entry disposition tables predate the second commit; they're now off by 4. The commit message for Not blocking — the commit message is accurate — but worth updating before this comes out of draft. 🟡 Nit —
|
Every allow entry on this floor is a shell rule, and a consumer setting autoMode.classifyAllShell: true suspends all shell allow rules. The component's own README described these grants as deterministic without that qualifier, which is false for the fleet's own configuration once dotfiles#315 lands. Record the scope limit, note that deny is unaffected because the setting suspends allow rules only, and tell contributors to check whether a prompting session routes shell through the classifier before proposing a floor addition that cannot fix it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H6gcbtrPYdtMMwx2M8PfEu
|
Claude finished @kyle-sexton's task in 1m 54s —— View job PR Review
Scope: Commit Latest commit — README assessmentThe scope-limit block is accurate and well-placed: it correctly states that Carry-forward nits (three unresolved from prior cycles)🟡 Nit — bare
🟡 Nit — The pattern
🟡 Nit —
🟡 Nit — PR body math is stale (carry-forward) The PR description still reads "Allow floor 90 → 51" in multiple places; the current JSON has 55 entries (90 − 45 + 10 = 55), matching the SummaryThe latest commit adds accurate, needed documentation about auto-mode scope; no new issues. Four carry-forward nits remain open from prior review cycles — none are blocking. Math (55 entries) and JSON are consistent; the README now correctly characterises both what the floor grants and where those grants are inert. |
…verage The trim premise was false. "Auto mode covers these read-only entries" does not reach the lanes that never enter auto mode -- workflow subagents always run acceptEdits regardless of session mode, headless -p/SDK runs cannot answer a prompt, and a non-auto session is the posture this floor exists to define. Under classifyAllShell: true the premise buys nothing even inside auto mode, since no shell allow rule short-circuits the classifier there. The correct criterion is Claude Code's built-in read-only command set, which is promptless in EVERY mode and is not an allow rule, so classifyAllShell does not suspend it. Membership is command identity and much narrower than assumed. Verified on 2.1.219 in default mode with --setting-sources "": read-only git ran promptless through both the Bash and PowerShell tools, while every gh verb, every third-party linter, and claude plugin list were denied -- bare --version forms included. Restore the 29 entries that fail the corrected test (read-only gh inspection in both spellings, read-only lint tooling, claude plugin inspection) and keep trimmed only the 16 read-only git rows the built-in set actually covers. Allow floor 90 -> 84; deny (262) and ask untouched per dotfiles#309 G1. Replace the rationale in README.md rather than only the list: cite permissions "Read-only commands" instead of auto-mode-config, reconcile the classifyAllShell scope limit against the built-in set with the timing evidence, and give removals an explicit empirical test so the next contributor cannot re-derive the same mistake. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H6gcbtrPYdtMMwx2M8PfEu
…pper rows A test runner executes whatever test files are on disk, and a session that can write files plus a blanket pytest grant compose into a general code-execution grant wearing a narrow name — the same refusal melodic-software/dotfiles#315's git entry records three times. The two bare-wrapper rows never match anything today: the plugin bin/ directory is not on PATH and the skill invokes each wrapper as bash "${CLAUDE_PLUGIN_ROOT}/bin/<wrapper>" (claude-code-plugins 3fc72d351c); they return when claude-code-plugins#843 makes the bare name resolve. Allow floor 84 -> 78. README updated for both grounds and the bare-wrapper interim framing reconciled. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 3m 53s —— View job PR Review
Scope: Commit Latest commit — assessmentPytest removal ( The rationale is sound: a session that can write files plus a blanket test-runner grant compose into a general code-execution grant wearing a narrow name — the rule grammar cannot distinguish a test file the agent wrote this session from one already in the repository. The README's new "Test-suite invocations are deliberately absent" block states this cleanly and is the right place for it. This also resolves the bare Bare-wrapper removal ( Removal is correct. The plugin Entry count audit
Commit message "84 → 78" is accurate. Cumulative from Carry-forward nit resolution
🟡 Nit — PR body disposition tables are now significantly stale (carry-forward, escalated)The PR body's TRIM-45 table lists Additionally, the PROMOTE table still lists the four pytest forms, and the KEEP-35 table still lists 🟡 Nit —
|
…shape
Round-2 verifier findings. The two guarded bin/ wrappers now follow the
same interim path-form convention as the five plugin scripts — quoted
and unquoted bash "${CLAUDE_PLUGIN_ROOT}/bin/<wrapper>" spellings — so
dropping the dead bare rows no longer leaves the babysit gate tooling
with no floor coverage at all (allow 78 -> 82). README enumerates all
nine measured promptless git spellings (git branch --list was measured
separately), names the fleet default the trim rationale leans on, and
the interim paragraph now covers scripts and wrappers alike.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Claude encountered an error after 19s —— View job I'll analyze this and get back to you. |
|
Content complete at 99b4648 and re-verified by a fresh-context auditor (counts reconcile: baseline 90 = TRIM 16 + DROP 2 + KEEP 72; final 82 = 72 + PROMOTE 6 + REPLACE 4 path-form wrapper spellings; JSON/README/body consistent). Body amended to match. Two gates remain before merge, in order: (1) operator reads this amended body, then un-drafts; (2) merges only AFTER melodic-software/dotfiles#315 lands, so the standards-sync bot's dotfiles PR does not rewrite claude-permissions.json mid-flight under #315. |
|
Claude finished @kyle-sexton's task in 3m 38s —— View job PR Review
Scope: Entry count audit
Manually verified: 82 entries in Latest commit (99b4648) assessmentThe four new wrapper path-form entries follow the exact same quoted + unquoted convention as the five existing script rows: "Bash(bash \"${CLAUDE_PLUGIN_ROOT}/bin/source-control-babysit-merge\"*)",
"Bash(bash \"${CLAUDE_PLUGIN_ROOT}/bin/source-control-babysit-resolve-thread\"*)",
"Bash(bash ${CLAUDE_PLUGIN_ROOT}/bin/source-control-babysit-merge*)",
"Bash(bash ${CLAUDE_PLUGIN_ROOT}/bin/source-control-babysit-resolve-thread*)"These are correctly interleaved in alphabetical order within the allow array. The README update adds Carry-forward nit resolution
🟡 Nit —
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 99b464882a
ℹ️ 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".
…d value (#1275) No linked issue ## Summary `block-dangerous-git` treated every `--force-with-lease` spelling as safe force. Two of them are not, by git's own account, and the guard let them through while blocking `--force` for the same underlying hazard. ## Fix `--force-with-lease` and `--force-with-lease=<refname>` state no expected value, so git leases against the **remote-tracking ref**. From [git-push(1)](https://git-scm.com/docs/git-push), "A general note on safety": > supplying this option without an expected value, i.e. as `--force-with-lease` or `--force-with-lease=<refname>` interacts very badly with anything that implicitly runs `git fetch` on the remote to be pushed to in the background, e.g. `git fetch origin` on your repository in a cronjob. > > The protection it offers over `--force` is ensuring that subsequent changes your work wasn't based on aren't clobbered, but this is **trivially defeated if some background process is updating refs in the background**. So the lease can be satisfied by a ref *some other process* fetched, and the push clobbers work the pusher never saw — the failure mode `--force` has, reached by a slower road. Git also marks every form other than `=<refname>:<expect>` experimental. Those two no-expected-value forms are now blocked under a new **`push-lease-unsafe`** token, unless `--force-if-includes` (git 2.30+) is present — git's documented mitigation for exactly these forms, which it declares a no-op alongside an explicit `:<expect>`. ### What still passes - `--force-with-lease=<refname>:<expect>`, including an empty `<expect>` (asserts the ref must not exist — still explicit). - Any lease form paired with `--force-if-includes`. - A push dry-run, which disarms the whole check as before. ### Detection detail Unique-prefix abbreviations are handled. `--force`, `--force-with-lease` and `--force-if-includes` share the `--force` prefix, so `--force-w` and `--force-i` are the shortest spellings git accepts, and both match. A shorter `--forc` is ambiguous and git rejects it outright, which is why the exact `--force` arm needs no abbreviation handling. After `--`, words are operands rather than flags, so a literal `--force-if-includes` refspec does not disarm the check. ## Why the hook, and not the permission deny-list This started from the opposite direction: a `--force-with-lease` push was denied by the `claude-permissions` floor, and the obvious fix looked like removing that deny. Research against [the permissions docs](https://code.claude.com/docs/en/permissions.md) killed that: > Rules are evaluated in order: deny, then ask, then allow. The first match in that order determines the outcome, and rule specificity doesn't change the order. > A broad deny rule like `Bash(aws *)` blocks every matching call, including calls that also match a narrower allow rule like `Bash(aws s3 ls)`, so a deny rule can't carry allowlist exceptions. Bash rules are whole-string globs with `*` as the only metacharacter — no negation. So "deny the unsafe lease forms, allow `=<ref>:<expect>`" is **not expressible** in the permission language, and the docs name a PreToolUse hook as the mechanism for what globs cannot express. This is that hook. The blunt deny in `melodic-software/standards` is therefore doing a job the permission layer cannot do precisely. Removing it before this landed would have been a net widening — it would have exposed the unsafe bare form, which `guardrails` permitted. With this merged, that deny can be dropped and the policy becomes: safe form allowed, unsafe forms blocked, both enforced where the distinction is actually expressible. ## Testing `block-dangerous-git.test.sh` — **261 pass, 0 fail**. 14 new cases: bare, `=<refname>`, `=<refname>:<expect>`, empty `<expect>`, both abbreviations, `--force-if-includes` alone and paired, dry-run, and the `--` operand boundary. Three existing cases asserted the old permissive behavior and were updated to the new contract; one PowerShell case likewise, plus a new PowerShell case for the passing form. `shellcheck -x` clean at the repo ruleset. `markdownlint-cli2` clean. `plugin.json` validates. ## Related - `melodic-software/standards#267` — in flight on the same `claude-permissions` component (it trims the **allow** floor; this affects **deny** policy). Its README states "Force/destructive spellings stay covered by `deny`, which always wins" — the follow-up that drops the lease deny will need to update that sentence. - Follow-up, not in this PR: remove the four `--force-with-lease` deny patterns (`Bash` and `PowerShell` mirrors) from the `claude-permissions` component now that the precise check exists here. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
… in the hook (#272) ## Summary The permission floor denied every `--force-with-lease` spelling — including the forms that are actually safe. This removes those four patterns and moves enforcement to the one place the distinction can be expressed. ## Why `deny` cannot do this job Claude Code's Bash rules are whole-string globs with `*` as the only metacharacter, and precedence is fixed ([permissions](https://code.claude.com/docs/en/permissions)): > Rules are evaluated in order: deny, then ask, then allow. The first match in that order determines the outcome, and rule specificity doesn't change the order. > A broad deny rule like `Bash(aws *)` blocks every matching call, including calls that also match a narrower allow rule like `Bash(aws s3 ls)`, so a deny rule can't carry allowlist exceptions. No negation, no exceptions. So a `deny` here is all-or-nothing. ## Why that matters — the forms are not equivalent [git-push(1)](https://git-scm.com/docs/git-push), "A general note on safety": > supplying this option without an expected value, i.e. as `--force-with-lease` or `--force-with-lease=<refname>` interacts very badly with anything that implicitly runs `git fetch` … this is **trivially defeated if some background process is updating refs in the background**. Only `--force-with-lease=<refname>:<expect>` states the expectation, and it is the one form git does not mark experimental. A single glob cannot deny the unsafe spellings and permit the safe one — so the floor denied all of them, which is why a correctly-formed safe push was blocked in practice. ## What replaces it The `guardrails` plugin's `block-dangerous-git` PreToolUse hook, which parses the argv and can therefore make the distinction: - Blocks any lease that resolves against something **movable at push time** — bare, `=<refname>`, or an `=<refname>:<expect>` whose `<expect>` is a name like `origin/main`, `HEAD`, or `refs/remotes/...`. - Permits an expectation git cannot resolve to something newer: an object id, or the empty string (asserting the ref must not exist). - Honors `--force-if-includes` (git 2.30+) as git's documented mitigation for the unpinned forms. - Tracks the last-wins negations git documents as `--[no-]force-with-lease` and `--[no-]force-if-includes`. Claude Code's own docs name a PreToolUse hook as the mechanism for exactly what globs cannot express. ## Ordering — this lands second, deliberately Removing the deny on its own would have been a **net widening**. The hook permitted every lease form until melodic-software/claude-code-plugins#1275, so dropping the blunt rule first would have exposed the unsafe spellings with nothing catching them. The hook hardens first; the blunt rule comes out after. ## README "Force/destructive spellings stay covered by `deny`, which always wins" is corrected rather than deleted — it still holds for every other force spelling. The carve-out is recorded beneath it with the reason and both upstream citations, so the next reader does not re-add the patterns. ## Verification - `claude-permissions.json` validates; the four removed entries are the only change to it (2 Bash, 2 PowerShell mirrors). - Pre-commit gates green: biome, editorconfig, gitleaks, typos, markdownlint. ## Related - melodic-software/claude-code-plugins#1275 — the hook that makes this safe. **Merge that first.** - #267 — in flight on the same component; it trims the **allow** floor while this touches **deny**, so they should auto-merge. Its README rewrite touches the same paragraph, so whichever lands second should confirm the carve-out survived. No linked issue: this is the second half of the melodic-software/claude-code-plugins#1275 change, not a separately tracked defect. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ns-auto-mode-floor-trim
|
Claude encountered an error after 2s —— View job I'll analyze this and get back to you. |
|
Warning Automated review did not complete — this is an infrastructure failure, not a review verdict. Treat any Claude comment on this PR (including a placeholder like "I'll analyze this and get back to you") as incomplete, not "no findings."
Re-running the job, or pushing a new commit, will retry the review. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: aecd7b8250
ℹ️ 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".
…grant The pull wildcard pre-approved git pull --no-verify (documented as bypassing the pre-merge and commit-msg hooks) and the --force/-f/ +<refspec> forced-overwrite forms the fetch family already denies — deny now carries the pull spellings of both families in both shells, args-before-flag forms included. And gh run rerun takes a bare run id naming any accessible run, so no floor glob can hold it to flaky CI on merged workflow code — the allow row is dropped (81 rows) and reruns are judged per session, recorded beside the test-suite absence with the guarded-wrapper end state named. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ha8DkNT4nSnVjKDNWVpj3w
|
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: 318114b476
ℹ️ 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".
| "Bash(git pull * -f *)", | ||
| "Bash(git pull * -f)", | ||
| "Bash(git pull --force*)", | ||
| "Bash(git pull -f *)", |
There was a problem hiding this comment.
Deny the exact
git pull -f spelling
In a repository whose configured fetch refspec maps a remote ref directly to another local branch, bare git pull -f force-updates that branch and can discard unpushed commits; git pull -h describes -f as “force overwrite of local branch” (git-pull documentation). The fresh deny rows added after the earlier review still only match git pull -f with a trailing space, while the new wildcard allow pre-approves the bare spelling. Add exact Bash(git pull -f) and corresponding PowerShell denies.
Useful? React with 👍 / 👎.
What
Re-derives the
claude-permissionsallow floor against Claude Code auto mode'sbuilt-in coverage (fleet default is now
permissions.defaultMode: "auto";migration tracked in melodic-software/dotfiles#309, this PR is its P1b phase).
Allow floor 90 → 81; deny grows by 14 pull-spelling rows (
--no-verifyand forced-fetch families mirrored ontogit pull, both shells — the review round that also dropped the rerun grant); the component carries no ask array.An earlier shape of this PR trimmed 45 rows on the premise "auto mode covers
read-only commands promptless." That premise was then MEASURED and found false
for everything except read-only git (empirical record: the operator-local
migration file
.work/auto-mode-defaults/RESEARCH.md, "Addendum — built-inread-only set, MEASURED" — not repo-reachable, so the decisive figures are
inlined here;
claude -p --setting-sources "" --permission-mode default,v2.1.219): 9/9 git inspection spellings ran promptless (
status,diff,log,show,branch,branch --list,ls-files,merge-base,rev-parse); 16/16 non-git commands were denied — everyghread verb, every third-party linter, evenbare
--version. Membership is command identity, not flag safety, and it istool-agnostic (git ran promptless through
PowerShell()too). The trim wasre-derived accordingly:
Bash()+ 6PowerShell()spellings). The built-in read-only command set runs thesepromptless in every mode, so floor entries for them are dead weight
everywhere, not just under auto.
ghverbs, third-party linters, andclaude plugininspection rows the earlier shape wrongly trimmed. Measureddenied without them; they are load-bearing in every non-auto lane (workflow
subagents always run
acceptEdits; headless-p/SDK runs fail with nobodyto answer a prompt).
Bash(source-control-babysit-merge *)/Bash(source-control-babysit-resolve-thread *)match nothing today: theplugin
bin/directory is not on the shell's PATH and the skill invokeseach wrapper as
bash "${CLAUDE_PLUGIN_ROOT}/bin/<wrapper>"(claude-code-plugins
3fc72d351c). They are dropped, and the wrappersinstead carry the same interim path-form convention as the five plugin
scripts already on the floor — quoted and unquoted
Bash(bash …${CLAUDE_PLUGIN_ROOT}/bin/<wrapper>…*)spellings, 4 rows.Bare-name rows return when claude-code-plugins#843 makes the bare name
resolve.
pytestrows the earlier shape added. A testrunner executes whatever test files are on disk, and a session that can
write files plus a blanket
pytestgrant compose into a generalcode-execution grant wearing a narrow name — the same refusal
melodic-software/dotfiles#315's git entry records three times. Test runs
are judged per session.
unattended-lane need, per the component's change discipline:
git pull(bare + starred) and four gh write verbs (rationale below). No PowerShell
parity rows: the PS-mirror convention covers read-only inspection only, and
write verbs have never carried mirrors.
Promote — issue/PR metadata verbs and CI re-run
gh issue close *,gh issue reopen *,gh pr edit *— the same class asfloor incumbents already present (
gh issue comment/create/edit,gh pr comment/create/ready); excluding them was an arbitrary gap in anotherwise-consistent issue/PR metadata-write posture.
Considered, not promoted (decision record)
Bash(gh api graphql *),Bash(gh api orgs/*),Bash(gh api repos/*)—empirical evidence in auto-mode classifier: deferred vendor-surface gaps from #697 (compound decomposition, prefix-allow short-circuit, natural-language autoMode.allow) claude-code-plugins#1235 (gap 2)
shows prefix allow rules of exactly this shape did NOT short-circuit the
classifier's category safety layer for external writes. They also widen the
granted surface in non-auto sessions, which is precisely the posture the
floor's rows exist to define. Kept machine-local.
Bash(gh workflow run *)— dispatches arbitrary workflows withoperator-controlled inputs; a CI-execution trigger is a different risk tier
from issue/PR metadata edits, and the
claude-ops: tune auto-mode classifier from observed team usage (step-3 guardrail, 1→2 residue) claude-code-plugins#697 precedent keeps high-blast-radius
write verbs (merge) off the floor. Kept machine-local.
Edit(//**/github.com/melodic-software/**)— encodes this machine'scheckout layout; a fleet-distributed floor must not carry a machine's
directory layout. Kept machine-local.
Scope limit under auto mode
These grants are deterministic only outside auto mode's
classifyAllShell.That key is NOT yet set fleet-wide: G3a split it out of
melodic-software/dotfiles#315 into its own gated follow-up draft PR in
dotfiles, which lands only after the operator's prose-grant test
(dotfiles#309 P3 test 3) passes. Until then the
narrow pre-classifier short-circuit these rows provide still operates in
auto-mode sessions for matching spellings. Once the key lands, every shell
allow rule is suspended in auto-mode sessions and this floor is the fallback
posture for non-auto lanes — which the measurement above shows are exactly the
lanes that need it.
denyis unaffected in every mode and every regime —classifyAllShellsuspends allow rules only; the 262 deny entries stay pre-classifier and
non-overridable, which is exactly why G1 keeps all of them.
Why
standards: distribute pre-approved safe-command settings.json allowlist via sync (1→2 residue) claude-code-plugins#695) to pre-approve safe commands so
unattended loops never prompt. Auto mode provides that natively for
read-only git only — the measured set — so exactly those entries no longer
pay for their maintenance surface.
gh pr mergestays out of the allow floorand
gh pr merge --autostays denied, perclaude-ops: tune auto-mode classifier from observed team usage (step-3 guardrail, 1→2 residue) claude-code-plugins#697; babysit merges keep going through
the guarded gate wrapper.
pre-classifier and non-overridable, while built-in coverage is consent-gated
soft_deny — trimming deny would downgrade hard blocks to consent gates.
Per-entry disposition (reconciles to 90)
Baseline 90 = TRIM 16 + DROP 2 + KEEP 72; final 81 = KEEP 72 + PROMOTE 5 +
REPLACE 4 (the wrappers' path-form spellings). A review round later dropped the
sixth PROMOTE candidate (
gh run rerun *— a bare run id names any accessiblerun, so no floor glob holds it to merged workflow code; judged per session
until a guarded wrapper exists).
TRIM — 16 entries (read-only git, built-in-covered, measured)
Bash(git branch --list *)Bash(git branch)Bash(git diff *)Bash(git log *)Bash(git ls-files *)Bash(git merge-base *)Bash(git rev-parse *)Bash(git show *)Bash(git status *)Bash(git status)PowerShell(git diff *)PowerShell(git log *)PowerShell(git merge-base *)PowerShell(git rev-parse *)PowerShell(git show *)PowerShell(git status *)DROP 2 / REPLACE 4 — bare wrappers out, path-form spellings in
Dropped (match nothing until ccp#843):
Bash(source-control-babysit-merge *)Bash(source-control-babysit-resolve-thread *)Added in their place (the real invocation shape, parity with the five
script rows):
Bash(bash "${CLAUDE_PLUGIN_ROOT}/bin/source-control-babysit-merge"*)Bash(bash ${CLAUDE_PLUGIN_ROOT}/bin/source-control-babysit-merge*)Bash(bash "${CLAUDE_PLUGIN_ROOT}/bin/source-control-babysit-resolve-thread"*)Bash(bash ${CLAUDE_PLUGIN_ROOT}/bin/source-control-babysit-resolve-thread*)KEEP — 72 entries
Everything else in the baseline: the non-destructive working verbs, the gh
write incumbents, the RESTORED read-only
gh/linter/claude pluginrows(measured load-bearing), the 10 interim
${CLAUDE_PLUGIN_ROOT}script-pathrules (README carries the interim note; end state is bare wrappers on the
plugin
bin/PATH, trigger claude-code-plugins#843), and the PowerShellread-only mirrors outside the built-in git set.
PROMOTE — 6 entries
Bash(gh issue close *)Bash(gh issue reopen *)Bash(gh pr edit *)Bash(git pull *)Bash(git pull)Status
DRAFT — stays draft pending operator review of this amended body; merges AFTER
melodic-software/dotfiles#315 (merging this first would trigger the
standards→dotfiles sync bot to rewrite
.chezmoidata/claude-permissions.jsonmid-flight under #315).
Related
No linked issue. This is the P1b phase of a cross-repo migration; it closes no
issue in this repository.
🤖 Generated with Claude Code