From gh
Manage Git hooks with husky v9. Use when the user asks about git hooks setup, pre-commit hooks, commit-msg hooks, husky configuration, the prepare script, or CI integration for git hooks. Trigger on mentions of 'husky', '.husky/', 'prepare script', or git hook lifecycle management.
How this skill is triggered — by the user, by Claude, or both
Slash command
/gh:huskyThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Opinionated guidance for husky v9 git hooks management. Covers installation, hook authoring, CI integration, and real-world patterns.
Opinionated guidance for husky v9 git hooks management. Covers installation, hook authoring, CI integration, and real-world patterns.
Husky uses Git's native core.hooksPath to run shell scripts from .husky/ on git events (commit, push, merge, etc.). It has no runtime dependencies, runs in ~1ms, and supports all 13 client-side git hooks.
When to use husky:
Not using Node.js? For pure Go, Python, or polyglot projects without
package.json, consider the lefthook skill instead — a Go binary with no runtime dependencies. It includes a husky-vs-lefthook decision guide with checklists.
npm install --save-dev husky
npx husky init
npx husky init does two things:
.husky/pre-commit with a sample npm test script"prepare": "husky" to package.jsonThe prepare script runs automatically on npm install, so all team members get hooks installed when they set up the project.
Manual setup (without npx husky init):
npm install --save-dev husky
# Add to package.json scripts:
# "prepare": "husky"
# Then create hooks manually in .husky/
prepare Script{
"scripts": {
"prepare": "husky"
}
}
This is the canonical pattern — husky runs during npm install to configure core.hooksPath.
For CI/production environments where npm install runs but hooks should not be installed:
{
"scripts": {
"prepare": "husky || true"
}
}
Or use an install guard in .husky/install.mjs:
// Skip husky in CI or production
if (process.env.CI === 'true' || process.env.NODE_ENV === 'production') process.exit(0)
const husky = await import('husky')
husky.default()
Then update prepare:
"prepare": "node .husky/install.mjs"
Hook files live in .husky/ and are plain shell scripts. No JSON config needed.
# Create a pre-commit hook
cat > .husky/pre-commit << 'EOF'
#!/usr/bin/env bash
set -euo pipefail
npm test
EOF
chmod +x .husky/pre-commit
Common hooks:
| Hook | Trigger | Typical Use |
|---|---|---|
pre-commit | Before commit is created | Lint, test, validate |
commit-msg | After commit message written | commitlint validation |
pre-push | Before push to remote | Full test suite, build |
post-merge | After merge completes | npm install to sync deps |
post-checkout | After branch switch | npm install to sync deps |
prepare-commit-msg | Before commit message editor | Prepend branch name to message |
# .husky/pre-commit
npx lint-staged
// package.json
{
"lint-staged": {
"*.{js,ts}": "eslint --fix",
"*.{css,md}": "prettier --write"
}
}
# .husky/commit-msg
npx commitlint --edit $1
# .husky/pre-commit
#!/usr/bin/env bash
set -euo pipefail
if command -v claude >/dev/null 2>&1; then
claude plugin validate . || {
echo "FAIL: Marketplace validation failed."
exit 1
}
fi
See this repo's actual .husky/pre-commit for a full real-world example combining marketplace validation with lychee link checking.
Skip hooks in CI by setting HUSKY=0:
# GitHub Actions
env:
HUSKY: 0
# Shell one-liner
HUSKY=0 npm install
Skip a single command (not recommended — prefer CI env var):
git commit --no-verify -m "chore: skip hooks"
# or
HUSKY=0 git commit -m "chore: skip hooks"
Always start with set -euo pipefail — exits immediately on error, unset variables, or pipe failure.
Use #!/usr/bin/env bash — portable shebang that works on macOS and Linux.
Guard optional tools with command -v — skip gracefully if a tool is not installed:
command -v node >/dev/null 2>&1 || { echo "SKIP: node not found"; exit 0; }
Use non-zero exit codes to abort the git operation — exit 1 cancels the commit/push.
Keep hooks fast — pre-commit hooks run on every commit; slow hooks hurt developer experience. Prefer lint-staged over full linting.
When using nvm/fnm/volta, GUI git clients may not source shell init files. Fix by adding your NVM init to ~/.config/husky/init.sh:
# ~/.config/husky/init.sh
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
Hooks not running:
core.hooksPath is set: git config core.hooksPath → should show .huskyls -la .husky/ → look for rwxr-xr-xnpm install to trigger the prepare scriptcommand not found in hook:
~/.config/husky/init.shHooks blocked by --no-verify:
--no-verify usage — use HUSKY=0 in CI insteadHooks installed but not executing:
#!/usr/bin/env bash (not #!/bin/sh on macOS)references/hooks-reference.rst — All 13 git hook types, v8→v9 migration notes, script patterns, and monorepo setup.npx claudepluginhub nq-rdl/agent-extensions --plugin ghCreates structured, bite-sized implementation plans from specs or requirements before writing code. Useful for breaking down multi-step tasks into testable steps with file structure and task boundaries.