Skip to content
Back to skills

Git Hooks

BSecurity

Set up pre-commit hooks for linting, formatting, and type-checking with commit message enforcement using conventional commits. Auto-detects stack and configures husky, lefthook, or pre-commit framework with lint-staged. Use when you want to enforce code quality on every commit, add conventional commits, prevent bad code from being committed, or set up CI-mirrored hook checks.

  • 15 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 29, 2026
ai-agentstypescriptpythonrustgorubynodegit

Works with

  • cli

Security analysis

B88/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned May 29, 2026

npx -y skills add tinh2/skills-hub-registry --skill git-hooks --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Git Hooks?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Git Hooks
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/tinh2-git-hooks/badge)](https://www.skillsdirectory.com/skills/tinh2-git-hooks)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: git-hooks
description: "Set up pre-commit hooks for linting, formatting, and type-checking with commit message enforcement using conventional commits. Auto-detects stack and configures husky, lefthook, or pre-commit framework with lint-staged. Use when you want to enforce code quality on every commit, add conventional commits, prevent bad code from being committed, or set up CI-mirrored hook checks."
version: "2.0.0"
category: productivity
platforms:
  - CLAUDE_CODE
---

You are in AUTONOMOUS MODE. Do NOT ask questions. Do NOT pause for confirmation.
Execute every phase below in sequence, making decisions based on what you find.

============================================================
PHASE 0 — INPUT
============================================================

$ARGUMENTS may contain:
- `--tool=TOOL` — force a specific hook manager: `husky`, `lefthook`, `pre-commit`
- `--no-commit-msg` — skip commit message hook setup
- `--no-lint-staged` — run full lint instead of staged-only
- `--ci` — also generate CI workflow to mirror hook checks

If no arguments, auto-detect the best hook tool for the stack.

============================================================
PHASE 1 — STACK DETECTION
============================================================

Detect the project stack and existing tooling:

**Language & Tooling**:
- `package.json` → Node/TS — prefer husky + lint-staged
- `pyproject.toml` / `requirements.txt` → Python — prefer pre-commit framework
- `go.mod` → Go — prefer lefthook or pre-commit
- `Cargo.toml` → Rust — prefer lefthook
- `pubspec.yaml` → Flutter/Dart — prefer lefthook
- `Gemfile` → Ruby — prefer lefthook or overcommit
- Multiple languages → prefer lefthook (polyglot native)

**Existing Hooks** (check and preserve):
- `.husky/` directory — existing husky setup
- `.lefthook.yml` or `lefthook.yml` — existing lefthook setup
- `.pre-commit-config.yaml` — existing pre-commit setup
- `.git/hooks/` — raw git hooks (will be replaced)

**Lint & Format Tools** (detect what to run in hooks):
- ESLint: `.eslintrc.*` / `eslint.config.*` / `biome.json`
- Prettier: `.prettierrc*` / `biome.json`
- TypeScript: `tsconfig.json` → run `tsc --noEmit`
- Ruff: `ruff.toml` / `pyproject.toml [tool.ruff]`
- Black: `pyproject.toml [tool.black]`
- mypy: `mypy.ini` / `pyproject.toml [tool.mypy]`
- golangci-lint: `.golangci.yml` / `.golangci.yaml`
- gofmt/goimports: always available with Go
- Clippy: always available with Rust
- rustfmt: always available with Rust
- dart analyze / dart format: always available with Flutter

Record: hook tool, lint commands, format commands, type-check command, test command.

============================================================
PHASE 2 — SET UP HOOK MANAGER
============================================================

**If Node.js (husky + lint-staged)**:

1. Install dependencies:
   ```
   npm install --save-dev husky lint-staged
   ```
2. Initialize husky:
   ```
   npx husky init
   ```
3. Create `.husky/pre-commit`:
   ```sh
   npx lint-staged
   ```
4. Add `lint-staged` config to `package.json`:
   ```json
   {
     "lint-staged": {
       "*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
       "*.{json,md,yml,yaml}": ["prettier --write"]
     }
   }
   ```
   Adjust glob patterns and commands based on detected linters.
   If Biome is detected instead of ESLint+Prettier:
   ```json
   {
     "lint-staged": {
       "*.{js,jsx,ts,tsx,json}": ["biome check --write"]
     }
   }
   ```
5. If TypeScript detected, add type-check to pre-commit (runs on all files, not staged):
   ```sh
   npx lint-staged
   npx tsc --noEmit
   ```

**If Python (pre-commit framework)**:

1. Install: `pip install pre-commit` (or add to dev dependencies)
2. Create `.pre-commit-config.yaml`:
   ```yaml
   repos:
     - repo: https://github.com/astral-sh/ruff-pre-commit
       rev: v0.8.0
       hooks:
         - id: ruff
           args: [--fix]
         - id: ruff-format
     - repo: https://github.com/pre-commit/mirrors-mypy
       rev: v1.13.0
       hooks:
         - id: mypy
   ```
   Adjust repos based on detected tools (Black instead of Ruff, pyright instead of mypy).
3. Install hooks: `pre-commit install`

**If Go / Rust / Flutter / Polyglot (lefthook)**:

1. Install lefthook (detect best method):
   - npm: `npm install --save-dev lefthook`
   - brew: `brew install lefthook`
   - go: `go install github.com/evilmartians/lefthook@latest`
2. Create `lefthook.yml`:
   ```yaml
   pre-commit:
     parallel: true
     commands:
       lint:
         glob: "*.go"
         run: golangci-lint run --fix {staged_files}
       format:
         glob: "*.go"
         run: gofmt -w {staged_files}
   ```
   Adjust commands per detected language.
3. Install hooks: `lefthook install`

============================================================
PHASE 3 — COMMIT MESSAGE HOOK
============================================================

Skip if `--no-commit-msg` was passed.

Set up conventional commit enforcement:

**For husky (Node.js)**:
1. Install: `npm install --save-dev @commitlint/cli @commitlint/config-conventional`
2. Create `commitlint.config.js`:
   ```js
   export default { extends: ['@commitlint/config-conventional'] };
   ```
3. Create `.husky/commit-msg`:
   ```sh
   npx --no -- commitlint --edit $1
   ```

**For pre-commit (Python)**:
Add to `.pre-commit-config.yaml`:
```yaml
  - repo: https://github.com/compilerla/conventional-pre-commit
    rev: v3.6.0
    hooks:
      - id: conventional-pre-commit
        stages: [commit-msg]
```
Run: `pre-commit install --hook-type commit-msg`

**For lefthook**:
Add to `lefthook.yml`:
```yaml
commit-msg:
  commands:
    conventional:
      run: |
        MSG=$(head -1 {1})
        if ! echo "$MSG" | grep -qE '^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?!?: .+'; then
          echo "Commit message must follow Conventional Commits format"
          echo "Examples: feat: add login, fix(auth): token expiry"
          exit 1
        fi
```

============================================================
PHASE 4 — VERIFY HOOKS WORK
============================================================

1. Run the pre-commit hook manually to verify it works:
   - Husky: `npx lint-staged`
   - Pre-commit: `pre-commit run --all-files`
   - Lefthook: `lefthook run pre-commit`

2. If the hook fails on existing code:
   - Auto-fix what can be auto-fixed (formatting, simple lint rules)
   - Commit the fixes: `fix: auto-fix lint and format violations`
   - Re-run to verify hooks pass

3. Test the commit-msg hook with an invalid message to confirm it rejects it,
   then test with a valid conventional commit message.

============================================================
PHASE 5 — CI MIRROR (IF --ci)
============================================================

If `--ci` was passed, generate a GitHub Actions workflow that mirrors the hook checks:

Create `.github/workflows/lint.yml`:
```yaml
name: Lint
on:
  pull_request:
    branches: [main, master]
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - # setup language runtime
      - # run same lint/format/typecheck commands as hooks
```

This ensures hooks cannot be bypassed with `--no-verify`.


============================================================
SELF-HEALING VALIDATION (max 2 iterations)
============================================================

After completing, validate the output was produced correctly:

1. Verify generated files exist and are syntactically valid.
2. Run any available validation (lint, type-check, dry-run).
3. If the skill produces configuration, verify it parses without errors.

IF VALIDATION FAILS:
- Diagnose from error context and re-generate the failing artifact
- Repeat up to 2 iterations

============================================================
OUTPUT
============================================================

Print a summary:

```
## Git Hooks Setup Complete

### Hook Manager: {husky|lefthook|pre-commit}

### Pre-Commit Hooks
- Lint: {eslint --fix | ruff --fix | golangci-lint run}
- Format: {prettier --write | ruff-format | gofmt}
- Type Check: {tsc --noEmit | mypy | N/A}
- Scope: {staged files only | all files}

### Commit-Msg Hook
- Enforcing: Conventional Commits (feat|fix|docs|...)

### Files Created/Modified
- {list of files created or modified}

### Existing Violations Fixed
- {N auto-fixable issues fixed, or "none"}
```

============================================================
NEXT STEPS
============================================================

1. Make a test commit to verify hooks run correctly
2. Run `/linter` if lint configuration needs improvement
3. Run `/release` to set up automated releases that consume conventional commits
4. Consider adding `--no-verify` to your CI push commands if hooks run in CI separately


============================================================
SELF-EVOLUTION TELEMETRY
============================================================

After producing output, record execution metadata for the /evolve pipeline.

Check if a project memory directory exists:
- Look for the project path in `~/.claude/projects/`
- If found, append to `skill-telemetry.md` in that memory directory

Entry format:
```
### /git-hooks — {{YYYY-MM-DD}}
- Outcome: {{SUCCESS | PARTIAL | FAILED}}
- Self-healed: {{yes — what was healed | no}}
- Iterations used: {{N}} / {{N max}}
- Bottleneck: {{phase that struggled or "none"}}
- Suggestion: {{one-line improvement idea for /evolve, or "none"}}
```

Only log if the memory directory exists. Skip silently if not found.
Keep entries concise — /evolve will parse these for skill improvement signals.

============================================================
DO NOT
============================================================

- Do NOT install multiple hook managers — pick one and use it consistently
- Do NOT configure hooks that take longer than 10 seconds on staged files
- Do NOT run full test suites in pre-commit — only lint, format, and type-check
- Do NOT silently swallow hook errors — hooks must fail loudly with clear messages
- Do NOT overwrite existing hook configurations without reading them first
- Do NOT use deprecated commitlint configs (e.g., `.commitlintrc` without module type)
- Do NOT add hooks for tools that are not installed or configured in the project

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…