Skip to content

feat(guardrails): serve the git hooks to lefthook repositories as a remote - #9504

Merged
kyle-sexton merged 15 commits into
mainfrom
feat/guardrails-lefthook-remote
Oct 24, 2026
Merged

kyle-sexton merged 15 commits into
mainfrom
feat/guardrails-lefthook-remote

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Refs: #9426

Summary

/guardrails:setup apply install-git-hooks scope=shared in a lefthook repository, or one with no hook manager yet, now commits one lefthook remotes: entry instead of copies under .githooks/guardrails/. Lefthook fetches plugins/guardrails/git-hooks/lefthook-remote.yml and its scripts from this repository's main branch and refetches them every 24h. Every consumer then runs the guardrails hooks as merged to main, with no refresh pull requests and no lint exclusions. This is the owner's decision. Husky and plain hooks keep the shared copies.

What a consumer commits in lefthook.yml (from install.mjs plan --scope remote):

remotes:
  - git_url: https://github.com/melodic-software/claude-code-plugins
    ref: main
    refetch_frequency: 24h
    configs:
      - plugins/guardrails/git-hooks/lefthook-remote.yml

Footprint. install.mjs is a shared copy: its canonical source is lib/git-hooks/install.mjs, registered in scripts/shared-copies.txt:496-505. Changing guardrails' copy therefore means changing the canonical and regenerating all 10 carriers. --check-bump then needs a fragment for each carrier, written with scripts/new-changelog-fragment.sh --carriers-of. The session-start drift notice runs that installer through lib/prerequisites.mjs, which is also shared (scripts/shared-copies.txt:234), so no guardrails-only module could quiet it. The new mode is opt-in through an entries.json remote block, so the other nine plugins behave exactly as before.

Ref: main (owner decision). Consumers track this repository's main, which changes only through reviewed pull requests under main's existing rulesets. lefthook-remote.test.sh runs end to end in PR CI: test-bash installs the pinned lefthook (2.2.2, SHA-256 checked, .github/scripts/pr-require-checks/install-lefthook.sh) on the leg that runs it, and GUARDRAILS_REQUIRE_LEFTHOOK=1 makes a missing lefthook fail instead of skip. There is no release branch and no move workflow.

Cache path. <git common dir>/info/lefthook-remotes/claude-code-plugins-main/ (lefthook's <repo name>-<ref>, RemoteDirectoryName in internal/git/remote.go).

#9426 coverage

  • Delivered for lefthook consumers, because the remote removes the committed copies: items 1 (mode 100644), 2 (linted vendored copies), 3 (first-commit scan cost), 8 (on-disk mode), 9 (lint mirrors of the copies) and 10 (undetected drifted copies).
  • Remaining for later work: items 1 to 3 for husky and plain-hook consumers, which keep the shared copies, and items 4 to 7 and 11 to 14 (entry-script defects that the remote does not change).

Fix

  • lib/git-hooks/install.mjs and its 10 regenerated copies:
    • entries.json accepts an optional remote block (git_url, ref, config), and it is validated.
    • plan --scope remote writes nothing. It returns these decisions:
      • lefthook-config with the snippet above;
      • lefthook-install until every entry event's hook is lefthook's and the remote is fetched;
      • migrate (from: shared), naming .githooks/guardrails/ and the old guardrails-<entry> jobs;
      • remote-needs-lefthook for husky or plain hooks;
      • remote-source-dir when the consumer's lefthook config sets its own source_dir;
      • declined and the tool decisions, as before.
    • verify reports ok only when three things hold: the config has a remotes: entry with exactly the plugin's git_url, ref and config in block or flow YAML, TOML or JSON (another ref is missing with "set ref: main", and plan returns lefthook-config with foundRef), the event hook is lefthook's, and <git-path info>/lefthook-remotes/claude-code-plugins-main/<config> exists. Otherwise it reports missing with "run lefthook install".
    • copy --scope remote is a usage error.
  • plugins/guardrails/git-hooks/lefthook-remote.yml holds the three jobs, named guardrails-remote-<entry>. entries.json gains the remote block.
  • .lefthook/<event>/guardrails-<entry>.sh at the repository root: three one-line scripts, each running the plugin's own entry script. The scripts have to live there. When a remote config sets a top-level source_dir, it overrides the consumer's own source_dir and breaks the consumer's own script jobs (evidence below). With no source_dir, lefthook looks up a remote's scripts under the remote repository's root .lefthook/.
  • skills/setup/SKILL.md: scope=shared runs plan --scope remote first. A clone-only opt-out skips the guardrails-remote-<name> job in the clone's lefthook local config, pointing at lefthook's docs for the syntax (tested with skip: true: lefthook prints "(skip) by condition"). reference/git-hook-decisions.md and the README also cover the new mode.
  • Tests:
    • 8 cases in lib/git-hooks/install.test.mjs. The first 7 were checked against the old installer by restoring HEAD's install.mjs, and all 7 failed. The source_dir case fails there too, because the old installer has no --scope remote. Review added 7 more (another ref, another host or a comment, quoted and commands: job names, local copies in a remote plan, key order with flow-style YAML, TOML and JSON configs, and source_dir in TOML and JSON); each fails on the installer before its fix.
    • New plugins/guardrails/git-hooks/lefthook-remote.test.sh. It runs 11 static checks everywhere. When lefthook is on PATH it adds end-to-end cases against a file:// stand-in: the three entries block from the fetched copy, the cache is claude-code-plugins-main, and a new commit on main reaches the consumer on lefthook install.
    • One new case in scripts/plan-test-lanes.test.sh for the lefthook need.
  • Fragments: guardrails minor, and the 9 other carriers patch.

Verification

Step 1 probe with lefthook 2.2.2 (lefthook version), run in throwaway repositories (obs-lefthook-remote-* beside the worktree). The stand-in is a local bare repository holding this branch's plugins/guardrails and .lefthook/. The consumer's lefthook.yml holds the exact snippet above, and git config url.file://<stand-in>.insteadOf https://github.com/melodic-software/claude-code-plugins points that URL at the stand-in. Findings:

Question Evidence
Where lefthook stores a remote Verbose install: git -C <repo>/.git/info/lefthook-remotes clone --quiet --origin origin --depth 1 --branch main <url> claude-code-plugins-main, then fetch --depth 1 origin -- main and checkout FETCH_HEAD. That is a shallow clone at <git common dir>/info/lefthook-remotes/<repo name>-<ref>/. A linked worktree uses the same one (git rev-parse --git-path info names the main .git/info).
How a remote job runs a remote script A script: job whose file is in the remote. The probe printed pwd=<consumer root> src=<consumer>/.git/info/lefthook-remotes/.../probe.sh args=.git/COMMIT_EDITMSG, so the script runs from the fetched copy with the consumer as its working directory and git's arguments. A run: command also runs in the consumer root, but nothing gives it the remote's path.
source_dir in a remote It merges over the consumer's: lefthook dump showed one top-level source_dir: plugins/guardrails/git-hooks/lefthook/, and the consumer's own script: mine.sh job failed with script does not exist: mine.sh. Without it, scripts resolve under the remote's root .lefthook/, and both the consumer's .lefthook/pre-commit/mine.sh and the remote's scripts ran.
The three entries from the fetched copy commit-msg: an off-pattern subject blocked (Rewrite the subject to match the pattern..., rc=1) and ABC-1: initial passed. pre-commit: notes.md:2: secret or credential pattern: GitHub PAT, rc=1. pre-push (use_stdin: true, on a branch with no upstream, pushing main): readme.md:1: stale-path-verify: cited path(s) in readme.md were deleted from this repo, rc=1. Each entry found its libraries in the plugin layout and read the consumer's index, message and .claude/source-control.md.
Same job name in two configs An old guardrails-commit-msg-convention run: job plus a remote job of that name merged into one job holding both run: and script:, which failed: either run, script, or group must be provided for a job. The remote jobs are therefore named guardrails-remote-<entry>. With different names, a half-migrated repository runs both.
Fetch failure, cache present The hook printed Couldn't sync https://github.com/melodic-software/claude-code-plugins main. Will continue with fallback version: main. and ran the cached jobs; the commit went through.
First install offline lefthook install printed Couldn't sync from ... Will continue anyway: exit status 128 and sync hooks: ✔️ but installed only prepare-commit-msg, so commits were unchecked. Restoring the network did not repair it; a second lefthook install did. verify now reports missing in this state.
ref and refetch lefthook install always fetches, for a branch and for a force-moved tag alike. A hook run within 24h does not fetch. A hook run after the cache's .git mtimes were aged 25h did fetch, for the branch and the tag alike. The ref docs warn against dropping ref once used. Per the refetch_frequency docs, "Failure to fetch does not cause an error, but just a warning message."
Consumer source_dir When a consumer sets source_dir: .hooks/, lefthook looks for the remote's scripts under .hooks/ in the fetched copy: guardrails-remote-pre-commit-content: script does not exist: guardrails-pre-commit-content.sh, and the commit fails. plan --scope remote now returns remote-source-dir for this case. None of standards' components/lefthook-*/lefthook.yml sets source_dir.
Pilot consumer (standards main at eaac7fa) plan --scope remote returned lefthook-config, lefthook-install, and migrate (from: shared, the three .githooks/guardrails/ scripts, the three guardrails-<entry> jobs). After applying them (snippet added, .githooks/guardrails/ and the three jobs removed, the pre-commit exclude line dropped), lefthook install synced commit-msg, pre-commit, pre-push and verify printed ok three times. lefthook dump showed the remote jobs merged alongside standards' commands: and hook-level exclude. A non-conventional subject blocked; a conventional one committed, with editorconfig, typos, gitleaks and guardrails-remote-pre-commit-content passing.
Invalid remote YAML Every commit in the consumer failed with Error: yaml: ... (rc=1), and lefthook install failed the same way before it refetched. To recover, run rm -rf "$(git rev-parse --git-path info)/lefthook-remotes/claude-code-plugins-main" && lefthook install once the fix is on main (also in the README) (the empty-cache reinstall above is the evidence).

Suites:

  • node --test lib/git-hooks/install.test.mjs: 60 pass.
  • bash plugins/guardrails/git-hooks/lefthook-remote.test.sh with GUARDRAILS_REQUIRE_LEFTHOOK=1 and lefthook 2.2.2: 19 pass. With lefthook stripped from PATH: a SKIP, or a FAIL when GUARDRAILS_REQUIRE_LEFTHOOK=1.
  • plan-test-lanes.test.sh 43 pass. actionlint is clean on pr-require-checks.yml.
  • Every plugins/*/git-hooks/*.test.sh and plugins/guardrails/hooks/git-hooks-notice.test.sh pass.
  • scripts/sync-shared-copies.sh --check reports 520 copies match.
  • --check-bump origin/main passes.
  • scripts/check-changelog-fragments.sh --check passes.
  • shellcheck and shfmt are clean on the new shell files.

Limitations:

  • Each consumer clone holds a depth-1 checkout of this whole repository. Measured: 188M and 12,703 files, cloned in 6 s. Lefthook remotes have no sparse checkout. Linked worktrees share one copy.
  • A broken lefthook-remote.yml on main would block every consumer's commits until it is fixed and refetched. Before merge, test-bash installs the pinned lefthook on the leg that runs lefthook-remote.test.sh (a new lefthook need in scripts/plan-test-lanes.sh) and sets GUARDRAILS_REQUIRE_LEFTHOOK=1, so that suite fails there instead of skipping.
  • verify looks for lefthook 2.2.2's observed cache path, <repo name>-<ref>, and falls back to any <repo name>-* directory holding the config, so a lefthook release that renames it still verifies.
  • A consumer with its own lefthook source_dir cannot use the remote (remote-source-dir).
  • Every consumer runs main within 24h of a merge; a change to the hooks reaches them only through a reviewed pull request whose CI ran the end-to-end test.

Related

🤖 Generated with Claude Code

kyle-sexton and others added 5 commits October 23, 2026 17:50
…emote

Shared scope with lefthook now commits one lefthook `remotes:` entry instead
of copies under .githooks/guardrails/: lefthook fetches
plugins/guardrails/git-hooks/lefthook-remote.yml and its scripts from this
repository's main and refetches them every 24h, so every consumer runs the
current hooks with no refresh pull request and no lint exclusion.

- lib/git-hooks/install.mjs (and its 10 generated copies): an optional
  `remote` block in entries.json; `plan --scope remote` returns the snippet,
  lefthook-install, migrate (from: shared) and remote-needs-lefthook
  decisions; verify reports ok only when the config carries the remote, the
  event hook is lefthook's and the remote is fetched. Plugins without the
  block are unchanged.
- .lefthook/<event>/guardrails-<entry>.sh: lefthook looks up a remote's
  scripts under the remote repository's root .lefthook/; each runs the
  plugin's own entry script.
- Remote job names are guardrails-remote-<entry>: lefthook merges a job of
  the same name across configs, and the shared-copy job's run: plus the
  remote's script: fail as one job.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lefthook looks up a remote config's scripts under the consumer's own
source_dir inside the fetched copy, so a consumer that sets one gets
"script does not exist" on every commit (probed with lefthook 2.2.2).
`plan --scope remote` now returns a remote-source-dir decision there and
setup falls back to shared copies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Consumers now fetch the guardrails hooks from refs/heads/guardrails-release
rather than main, so they run released code only (owner decision on #9504).

- release-move-guardrails-ref.yml: on a push to main that touches the
  guardrails manifest, or a manual run from main, fast-forwards
  guardrails-release to main's newest guardrails version change, creating
  it on the first run. It refuses any other ref, a target off main and a
  move that is not a fast-forward, and pushes with the job's GITHUB_TOKEN
  (contents: write on that job only), which starts no workflow.
- .github/scripts/guardrails-release-ref/move.sh decides the move; its
  test covers each case.
- verify reads the cache directory lefthook 2.2.2 names, which writes each
  "-" of the ref as "--" (claude-code-plugins-guardrails--release), and
  still accepts the unescaped name an earlier lefthook used.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…release

A broken lefthook-remote.yml on guardrails-release would block every
consumer's commits, and CI ran only the static half of its test.

- .github/scripts/guardrails-release-ref/install-lefthook.sh installs the
  fleet's lefthook 2.2.2, checked against the release's published SHA-256.
- release-move-guardrails-ref.yml runs lefthook-remote.test.sh against the
  target commit with that lefthook before it pushes, so a failing target
  stops the run.
- test-bash installs it on the leg that runs lefthook-remote.test.sh (a new
  `lefthook` need in plan-test-lanes.sh) and sets
  GUARDRAILS_REQUIRE_LEFTHOOK=1, so the end-to-end cases fail there rather
  than skip.
- README: the recovery command for a clone whose fetched remote no longer
  parses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kyle-sexton and others added 2 commits October 23, 2026 21:27
… a shadowing tag

Review fixes for the remote install mode:
- verify and plan read the remotes: entry whose git_url is exactly the
  plugin's; another ref is a lefthook-config decision (foundRef) and a
  missing verdict that says to set the ref, and another host or a comment
  no longer counts as configured.
- Leftover shared jobs are found under a quoted name or a commands: key,
  and a remote plan also lists local copies to migrate.
- The move workflow refuses while a guardrails-release tag exists, since
  consumers fetch the short name and git prefers the tag.
- The setup skill's scope question says shared lefthook runs the released
  hooks fetched daily.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… in TOML or JSON

The exact-match reader only understood YAML items that start with git_url,
so a TOML or JSON lefthook config, or reordered keys, read as unconfigured.
It now reads each remotes entry whole, in all three formats.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton
kyle-sexton marked this pull request as ready for review October 24, 2026 01:38
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-24T01:39:45.389526Z 5529a1c Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5529a1c3bc

ℹ️ 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".

Comment thread lib/git-hooks/install.mjs Outdated
Comment thread plugins/guardrails/skills/setup/SKILL.md Outdated
@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

claude-security-review reviewed 4381c64bf6ffe19dbcc4419bab1a255edf2ee82a: 0 finding(s), 0 as inline comments.

Incremental security review of 4381c64 against 7132cf3: no security issues found.

The change is a single character class edit. In lefthookRemotes (lib/git-hooks/install.mjs:579) the remotes: block regex goes from [ \t-] to [ \t#-], so a column-0 comment no longer ends the block early. The edit is carried unchanged into the 10 generated copies, and lib/git-hooks/install.test.mjs gains one regression test.

  • Commented-out entries stay inert. Line 586 strips whole-line comments (^[ \t]*#.*$) from each entry before git_url, ref and configs are read. The entry split (line 582) and indent detection (line 580) key on - at the start of a line, so a # - git_url: ... line neither starts an entry nor adds keys to the previous one. A comment cannot make verify report ok for a remote that is not configured.
  • No wider trust boundary. The parser is read-only and feeds only the verify and plan decisions. It never executes or fetches anything from the parsed text. The regex is linear, so there is no ReDoS concern.
  • Worst failure is benign. The old behavior hid later entries and could report missing. The new behavior is stricter about what counts as an entry.
  • No manifest, workflow or instruction-surface changes in this increment, so no manifest <field> lines apply. The change touches no trust-gate path.

critical-findings: 0

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

claude-review: 2 inline finding(s) on 5529a1c3bc9bbcde210dcadc740dbc26f4b9008a; the summary is in this lane's pull request comment.

claude-lane: claude-review

Comment thread lib/git-hooks/install.mjs Outdated
Comment thread lib/git-hooks/install.mjs Outdated
@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

claude-review reviewed 4381c64bf6ffe19dbcc4419bab1a255edf2ee82a: 0 finding(s), 0 as inline comments.

Incremental review of 4381c64 against 7132cf3: no findings.

The change widens the remotes: block regex in lefthookRemotes from [ \t-] to [ \t#-] at lib/git-hooks/install.mjs:579. A column-0 comment between two entries no longer ends the block and hides the entries after it. I read the function in the head file and traced the downstream steps:

  • A column-0 comment line stays inside the block and is attached to the preceding entry's raw text. raw.replace(/^[ \t]*#.*$/gm, "") strips it before any key is read, so it cannot add a git_url, ref or configs value.
  • The ^${indent}-[ \t]+ split cannot match a comment line, because the line starts with #. This holds when the indent is empty too.
  • A trailing column-0 comment after the last entry is now consumed and then stripped. A following top-level key such as pre-commit: still ends the block, since it starts with none of space, tab, # or -.

The new test a column-0 comment between remotes entries hides no entry (lib/git-hooks/install.test.mjs:754) places a column-0 comment between a foreign entry and the plugin's entry. It asserts that verify reports ok and that plan returns no lefthook-config decision. Before the fix, the block stopped at the comment and the plugin's entry was invisible, so the test targets the bug. I did not run the test suite: the lane has no shell. The 60-pass claim in the PR body is author-claimed and unverified by me.

The same one-line change appears in the 10 carrier copies (actionlint, bash-format, biome-format, go-format, guardrails, instruction-placement, markdown-format, powershell-format, ruff-format, typos-format). Each hunk in the diff is identical to the canonical one, so the shared copies stay in step. I did not run sync-shared-copies.sh --check.

No plugin.json or marketplace.json change in this increment, so no manifest lines apply. No cost or trust-gate files are touched, so there is no hold.

kyle-sexton and others added 2 commits October 23, 2026 21:41
…nd point at lefthook's local-override docs

- remotePlan read source_dir with a YAML-only expression, so a TOML or
  JSON config with its own source_dir was offered the remote, whose
  scripts it cannot find.
- The setup skill no longer restates lefthook's local-override schema;
  it points at the lefthook-local and skip pages with an as-of date and
  recheck trigger.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A configs: [a, b] list or a {git_url: ..., ref: ..., configs: [...]} item
read as no remote, so a correctly configured repository never verified and
plan offered a second entry. Comment lines inside an item are skipped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton

Copy link
Copy Markdown
Member Author

Reply to the claude-security-review finding on 5529a1c (consumers run code from an unprotected mutable branch):

Finding Classification Evidence
Nothing restricts who can move or delete guardrails-release, so any account or contents: write workflow token can ship code to every migrated consumer within 24h VALID; whether to merge before the protection lands is held for the owner (UNCERTAIN) gh api repos/melodic-software/claude-code-plugins/rulesets lists rulesets only for the default branch and release/plugins. AGENTS.md says lanes "read untrusted issue and PR text while holding push credentials", so an attacker does not need a human account. The local security review found the tag-shadowing variant; a local probe with git 2.53 confirmed it, and the workflow now refuses to move the branch while such a tag exists.

The fix is a ruleset in github-iac (branch create, update and delete; tag creation; a dedicated App bypass), tracked in #9531. That is an org trust-boundary change, so this PR does not make it. The open question for the owner is whether this PR merges before #9531 lands or waits for it. The branch comes into existence when the guardrails release PR merges, and /guardrails:setup offers the remote from that release onward. This PR is not being merged until the owner answers.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

claude-review: 1 inline finding(s) on 70f2fd904d4b8d871ffee703f3688fba34066ea5; the summary is in this lane's pull request comment.

claude-lane: claude-review

Comment thread lib/git-hooks/install.mjs
Comment thread .github/workflows/pr-require-checks.yml
Comment thread .github/workflows/release-move-guardrails-ref.yml Outdated
Comment thread lib/git-hooks/install.mjs
…ase branch

Owner decision: consumers' lefthook remote fetches main, which changes only
through reviewed pull requests under main's rulesets with the remote's
end-to-end test in PR CI. entries.json `remote.ref` is now `main` (cache
dir claude-code-plugins-main), and the guardrails-release branch, its move
workflow, move.sh and its test are removed. The pinned lefthook installer
moves to .github/scripts/pr-require-checks/, still used by test-bash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton

Copy link
Copy Markdown
Member Author

Follow-up on the claude-security-review finding (consumers run code from an unprotected mutable branch), after the owner's decision:

Finding Classification Evidence
Nothing restricts who can move or delete guardrails-release INCORRECT as of ab4c635 (the branch no longer exists in this design) ab4c635 sets entries.json remote.ref to main and removes release-move-guardrails-ref.yml, move.sh and its test. Consumers now track main, which changes only through reviewed pull requests under main's existing rulesets. lefthook-remote.test.sh runs end to end in PR CI: test-bash installs the pinned lefthook and sets GUARDRAILS_REQUIRE_LEFTHOOK=1.

No branch is left to protect, so the follow-up #9531 is closed.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

claude-security-review: 1 inline finding(s) on ab4c635855894b3b3c4be382be917eedc0bf6808; the summary is in this lane's pull request comment.

claude-lane: claude-security-review

Comment thread plugins/guardrails/git-hooks/entries.json
kyle-sexton and others added 2 commits October 23, 2026 22:32
…consumer

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a renamed lefthook cache

- A key named in a trailing comment (`# pinned, ref: develop`) no longer
  shadows the entry's real key.
- verify falls back to any <repo name>-* directory under lefthook-remotes
  that holds the config, so a lefthook that renames its cache still
  verifies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton
kyle-sexton enabled auto-merge October 24, 2026 02:35

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

claude-review: 1 inline finding(s) on 0267d3510d05f7e93a42cb5503216963e93a8a80; the summary is in this lane's pull request comment.

claude-lane: claude-review

Comment thread lib/git-hooks/install.mjs Outdated
Comment thread plugins/guardrails/README.md
Comment thread plugins/guardrails/git-hooks/entries.json

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

claude-security-review: 1 inline finding(s) on 7132cf3619ae1defcbf23bd86d8f981609d6c0d0; the summary is in this lane's pull request comment.

claude-lane: claude-security-review

Comment thread plugins/guardrails/git-hooks/entries.json

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

claude-review: 1 inline finding(s) on 7132cf3619ae1defcbf23bd86d8f981609d6c0d0; the summary is in this lane's pull request comment.

claude-lane: claude-review

Comment thread lib/git-hooks/install.mjs Outdated
A column-0 comment inside the YAML remotes: block ended the block, so
later entries went unparsed and plan offered a duplicate remote.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton
kyle-sexton added this pull request to the merge queue Oct 24, 2026
Merged via the queue into main with commit 47a5e84 Oct 24, 2026
43 checks passed
@kyle-sexton
kyle-sexton deleted the feat/guardrails-lefthook-remote branch October 24, 2026 03:58
kyle-sexton added a commit to melodic-software/codex-plugins that referenced this pull request Oct 24, 2026
…lugins lefthook remote (#148)

No related issue: rolls out the guardrails lefthook remote
(claude-code-plugins#9504)

## Summary

Runs the guardrails plugin's three git hooks in this repository from one
lefthook `remotes:` entry, so every clone gets the same hooks from
`lefthook install` and they update from `claude-code-plugins` main every
24 hours, with no vendored copies:

- `commit-msg-convention` (commit-msg): the subject against the synced
commit convention
(`docs/conventions/source-control/commit-convention.yml`).
- `pre-commit-content` (pre-commit): secrets and machine-specific paths
on added lines.
- `reference-verify` (pre-push): CLI flags, `/plugin:skill` references
and deleted paths on pushed lines.

No plugin component changes, so the plugin documentation preflight in
`AGENTS.md` does not apply; this is repository tooling only.

## Fix

- `lefthook.yml` (new; the repository had none): one `remotes:` entry,
`git_url: https://github.com/melodic-software/claude-code-plugins`,
`ref: main`, `refetch_frequency: 24h`, `configs:
[plugins/guardrails/git-hooks/lefthook-remote.yml]`, from `install.mjs
plan --scope remote`.
- Nothing else differs from `main`: the earlier vendored
`.githooks/guardrails/` copies, their lefthook jobs, the README layout
lines and the `.claude/source-control.md` `subject_pattern` are gone
(the synced commit convention supplies the pattern).
- Installer `no-ci-rerun` decision: no CI workflow here runs
`jq`/`reference-verify`, so a commit pushed without the hook is not
re-checked in CI.

## Verification

`install.mjs verify --repo <worktree>` after `lefthook install` (rc 0):

```
ok	commit-msg-convention
ok	pre-commit-content
ok	reference-verify
```

A second `plan --scope remote` returns no `lefthook-config` or `migrate`
decision. This PR's commit ran the remote `commit-msg` and `pre-commit`
hooks and the push ran `guardrails-remote-reference-verify`.

Observation runs against this repository's history in report-only mode,
before blocking (the remote serves the same hook scripts, so this
evidence holds):

| Hook | Observation | Findings | Classification |
|---|---|---|---|
| `reference-verify` | pre-push replay of `origin/main~137..origin/main`
(whole history, 138 commits), 35 changed `.md`/`.sh`/`.ps1` files, 3 s |
0 | none; largest scanned file is 46,507 bytes, under the 128 KiB
argument limit |
| `pre-commit-content` | each of the last 100 non-merge commits replayed
into the index (1 to 15 staged files each, that commit's own), 14 s
total | 1 commit (09e5a79, #119) | narrowly justified exception:
`validate-marketplace.test.mjs:773` feeds `C:\Users\alice\plugin` to the
validator as test input it must reject. Current content is clean; a
future edit of that line would block. Repo-side exemption list tracked
as item 5 of
[claude-code-plugins#9426](melodic-software/claude-code-plugins#9426)
|
| `commit-msg-convention` | subject pattern tested against all 138
subjects on main | 1 non-matching: `Initial commit` | narrowly justified
exception: the repository's root commit, historical only |

## Related

-
[claude-code-plugins#9504](melodic-software/claude-code-plugins#9504):
the lefthook remote config this entry points at.
-
[claude-code-plugins#9426](melodic-software/claude-code-plugins#9426):
the rollout and the installer defects it tracks.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
kyle-sexton added a commit to melodic-software/cursor-plugins that referenced this pull request Oct 24, 2026
…lugins lefthook remote (#126)

No related issue: rolls out the guardrails lefthook remote
(claude-code-plugins#9504)

## Summary

Runs the guardrails plugin's three git hooks in this repository from one
lefthook `remotes:` entry, so every clone gets the same hooks from
`lefthook install` and they update from `claude-code-plugins` main every
24 hours, with no vendored copies:

- `commit-msg-convention` (commit-msg): the subject against the synced
commit convention
(`docs/conventions/source-control/commit-convention.yml`).
- `pre-commit-content` (pre-commit): secrets and machine-specific paths
on added lines.
- `reference-verify` (pre-push): CLI flags, `/plugin:skill` references
and deleted paths on pushed lines.

These are repository git hooks, not a plugin port or Cursor plugin
hooks, so the trust-review rule for ports that add MCP servers or hooks
does not apply.

## Fix

- `lefthook.yml` (new): one `remotes:` entry, `git_url:
https://github.com/melodic-software/claude-code-plugins`, `ref: main`,
`refetch_frequency: 24h`, `configs:
[plugins/guardrails/git-hooks/lefthook-remote.yml]`, from `install.mjs
plan --scope remote`.
- Nothing else differs from `main`: the earlier vendored
`.githooks/guardrails/` copies, their lefthook jobs, the README layout
lines and the new `.claude/source-control.md` are gone (the synced
commit convention supplies the pattern).

## Verification

`install.mjs verify --repo <worktree>` after `lefthook install` (rc 0):

```
ok	commit-msg-convention
ok	pre-commit-content
ok	reference-verify
```

A second `plan --scope remote` returns no decisions. This PR's commit
ran `guardrails-remote-pre-commit-content` and
`guardrails-remote-commit-msg-convention`, and its push ran
`guardrails-remote-reference-verify`, all passing.

Observation runs against this repository's history in report-only mode
(the remote serves the same hook scripts, so this evidence holds):

| Hook | Observation | Findings | Classification |
|---|---|---|---|
| `reference-verify` | pre-push replay of `origin/main~121..origin/main`
(the repo has 122 commits), 52 changed files, 3 s | 0 | none |
| `pre-commit-content` | each of the last 100 non-merge commits replayed
into the index (every replay staged 1 or more files, only that
commit's), 8 s total | 1 commit (3ef6f19, #23): 4 lines | narrowly
justified exception: `scripts/sync-local.sh` and
`plugins/plugin-ops/skills/sync-local/SKILL.md` name the `D:\`/`C:\`
`repos\github.com\melodic-software\cursor-plugins` checkouts in the
deliberate, fixed fallback list `sync-local` tries when no `-Source` is
given (README, Install / update). Current content still has them, so a
future edit of those lines would block. Whether that fallback list fits
the plugin design boundary (no machine paths) is a separate question for
the owner |
| `commit-msg-convention` | subject pattern against all 122 subjects on
main | 2 non-matching | pre-convention history: `Add Cloud Agent
environment for cursor-plugins (#18)` and `Initial commit` |

## Related

-
[claude-code-plugins#9504](melodic-software/claude-code-plugins#9504):
the lefthook remote config this entry points at.
-
[claude-code-plugins#9426](melodic-software/claude-code-plugins#9426):
the rollout and the installer defects it tracks.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
kyle-sexton added a commit to melodic-software/standards that referenced this pull request Oct 24, 2026
…lugins lefthook remote (#865)

No related issue: rolls out the guardrails lefthook remote
(melodic-software/claude-code-plugins#9504)

## Summary

The guardrails git hooks now run from one lefthook `remotes:` entry
tracking `melodic-software/claude-code-plugins` `main` (refetched daily)
instead of copies vendored under `.githooks/guardrails/` by #852. Every
clone gets the same hooks from committed config, with nothing per
machine and no copies to drift.

## Fix

- `lefthook.yml`: add the `remotes:` entry; drop the three
`guardrails-<entry>` jobs and the `.githooks/guardrails/**` pre-commit
exclude.
- Delete `.githooks/guardrails/` (16 files).
- `pr-require-checks.yml`: drop the `.githooks/guardrails` ShellCheck
and machine-path excludes.
- `components/commit-convention/commit-convention.test.sh`: fetch the
guardrails plugin from claude-code-plugins `main` (sparse, depth 1) for
the resolver and commit-msg hook, the same ref consumers run. The suite
already needed network for the check-contract action.

## Verification

- `install.mjs verify`: `ok` for commit-msg-convention,
pre-commit-content, reference-verify; `plan --scope remote` returns no
decisions.
- This commit ran `guardrails-remote-pre-commit-content` and
`guardrails-remote-commit-msg-convention` from the fetched remote; both
passed.
- `bash harness/shell/run-tests.sh
components/commit-convention/commit-convention.test.sh`: 1 passed.

## Related

- melodic-software/claude-code-plugins#9504
(remote mode)
-
melodic-software/claude-code-plugins#9426 (comment)
(owner decision: `ref: main`)
- #852 (the copies this removes)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
kyle-sexton added a commit to melodic-software/agent-plugins that referenced this pull request Oct 24, 2026
…lugins lefthook remote (#108)

No related issue: rolls out the guardrails lefthook remote
(claude-code-plugins#9504)

## Summary

Runs the guardrails plugin's three git-hook entries in every clone of
this repository from one committed lefthook `remotes:` entry, so each
machine gets the same hooks from `lefthook install` and picks up
upstream fixes automatically:

- `commit-msg-convention` (commit-msg): the subject against the rule in
`docs/conventions/source-control/commit-convention.yml`.
- `pre-commit-content` (pre-commit): secrets and machine-specific paths
on added lines.
- `reference-verify` (pre-push): CLI flags, `/plugin:skill` references
and deleted paths on pushed lines.

## Fix

- `lefthook.yml` (new; the repository had no hook manager): one
`remotes:` entry, `git_url:
https://github.com/melodic-software/claude-code-plugins`, `ref: main`,
`refetch_frequency: 24h`, config
`plugins/guardrails/git-hooks/lefthook-remote.yml`.
- That is the whole diff against `main`. The earlier revision of this PR
vendored copies under `.githooks/guardrails/` and added a
`.claude/source-control.md` carrying `subject_pattern`; both are gone.
The subject rule now comes from the standards-synced
`commit-convention.yml`.
- No other changes kept.

## Verification

- `install.mjs verify --repo <worktree>` (rc 0):
  ```
  ok	commit-msg-convention
  ok	pre-commit-content
  ok	reference-verify
  ```
- `install.mjs plan --scope remote` afterwards: no decisions left.
- `lefthook install`: `sync hooks: ✔️(pre-push, commit-msg,
pre-commit)`. This PR's commit ran the remote `pre-commit-content` (0.04
s) and `commit-msg-convention` (0.04 s), and its push ran
`reference-verify`.

Observation runs from the earlier revision, still valid because the
remote runs the same hook scripts:

| Hook | Observation | Findings | Classification |
|---|---|---|---|
| `reference-verify` | pre-push replay of `origin/main~100..origin/main`
(102 commits in all), 20 changed files, 5 of them `.md`/`.sh`, 0.5 s | 0
| none |
| `pre-commit-content` | each of the last 100 non-merge commits replayed
into the index (179 staged paths in all, no replay empty), 7 s total | 0
| none |
| `commit-msg-convention` | subject rule tested against all 102 subjects
on main | 1 non-matching: `Initial commit` | narrowly justified
exception: the repository's root commit, written before the convention;
no later subject misses |

## Related

-
[claude-code-plugins#9504](melodic-software/claude-code-plugins#9504):
the lefthook remote config this points at.
-
[claude-code-plugins#9426](melodic-software/claude-code-plugins#9426):
rollout tracking and known hook defects.
-
[standards#852](melodic-software/standards#852):
the pilot.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
kyle-sexton added a commit to melodic-software/ci-runner that referenced this pull request Oct 24, 2026
…lugins lefthook remote (#493)

No related issue: rolls out the guardrails lefthook remote
(claude-code-plugins#9504)

## Summary

Runs the guardrails plugin's three git-hook entries in every clone of
this repository from one committed lefthook `remotes:` entry, so each
machine gets the same hooks from `lefthook install` and picks up
upstream fixes automatically:

- `commit-msg-convention` (commit-msg): the subject against the rule in
`docs/conventions/source-control/commit-convention.yml`.
- `pre-commit-content` (pre-commit): secrets and machine-specific paths
on added lines.
- `reference-verify` (pre-push): CLI flags, `/plugin:skill` references
and deleted paths on pushed lines.

## Fix

- `lefthook.yml` (new; the repository had no hook manager): one
`remotes:` entry, `git_url:
https://github.com/melodic-software/claude-code-plugins`, `ref: main`,
`refetch_frequency: 24h`, config
`plugins/guardrails/git-hooks/lefthook-remote.yml`.
- That is the whole diff against `main`. The earlier revision of this PR
vendored copies under `.githooks/guardrails/` and needed ShellCheck,
shfmt and machine-path exclusions for them in
`.github/workflows/pr-require-checks.yml`, plus a `subject_pattern` in
`.claude/source-control.md`; all of that is gone. The subject rule now
comes from the standards-synced `commit-convention.yml`.
- No other changes kept.

## Verification

- `install.mjs verify --repo <worktree>` (rc 0):
  ```
  ok	commit-msg-convention
  ok	pre-commit-content
  ok	reference-verify
  ```
- `install.mjs plan --scope remote` afterwards: no decisions left.
- `lefthook install`: `sync hooks: ✔️(commit-msg, pre-push,
pre-commit)`. This PR's commits ran the remote `pre-commit-content` and
`commit-msg-convention`, and its push ran `reference-verify`.

Observation runs from the earlier revision, still valid because the
remote runs the same hook scripts:

| Hook | Observation | Findings | Classification |
|---|---|---|---|
| `reference-verify` | pre-push replay of
`origin/main~200..origin/main`, 28 changed `.md`/`.sh`/`.ps1` files, 6 s
| 0 | none; no file in the range exceeds the argument-size limit
(largest `README.md`, 31,947 bytes) |
| `pre-commit-content` | each of the last 100 non-merge commits replayed
into the index (1 to 65 staged files each; every count matches that
commit's own change list, renames counted once), 10 s total | 0 | none.
A planted `/home/<name>/...` probe was caught (rc 1), so the replay
exercises the check |
| `commit-msg-convention` | subject rule tested against the last 500
subjects on main (all 308) | 1 non-matching: `Initial commit` | narrowly
justified exception: GitHub's repository-creation commit, never made
through a hook |

## Related

-
[claude-code-plugins#9504](melodic-software/claude-code-plugins#9504):
the lefthook remote config this points at.
-
[claude-code-plugins#9426](melodic-software/claude-code-plugins#9426):
rollout tracking and known hook defects.
-
[standards#852](melodic-software/standards#852):
the pilot.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
kyle-sexton added a commit to melodic-software/.github that referenced this pull request Oct 24, 2026
…lugins lefthook remote (#211)

No related issue: rolls out the guardrails lefthook remote
(claude-code-plugins#9504)

## Summary

Runs the guardrails plugin's three git-hook entries in every clone of
this repository from one committed lefthook `remotes:` entry, so each
machine gets the same hooks from `lefthook install` and picks up
upstream fixes automatically:

- `commit-msg-convention` (commit-msg): the subject against the rule in
`docs/conventions/source-control/commit-convention.yml`.
- `pre-commit-content` (pre-commit): secrets and machine-specific paths
on added lines.
- `reference-verify` (pre-push): CLI flags, `/plugin:skill` references
and deleted paths on pushed lines.

## Fix

- `lefthook.yml` (new; the repository had no hook manager): one
`remotes:` entry, `git_url:
https://github.com/melodic-software/claude-code-plugins`, `ref: main`,
`refetch_frequency: 24h`, config
`plugins/guardrails/git-hooks/lefthook-remote.yml`.
- That is the whole diff against `main`. The earlier revision of this PR
vendored copies under `.githooks/guardrails/` and needed:
- ShellCheck exclusions for them in
`.github/workflows/pr-require-checks.yml` and `.cursor/check.sh`.
  - A README note describing them.
  - A regex `subject_pattern` in `.claude/source-control.md`.

All of that is gone. The subject rule now comes from the
standards-synced `commit-convention.yml`.
- No other changes kept.

## Verification

- `install.mjs verify --repo <worktree>` (rc 0):
  ```
  ok	commit-msg-convention
  ok	pre-commit-content
  ok	reference-verify
  ```
- `install.mjs plan --scope remote` afterwards: no configuration
decisions left, only the advisory `no-ci-rerun`: no CI workflow re-runs
reference-verify's jq check.
- `lefthook install`: `sync hooks: ✔️(pre-commit, commit-msg,
pre-push)`. This PR's commit ran the remote `pre-commit-content` (0.11
s) and `commit-msg-convention` (0.03 s), and its push ran
`reference-verify`.

Observation runs from the earlier revision, still valid because the
remote runs the same hook scripts:

| Hook | Observation | Findings | Classification |
|---|---|---|---|
| `reference-verify` | pre-push replay of `origin/main~182..origin/main`
(whole history after the root commit; 24 changed `.md`/`.sh`/`.ps1`
files), 2 s | 0 | none |
| `pre-commit-content` | each of the last 100 non-merge commits replayed
into the index (1 to 18 staged files per commit, none empty), 8 s total
| 0 | none |
| `commit-msg-convention` | subject rule tested against all 183 subjects
on main | 1 non-matching: `Initial commit` (root commit) | narrowly
justified exception: the repository's creation commit, never re-checked
|

## Related

-
[claude-code-plugins#9504](melodic-software/claude-code-plugins#9504):
the lefthook remote config this points at.
-
[claude-code-plugins#9426](melodic-software/claude-code-plugins#9426):
rollout tracking and known hook defects.
-
[standards#852](melodic-software/standards#852):
the pilot.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
kyle-sexton added a commit to melodic-software/.github that referenced this pull request Oct 24, 2026
No related issue: follow-up to a review finding on #211
(claude-code-plugins#9504 rollout)

## Summary

Lists `lefthook.yml` in README's "What's here" inventory, which the
tracked-file inventory rule (`AGENTS.md`, Code Review Rules) requires
for every added file.

## Fix

- `README.md`: new **Git hooks** bullet. `lefthook.yml` holds one
`remotes:` entry running the guardrails hooks from
`claude-code-plugins`, and the hook scripts are owned there.

## Verification

- This commit ran the remote `pre-commit-content` and
`commit-msg-convention` hooks (both pass); the push ran
`reference-verify`.
- Addresses the [Codex finding on
#211](#211 (comment)).

## Related

- [#211](#211): added
`lefthook.yml`.
-
[claude-code-plugins#9504](melodic-software/claude-code-plugins#9504):
the remote config.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
kyle-sexton added a commit to melodic-software/claude-code-account-rotation that referenced this pull request Oct 24, 2026
…lugins lefthook remote (#331)

No related issue: rolls out the guardrails lefthook remote
(claude-code-plugins#9504)

## Summary

Runs the guardrails plugin's three git hooks in this repository from one
lefthook `remotes:` entry, so every clone gets the same hooks from
committed config and picks up upstream changes within 24 h:

- `commit-msg-convention` (commit-msg): the subject against the
repository's commit convention
(`docs/conventions/source-control/commit-convention.yml`).
- `pre-commit-content` (pre-commit): secrets and machine-specific paths
on added lines.
- `reference-verify` (pre-push): CLI flags, `/plugin:skill` references
and deleted paths on pushed lines.

## Fix

- `lefthook.yml` (new; the repository had no root lefthook config): only
a `remotes:` entry for
`https://github.com/melodic-software/claude-code-plugins`, `ref: main`,
`refetch_frequency: 24h`, config
`plugins/guardrails/git-hooks/lefthook-remote.yml`. The synced
`.lefthook/base.yml` and `.lefthook/dotnet.yml` fragments stay unwired,
as before.
- Compared with the earlier revision of this PR, removed: the vendored
`.githooks/guardrails/` copies, the three local `guardrails-*` jobs, and
the new `.claude/source-control.md` with its `subject_pattern` (main now
carries `commit-convention.yml`).
- No other change.

## Verification

`install.mjs verify --repo <worktree>` (rc 0):

```text
ok	commit-msg-convention
ok	pre-commit-content
ok	reference-verify
```

- `install.mjs plan --scope remote` afterwards: no `lefthook-config` or
`migrate` decision left. This PR's commit ran
`guardrails-remote-pre-commit-content` (0.06 s) and
`guardrails-remote-commit-msg-convention` (0.04 s); its push ran
`guardrails-remote-reference-verify` (0.07 s).
- `install.mjs plan` reports the advisory `no-ci-rerun` for
`reference-verify` (`jq`): no CI workflow here runs it, so a skipped
push is not re-checked in CI.

Observation runs from the earlier revision still hold, since the remote
runs the same hook scripts:

| Hook | Observation | Findings | Classification |
|---|---|---|---|
| `reference-verify` | pre-push replay of
`origin/main~200..origin/main`, 39 changed `.md`/`.sh`/`.ps1` files, 14
s | 0 | none; largest file in range `CHANGELOG.md` at 79,256 bytes,
under the 128 KiB argument limit |
| `pre-commit-content` | each of the last 100 non-merge commits replayed
into the index (1 to 29 staged files each), 20 s total | 0 | none |
| `commit-msg-convention` | `subject_pattern` tested against all 234
subjects on main | 1 non-matching: `Initial commit` (the root commit) |
narrowly justified exception: the repository's first commit, never
repeated |

## Related

-
[claude-code-plugins#9504](melodic-software/claude-code-plugins#9504):
the lefthook remote config this points at.
-
[claude-code-plugins#9426](melodic-software/claude-code-plugins#9426):
the rollout and its recorded design decision.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant