feat(cli): resolve hook registration at install, and on demand - #100
Merged
MajorLift merged 1 commit intoJul 31, 2026
Merged
Conversation
Copying a hook does not activate it. Claude Code runs one only once it is registered in settings.json, and the path to register is absolute — different per machine and per consumer repo — so the setup doc could only ever say `/absolute/path/to/...` and leave the reader to work it out. `tools/install` now prints the registration when any installed skill ships a hook, with every path resolved against the actual install. `metamask-skills hooks` prints the same thing on demand, for anyone who scrolled past it or is re-registering later. The output is valid JSON as printed. An earlier version emitted a trailing comma and told the reader to remove it, which is a worse thing to hand someone than no JSON at all. Neither surface writes to settings.json. Editing a user's operator config is a larger permission than "copy files into the repo you pointed me at", and worth deciding deliberately rather than inheriting as a side effect of shipping one hook.
MajorLift
merged commit Jul 31, 2026
c579591
into
jongsun/ci/ship-hooks-and-trigger-check
28 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #99, which is what makes
hooks/reach a consumer at all. Base is #99's branch, notmain— review that one first.The gap
Copying a hook does not activate it. Claude Code runs one only once it is registered in
settings.json, and the path to register is absolute — different per machine, per consumer repo, and permms-prefixed skill directory. So the setup reference could only ever say:and leave the reader to work out what that is. Meanwhile
evidencecites the hook twice in its body as its enforcement mechanism, so someone installing it reasonably assumes the gate is live. It isn't.Two surfaces, one output
At install — when any installed skill ships a hook,
tools/installprints the registration with every path resolved against the actual install:On demand —
metamask-skills hooks [--target <path>]prints the same thing, for anyone who scrolled past it or is re-registering later. Says "No installed skill ships a hook" rather than printing empty JSON, and exits non-zero only when the target has no installed skills at all.What it deliberately does not do
Neither surface writes to
settings.json. Editing a user's operator config is a materially larger permission than "copy files into the repo you pointed me at", and it should be decided deliberately rather than inherited as a side effect of shipping one hook. This is also the only hook in the corpus — a sample of one is thin evidence for automating a write to$HOME.Test plan
yarn test— 69 pass / 0 fail across three fileshooks/evidence-gate.py: file delivered, registration printed, path resolvedJSON.parse, matcher and command checkedmetamask-skills hooksemits the same registrationNote
An earlier version emitted a trailing comma and told the reader to delete it. Handing someone JSON that doesn't parse is worse than handing them none, so the entries are joined properly and the output is valid as printed.