Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Record a vetted Hex package version in hex_vet.exs after a security review — manages the audit ledger, not the scanner. Use to approve a dep after phx-deps-audit findings or to initialize hex_vet.exs.
.claude/skills/oliver-kriska-phx-deps-vet/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-06 | ✗→✓ | ▲ Improved | 125% | 0% |
| case-12 | ✗→✓ | ▲ Improved | -6% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 12% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 31% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 65% | 0% |
Review a Hex package version, run Phase 1 supply-chain rules against it, prompt the user for a verdict, append the result to hex_vet.exs (project-root audit ledger). Vetted versions get downgraded to INFO on subsequent /skill:phx-deps-audit runs.
Run this AFTER /skill:phx-deps-audit to clear findings. Run this BEFORE merging a mix.lock PR to certify new versions.
text/skill:phx-deps-vet phoenix 1.7.21 # vet a single package version /skill:phx-deps-vet --seed # import curated baseline seed (~30 pkgs) /skill:phx-deps-vet --list # show existing ledger entries /skill:phx-deps-vet --check # cross-check mix.lock vs ledger
AskUserQuestionconfirmation. Drive-by trust ruins the ledger's value.
mix.lock has version X and theledger vets X-1, emit INFO and treat X as unvetted. Don't silently trust the older entry.
hex_vet.exs is a first-classsecurity artifact, visible in PR review. Don't move it into .claude/.
inspect/2. When appending, read the file withCode.eval_file/1, mutate the map, and write back via inspect(term, pretty: true, limit: :infinity). Hand-rolled string appends drift over time.
being vetted. No silent :safe_to_deploy defaults.
an AskUserQuestion (criteria split, new/overwrite/no-op) MUST be derived from the loaded data before prompting — e.g. Enum.frequencies_by(seed.audits, & &1.criteria). Eyeballing the file and approving on wrong numbers corrupts the consent.
hex_vet.exstextIf hex_vet.exs exists at project root: Read it via Code.eval_file/1 Else: Write the empty-ledger stub (see references/hex-vet.md §"Empty ledger") Inform user: "Created hex_vet.exs at project root."
<pkg> <version> → single-vet path (Step 3-7).--seed → import priv/hex_vet_seed.exs. Before prompting,Code.eval_file/1 the seed and compute (Iron Law #6): the criteria split (Enum.frequencies_by(seed.audits, & &1.criteria)) and, against any existing ledger, exact new / overwrite / no-op counts. Put those computed numbers in the AskUserQuestion. Also state up front that the seed is a provenance baseline, not certification of your current mix.lock (per Iron Law #2, seed versions older than the locked ones stay unvetted). Ask before overwriting existing entries.
--list → render the audits table; exit.--check → compare ledger entries with mix.lock; warn ondrift. Read the lock via Code.eval_file("mix.lock") with 2>/dev/null — modern locks have quoted keys and emit a found quoted keyword warning per package (tens of KB of noise that gets persisted as an oversized tool result otherwise).
Run the deps-audit corpus loader. Cache lives at ~/.cache/phx-deps-audit/corpus/<pkg>/<version>/contents/. Use:
textbash ../phx-deps-audit/smoke-test/corpus.d/fetch.sh \ <pkg> <version>
Source the rules from ../phx-deps-audit/references/rules-impl.md. Run run_all_rules over the cached dir. Write findings to a temp vet-findings.jsonl. Set FINDINGS_FILE to override default path.
Print the findings table per ../phx-deps-audit/references/output-renderer.md. On zero findings: say "No findings — vet from a clean baseline." On any finding: show severity, file, line, snippet inline.
Call AskUserQuestion with these 4 options:
:safe_to_deploy — full trust; findings investigated and cleared.:safe_to_run — trust in non-production envs only (test deps).:does_not_implement_crypto — Mozilla-style sub-criterion.Skip — defer decision; don't write an entry.If any finding is BLOCK severity: default-highlight Skip. Require explicit override before writing :safe_to_deploy over a BLOCK.
Read existing hex_vet.exs via Code.eval_file/1. Append the audit map below to :audits. Write back via Code.format_string!(inspect(...)).
elixir%{ package: "<pkg>", version: "<version>", criteria: <verdict_atom>, reviewer: "<git config user.email>", notes: "<user-provided one-liner OR findings summary>", reviewed_at: ~D[<today>] }
Write back via Code.format_string!(inspect(term, pretty: true)). Confirm to user: "Added <pkg> <version> to hex_vet.exs."
/skill:phx-deps-audit to clear vetted findings.mix.lock PR to certify new versions./skill:phx-deps-vet --check to detect ledger drift vs mix.lock./skill:phx-deps-audit auto-downgrades vetted findings to INFO.references/hex-vet.md — schema, parser, lookupreferences/seed.md — --seed flag, curated baseline../phx-deps-audit/references/rules-impl.md — thesame rules /skill:phx-deps-audit runs
mix phx.deps_vet to a separate Hexpackage phx_deps_vet for non-CC users.
that gates mix deps.get.
imports: untiltrust-chain semantics are designed.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 10,206 | 7,680 | -25% | 1 | 1 | 0% | 1,143 | 2,054 | +80% | 0 | 0 | — |
case-02 | fail→fail | 14,779 | 6,438 | -56% | 1 | 1 | 0% | 2,999 | 2,035 | -32% | 0 | 0 | — |
case-03 | fail→fail | 7,483 | 8,028 | +7% | 1 | 1 | 0% | 341 | 2,155 | +532% | 0 | 0 | — |
case-04 | pass→pass | 7,585 | 6,699 | -12% | 1 | 1 | 0% | 1,223 | 2,475 | +102% | 0 | 0 | — |
case-05 | pass→pass | 9,443 | 3,934 | -58% | 1 | 1 | 0% | 1,679 | 2,345 | +40% | 0 | 0 | — |
case-06 | fail→pass | 5,511 | 4,206 | -24% | 1 | 1 | 0% | 1,072 | 2,412 | +125% | 0 | 0 | — |
case-07 | fail→fail | 8,303 | 4,952 | -40% | 1 | 1 | 0% | 1,475 | 2,666 | +81% | 0 | 0 | — |
case-08 | fail→fail | 4,343 | 4,458 | +3% | 1 | 1 | 0% | 707 | 2,059 | +191% | 0 | 0 | — |
case-09 | pass→pass | 4,205 | 1,767 | -58% | 1 | 1 | 0% | 664 | 2,024 | +205% | 0 | 0 | — |
case-10 | pass→pass | 9,110 | 4,319 | -53% | 1 | 1 | 0% | 1,367 | 2,449 | +79% | 0 | 0 | — |
case-11 | fail→fail | 2,510 | 13,114 | +422% | 1 | 1 | 0% | 319 | 2,021 | +534% | 0 | 0 | — |
case-12 | fail→pass | 11,724 | 3,497 | -70% | 1 | 1 | 0% | 2,078 | 1,962 | -6% | 0 | 0 | — |
case-13 | fail→pass | 11,723 | 3,197 | -73% | 1 | 1 | 0% | 2,015 | 2,264 | +12% | 0 | 0 | — |
case-14 | fail→pass | 11,051 | 4,166 | -62% | 1 | 1 | 0% | 1,910 | 2,498 | +31% | 0 | 0 | — |
case-15 | fail→pass | 8,685 | 4,799 | -45% | 1 | 1 | 0% | 1,535 | 2,527 | +65% | 0 | 0 | — |
case-16 | fail→pass | 6,703 | 2,136 | -68% | 1 | 1 | 0% | 1,113 | 2,135 | +92% | 0 | 0 | — |
case-17 | fail→pass | 8,347 | 2,674 | -68% | 1 | 1 | 0% | 1,492 | 2,172 | +46% | 0 | 0 | — |
case-18 | fail→pass | 10,785 | 2,211 | -79% | 1 | 1 | 0% | 1,917 | 2,111 | +10% | 0 | 0 | — |
case-19 | fail→pass | 8,085 | 3,602 | -55% | 1 | 1 | 0% | 1,318 | 2,353 | +79% | 0 | 0 | — |
case-20 | fail→fail | 17,717 | 28,553 | +61% | 1 | 1 | 0% | 3,973 | 7,929 | +100% | 0 | 0 | — |
case-21 | fail→fail | 42,365 | 5,773 | -86% | 1 | 1 | 0% | 2,453 | 2,083 | -15% | 0 | 0 | — |
case-22 | fail→fail | 23,694 | 23,256 | -2% | 1 | 1 | 0% | 5,013 | 6,222 | +24% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 16 counted toward the lift figure. The other 6 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +41 percentage points is the difference between those two pass rates over the 16 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.