agentleFS
chrislacey89chrislacey89/skills/setup-pre-commit/SKILL.md

setup-pre-commit

Skill4 starsChanged 7 days agoMITView on GitHub

Infrastructure skill for setting up commit-time quality gates. Use when a repo needs Lefthook-based pre-commit hooks for formatting, linting, type checking, and tests, plus a secret scan at commit and a dependency audit at push. Supports downstream /execute and /pre-merge, but is not part of the normal feature-delivery pipeline.

  • Deletes or force-pushes
  • Installs packages

124 other projects use a version of this, 104 of them edited.

Adopted by

Most recently taken up by

Used with

Projects with it also use migrate-to-shoehorn, writing-beats and 7 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • simo97Skill

    migrate-to-shoehorn

    Migrate test files from `as` type assertions to @total-typescript/shoehorn. Use when user mentions shoehorn, wants to replace `as` in tests, or needs partial test data.

    Also in 73 projects that use this

  • LesaniSkill

    writing-beats

    Shape an article as a journey of beats, choose-your-own-adventure style. The user picks a starting beat from the raw material, you write only that beat, then offer options for where to pivot next, beat by beat, until the article reaches a natural end. Use when the user has raw material and wants to assemble it as a narrative rather than an argument.

    Also in 63 projects that use this

  • liufeng1976Skill

    setup-ts-deep-modules

    Wire dependency-cruiser into a TypeScript repo so each package is a deep module — implementation hidden in subfolders, reachable only through its entry-point files. User-invoked.

    Also in 41 projects that use this

  • LesaniSkill

    writing-shape

    Take a markdown file of raw material and shape it into an article through a conversational session — drafting candidate openings, growing the piece paragraph by paragraph, arguing about format (lists, tables, callouts, quotes) at each step. Use when the user has a pile of notes, fragments, or a rough draft and wants help turning it into something publishable.

    Also in 63 projects that use this

  • simo97Skill

    edit-article

    The user will invoke this skill to help them edit an article.

    Also in 38 projects that use this

  • RoentekSkill

    loop-me

    Grill me about specs for the workflows I want to build, within this workspace.

    Also in 52 projects that use this

  • +1 more from Lesani

The file

Show its rules and text

We split this skill into the rules it gives an agent

15 rules. 0 are common, 7 are distinctive, and 8 are very specific to this project.

  • 0

    Common

    Most of the 112 edited versions we read keep these.

  • 7

    Distinctive

    This author's own choices. Worth a look.

  • 8

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Use /setup-pre-commit when a project needs commit-time formatting, linting, type checking, and test hooks.

    line 12
  2. Very specific:

    Do not use it as part of the default feature pipeline.

    line 14
  3. Very specific:

    Check for pnpm-lock.yaml (pnpm), package-lock.json (npm), yarn.lock (yarn), bun.lockb (bun).

    line 28
  4. Distinctive:

    Before installing anything, check what's already in the project:

    line 34
  5. Distinctive:

    If an existing formatter/linter is detected: use it. Don't install a competing tool.

    line 43
  6. Distinctive:

    Ask: "No formatter/linter detected.

    line 47
  7. Distinctive:

    If an audit step is detected: leave it where it is and do not add a second one.

    line 60
  8. Distinctive:

    If nothing is detected: use gitleaks and the package manager's audit.

    line 62
  9. Very specific:

    Add a prepare script to package.json so hooks are installed automatically for anyone who clones the repo:

    line 104
  10. Very specific:

    Create lefthook.yml at the repo root.

    line 116
  11. Very specific:

    If the repo has no typecheck script in package.json, omit that command and tell the user

    line 208
  12. Distinctive:

    Only create if no config exists and the user chose to install a new tool.

    line 214
  13. Very specific:

    If secret-scan passes with the fixture staged, the gate is not working.

    line 268
  14. Distinctive:

    If the project previously used Husky:

    line 273
  15. Very specific:

    Update the prepare script in package.json from "husky" to "lefthook install".

    line 284

“Common” is measured: kept by at least 6 in 10 of the 112 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Setup Pre-Commit Hooks

Invocation Position

This is an infrastructure skill, not a normal feature-delivery stage.

Use /setup-pre-commit when a project needs commit-time formatting, linting, type checking, and test hooks.

Do not use it as part of the default feature pipeline. It prepares the repo so later /execute and /pre-merge steps have stronger feedback loops.

What This Sets Up

  • Lefthook for git hook management (fast, zero-dependency, config-as-code)
  • Formatting + linting on staged files (Biome preferred; Prettier, ESLint, or others supported)
  • Typecheck and test scripts in the pre-commit hook
  • Secret scan on staged changes in the pre-commit hook (gitleaks, unless the repo already runs a scanner)
  • Dependency audit in the pre-push hook, using the detected package manager's own audit command

Steps

1. Detect Package Manager

Check for pnpm-lock.yaml (pnpm), package-lock.json (npm), yarn.lock (yarn), bun.lockb (bun). Use whichever is present. Default to npm if unclear.

Store the detected package manager — it's used for all install and run commands below.

2. Detect Existing Formatter/Linter

Before installing anything, check what's already in the project:

# Check package.json for existing tools
cat package.json | grep -E "biome|prettier|eslint|oxlint|dprint" 2>/dev/null
# Check for config files
ls biome.json biome.jsonc .prettierrc .prettierrc.* prettier.config.* .eslintrc* eslint.config.* 2>/dev/null

If an existing formatter/linter is detected: use it. Don't install a competing tool.

If nothing is detected: recommend Biome (single tool for formatting + linting, fast, zero-config defaults) and confirm with the user before installing.

Ask: "No formatter/linter detected. I'd recommend Biome — it handles both formatting and linting in one tool, is very fast, and works out of the box. Want to go with Biome, or would you prefer Prettier, ESLint, or something else?"

The same rule covers the two security gates Step 5 adds. Check for a secret scanner or a dependency audit the repo already runs:

# Secret-scanner config
ls .gitleaks.toml .gitleaksignore .secrets.baseline .trufflehog* .pre-commit-config.yaml 2>/dev/null
# A scanner or an audit already wired into hooks, scripts, or CI
grep -rnE "gitleaks|trufflehog|detect-secrets|ggshield|[a-z] audit" lefthook.yml package.json .pre-commit-config.yaml .github/workflows 2>/dev/null

If a secret scanner is detected: keep it. Wire Step 5's secret-scan command to that tool, or leave the command out when the existing setup already runs it at commit time. A .gitleaks.toml or .gitleaksignore is configuration gitleaks reads on its own; leave both as they are.

If an audit step is detected: leave it where it is and do not add a second one.

If nothing is detected: use gitleaks and the package manager's audit. Neither needs a question — a repo with no scanner has no preference to override.

3. Install Dependencies

Install as devDependencies using the detected package manager:

Lefthook (always):

# pnpm
pnpm add -D lefthook

# npm
npm install -D lefthook

# yarn
yarn add -D lefthook

# bun
bun add -D lefthook

Formatter/linter (based on detection or user choice):

ToolInstallConfig file
Biome (preferred)@biomejs/biomebiome.json
Prettierprettier.prettierrc
ESLinteslinteslint.config.*
Prettier + ESLintprettier eslintboth
oxlintoxlintoxlint.json
dprintdprintdprint.json

Secret scanner (when Step 2 found none): gitleaks is a standalone binary, not an npm package, so it does not go in devDependencies. Install it by one of the routes in gitleaks § Installing, and tell the user that everyone who commits to the repo needs it on PATH. If you cannot install it (no package manager for it, a restricted sandbox, no network), stop before Step 9 and ask the user: the fail-closed gate would block the smoke-test commit, and dropping secret-scan or making it skip when the binary is absent is the user's decision, not yours. When no user is present to answer (this skill was invoked by /init-pipeline Path B, so by /execute Step 0 or an AFK Ralph iteration), do not wait and do not decide: leave lefthook.yml as Step 5 wrote it, skip Step 9 (commit nothing), and end the run by reporting to the caller that secret-scan is blocked because gitleaks is not on PATH, with the uncommitted scaffold left in the working tree. Every "ask the user" in Step 7 follows this same rule. The dependency audit needs no install; it ships with the package manager.

4. Initialize Lefthook

npx lefthook install

This creates the git hook symlinks. No .husky/ directory, no prepare script needed — Lefthook manages hooks directly via lefthook.yml.

Add a prepare script to package.json so hooks are installed automatically for anyone who clones the repo:

{
  "scripts": {
    "prepare": "lefthook install"
  }
}

5. Create lefthook.yml

Create lefthook.yml at the repo root. The configuration depends on which formatter/linter was detected or chosen.

With Biome (preferred):

pre-commit:
  parallel: true
  commands:
    format-and-lint:
      glob: "*.{js,ts,jsx,tsx,json,css}"
      run: npx @biomejs/biome check --write --staged {staged_files}
      stage_fixed: true
    typecheck:
      run: {package_manager} run typecheck
    test:
      run: {package_manager} run test

With Prettier:

pre-commit:
  parallel: true
  commands:
    format:
      glob: "*.{js,ts,jsx,tsx,json,css,md,yml,yaml}"
      run: npx prettier --write {staged_files}
      stage_fixed: true
    typecheck:
      run: {package_manager} run typecheck
    test:
      run: {package_manager} run test

With ESLint:

pre-commit:
  parallel: true
  commands:
    lint:
      glob: "*.{js,ts,jsx,tsx}"
      run: npx eslint --fix {staged_files}
      stage_fixed: true
    typecheck:
      run: {package_manager} run typecheck
    test:
      run: {package_manager} run test

With Prettier + ESLint:

pre-commit:
  parallel: true
  commands:
    format:
      glob: "*.{js,ts,jsx,tsx,json,css,md,yml,yaml}"
      run: npx prettier --write {staged_files}
      stage_fixed: true
    lint:
      glob: "*.{js,ts,jsx,tsx}"
      run: npx eslint --fix {staged_files}
      stage_fixed: true
    typecheck:
      run: {package_manager} run typecheck
    test:
      run: {package_manager} run test

Security gates (add to whichever config above was used):

pre-commit:
  commands:
    secret-scan:
      run: gitleaks git --pre-commit --staged --redact

pre-push:
  commands:
    dependency-audit:
      run: {package_manager} audit

Merge these into the config rather than appending a second pre-commit: key. The audit calls the registry, which makes it too slow for every commit, so it runs on pre-push.

  • Secret scan. The command's flags are documented in gitleaks git --help and gitleaks § Commands. When the scan flags a fixture or a test key, suppress that one finding with the scanner's own mechanism — gitleaks:allow, .gitleaksignore, or an allowlist in .gitleaks.toml. Do not narrow the command to make a finding go away.
  • Dependency audit. Each manager documents its own severity threshold, ignore list, and exit codes: npm, pnpm, bun, yarn classic. The yarn exception is under Adapt the config below.
  • Both gates fail closed. A finding blocks the commit or push. So does a scanner missing from PATH, and so does an npm, pnpm, or bun audit that cannot reach the registry. Leave it that way: no || true, no wrapper that skips when the tool is absent. A gate that passes when it could not run reports the same green as one that ran and found nothing.

Adapt the config:

  • Replace {package_manager} with the detected package manager (pnpm, npm, yarn, bun). The one exception is the dependency-audit line under yarn 2 and later, where the command is yarn npm audit, not yarn audit; check yarn --version before writing it (yarn 1 keeps yarn audit)
  • If the repo has no typecheck script in package.json, omit that command and tell the user
  • If the repo has no test script in package.json, omit that command and tell the user
  • Adjust glob patterns to match the project's file types

6. Create Formatter Config (if missing)

Only create if no config exists and the user chose to install a new tool.

Biome (biome.json):

{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "formatter": {
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 80
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  }
}

Prettier (.prettierrc):

{
  "useTabs": false,
  "tabWidth": 2,
  "printWidth": 80,
  "singleQuote": false,
  "trailingComma": "es5",
  "semi": true,
  "arrowParens": "always"
}

7. Verify

  • lefthook.yml exists at repo root
  • prepare script in package.json is "lefthook install"
  • Formatter/linter config exists
  • Run npx lefthook run pre-commit to verify hooks work
  • No .husky/ directory exists (if migrating from Husky, remove it)
  • The secret scan blocks a staged secret. Skip this check when Step 2 left secret-scan out because the repo already scans; otherwise stage a throwaway fixture, run the hook, and confirm secret-scan fails; then unstage and delete the fixture. Nothing is committed either way:

    printf '%s PRIVATE KEY-----\n%s\n-----END RSA PRIVATE KEY-----\n' '-----BEGIN RSA' "$(openssl rand -base64 48)" > fixture-secret.txt
    git add fixture-secret.txt
    npx lefthook run pre-commit   # expect secret-scan to fail
    git reset -q fixture-secret.txt && rm fixture-secret.txt

    If secret-scan passes with the fixture staged, the gate is not working. Fix it before Step 9 rather than committing a scaffold that reports green.

  • Run npx lefthook run pre-push and confirm dependency-audit ran. Skip this check when Step 2 left dependency-audit out because the repo already audits. A failure here that lists advisories is the gate working on the repo's current dependencies; show the user the output and let them decide what to upgrade. Do not weaken the command to get a green run. Setting a severity threshold or an ignore entry (Step 5 links where each manager documents them), including for an advisory that has no fix, is the user's decision, not yours: this gate will block every push until they make it, so ask rather than edit. With no user present, apply Step 3's unattended rule: report the output and the blocked push gate to the caller, edit nothing, and commit nothing.

8. Clean Up Husky (if migrating)

If the project previously used Husky:

# Remove Husky artifacts
rm -rf .husky
# Remove Husky from dependencies
{package_manager} remove husky lint-staged
# Remove .lintstagedrc if it exists and is no longer needed
rm -f .lintstagedrc .lintstagedrc.* lint-staged.config.*

Update the prepare script in package.json from "husky" to "lefthook install".

9. Commit

Stage all changed/created files and commit with message:

chore: add pre-commit hooks (lefthook + biome, secret scan, dependency audit) (or substitute the actual formatter name, and drop the name of any gate Step 2 found the repo already had)

This will run through the new pre-commit hooks — a good smoke test that everything works.

Why Lefthook over Husky

  • No node_modules dependency at hook runtime — Lefthook hooks run directly, no npx lint-staged wrapper
  • Config as code — lefthook.yml is declarative and version-controlled; Husky uses shell scripts in .husky/
  • Parallel execution — runs formatting, typecheck, and tests in parallel by default
  • {staged_files} built-in — no need for lint-staged as a separate dependency; Lefthook handles staged file filtering natively
  • stage_fixed: true — automatically re-stages files after formatting fixes, no extra tooling
  • Glob filtering — only runs tools on matching file types, no wasted cycles

Why Biome as Default

  • Single tool — replaces both Prettier (formatting) and ESLint (linting)
  • Fast — written in Rust, 10-100x faster than Prettier + ESLint
  • Zero config — works out of the box with sensible defaults
  • Compatible — 97% Prettier-compatible formatting, growing ESLint rule coverage
  • One config file — biome.json instead of .prettierrc + .eslintrc + conflicting rules

Handoff

  • Expected input: a repo that needs commit-time quality gates
  • Produces: working git hooks and tool configuration for commit-time checks, plus a secret scan at commit and a dependency audit at push
  • Supports downstream: /execute and /pre-merge by making basic verification more automatic
  • What comes next: return to normal feature work with stronger local feedback loops

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.