Pre-commit Hooks skill for Codex

Hooks that fix staged files in seconds, not minutes. Codex picks the hook manager that fits the repo, wires formatters and linters to run only on staged files with auto-fix, adds secret and large-file checks, and keeps slow work like full type checks in pre-push or CI. It lands the first mass reformat as a separate commit, times a real commit against a five-second budget, and adds a CI job so skipped hooks still get caught.

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- pre-commit-hooks

Installs to ~/.agents/skills/pre-commit-hooks/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $pre-commit-hooks, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Sets up fast git hooks that format and lint only staged files - the pre-commit framework (or prek) for Python and polyglot repos, husky with lint-staged or lefthook for JavaScript and TypeScript - plus secret scanning, commit-msg checks and a CI job that runs the same hooks so --no-verify cannot skip them. Use when asked to add pre-commit hooks, set up husky or lint-staged, speed up slow commit hooks, fix hooks that reformat unstaged work, or make local checks match CI.

Use it when

  • A repo has no local checks and broken formatting keeps reaching PRs
  • Commit hooks are slow enough that people bypass them
  • Hooks are rewriting or losing unstaged work
  • Local hook results disagree with CI

Use something else when

How to check the result

Make a test commit with a deliberate formatting error, confirm the hook fixes and stages it in under five seconds, then confirm the CI job fails on the same error when committed with --no-verify.

The mistake it prevents

Running the whole test suite or a full-project type check in pre-commit, which makes hooks slow enough that everyone starts committing with --no-verify.

~/.agents/skills/pre-commit-hooks/SKILL.md

--- name: pre-commit-hooks description: Sets up fast git hooks that format and lint only staged files - the pre-commit framework (or prek) for Python and polyglot repos, husky with… license: MIT ---

Good hooks finish in a few seconds, touch only staged files, fix what they can automatically, and never surprise the developer by rewriting unstaged work. They are a convenience layer: CI runs the exact same checks on every PR, because anyone can commit with --no-verify.

Before changing anything

  • Read AGENTS.md, package.json scripts, pyproject.toml, and any existing .pre-commit-config.yaml, .husky/, lefthook.yml or .lintstagedrc*.
  • Check git config core.hooksPath; if set, another tool already owns the hooks and a second installer will silently fight it.
  • Note the linters and formatters already configured. Hooks should call the project’s tools with the project’s config, never introduce a parallel config.

Choose the hook manager

RepoDefaultWhy
Python, or several languagespre-commit framework (or prek, a faster compatible reimplementation)Pinned, isolated tool environments, huge hook ecosystem
JS/TS with package.json at the roothusky + lint-stagedUses the project’s own node_modules, zero extra runtime
JS/TS monorepo or need parallel hooks across languageslefthookSingle binary, parallel commands, glob filters, stage_fixed
Repo already uses one of theseKeep itMigrating hook managers is churn with no user benefit

What belongs in which hook

HookPut hereKeep out
pre-commitFormatters with auto-fix, fast linters on staged files, merge-conflict markers, large-file and private-key checks, secret scanFull test suite, type-checking the whole project, anything needing network
commit-msgConventional Commits or ticket-ID checkAnything slow
pre-pushType check, affected unit tests, if they finish in under about a minuteIntegration tests, builds
CIEverything above on all files, plus the real test suite-

Budget: aim for under 5 seconds for a typical commit, with 10 seconds as the hard ceiling. Slower hooks get bypassed, and then they protect nothing.

pre-commit framework

# .pre-commit-config.yaml
default_install_hook_types: [pre-commit, commit-msg]
minimum_pre_commit_version: "3.2.0"
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v6.0.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-toml
      - id: check-merge-conflict
      - id: check-added-large-files
        args: [--maxkb=500]
      - id: detect-private-key
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.17.3
    hooks:
      - id: ruff-check
        args: [--fix]
      - id: ruff-format          # after ruff-check --fix, since fixes may need reformatting
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.24.0
    hooks:
      - id: gitleaks
  - repo: local
    hooks:
      - id: mypy-changed
        name: mypy (staged files)
        entry: uv run mypy
        language: unsupported    # formerly "system"; runs a tool already on PATH
        types: [python]
        require_serial: true
pre-commit install                 # writes hooks for default_install_hook_types
pre-commit autoupdate              # pin every repo to its latest tag; review the diff
pre-commit run --all-files         # first run on the whole repo; expect fixes
pre-commit run --from-ref origin/main --to-ref HEAD   # only files changed on this branch
  • The first run clones hook repos and builds isolated environments into ~/.cache/pre-commit; that needs network. In a Codex sandbox with network off, ask for approval or run the underlying tools directly (ruff check --fix, ruff format).
  • language: unsupported hooks use whatever is installed; prefer them for type checkers that must see the project’s dependencies.
  • autoupdate --freeze pins commit SHAs instead of tags, useful for supply-chain policy.
  • Hooks receive only staged files that match types/files. A hook that must see the whole project (mypy with cross-module types) needs pass_filenames: false, and is usually better in pre-push or CI.

husky + lint-staged

npm install --save-dev husky lint-staged
npx husky init       # creates .husky/pre-commit and sets "prepare": "husky" in package.json
# .husky/pre-commit  (husky v9: plain commands, no shebang or sourcing lines needed)
npx lint-staged
// lint-staged.config.js
export default {
  "*.{js,jsx,ts,tsx}": ["eslint --fix --max-warnings=0", "prettier --write"],
  "*.{json,md,yml,yaml,css}": "prettier --write",
  // Function form: run once without file arguments (tsc cannot type-check single files)
  "*.{ts,tsx}": () => "tsc --noEmit -p tsconfig.json",
};
  • lint-staged stashes unstaged changes, runs on staged content, re-adds fixed files and restores the rest, so partially staged files are safe. Do not add a manual git add to the commands.
  • Running tsc on every commit is often too slow for large projects; move it to pre-push (.husky/pre-push) if it exceeds the budget.
  • Skip hook installation in CI and production installs with HUSKY=0.
  • Swap npx for pnpm exec or yarn per the lockfile in the repo.

lefthook

# lefthook.yml
pre-commit:
  parallel: true
  commands:
    lint:
      glob: "*.{js,ts,tsx}"
      run: npx eslint --fix {staged_files}
      stage_fixed: true
    format:
      glob: "*.{js,ts,tsx,json,md}"
      run: npx prettier --write {staged_files}
      stage_fixed: true

Install with npx lefthook install (or the binary from your package manager).

Same checks in CI

# GitHub Actions step (pre-commit framework)
- uses: actions/setup-python@v5
  with: { python-version: "3.12" }
- run: pipx run pre-commit run --all-files --show-diff-on-failure

For husky setups, CI runs the underlying scripts (npm run lint, npm run format:check) instead of lint-staged, because there is nothing staged in CI.

Workflow

- [ ] 1. Inventory existing hooks, core.hooksPath and tool configs
- [ ] 2. Pick the manager (table above) and the hook stages
- [ ] 3. Add the config, install, run on all files once
- [ ] 4. Commit the mass-format result separately from the hook config
- [ ] 5. Add the commit SHA of that format commit to .git-blame-ignore-revs
- [ ] 6. Time a typical commit; move anything slow to pre-push or CI
- [ ] 7. Add the CI job and document install steps in AGENTS.md / CONTRIBUTING.md

Gotchas

  • First adoption on an old repo rewrites hundreds of files. Land that as its own commit (with the user’s approval for the churn) so feature diffs stay readable.
  • Two formatters on the same files (Prettier and Biome, Black and Ruff format) oscillate. One formatter per file type.
  • Hooks that need network (npm audit, remote schema fetches) fail offline and in sandboxes. Keep them in CI.
  • git commit --no-verify and SKIP=hook-id git commit exist for emergencies. Never use them to get past a failing hook without telling the user; fix the cause instead.
  • A hook that modifies files without auto-staging them leaves the commit missing the fix. Use lint-staged, stage_fixed, or the pre-commit framework, which all handle this.
  • Windows and GUI git clients run hooks without your shell profile; avoid relying on aliases or nvm-loaded PATH entries in hook scripts.

Verify

Test on a throwaway branch with a clean working tree (ask first if it is dirty):

git switch -c tmp/hook-check
printf 'x = 1 \n' > hook_sample.py && git add hook_sample.py   # trailing space to fix
time git commit -m "test: hook check"                          # observe fixes and timing
git show --stat HEAD
git switch - && git branch -D tmp/hook-check                   # discard the test branch

Report: hooks installed, measured time for a typical commit, which checks moved to pre-push or CI, and the CI job that enforces the same rules.

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Pre-commit Hooks"
  short_description: "Hooks that fix staged files in seconds, not minutes"
  default_prompt: "$pre-commit-hooks Add pre-commit hooks to this Python repo for ruff, formatting and secret scanning"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
Just launched

Codex Skills Pro is live

79 premium skills for Codex, each with scripts, references and an evidence report that proves the result.

Bought one by one$882.21
All 79 skills$49
94% off

That's $0.62 a skill, paid once.

Get all 79 for $49Or pick single skills from $4.99 →

Secure checkout by Creem