feat(source-control): pin plugin install --config behaviours and move branch_issue_pattern to the cascade - #4581
Conversation
…ntrol.md cascade parse-branch-issue.sh now reads `## branch_issue_pattern` from the local, team, and user-global source-control.md layers before the deprecated userConfig value, which it still honors as a fallback with a deprecation note on stderr; a layer holding an invalid ERE is reported and skipped. create.md keeps the script's stderr visible. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The os_toast option descriptions now say macOS (osascript) or Linux (requires notify-send), with no effect on Windows where the terminal channels carry the alert. README options blocks regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rrect the scope caveat hook-config-delivery gains facts 9-12 from a sandbox probe on Claude Code 2.1.283 (the value always lands in user settings, validation warns but exits 0, no CLI unset path, same-scope rerun is a pure config write), a per-row Verified column, and recheck triggers for the new rows (contract 1.3.0). plugin-reconfiguration's verified-version record moves to 2.1.283 with the scope-mismatch fact, caveat 2 gets the measured rationale, and a fourth caveat says to read the output rather than the exit code. The setup skills of source-control, desktop-notification and typos-format follow. ADR 0039 records which babysit keys stay in userConfig and which move to the source-control.md cascade; config-resolution.md states the multi-domain consequence. The out-of-tree create path runs parse-branch-issue.sh with CLAUDE_PROJECT_DIR set to the worktree. source-control 0.61.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rage Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n record The smoke-test record and migration playbook restated the 2.1.240 pin as untested at project scope; the owner record now covers it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…w the reconfigure record parse-branch-issue.sh reads fenced values, ignores headings inside fences, rejects backreferences, prints only an all-digit capture, and keeps pattern text out of its stderr notes. Setup check and apply cover branch_issue_pattern. The plugin-reconfiguration record states exactly what the 2.1.283 probe measured, and ADR 0039 decision 3 matches #4572. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… pin Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… skills Nineteen setup skills said a headless `claude plugin install --config` rerun at the wrong scope "lands at a scope that does not load". Measured on Claude Code 2.1.283, `--config` always writes the value to user settings whatever `-s` says; `-s` governs the install record, so a rerun at a scope other than the installed one adds a second install record at that scope and enables the plugin there. The advice (pass the scope `claude plugin list` reports, run from the project directory for a project/local scope) is unchanged; only the stated reason changes. Three setup evals carrying the same reason are updated to match. Each plugin gets a patch bump and a CHANGELOG entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Claude finished @kyle-sexton's task in 4m 20s —— View job Code review complete
No blocking or high-signal findings. No inline comments were posted. What I reviewedThis PR touches 87 files, but the substantive logic lives in a small set of them; the rest is a mechanical fleet-wide caveat-text correction (documented in the PR body) plus version/CHANGELOG bumps. I focused review effort accordingly:
Verification claims in the PR body (sandbox probe hashes, |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a486b3acad
ℹ️ 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".
|
Claude finished @kyle-sexton's task in 3m 59s —— View job Security review complete
Scope: Of the 87 changed files, the vast majority are version bumps, CHANGELOG entries, and doc/caveat-text corrections with no executable surface. The only new code with a security-relevant attack surface is Finding (1)IMPORTANT — regex-DoS (catastrophic backtracking) bypasses
Suggested fixes (inline comment has details): wrap the match in Caveat on this finding: I could not run a live timing test in this environment — Bash tool calls beyond simple What I checked and ruled out
|
…anch-only apply, and add the exit-0 caveat to setup skills Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 59s —— View job Security review complete
Skip gate: criterion 3 (already-reviewed head, surface unchanged). The only file in this PR with executable security-relevant surface is Everything in that range is documentation/skill-text only: The prior security review on this PR (commit No new findings on this head. No inline comments were posted. |
|
Claude finished @kyle-sexton's task in 3m 26s —— View job Code review complete
No blocking or high-signal findings. No inline comments were posted. ScopeHEAD moved from
Spot-checked Security-relevant surface (the ReDoS finding on |
…atterns in branch_issue_pattern resolution
parse-branch-issue.sh accepts a leading UTF-8 BOM and a closing # sequence
on the heading. A near-miss H2 (for example `## branch_issue_pattern:`)
stops resolution with a note and exit 1 instead of falling to a lower
source that could close the wrong issue. A heading or HTML comment as the
first value line, and an unterminated fence with content, skip the layer
with a note.
Before a pattern is compiled or matched it must stay within 200
characters, {m,n} bounds of at most 16, and no quantifier on a group whose
body already holds one, so a nested bounded repetition can no longer
exhaust memory at compile time. Setup's validation step applies the same
limits; config-resolution.md documents the parsing rules and limits.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ope-only-and-config # Conflicts: # plugins/source-control/.claude-plugin/plugin.json # plugins/source-control/CHANGELOG.md Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
#4673) (#4760) <!-- CURSOR_AGENT_PR_BODY_BEGIN --> Closes #4673 ## Summary **Decision: stop (fail closed).** A layer whose `## branch_issue_pattern` exists but yields no usable pattern stops resolution (no stdout, exit 1, “resolution stopped”) instead of falling through to a wrong `Closes #N`. Declared exception to config-cascade soft-degrade. Empty sections also stop. `source-control` → 0.62.0. ## Fix - `parse-branch-issue.sh` + tests (64/0); docs that said “skipped”; config-cascade Declared entry. ## Verification - [x] 64 pass; 23 new cases fail against main’s skip behaviour (per [Settle remaining easy decisions](bc-88a9acd4-df6d-53b4-9419-d1b8599bde83)) ## Related - #4581 (shipped skip), #4572 (other keys on cascade) <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-ab53da24-b89d-4314-a060-0da474e837e9?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-ab53da24-b89d-4314-a060-0da474e837e9&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
… docs (#5266) Refs: #3574 Refs: #4784 Refs: #4671 Refs: #5096 Refs: #3686 Refs: #4240 Refs: #3356 Refs: #5057 Refs: #4581 ## Summary Audit fixes for `plugins/go-format` (REPORT.md finding `plugin-go-format` and the 3c row for `hooks/probe-prerequisite.sh:43-52`). Closes no issue: #3574 is owned by core-docs and waits on an owner decision. - The SessionStart prerequisite probe ran even with `go_format_enabled=false`, so the disabled plugin still printed a `goimports was not found` notice. - README, setup skill, hook header comments and evals still described the hook as unconditional, which predates the gitignore exemption (#4784). - The setup skill's toggle-off step carried stale scope advice that contradicts the reconfiguration convention. ## Fix - `hooks/hooks.json`: the SessionStart row passes `--run-if-unset-or-true GO_FORMAT_ENABLED` to the launcher, the same shape as `typos-format`. `probe-prerequisite.sh`, `hook-utils.sh` and `exec-bash.mjs` are untouched (the first two are byte-pinned to the shared copy). - `hooks/go-format.test.sh`: hook-wiring selectors match the new args; new behavioral cases assert no notice with the switch off and the notice with it unset or `true`. - `README.md`, `skills/setup/SKILL.md`, `hooks/go-format.sh` and `go-format.test.sh` header comments: "no consumer-config opt-in gate" replaces "unconditional"; the gitignored-file skip and `go_format_lint_gitignored` are documented; the setup `check` action reports the option's effective value. - `skills/setup/SKILL.md` toggle-off: prints the convention's short form (`-s user`, never uninstall to reconfigure, next-session observation, read output not exit code) and cites the convention. - `skills/setup/evals/evals.json`: new eval for the gitignore option; eval 5 aligned with the short form. - `plugin.json` 0.4.5 to 0.4.6 with a CHANGELOG entry. The `plugin.json` description ("Runs unconditionally (no consumer-config gate)") stays accurate; changing it would force a `docs/catalog.md` regeneration outside this change's scope. - Cross-group requests applied: the setup toggle-off step keeps `-s user` per the convention on main, and the setup `check` action keeps `node` a FAIL behind the kill switch. README Requirements and the setup `check` action declare Node.js (hook-launcher request). CHANGELOG entries 0.3.62, 0.3.63, 0.4.2 and 0.4.3 read "Shared launcher/library sync; no change to this plugin's behavior" and 0.4.1 drops the shell-form sentence; these released-entry edits are declared in the 0.4.6 entry and are not folded or renumbered. ## Verification - `bash plugins/go-format/hooks/go-format.test.sh`: PASS=66 FAIL=0 - `bash scripts/validate-plugins.sh`: all manifests and catalog validated - `bash scripts/check-changelog-parity.sh --check --check-order`: pass - `bash scripts/check-prerequisite-probes.test.sh`, `check-hook-exec-form.sh`, `check-hook-userconfig-argv.sh`, `check-hook-wiring-liveness.sh`, `check-killswitch-hoist.sh`, `check-cross-plugin-source-drift.sh`, `check-hooks-description.sh`, `check-purged-em-dashes.sh`: exit 0 - `bash scripts/check-changed-skills.sh origin/main`: setup skill PASS, 0 errors - `python3 scripts/sync-plugin-options-docs.py --check`, `node scripts/generate-catalog.mjs --check`: exit 0 ## Related Audit findings: `plugin-go-format` (correctness, docs-coherence, convention); 3c row `probe-prerequisite.sh:43-52`; 3d finding #3574 (owned by core-docs, not changed here). Related issues: #4784, #4671, #5096, #3686, #4240, #3356, #5057, #4581. Applied from other groups: hook-launcher F43, F44 and the node declaration; the scope wording request was not applied (see below). Skipped: biome-format request to gate the SessionStart row, already done in this PR (`hooks.json` passes `--run-if-unset-or-true GO_FORMAT_ENABLED`, with disabled, unset and `true` probe tests). The setup toggle-off step follows caveat 2 as it reads on main (`-s user`); the conventions group (#5313) owns changing it, after which the setup skills can follow. Cross-group requests: - core-docs: include go-format's setup rationale (`SKILL.md:69`) as evidence in the #3574 decision packet; optionally reword the `plugin.json` description together with `docs/catalog.md` if the owner wants the gitignore exemption named. - conventions: `scripts/sync-plugin-options-docs.py:126` emits "pass the scope `claude plugin list` reports", contradicting the reconfiguration convention's caveat 2; fix the template and regenerate every README's generated options block (go-format's generated block changes in that run). - biome-format and markdown-format carry the same probe-gate defect; their own groups own the fix. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01EugXnFddtpHcY5gTuyEirB --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…t-ssot, write-for-agents and the changelog (#5296) Refs: #3574 Refs: #4784 Refs: #4671 Refs: #5096 Refs: #3686 Refs: #4240 Refs: #3356 Refs: #5057 Refs: #4581 ## Summary Audit fixes for `plugins/go-format` (REPORT.md finding `plugin-go-format` and the 3c row for `hooks/probe-prerequisite.sh:43-52`). Closes no issue: #3574 is owned by core-docs and waits on an owner decision. - The SessionStart prerequisite probe ran even with `go_format_enabled=false`, so the disabled plugin still printed a `goimports was not found` notice. - README, setup skill, hook header comments and evals still described the hook as unconditional, which predates the gitignore exemption (#4784). - The setup skill's toggle-off step carried stale scope advice that contradicts the reconfiguration convention. ## Fix - `hooks/hooks.json`: the SessionStart row passes `--run-if-unset-or-true GO_FORMAT_ENABLED` to the launcher, the same shape as `typos-format`. `probe-prerequisite.sh`, `hook-utils.sh` and `exec-bash.mjs` are untouched (the first two are byte-pinned to the shared copy). - `hooks/go-format.test.sh`: hook-wiring selectors match the new args; new behavioral cases assert no notice with the switch off and the notice with it unset or `true`. - `README.md`, `skills/setup/SKILL.md`, `hooks/go-format.sh` and `go-format.test.sh` header comments: "no consumer-config opt-in gate" replaces "unconditional"; the gitignored-file skip and `go_format_lint_gitignored` are documented; the setup `check` action reports the option's effective value. - `skills/setup/SKILL.md` toggle-off: prints the convention's short form (`-s user`, never uninstall to reconfigure, next-session observation, read output not exit code) and cites the convention. - `skills/setup/evals/evals.json`: new eval for the gitignore option; eval 5 aligned with the short form. - `plugin.json` 0.4.5 to 0.4.6 with a CHANGELOG entry. The `plugin.json` description ("Runs unconditionally (no consumer-config gate)") stays accurate; changing it would force a `docs/catalog.md` regeneration outside this change's scope. - Cross-group requests applied: the setup toggle-off step keeps `-s user` per the convention on main, and the setup `check` action keeps `node` a FAIL behind the kill switch. README Requirements and the setup `check` action declare Node.js (hook-launcher request). CHANGELOG entries 0.3.62, 0.3.63, 0.4.2 and 0.4.3 read "Shared launcher/library sync; no change to this plugin's behavior" and 0.4.1 drops the shell-form sentence; these released-entry edits are declared in the 0.4.6 entry and are not folded or renumbered. ## Verification - `bash plugins/go-format/hooks/go-format.test.sh`: PASS=66 FAIL=0 - `bash scripts/validate-plugins.sh`: all manifests and catalog validated - `bash scripts/check-changelog-parity.sh --check --check-order`: pass - `bash scripts/check-prerequisite-probes.test.sh`, `check-hook-exec-form.sh`, `check-hook-userconfig-argv.sh`, `check-hook-wiring-liveness.sh`, `check-killswitch-hoist.sh`, `check-cross-plugin-source-drift.sh`, `check-hooks-description.sh`, `check-purged-em-dashes.sh`: exit 0 - `bash scripts/check-changed-skills.sh origin/main`: setup skill PASS, 0 errors - `python3 scripts/sync-plugin-options-docs.py --check`, `node scripts/generate-catalog.mjs --check`: exit 0 ## Related Audit findings: `plugin-go-format` (correctness, docs-coherence, convention); 3c row `probe-prerequisite.sh:43-52`; 3d finding #3574 (owned by core-docs, not changed here). Related issues: #4784, #4671, #5096, #3686, #4240, #3356, #5057, #4581. Applied from other groups: hook-launcher F43, F44 and the node declaration; the scope wording request was not applied (see below). Skipped: biome-format request to gate the SessionStart row, already done in this PR (`hooks.json` passes `--run-if-unset-or-true GO_FORMAT_ENABLED`, with disabled, unset and `true` probe tests). The setup toggle-off step follows caveat 2 as it reads on main (`-s user`); the conventions group (#5313) owns changing it, after which the setup skills can follow. Cross-group requests: - core-docs: include go-format's setup rationale (`SKILL.md:69`) as evidence in the #3574 decision packet; optionally reword the `plugin.json` description together with `docs/catalog.md` if the owner wants the gitignore exemption named. - conventions: `scripts/sync-plugin-options-docs.py:126` emits "pass the scope `claude plugin list` reports", contradicting the reconfiguration convention's caveat 2; fix the template and regenerate every README's generated options block (go-format's generated block changes in that run). - biome-format and markdown-format carry the same probe-gate defect; their own groups own the fix. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01EugXnFddtpHcY5gTuyEirB --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

No related issue: the source item is a local handoff queue entry; the one follow-up it produced is #4572, linked under Related, and this PR does not close it.
Summary
Records four
claude plugin install --configbehaviours in the hook-config-delivery facts table,corrects the reconfigure scope caveat that those measurements contradict, rules on where
source-control's babysit identity and topology keys live, moves
branch_issue_patternonto the.claude/source-control.mdcascade, and makes the twoos_toastoption descriptions name theirplatform.
Fix
in a sandbox on Claude Code 2.1.283 (2026-09-27):
--configwritespluginConfigsto user settings whatever-ssays;-sgoverns only theinstall record and
enabledPlugins.exit 0; a prose-enumerated string and a non-existent
directoryare stored. A declaredoptionsfixed list is enforced (doc-stated, plugins need v2.1.271 to load it).config/configuresubcommand and no CLI unset path.directory at local scope).
coverage. Caveat 2's rationale ("or the write lands at a scope that does not load") was wrong: the
value always lands in user settings. The measured risk is the reverse: a rerun at another scope adds
an install record there and enables the plugin at that scope (a default
-s userrerun enables itmachine-wide). New caveat 4: read the CLI output, not the exit code. plugin-philosophy,
extensibility-contract-smoke-tests, and migration-playbook now point at this record instead of
restating 2.1.240.
userConfig,with the multi-domain consequence stated.
branch_issue_patternmoves now. Ten repository-toolingkeys move later under source-control: migrate ten babysit repository-tooling keys from userConfig to the source-control.md cascade #4572 with default-branch resolution and union/unit merge modes.
config-resolution.mdstates the consequence and cites the ADR.parse-branch-issue.shresolvesbranch_issue_patternfrom the threecascade layers (local > team > user-global) before the now-deprecated
userConfigvalue, whichprints a deprecation note on stderr and is kept as a fallback until a later minor release no
earlier than 2026-12-27. Hardening: a fenced value is read, a fenced heading is ignored, a
backreference pattern is rejected, output must be digits, and notes never echo the raw pattern.
setupchecks and writes the key.create.mdpassesCLAUDE_PROJECT_DIR="$WT"on theout-of-tree path and no longer discards the script's stderr.
and Linux (notify-send), with no effect on Windows; README option blocks regenerated.
corrected. The uninstall recipe the item names was already removed in typos-format 0.6.23 (fix(setup): unstamped
--configclaim prescribes a destructive reinstall across 18 setup skills #3111).actionlint, ai-briefing, bash-format, biome-format, bugs, context-budget, disk-hygiene, education,
eol-normalizer, go-format, knowledge, machine-health, markdown-format, powershell-format,
rate-limit-guard, repo-hygiene, ruff-format, session-flow, and skill-quality, plus the setup evals
of actionlint, bash-format, and repo-hygiene that asserted the wrong reason. The advice is
unchanged; only the reason is.
Verification
CLAUDE_CONFIG_DIR,HOME,USERPROFILE,APPDATA,LOCALAPPDATAunder thesession scratchpad, a local directory marketplace, and a fixture git repo. Positive control before
any write: fixture
claude plugin list --jsonreturned[]. After both batches, hashes of the real~/.claude/settings.json,installed_plugins.json, andknown_marketplaces.jsonwere unchanged.parse-branch-issue.test.sh: 36 passed, 0 failed, 36 test calls. shellcheck clean on the scriptand test.
sync-plugin-options-docs.py --check,check-changelog-parity.sh --check-bump 039578b98, andmarkdownlint on touched markdown: pass. No U+2014 in added lines. The three touched evals.json
load and pass
check-evals-quality.shwith 0 warnings.acceptance bullets PASS, with no CLI overclaim against the probe record.
check-changed-skills.sh: its one failure ispush-branch.test.sh, a file this PR does not touch.It fails because this host's global gpg signing applies to the test's commits, and it passes 21/0
with
GIT_CONFIG_GLOBAL=/dev/null.Related
validator, with the rationale withheld, returned HYBRID, and that verdict was adopted (ADR 0039).
lane (see deferred below).
optionsfield: deferred as a plugin-philosophy gate decision, becausedeclaring it raises the load floor to v2.1.271.
replace a hold list under plain per-key override, is security-policy-loosening and is left out.
guardrails, and claude-ops, which belong to a different session.
sensitiveoption, and a same-scope string rerun at local scope.branch_issue_patternmoving to a repo-writable layer lets a repository choose whichopen issue
Closes #names. The value carries no authority, and the output is now digits-only.🤖 Generated with Claude Code