Claude Code for pre-commit: Automated Git Hook Management — Claude Skills 360 Blog
Blog / AI / Claude Code for pre-commit: Automated Git Hook Management
AI

Claude Code for pre-commit: Automated Git Hook Management

Published: December 18, 2027
Read time: 5 min read
By: Claude Skills 360

pre-commit manages git hooks across languages. pip install pre-commit. Install hooks: pre-commit install. Run all: pre-commit run --all-files. Single hook: pre-commit run ruff --all-files. Update: pre-commit autoupdate. Skip on commit: git commit --no-verify (use sparingly). Uninstall: pre-commit uninstall. Clean cache: pre-commit clean. .pre-commit-config.yaml: repos: list with repo: URL, rev: pinned tag, hooks: [{id: hookname}]. default_stages: [pre-commit]. default_language_version: {python: python3.12}. fail_fast: true — stop after first failure. Hook fields: id, name, language, entry, types, exclude, files, args, always_run, pass_filenames, stages. Built-in pre-commit/pre-commit-hooks repo: trailing-whitespace, end-of-file-fixer, check-yaml, check-json, check-toml, check-xml, check-merge-conflict, check-added-large-files, detect-private-key, no-commit-to-branch, mixed-line-ending. Custom local hook: - repo: local; hooks: [{id: pytest-unit, name: unit tests, entry: pytest tests/unit, language: system, pass_filenames: false, always_run: true}]. Stages: pre-commit (default), commit-msg, pre-push, manual. Install commit-msg hook: pre-commit install --hook-type commit-msg. pre-commit.ci: add .pre-commit-ci.yaml with autofix_prs: true, autoupdate_schedule: weekly. SKIP=ruff git commit -m "..." — skip specific hooks by ID. Environment: additional_dependencies: ["ruff==0.4.0"] — pin hook tool versions. language: python hooks run in hook’s own virtualenv. language: system uses project’s virtualenv. Claude Code generates pre-commit configs for Python, JavaScript, Go, and polyglot projects.

CLAUDE.md for pre-commit

## pre-commit Stack
- Version: pre-commit >= 3.7 | pip install pre-commit
- Install: pre-commit install (once per clone)
- Run: pre-commit run --all-files | git commit triggers automatically
- Config: .pre-commit-config.yaml with repos/rev/hooks
- Update: pre-commit autoupdate (quarterly — use --freeze for pinned hashes)
- Skip: SKIP=hookid git commit (selective) | --no-verify (all hooks, rare)
- CI: pre-commit run --all-files in pipeline + pre-commit.ci for auto PRs

pre-commit Hook Pipeline

# .pre-commit-config.yaml
# Install: pre-commit install
# Run all: pre-commit run --all-files
# Update revs: pre-commit autoupdate

default_language_version:
  python: python3.12

default_stages: [pre-commit]

# Fail fast: stop after first failing hook (set false for full report)
fail_fast: false

repos:

  # ── 1. Universal file hygiene ──────────────────────────────────────────────
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.6.0
    hooks:
      # Remove trailing whitespace from all text files
      - id: trailing-whitespace
        args: [--markdown-linebreak-ext=md]

      # Ensure every file ends with a newline
      - id: end-of-file-fixer

      # Validate YAML syntax
      - id: check-yaml
        args: [--allow-multiple-documents]

      # Validate JSON syntax
      - id: check-json

      # Validate TOML syntax
      - id: check-toml

      # Detect git merge conflict markers left in files
      - id: check-merge-conflict

      # Block committing files > 500 KB (use Git LFS for large assets)
      - id: check-added-large-files
        args: [--maxkb=500]

      # Scan for private keys accidentally staged
      - id: detect-private-key

      # Prevent direct commits to main/master
      - id: no-commit-to-branch
        args: [--branch, main, --branch, master]

      # Normalize line endings (prefer LF on all platforms)
      - id: mixed-line-ending
        args: [--fix=lf]

      # Verify Python files parse (catches syntax errors before CI)
      - id: check-ast

      # Verify __init__.py files in packages exist
      - id: check-docstring-first

  # ── 2. Ruff — linting + formatting (replaces flake8, isort, Black) ─────────
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.4.4
    hooks:
      # Lint and auto-fix: import sorting, pyupgrade, bugbear, etc.
      - id: ruff
        args: [--fix, --exit-non-zero-on-fix]

      # Format: Black-compatible whitespace and indentation
      - id: ruff-format

  # ── 3. mypy — static type checking ────────────────────────────────────────
  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.10.0
    hooks:
      - id: mypy
        args: [--strict, --ignore-missing-imports]
        # Only run on .py files in src/ (skip tests for speed)
        files: ^src/
        additional_dependencies:
          - types-requests
          - types-PyYAML
          - types-python-dateutil

  # ── 4. Bandit — security linting ──────────────────────────────────────────
  - repo: https://github.com/PyCQA/bandit
    rev: 1.7.8
    hooks:
      - id: bandit
        args: [-c, pyproject.toml, -ll]   # HIGH severity only
        files: ^src/
        additional_dependencies: ["bandit[toml]"]

  # ── 5. Commit message linting ──────────────────────────────────────────────
  - repo: https://github.com/commitizen-tools/commitizen
    rev: v3.27.0
    hooks:
      - id: commitizen
        stages: [commit-msg]

  # ── 6. Secrets scanning ───────────────────────────────────────────────────
  - repo: https://github.com/Yelp/detect-secrets
    rev: v1.5.0
    hooks:
      - id: detect-secrets
        args: [--baseline, .secrets.baseline]
        exclude: tests/fixtures/

  # ── 7. Local hooks — project-specific checks ──────────────────────────────
  - repo: local
    hooks:
      # Fast unit tests (no slow/integration tests)
      - id: pytest-unit
        name: pytest unit tests
        entry: pytest tests/unit/ -x -q --tb=short
        language: system
        pass_filenames: false
        always_run: true
        stages: [pre-push]   # only on push, not every commit

      # Check that pyproject.toml is valid
      - id: check-pyproject
        name: validate pyproject.toml
        entry: python -c "import tomllib; tomllib.load(open('pyproject.toml','rb'))"
        language: system
        files: ^pyproject\.toml$
        pass_filenames: false

      # Enforce no print() statements in src/ (use logger instead)
      - id: no-print-statements
        name: no print() in src/
        entry: ruff check --select T201 src/
        language: system
        pass_filenames: false
        files: ^src/.*\.py$
# scripts/pre_commit_helpers.py
# Utility functions for pre-commit workflow management.
from __future__ import annotations

import subprocess
import sys
from pathlib import Path


def install_hooks(hook_types: list[str] | None = None) -> None:
    """
    Install pre-commit hooks for the current repo.
    Installs pre-commit and pre-push hooks by default.
    Run once after cloning: python scripts/pre_commit_helpers.py install
    """
    cmds = [["pre-commit", "install"]]
    for ht in (hook_types or ["commit-msg"]):
        cmds.append(["pre-commit", "install", "--hook-type", ht])
    for cmd in cmds:
        subprocess.run(cmd, check=True)
    print("pre-commit hooks installed.")


def run_all(fix: bool = True) -> int:
    """
    Run all hooks on every file.
    Used in CI and for bulk clean-up after adding new hooks.
    Returns the exit code (0 = all pass, non-zero = failures).
    """
    env_skip = ""   # set to "mypy,bandit" to skip slow hooks in dev
    cmd = ["pre-commit", "run", "--all-files"]
    result = subprocess.run(cmd, check=False)
    return result.returncode


def autoupdate(freeze: bool = False) -> None:
    """
    Update all hook revs to the latest tagged version.
    Use --freeze to pin to commit SHAs instead of tags.
    Run quarterly or before a security audit.
    """
    cmd = ["pre-commit", "autoupdate"]
    if freeze:
        cmd.append("--freeze")
    subprocess.run(cmd, check=True)


def generate_secrets_baseline(output: str = ".secrets.baseline") -> None:
    """
    Generate a baseline file for detect-secrets.
    Run once to acknowledge existing secrets in the repo, then commit the baseline.
    New secrets introduced after the baseline will fail the hook.
    """
    subprocess.run(
        ["detect-secrets", "scan", "--baseline", output],
        check=True,
    )
    print(f"Secrets baseline written to {output}")
    print("Commit .secrets.baseline to the repo.")


# ── GitHub Actions CI integration ─────────────────────────────────────────────

GITHUB_ACTIONS_PRE_COMMIT = """
# .github/workflows/pre-commit.yml
name: pre-commit

on:
  push:
    branches: [main]
  pull_request:

jobs:
  pre-commit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - uses: pre-commit/[email protected]
        # This action caches hook environments and runs pre-commit run --all-files
        # Fails the PR if any hook fails or modifies files
"""

# ── .pre-commit-ci.yaml — cloud auto-fix service ─────────────────────────────

PRE_COMMIT_CI_CONFIG = """
# .pre-commit-ci.yaml — enables pre-commit.ci to auto-fix PRs
ci:
  autofix_commit_msg: "style: pre-commit auto-fixes"
  autofix_prs: true
  autoupdate_commit_msg: "chore: pre-commit autoupdate"
  autoupdate_schedule: weekly
  skip: [mypy, bandit, pytest-unit]   # skip slow hooks in CI auto-fix
  submodules: false
"""

# ── Developer onboarding script ───────────────────────────────────────────────

ONBOARDING_SCRIPT = """
#!/usr/bin/env bash
# scripts/setup_dev.sh — run once after cloning the repo
set -euo pipefail

echo "Setting up development environment..."

# 1. Install Python dependencies
pip install -e ".[dev]"

# 2. Install pre-commit hooks
pre-commit install
pre-commit install --hook-type commit-msg
pre-commit install --hook-type pre-push

# 3. Generate secrets baseline if not present
if [ ! -f .secrets.baseline ]; then
    detect-secrets scan --baseline .secrets.baseline
    echo "Secrets baseline generated — commit .secrets.baseline"
fi

# 4. Run hooks once on all files to verify setup
pre-commit run --all-files || echo "Some hooks failed — fix before committing"

echo "Done. pre-commit hooks active for all future git operations."
"""


if __name__ == "__main__":
    if len(sys.argv) > 1 and sys.argv[1] == "install":
        install_hooks()
    elif len(sys.argv) > 1 and sys.argv[1] == "run":
        sys.exit(run_all())
    elif len(sys.argv) > 1 and sys.argv[1] == "update":
        autoupdate(freeze="--freeze" in sys.argv)
    else:
        print("Usage: python pre_commit_helpers.py [install|run|update]")

For the husky + lint-staged alternative (JavaScript) — husky manages git hooks for Node.js projects and lint-staged runs linters only on staged files, but both are npm-only while pre-commit works across Python, Go, Rust, shell, and YAML in the same .pre-commit-config.yaml, shares a hook cache across all repos on the machine, and pre-commit autoupdate handles version bumps for every tool in one command. For the Makefile pre-commit target alternative — running make lint manually before commits is forgotten by at least one team member per sprint, while pre-commit install makes the hook fire automatically on every git commit without developer action, and pre-commit run --all-files in the GitHub Actions workflow ensures the same rules that run locally also block PRs when a developer bypasses hooks with --no-verify. The Claude Skills 360 bundle includes pre-commit skill sets covering .pre-commit-config.yaml structure, pre-commit-hooks built-ins, Ruff and ruff-format hooks, mypy and Bandit integration, local hooks for pytest and custom checks, commit-msg stage with commitizen, detect-secrets baseline workflow, pre-commit autoupdate strategy, GitHub Actions pre-commit/action integration, and pre-commit.ci for automated PR fixes. Start with the free tier to try git hook automation code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free