Skip to content

ci: validate and test Claude Code mods, and auto-bump the pinned CLI - #1564

Merged
potiuk merged 1 commit into
apache:mainfrom
potiuk:ci/claude-mod-checks
Oct 9, 2026
Merged

potiuk merged 1 commit into
apache:mainfrom
potiuk:ci/claude-mod-checks

Conversation

@potiuk

@potiuk potiuk commented Oct 9, 2026

Copy link
Copy Markdown
Member

Summary

Runs claude plugin validate --strict and claude plugin test on every Claude Code mod in the tree, and keeps the Claude Code version that checks them current.

Claude Code loads a hooks module only after its static analysis passes, and silently skips one that fails. A mod that cannot load therefore passes every other check here and does nothing on an adopter's machine. #1552 is that case today: its module imports node:fs, and its tests (node:test) pass under plain node. Step 3 of #1497 asked for these two commands in prek / CI; docs/when-to-use-mods.md already required them, with nothing enforcing it.

  • check-claude-mods (tools/dev/check-claude-mods.sh): validates and tests every plugin whose hooks/hooks.json declares modules. A mod with no *.test.ts fails. A no-op while the tree has no mod, which is the case on main today.
    • language: node, with @anthropic-ai/claude-code pinned in additional_dependencies, so prek installs it like lychee's toolchain: no local install, no login, no network beyond the npm install.
    • stages: [manual], so commits never fetch the ~220 MB binary. pre-commit.yml runs it in a step of its own, over the whole repo, on every PR and every push to main. Whole repo because a pin bump touches no mod file but has to re-check every mod.
  • check-claude-mods-local: the same script on ordinary commits, with the contributor's own claude. It skips when Claude Code is not installed or cannot run, and when the local version is older than the pin (an older CLI may not know events a mod uses). A newer one runs. CI skips this hook; the pinned run is authoritative.
  • bump-hook-npm-pins.yml + tools/dev/bump-hook-npm-pins.py: Dependabot's pre-commit ecosystem never touches additional_dependencies, so this moves those npm pins to the newest stable release past the package's cooldown, never backwards. Runs Monday / Wednesday / Friday and on demand. One fixed branch and one draft PR: a later bump updates the open PR in place (fresh signed commit on current main, back to draft so marking it ready starts the checks), and a run matching what the PR already carries changes nothing.
  • Cooldown: 7 days by default, matching .github/dependabot.yml; 12 hours for Claude Code. A cooldown buys time for a bad or compromised release to be withdrawn. Claude Code ships several times a day and replaces a bad release within hours, and a security problem in it is fixed by the next release, so a week-long wait would hold CI on the known-bad version rather than protect it. Adopters auto-update, so the check also has to track what they actually run.
  • docs/when-to-use-mods.md gains the import rule, the note on keeping a settings hook wired in hooks.json next to modules, and the CI and bump details. tools/dev/README.md gets rows for both scripts.

Claude Code is a dev-only tool here

Claude Code (@anthropic-ai/claude-code, licensed under Anthropic's terms rather than an open-source licence) is used only as a CI and developer check for Claude Code mods. It is not a dependency of anything Magpie ships: nothing from it is bundled, vendored, or redistributed in a release, a source archive, or a plugin. The local hook uses a contributor's own install when one exists and skips otherwise, so contributing to Magpie does not require it.

Type of change

  • Skill change (.claude/skills/<name>/) — eval fixtures updated below
  • Tool / bridge contract (tools/<system>/*.md)
  • Python package (tools/*/ with pyproject.toml)
  • Groovy reference impl
  • Cross-cutting (RFC, AGENTS.md, sandbox, privacy-LLM)
  • Documentation (docs/, README.md, CONTRIBUTING.md)
  • Project template (projects/_template/)
  • CI / dev loop (prek, workflows, validators)
  • Other

Test plan

  • prek run --all-files passes.
  • tools/dev/tests/test_bump_hook_npm_pins.py: 6 tests (cooldown, pre-releases, numeric ordering, never backwards, only exact pins in additional_dependencies).
  • Pinned hook on main's tree: passes (no mods).
  • Pinned hook with feat(setup): add zero-token setup drift check Claude Code mod (part of #1497) #1552's hooks/ files dropped in: fails on node:fs (validate) and node:test (test).
  • Local hook with a local Claude Code 2.1.295: same failures. Skip paths checked: no claude on PATH, claude present but not runnable, local older than the pin.
  • Both commands run with no login and CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1, against a throwaway config dir.
  • bump-hook-npm-pins.py run live against npm: moved the pin 2.1.292 -> 2.1.295, the commit in this PR.
  • bump-hook-npm-pins.yml needs main and Actions to run; its first scheduled or manual run after merge is the real test.

RFC-AI-0004 compliance

  • HITL — the bump workflow opens or updates a draft PR; nothing merges without a maintainer marking it ready and merging.
  • Sandbox — the check runs no network beyond the npm install, and uses a throwaway Claude Code config dir rather than ~/.claude.
  • Vendor neutrality — the check applies only to Claude Code mods, which are additive per docs/when-to-use-mods.md; no skill depends on it.
  • Conversational + correctable — N/A (CI tooling).
  • Write-access discipline — N/A (no outbound messages).
  • Privacy LLM — N/A (no model calls; neither command signs in or reaches a model).

Linked issues

Refs #1497 (step 3). Will make #1552's CI fail until its module uses the mods API.


Was generative AI tooling used to co-author this PR?
  • Yes — Claude Code (Opus 5)

Generated-by: Claude Code (Opus 5) following the guidelines

🤖 Generated with Claude Code

Claude Code loads a hooks module only after its static analysis passes
and silently skips one that fails, so a mod that cannot load passed
every check here and did nothing on an adopter's machine.

- check-claude-mods runs `claude plugin validate --strict` and
  `claude plugin test` on every plugin whose hooks/hooks.json declares
  `modules`, with Claude Code pinned in the prek hook env. It is in the
  manual stage, so commits never fetch the binary; the prek workflow
  runs it over the whole repo on every PR and push to main.
- check-claude-mods-local runs the same check on ordinary commits with
  the contributor's own Claude Code, skipping when it is absent or older
  than the pin.
- bump-hook-npm-pins.yml moves npm pins in hooks' additional_dependencies
  (which Dependabot never touches) three times a week, keeping a single
  draft PR updated in place. The cooldown is 7 days by default and 12
  hours for Claude Code, which replaces a bad or vulnerable release
  within hours.

Claude Code is a dev-only tool here: nothing from it ships in a release
or a plugin.

Generated-by: Claude Opus 5
@github-actions github-actions Bot added family:tools tools/* family:docs Docs, MISSION.md, READMEs family:ci .github workflows, prek, validators substrate:framework-dev Tool substrate: build / validate / eval the framework itself labels Oct 9, 2026
@potiuk
potiuk merged commit 562004f into apache:main Oct 9, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

family:ci .github workflows, prek, validators family:docs Docs, MISSION.md, READMEs family:tools tools/* substrate:framework-dev Tool substrate: build / validate / eval the framework itself

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant