Problem
LLM-assisted coding silently ships whatever package version the model remembers from training. That produces hallucinated versions that never existed, stale two-year-old pins, silent downgrades to vulnerable builds when the model "fixes" CI, and no audit trail of why a version was chosen. For a supply-chain-conscious team, that's not a style issue - it's an unreviewed dependency decision made by a language model.
Approach
A Claude Code PreToolUse hook intercepts every edit to a dependency
manifest before it lands. If the change adds, bumps or downgrades a package
without a fresh, source-cited version check on record, the tool call is
rejected with exit 2 - Claude must look the version up (WebSearch,
registry page), record it with /vs-record, then retry the edit.
Claude edits package.json ──► PreToolUse hook
│
check log fresh? ──── yes ──► edit lands
│
no
│
exit 2: BLOCKED ──► WebSearch latest
│
/vs-record (source cited)
│
retry ──► edit landsThe check log is the audit trail: package, version, source URL, timestamp. Five ecosystems are covered in v0.1 - npm, pip, Poetry/uv, Cargo, NuGet.
Tradeoffs
- Hard-fail over advisory. Dependabot-style tools review after the fact; a blocking hook adds friction on every dependency change. The friction is the feature - an advisory the model can ignore protects nothing.
- Shell, not a runtime. The hook is plain shell for zero-dependency portability into any repo - at the cost of richer diffing a runtime language would allow.
- Doesn't fight intent. Pinning an old version on purpose stays possible; the requirement is a fresh, cited decision, not a new version.
Outcome
Released on GitHub under MIT with tagged releases. Dogfooded continuously -
including on this site, where every dependency in package.json was
registry-verified before install.