Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when adding Husky + lint-staged + Prettier pre-commit hooks: emit the exact v9 house-style config files (no-shebang hook, `*` glob, es5 commas).
.claude/skills/setup-husky-pre-commit/SKILL.md| Model | Eval pass | Runs |
|---|---|---|
| gemini-3.6-flash | 100% | 5 |
| Model | Lift | Δ tokens | Δ turns | Cases | Verified |
|---|---|---|---|---|---|
| gemini-3.5-flashbest | +65% | — | 0% | 23 | 86d ago |
| gemini-3.6-flash | +35% | +142% | 0% | 23 | 54d ago |
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-14 | ✗→✓ | ▲ Improved | — | — |
| case-23 | ✗→✓ | ▲ Improved | — | — |
| case-03 | ✗→✓ | ▲ Improved | — | — |
| case-02 | ✗→✓ | ▲ Improved | — | — |
| case-01 | ✗→✓ | ▲ Improved | — | — |
Enforces the exact, arbitrary house style for a Husky v9 + lint-staged + Prettier pre-commit setup. Apply whenever the task is to add pre-commit hooks, initialize Husky, configure lint-staged, or wire commit-time formatting / typecheck / test into a Node repo. Produce these EXACT files. Do not improvise alternatives, do not modernize, do not "improve."
.husky/pre-commit is Husky v9 style (no boilerplate)#!/bin/sh, #!/usr/bin/env sh, or any #! first line is FORBIDDEN.Husky v9 sources the hook itself; a shebang is v8-and-earlier residue.
. "$(dirname "$0")/_/husky.sh" (and the older. "$(dirname -- "$0")/_/husky.sh") is FORBIDDEN. That is v8 boilerplate.
npx lint-stagednpm run typechecknpm run testOrder is load-bearing: format/lint the staged files first (fast, staged-only), then the slower full-repo typecheck, then test. Never reorder, never collapse into one line.
package-lock.json → npm, pnpm-lock.yaml → pnpm,yarn.lock → yarn, bun.lockb (or bun.lock) → bun.
npm/npx accordingly:npx lint-staged, npm run typecheck, npm run testpnpm lint-staged (or pnpm exec lint-staged), pnpm run typecheck, pnpm run testyarn lint-staged, yarn typecheck, yarn testbunx lint-staged, bun run typecheck, bun run testpackage.json has no typecheck script, OMIT line 2 and tell the user it was omitted.test script, OMIT line 3 and tell the user.typecheck/test script or a stub command (no tsc --noEmit, noecho "no tests"). lint-staged (line 1) is the only always-present line.
.lintstagedrc is exactly the all-files Prettier rulejson{ "*": "prettier --ignore-unknown --write" }
"*" — a single asterisk matching ALL files. NOT "*.{js,ts}",NOT "**/*", NOT a per-extension map.
prettier --ignore-unknown --write. --ignore-unknown is REQUIRED(Prettier silently skips files it can't parse — images, lockfiles — instead of crashing the commit). --write formats in place.
.prettierrc only if no Prettier config already existsCreate it only when the repo has no Prettier config (no .prettierrc, .prettierrc.json, .prettierrc.js, prettier.config.js, or a prettier key in package.json). If one exists, leave it untouched. When you do create it, use EXACTLY these seven keys/values:
json{ "useTabs": false, "tabWidth": 2, "printWidth": 80, "singleQuote": false, "trailingComma": "es5", "semi": true, "arrowParens": "always" }
The arbitrary, easy-to-get-wrong values: trailingComma is "es5" (NOT "all"), singleQuote is false (double quotes), semi is true, arrowParens is "always", printWidth is 80, tabWidth is 2, useTabs is false.
husky, lint-staged, prettier (these three, no more).prepare script to "husky" — NOT "husky install" (the v8 form).npx husky init (creates .husky/, adds the prepare script). NOTthe legacy npx husky install / husky add.
Stage everything and commit with EXACTLY this message:
Add pre-commit hooks (husky + lint-staged + prettier)Verbatim — same wording, same parenthical, lower-case husky + lint-staged + prettier. This commit also smoke-tests the hook (it runs through the new pipeline).
BEFORE (base emits the v8-style hook it was trained on):
sh#!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" npx lint-staged
AFTER (v9 — no shebang, no source line, three commands):
npx lint-staged
npm run typecheck
npm run testBEFORE (base collapses to one line, or reorders tests first):
npm test && npx lint-stagedAFTER:
npx lint-staged
npm run typecheck
npm run testBEFORE (base hardcodes npm even though pnpm-lock.yaml is present):
npx lint-staged
npm run typecheck
npm run testAFTER (pnpm detected):
pnpm exec lint-staged
pnpm run typecheck
pnpm run testbuild scriptBEFORE (base invents the missing scripts):
npx lint-staged
npm run typecheck
npm run testAFTER (omit the two missing lines, and say so):
npx lint-staged> Note: your package.json has no typecheck or test script, so those lines were omitted. > Add the scripts and re-add the lines if you want them gated at commit time.
BEFORE (base scopes to JS/TS extensions, its common default):
json{ "*.{js,ts,jsx,tsx}": "prettier --write" }
AFTER (all files, ignore-unknown):
json{ "*": "prettier --ignore-unknown --write" }
BEFORE (base reaches for the "modern" defaults — all commas, single quotes):
json{ "trailingComma": "all", "singleQuote": true, "tabWidth": 2 }
AFTER (house style — es5 commas, double quotes, full seven keys):
json{ "useTabs": false, "tabWidth": 2, "printWidth": 80, "singleQuote": false, "trailingComma": "es5", "semi": true, "arrowParens": "always" }
BEFORE (base uses the deprecated v8 form):
json{ "scripts": { "prepare": "husky install" } }
AFTER:
json{ "scripts": { "prepare": "husky" } }
BEFORE: chore: add husky and prettier pre-commit hooks AFTER: Add pre-commit hooks (husky + lint-staged + prettier)
pnpm-workspace.yamlor a .yarnrc; only the four lockfiles decide, and absence means npm.
packageManager field if set;otherwise npm. Don't emit two runners.
.lintstagedrcand the hook. Mention you kept their config.
.husky/pre-commit → replace its contents with the v9 three-line form; do notappend your lines under their old shebang/source boilerplate.
typecheck exists but not test (or vice-versa) → keep the one that exists, omit andreport the missing one. It is not all-or-nothing.
.husky/pre-commit and root .lintstagedrc;do not scatter per-package hooks unless explicitly asked.
.lintstagedrc; this config isPrettier-only by house rule. Mention they can add lint to the typecheck/test scripts.
.husky/pre-commit; always emit the bare v9 three-line file._/husky.sh source line; always omit it (v9)."*.{js,ts}"; always use "*".--ignore-unknown; always include it so unparseable files don't crash the commit.trailingComma to "all"; always "es5".singleQuote to true; always false.prepare to "husky install"; always "husky".typecheck/test script; always omit the line and tell the user.Add pre-commit hooks (husky + lint-staged + prettier).#!/usr/bin/env sh + . .../_/husky.sh) from muscle memory.*.{js,ts,jsx,tsx} instead of "*", and dropping --ignore-unknown.trailingComma: "all", singleQuote: true)."husky install" for the prepare script.typecheck/test scripts (e.g. tsc --noEmit, echo "no tests") insteadof omitting the missing lines.
chore: …)..husky/pre-commit: no shebang, no source line, lint-staged → typecheck → test.typecheck/test lines omitted + reported..lintstagedrc = {"*": "prettier --ignore-unknown --write"}..prettierrc only if absent; the exact seven keys, es5 commas, double quotes.prepare: "husky"; init via npx husky init.Add pre-commit hooks (husky + lint-staged + prettier).| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-10 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-23 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.5-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted, and 20 counted toward the lift figure. The other 3 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 +35 percentage points is the difference between those two pass rates over the 20 comparable cases.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.5-flash | verified | 6/27/2026 | +65% |
Other measured skills in the registry, with their headline benchmark lift.