npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

claude-git-hooks

v3.11.3

Published

Git hooks with Claude CLI for code analysis and automatic commit messages

Readme

Claude Git Hooks

AI-powered git hooks for automatic commit messages, code analysis, and PR creation.

Requirements

  • Node.js >=16.9.0
  • Git
  • Claude CLI (authenticated)

Quick Start

npm install -g claude-git-hooks
cd your-project
claude-hooks install

Install verifies Node.js, npm, Git and the Claude CLI. --headless makes the install non-interactive (CI/containers) but still runs those checks — it changes interaction, never scope. To skip them deliberately:

claude-hooks install --headless                          # non-interactive, checks run
claude-hooks install --headless --skip-dependency-checks # opt out, prints a warning

Usage

Auto Commit Message

git commit -m "auto"
# Claude generates message from branch name + changes
# Format: [TASK-ID] type: description
# Example: branch feature/IX-123-auth → [IX-123] feat: add authentication

Create PR

claude-hooks create-pr develop
# Automatically pushes branch if unpublished (with confirmation)
# Analyzes diff, generates title/description, creates PR on GitHub

Auto-push feature (v2.11.0):

  • Detects unpublished branches or unpushed commits
  • Shows commit preview before pushing
  • Prompts for confirmation (configurable)
  • Handles diverged branches gracefully

Merge strategy awareness (v2.25.0):

  • Auto-detects required strategy from branch naming: feature/*/release-fix/* → squash, release-candidate/*/hotfix/*/→ main → merge commit
  • Displays strategy in PR preview; adds merge-strategy:squash or merge-strategy:merge-commit label
  • Prepends body reminder for merge-commit PRs; unknown patterns prompt user to select manually

Automatic label resolution (v2.31.0):

  • Resolves labels from 5 rule types: preset, size, quality, strategy, and defaults
  • Remote config priority (your organisation's git-hooks-config repository, labels.json) with local fallback
  • Size labels: size:S (<10 files), size:M (10-50), size:L (50-100), size:XL (>100) — thresholds configurable remotely
  • Quality labels: breaking-change, security, performance from analysis result
  • Each rule type independently enabled/disabled via remote config

Team Configuration

Label rules, PR categories, and role-based permissions are managed centrally in a git-hooks-config repository belonging to your organisation. Changes there take effect immediately across all governed repositories — no tool update or deploy required. The repository is resolved from your configuration; see claude-hooks setup-github.

Code Knowledge Library (optional)

Several commands maintain a repository's Code Knowledge Library — per-file Markdown "books" extracted from source. create-pr regenerates stale books, bump-version and create-release verify them, pre-commit flags a book whose source changed, and close-release refuses to close on drift. All of it is skipped silently in a repository that has no Library, which is most of them.

Two pieces have to be present for any of it to run:

| Piece | What it is | Where it comes from | |---|---|---| | Content | .library/ with resolver.yaml, books and indexes | Committed in the repository | | Engine | The code that extracts and checks books | A package you declare, or a copy vendored into .library/ |

claude-git-hooks does not bundle an engine, and names none in its own code: it is a public package, and hardcoding one organisation's engine would ship a dependency most consumers cannot resolve. A repository says which engine maintains its books:

// .claude-hooks.json at the repository root — tracked, and never published
{
    "libraryEngine": "@your-scope/librarian"
}

claudeHooks.libraryEngine in package.json works too. Prefer .claude-hooks.json when the engine's name identifies your organisation and your package is public: package.json is published and rendered on the npm page, and .claude-hooks.json is neither.

Install the engine where the Library is maintained. Keep it out of dependencies — and out of devDependencies if it lives in a private repository, or npm ci will fail for anyone without access, CI included. CLAUDE_HOOKS_LIBRARY_ENGINE=@your-scope/librarian overrides the declaration for a single run.

An engine is expected to expose three entry points: its package root (the pipeline), /paths (path resolution) and /staleness (book checking).

No configuration needed if the engine is vendored. A repository that carries its own engine at .library/librarian/index.js, .library/paths.js and .library/tools/staleness.js is used as-is; that was the only layout before the engine became installable, and it still works.

With neither, a repository that has books reports as content-only: the commands say so once and carry on rather than failing.

Token Setup

claude-hooks setup-github  # Configure GitHub token for PR creation
claude-hooks setup-linear  # Configure Linear token for ticket enrichment

Option 1 - Settings file (recommended):

// .claude/settings.local.json (gitignored)
{ "githubToken": "ghp_..." }

Option 2 - Environment variable:

export GITHUB_TOKEN="ghp_..."

Create token at https://github.com/settings/tokens with scopes: repo, read:org

Linting & Formatting

Runs formatters and linters on staged files automatically during pre-commit, or on demand:

# Lint staged files (default)
claude-hooks lint

# Lint all files in a directory
claude-hooks lint src/

# Lint specific files
claude-hooks lint file1.js file2.java

# Mix of directories and files
claude-hooks lint src/ lib/utils/ file.js

Tools per preset (configured via your organisation's remote config repository):

| Preset | Tools | | ----------- | ----------------------------- | | frontend | Prettier, ESLint | | backend | Spotless | | fullstack | Prettier, ESLint, Spotless | | database | sqlfluff | | ai | Prettier, ESLint | | default | Prettier, ESLint |

Behavior:

  • Formatters run first (Prettier), then linters (ESLint) — format before lint
  • Auto-fix enabled by default — fixes and re-stages files automatically
  • Missing tools are skipped with install instructions (never blocks)
  • Unfixable issues are forwarded to the Claude judge for semantic resolution
  • Tool-to-preset mapping is fetched from remote config (team-controlled, no release needed)

Analyze Code (Interactive Review)

Run interactive code analysis before committing:

# Analyze staged changes (default)
claude-hooks analyze

# Analyze unstaged changes
claude-hooks analyze --unstaged

# Analyze all tracked files
claude-hooks analyze --all

What it does:

  • Analyzes selected file scope (staged, unstaged, or all)
  • Shows all issues (INFO, MINOR, MAJOR, CRITICAL, BLOCKER)
  • Interactive prompt with options:
    • Continue: Creates commit automatically with auto-generated message
    • Abort: Generate resolution prompt and fix issues
    • View: Show detailed issue list
  • Executes git commit -m "auto" --no-verify on confirmation
  • Works outside git hooks (no stdin limitations)

Use case: Complete analysis-to-commit workflow in one command.

Analyze Diff (without creating PR)

claude-hooks analyze-diff develop
# Generates PR metadata without creating

Analyze PR from GitHub URL

claude-hooks analyze-pr https://github.com/owner/repo/pull/123
# Fetches PR, applies preset guidelines, posts review comments

claude-hooks analyze-pr https://github.com/owner/repo/pull/123 --dry-run
# Analyze without posting comments

claude-hooks analyze-pr https://github.com/owner/repo/pull/123 --preset backend --model opus
# Override preset and model
  • Auto-detects preset from PR labels, Linear ticket labels, or file extensions
  • Enriches with Linear ticket context when [AUT-1234] found in PR title
  • Interactive comment workflow: confirm/skip each finding before posting
  • Classifies into inline (file:line) and general (review-level) categories

Bump Version

Automatic version management with CHANGELOG generation and Git tagging:

# Bump patch version (1.0.0 → 1.0.1)
claude-hooks bump-version patch

# Bump with suffix
claude-hooks bump-version minor --suffix SNAPSHOT  # → 1.1.0-SNAPSHOT

# Bump and generate CHANGELOG
claude-hooks bump-version major --update-changelog

# Preview without applying
claude-hooks bump-version patch --dry-run

# Push tag immediately (otherwise pushed by create-pr)
claude-hooks bump-version patch --push

# Manual workflow (skip automatic commit)
claude-hooks bump-version patch --no-commit

What it does:

  • Detects project type (Node.js, Maven, or monorepo with both)
  • Updates package.json and/or pom.xml
  • Generates CHANGELOG entry with Claude (analyzes commits)
  • Commits changes automatically with conventional commit format
  • Creates annotated Git tag with v prefix (e.g., v2.7.0)
  • Tags stay local by default (use --push to push immediately, or let create-pr handle it)

Version workflow:

2.7.0 → 2.8.0-SNAPSHOT    # Start development
2.8.0-SNAPSHOT → 2.8.0-RC # Release candidate
2.8.0-RC → 2.8.0          # Final release

Integration with create-pr:

  • Validates version alignment (package.json, pom.xml, CHANGELOG, tags)
  • Detects and prompts to push unpushed tags
  • Warns if local version ≤ remote version

Generate CHANGELOG

Standalone CHANGELOG generation (without version bump):

# Auto-detect version from package.json/pom.xml
claude-hooks generate-changelog

# Specific version with release marking
claude-hooks generate-changelog 2.7.0 --release

# Compare against different base branch
claude-hooks generate-changelog --base-branch develop

What it does:

  • Analyzes commits since last tag using Claude
  • Categorizes by Conventional Commits types (feat, fix, refactor, etc.)
  • Generates Keep a Changelog format entries
  • Discovers all CHANGELOG.md files (monorepo aware); prompts to select when multiple found
  • Updates the selected CHANGELOG.md automatically
  • Useful when bump-version --update-changelog fails

Disable/Enable Hooks

claude-hooks disable [pre-commit|prepare-commit-msg]
claude-hooks enable [pre-commit|prepare-commit-msg]

Uninstall

claude-hooks uninstall

Presets

claude-hooks presets              # List available
claude-hooks --set-preset backend # Set preset
claude-hooks preset current       # Show current

| Preset | Extensions | Focus | | --------- | ---------------------------------------- | ------------------------ | | backend | .java, .xml, .yml, .yaml | Spring Boot, JPA, OWASP | | frontend | .js, .jsx, .ts, .tsx, .css, .scss, .html | React, XSS, a11y | | fullstack | all above | API contract consistency | | database | .sql | SQL injection, indexes | | liquibase | .yaml, .sql | Liquibase changesets, rollback, T-SQL | | ai | .js, .json, .md, .sh | Node.js, Claude API | | default | multiple | General quality |

Skip Analysis

git commit --no-verify -m "message"

Judge Auto-Fix (opt-in)

The judge always reports its findings and the concrete patch it would apply. Whether that patch is written to your working tree is opt-in and off by default.

git commit -m "message"                    # default: fixes are suggested, not applied
CLAUDE_HOOKS_FIX=1 git commit -m "message" # apply fixes and stage them
CLAUDE_HOOKS_FIX=0 git commit -m "message" # force off, even if config enables it

Persistently, via .claude/config.json or the team's remote settings.json:

{ "judge": { "autoFix": true } }

Precedence: CLAUDE_HOOKS_FIX > user config > remote/team settings > packaged default (false).

A suggested-but-unapplied fix still blocks the commit — the defect is real and still present. Suggestion mode removes the mutation, not the quality gate.

Why off by default: field data across multiple sessions put auto-fixes at roughly 50/50 between resolving the issue and introducing an error that had to be reverted. Until fix quality is measured per issue category, the safe default is to show the patch and let you apply it.

Claude transport (CLI vs SDK)

How claude-hooks reaches Claude is an explicit configuration choice, independent of how you invoke it. The default is the Claude CLI, using your normal interactive login:

{ "claude": { "spawn": { "transport": "cli" } } }

Setting transport to "sdk" routes calls through the Anthropic SDK instead, which requires ANTHROPIC_API_KEY in the environment. This is a parked capability, not a supported configuration — spend is expected to stay on personal login tokens, so the SDK path is retained (and deliberately exercised by claude-hooks install --verify-sdk) but is not funded. Leave it on cli unless that changes.

Where it can be set, and where it cannot:

| Channel | Works? | |---|---| | lib/defaults.json (packaged default) | ✅ "cli" | | Team remote settings.json → claude.spawn.transport | ✅ deep-merged over the default | | Per-call transport option in code | ✅ overrides both | | User .claude/config.json | ❌ silently ignored — resolveSpawnConfig() reads the resolved claude section directly and never consults user config |

That last row is a real limitation, not an oversight in this table: wiring user config into spawn resolution would also change how claude.defaultModel resolves for existing callers, which is out of scope for a transport switch.

--headless does not select a transport. It means non-interactive — skip prompts — and nothing more. It used to also mean "use the SDK", which made --format json (which required --headless) unreachable without an API key. Those meanings are now separate, and --format json works on its own. Likewise CLAUDE_HOOKS_HEADLESS=1 no longer has any effect in the git hooks; they warn if it is set.

Debug Mode

claude-hooks --debug true|false|status

Extensions

Third-party tools plug into the pre-commit hook as isolated child processes. They are opt-in: an extension runs only when .claude/config.json names it, and remote team config may disable one but never enable it.

In v1 the wiring is narrower than the manifest schema: only pre-commit:pre-analysis and pre-commit:post-analysis are wired, and only sync-joining subscriptions there actually run. An async subscription — or one to any of the other ten hook points a manifest accepts — validates cleanly and shows as enabled in claude-hooks extension list, but is never launched and emits no metric.

claude-hooks extension list             # Installed extensions, activation and breaker state
claude-hooks extension enable <name>    # Clear a tripped circuit breaker
claude-hooks extension disable <name>   # Trip the breaker by hand

An extension that fails three times in a row is disabled automatically and stops being launched, so a broken integration costs three failed invocations rather than every commit. The trip lands on the third commit — or the second, if the extension subscribes to both wired pre-commit points and is therefore launched twice per commit. A new manifest version clears the breaker and restores the full three strikes. enable clears it too, but it does not opt the extension in, which stays a config decision.

Extension findings are reported, never judged. An extension runs an SDLC process parallel to the analysis — a linter, a scanner, a licence check — so its output is a pass/fail fact about the repo rather than a second opinion on the code. Its findings are therefore excluded from the judge entirely: they neither trigger a judge run nor appear in its input, and a clean commit stays a one-spawn commit no matter how much an extension reports. They are still shown, still counted in the totals, and still summarised in the "reported, not blocking" notice.

By default a finding also cannot block: it is clamped to info and stamped with the extension category, both of which the gate demotes. Adding "allowBlocking": true beside "enabled": true in an extension's entry lifts both, and does so deterministically — because the judge never sees the finding, nothing can dismiss it as a false positive. There is no allowJudging grant.

The opt-in must sit inside overrides, in a config declaring "version": "2.8.0". A section written at the top level is ignored — with a warning, but the extension will not run:

{
  "version": "2.8.0",
  "overrides": { "extensions": { "entries": { "my-extension": { "enabled": true } } } }
}

Telemetry

claude-hooks telemetry show   # View statistics
claude-hooks telemetry clear  # Clear data

Help & Issue Reporting

claude-hooks help "how do presets work?"  # AI-powered help (navigates .library/)
claude-hooks help --report-issue          # Interactive GitHub issue creation
claude-hooks --help                       # Static command reference

Batch Info

claude-hooks batch-info
# Shows: orchestration model, threshold, default analysis model
# Shows: per-model average analysis time and orchestration overhead (from telemetry)

Third-Party Integrations (extension points)

Third-party tools plug in through the extension-point contract — isolated child processes speaking JSON over stdio, opt-in per extension, and unable to block a commit unless explicitly granted. The in-process skillRegistry integration this replaced was removed with the contract (AUT-4409); a skillRegistry block left in your config is ignored and reported once on load.

Activation requires both a local install and a config opt-in:

| Installed locally | Enabled in config | Behaviour | | --- | --- | --- | | yes | yes | runs, bounded by the manifest timeout | | no | yes | one warning naming what is missing | | yes | no | nothing — opt-in is mandatory (INV-5) | | no | no | nothing |

claude-hooks extension list             # installed extensions, activation and breaker state
claude-hooks extension enable <name>    # clear a tripped circuit breaker
claude-hooks extension disable <name>   # trip the breaker by hand

Tools that need no adapter at all can be run straight from config as triggers — before or after any claude-hooks command, sync or async:

{ "on": "create-pr", "when": "after", "mode": "async", "timeoutMs": 30000,
  "run": ["automation-skills", "retro"] }

Writing or reintegrating an extension: see docs/EXTENSIONS.md — §8 for triggers (no adapter), §2–6 for contributions (JSON envelope), §9 for skills.

Other Commands

claude-hooks status   # Show hook status
claude-hooks update   # Update to latest version

Architecture Reference (AI Context)

Design Philosophy

Modular, decoupled, reusable code. Each component has a single responsibility and can be tested/modified independently.

Directory Map

| Path | Purpose | Key Exports | | ------------------ | -------------------------------------------------------- | ---------------------------------------- | | bin/claude-hooks | Thin CLI router - argument parsing, command dispatch | - | | lib/commands/ | Command modules - one file per CLI command | See table below | | lib/config.js | Config system - load/merge configuration | getConfig() | | lib/hooks/ | Git hook logic - Node.js implementations | pre-commit.js, prepare-commit-msg.js | | lib/utils/ | Reusable utilities - shared across commands | See table below | | templates/ | Static assets - bash wrappers, prompts, presets | Copied during install |

Command Modules (lib/commands/)

| Module | Purpose | Key Exports | | ----------------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------- | | helpers.js | Shared CLI utilities - colors, output, platform detection | colors, error(), success(), info(), checkGitRepo(), Entertainment | | install.js | Installation logic - dependencies, hooks, templates | runInstall(), extractLegacySettings() | | hooks.js | Hook management - enable, disable, status, uninstall | runEnable(), runDisable(), runStatus(), runUninstall() | | analyze.js | Interactive code analysis - analyze before committing | runAnalyze() | | analyze-diff.js | Diff analysis - generate PR metadata from git diff | runAnalyzeDiff() | | analyze-pr.js | PR analysis - analyze GitHub PR with team guidelines | runAnalyzePr() | | create-pr.js | PR creation - full workflow via Octokit | runCreatePr() | | bump-version.js | Version management - bump with CHANGELOG and Git tag | runBumpVersion() | | generate-changelog.js | CHANGELOG generation - standalone command | runGenerateChangelog() | | setup-github.js | Token setup - interactive GitHub configuration | runSetupGitHub() | | setup-linear.js | Token setup - interactive Linear configuration | runSetupLinear() | | presets.js | Preset management - list, set, show current | runShowPresets(), runSetPreset(), runCurrentPreset() | | update.js | Self-update - check and install latest version | runUpdate() | | migrate-config.js | Config migration - legacy to the current format | runMigrateConfig() | | debug.js | Debug toggle - enable/disable verbose logging | runSetDebug() | | telemetry-cmd.js | Telemetry commands - show/clear statistics | runShowTelemetry(), runClearTelemetry() | | diff-batch-info.js | Batch info - orchestration config + per-model speed telemetry | runDiffBatchInfo() | | help.js | Help, AI librarian, report-issue | runShowHelp(), showStaticHelp(), runShowVersion() |

Utility Modules (lib/utils/)

| Module | Purpose | Key Exports | | ------------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | analysis-engine.js | Shared analysis logic - file data, orchestration, results (v2.13.0) | buildFilesData(), runAnalysis(), consolidateResults(), displayResults() | | diff-analysis-orchestrator.js | Intelligent orchestration - semantic batch grouping via Opus (v2.20.0) | orchestrateBatches(), buildFileOverview(), detectDependencies() | | claude-client.js | Claude CLI wrapper - spawn, retry, model override | analyzeCode(), executeClaudeWithRetry(), extractJSON() | | prompt-builder.js | Prompt construction - load templates, replace variables, inject commit context | buildAnalysisPrompt(), loadPrompt() | | git-operations.js | Git abstractions - staged files, diff, branch comparison | getStagedFiles(), getDiff(), getRepoRoot(), resolveBaseBranch(), getDiffBetweenRefs() | | pr-metadata-engine.js | PR metadata generation - branch context, diff reduction (v2.14.0) | getBranchContext(), buildDiffPayload(), generatePRMetadata(), analyzeBranchForPR() | | github-api.js | Octokit integration - PR creation, PR analysis, token validation, content fetching | createPullRequest(), fetchPullRequest(), fetchPullRequestFiles(), createPullRequestReview(), parseGitHubPRUrl(), validateToken(), saveGitHubToken(), fetchFileContent(), fetchDirectoryListing(), createIssue() | | token-store.js | Token persistence - centralized settings.local.json read/write | loadToken(), saveToken(), hasToken(), loadLocalSettings() | | linear-connector.js | Linear integration - ticket context fetching with retry | fetchTicket(), extractLinearTicketFromTitle(), testConnection(), loadLinearToken() | | pr-statistics.js | PR statistics - write-only JSONL analytics | recordPRAnalysis() | | github-client.js | GitHub helpers - repo parsing, config-based reviewers | getReviewersForFiles(), parseGitHubRepo() | | reviewer-selector.js | Team-based reviewer selection - GitHub Teams API resolution (v2.32.0) | selectReviewers() | | preset-loader.js | Preset system - load tech-stack configurations | loadPreset(), listPresets() | | task-id.js | Task ID extraction - Jira, GitHub, Linear patterns | getOrPromptTaskId(), formatWithTaskId() | | judge.js | Auto-fix judge - LLM verdict + search/replace fixes (v2.20.0) | judgeAndFix(), applyFix() | | resolution-prompt.js | Issue resolution - AI-friendly fix prompts | generateResolutionPrompt() | | logger.js | Logging system - centralized output with debug mode | info(), warning(), error(), debug() | | interactive-ui.js | CLI UI components - previews, prompts, spinners | showPRPreview(), promptConfirmation(), promptMenu() | | telemetry.js | Local telemetry - track JSON parsing, retries | recordEvent(), displayStatistics() |

Execution Flow

Pre-commit Hook

git commit → templates/pre-commit (bash wrapper)
  → lib/hooks/pre-commit.js
  → getStagedFiles() → filterFiles() by preset extensions + size
  → buildFilesData() → runAnalysis() (via analysis-engine.js)
  → displayResults() → show quality gate status
  → judge evaluates ALL issues (any severity):
    → TRUE_ISSUE, judge.autoFix off (DEFAULT): patch printed as a suggestion,
      working tree untouched, issue stays unresolved
    → TRUE_ISSUE, judge.autoFix on: auto-fix via search/replace + git add
    → FALSE_POSITIVE: dismissed
    → LATENT: recorded, never fixed, never blocking (no caller reaches it today)
    → ALL resolved: exit 0 (pass)
    → ANY unresolved: generates resolution prompt → exit 1 (block)
    → judge failure: user warned → exit 1 (block)
  → judge disabled: original quality gate (blocks on critical/blocker only)

Note: For interactive review of non-blocking issues, use claude-hooks analyze before committing.

Commit Message Generation

git commit -m "auto" → templates/prepare-commit-msg (bash wrapper)
  → lib/hooks/prepare-commit-msg.js
  → extract task-id from branch name
  → generate message via Claude
  → write to COMMIT_EDITMSG

PR Metadata Generation (analyze-diff / create-pr)

claude-hooks analyze-diff|create-pr → bin/claude-hooks (router)
  → lib/commands/analyze-diff.js or create-pr.js (thin wrapper)
  → analyzeBranchForPR() (pr-metadata-engine.js)
    → resolveBaseBranch() (git-operations.js)
    → getDiffBetweenRefs() + getCommitsBetweenRefs()
    → buildDiffPayload() with tiered reduction (context → proportional → stat-only)
    → executeClaudeWithRetry() → PRMetadata
  → analyze-diff: formats to console + saves JSON
  → create-pr: additionally creates PR via Octokit API

PR Analysis (analyze-pr)

claude-hooks analyze-pr <url> → bin/claude-hooks (router)
  → lib/commands/analyze-pr.js
  → parseGitHubPRUrl() → fetchPullRequest() + fetchPullRequestFiles()
  → extractLinearTicketFromTitle() → fetchTicket() (optional enrichment)
  → resolvePreset() (labels → ticket → auto-detect → default)
  → loadPrompt('ANALYZE_PR.md') with preset guidelines + categories
  → executeClaudeWithRetry() → extractJSON() → normalizeCategory()
  → interactive comment workflow (confirm/skip)
  → createPullRequestReview() → inline + general comments
  → recordPRAnalysis() (JSONL statistics)

Config Priority

defaults (lib/config.js)
  < user config (.claude/config.json)
  < preset config (.claude/presets/{name}/)

Preset always wins - tech-stack specific has priority over user preferences.

claude.spawn does not follow this chain. Model, timeouts and transport resolve from lib/defaults.json merged with the team's remote settings.json. User .claude/config.json hydrates only analysis, commitMessage and linting, so a claude.spawn block placed there is silently ignored. Change those knobs in the remote settings file.

Environment variables

| Variable | Effect | |---|---| | CLAUDE_HOOKS_FIX=1 / =0 | Force judge auto-fix on or off for one hook run | | CLAUDE_HOOKS_PREFER_GLOBAL=1 | Make the hook shim resolve the globally installed package instead of the local checkout. Only relevant inside the claude-git-hooks repo itself, where the shim self-hosts so that a hook change gates itself | | CLAUDE_HOOKS_HEADLESS=1 | Inert. Once selected the SDK transport; now warns and does nothing. Use claude.spawn.transport |

Config Format (v2.8.0)

The version field is a config format version, unrelated to the package version. It is matched by major, so any 2.x or 3.x config is read as-is and 2.x configs keep working indefinitely — there is no forced migration.

New configs are still written as 2.8.0, deliberately. A config declaring a version an older installation does not recognise is fatal there — every release before this one compares the string exactly and fails the hook — so the reader learns to accept the next format before anything starts writing it. Nothing behavioural depends on which supported version the string names.

{
    "version": "2.8.0",
    "preset": "backend",
    "overrides": {
        "github": {
            "pr": {
                "defaultBase": "develop",
                "reviewers": ["user"],
                "autoPush": true, // Auto-push unpublished branches (v2.11.0)
                "pushConfirm": true, // Prompt before push (v2.11.0)
                "showCommits": true, // Show commit preview (v2.11.0)
                "verifyRemote": true // Verify remote exists (v2.11.0)
            }
        }
    }
}

Key Patterns

  • Factory: preset-loader.js - dynamic config per tech-stack
  • Template Method: prompt-builder.js - prompts from .md templates
  • Strategy: analysis-engine.js - sequential vs orchestrated analysis
  • Adapter: git-operations.js - git commands to JS functions
  • Command: lib/commands/*.js - one module per CLI command

Modification Guide

| To change... | Edit... | | ------------------------- | ------------------------------------------------- | | CLI argument parsing | bin/claude-hooks | | Install workflow | lib/commands/install.js | | PR creation flow | lib/commands/create-pr.js | | PR analysis from URL | lib/commands/analyze-pr.js | | Analysis logic | lib/hooks/pre-commit.js | | Message generation | lib/hooks/prepare-commit-msg.js | | Prompt templates | templates/*.md or .claude/prompts/*.md | | Preset definitions | templates/presets/{name}/ | | Config defaults | lib/config.js | | GitHub integration | lib/utils/github-api.js | | Claude CLI calls | lib/utils/claude-client.js | | Batch orchestration logic | lib/utils/diff-analysis-orchestrator.js | | Orchestration prompt | templates/DIFF_ANALYSIS_ORCHESTRATION_PROMPT.md | | Auto-fix judge logic | lib/utils/judge.js |

File Structure

claude-git-hooks/
├── bin/claude-hooks              # Thin CLI router - dispatch to commands
├── lib/
│   ├── config.js                 # Config system - load and merge
│   ├── commands/                 # Command modules - one per CLI command
│   │   ├── helpers.js            # Shared utilities - colors, output
│   │   ├── install.js            # Install command - hooks, templates
│   │   ├── hooks.js              # Hook management - enable/disable
│   │   ├── analyze-diff.js       # Diff analysis - PR metadata
│   │   ├── analyze-pr.js         # PR analysis - GitHub PR review
│   │   ├── create-pr.js          # PR creation - Octokit workflow
│   │   ├── setup-github.js       # Token setup - interactive GitHub config
│   │   ├── setup-linear.js       # Token setup - interactive Linear config
│   │   ├── presets.js            # Preset commands - list/set
│   │   ├── update.js             # Self-update - npm latest
│   │   ├── migrate-config.js     # Migration - legacy to current format
│   │   ├── debug.js              # Debug mode - toggle verbose
│   │   ├── telemetry-cmd.js      # Telemetry - show/clear stats
│   │   ├── diff-batch-info.js    # Batch info - orchestration config
│   │   └── help.js               # Help display - usage info
│   ├── hooks/                    # Git hooks - Node.js logic
│   │   ├── pre-commit.js         # Pre-commit analysis
│   │   └── prepare-commit-msg.js # Message generation
│   └── utils/                    # Reusable modules - shared logic
│       ├── diff-analysis-orchestrator.js  # Intelligent batch orchestration
│       ├── judge.js                      # Auto-fix judge (v2.20.0)
│       └── token-store.js               # Token persistence - settings.local.json
├── .library/                     # Code Knowledge Library - auto-generated module docs
│   ├── books/                    # One book per source module (auto + manual sections)
│   ├── extractor/                # Tree-sitter AST tooling
│   │   ├── extract.js            # Source → book auto-section generator
│   │   ├── parser.js             # WASM parser init and grammar loading
│   │   └── adapters/             # Language-specific CST → normalized AST
│   └── templates/                # Book schema and category reference
├── templates/
│   ├── pre-commit                # Bash wrapper - invokes Node.js
│   ├── prepare-commit-msg        # Bash wrapper - invokes Node.js
│   ├── DIFF_ANALYSIS_ORCHESTRATION_PROMPT.md  # Opus orchestration prompt
│   ├── *.md                      # Other prompt templates
│   └── presets/                  # Preset configurations
└── test/unit/                    # Jest tests

Analysis Routing (v2.20.0)

Two-tier strategy based on file count:

| Files | Strategy | Details | | ----- | ----------------------------- | ------------------------------------------------------------------------------ | | 1–2 | Sequential | Single Claude call, full context | | 3+ | Intelligent orchestration | Opus groups files semantically, assigns model per batch, shared commit context |

Orchestration flow (3+ files):

  1. Opus reads a lightweight file overview + detected cross-file dependencies
  2. Groups related files into semantically coherent batches
  3. Assigns model per batch: haiku (config/docs), sonnet (business logic), opus (security-critical)
  4. All batches run in parallel; each receives a shared commit overview header
  5. Falls back to one-file-per-batch if orchestration fails

Inspect orchestration settings:

claude-hooks batch-info   # Shows config + per-model avg speed from telemetry

Hardcoded Defaults

  • Max file size: 1MB
  • Max files per commit: unlimited by default (set analysis.maxFiles to cap)
  • Orchestrator threshold: 3 files
  • Orchestrator model: opus (internal, not configurable)
  • Extensions: discovered from .claude/extensions/, every one disabled until opted in per extension; blocking requires an explicit allowBlocking grant

Contributing

Branching Strategy

This repository follows simplified GitHub Flow:

  • Main branch: main (protected)
  • Feature branches: feature/issue-description or feature/TASK-ID-description
  • Fix branches: fix/issue-description
  • Hotfix branches: hotfix/urgent-description

Rules:

  1. All changes require PR to main
  2. No direct commits to main
  3. PRs require review (auto-merge NOT allowed)

Development Process

1. Initial setup

git clone <your fork or source checkout>
cd git-hooks
npm install
npm link  # Install globally as symlink for development

2. Create feature branch

git checkout -b feature/new-functionality
# or with task-id: feature/IX-123-new-functionality

3. Develop and test

npm run lint         # ESLint over lib/ bin/ test/ scripts/
                     # (fails on warnings too: --max-warnings 0)
npm run lint:fix     # Auto-fix ESLint issues
npm run format       # Format with Prettier (writes)
npm run format:check # Verify formatting WITHOUT writing — this is the CI gate
npm run test:e2e     # SDLC e2e; --local-remote is the DEFAULT: a throwaway bare repo
                     # stands in for origin, so no push rights are needed and origin
                     # is never touched
npm run test:e2e:origin # same suite with --against-origin: pushes test branches and
                     # deletes remote refs. Requires push authority.
#
# bash test/manual/sdlc-stability-check.sh --help   # full flag list
npm run test        # Run all tests (Jest)
npm run test:watch  # Tests in watch mode
npm run test:coverage # Coverage report

4. Local testing in a test repo

cd /path/to/test-repo
claude-hooks install --force --skip-auth  # Reinstall from symlink
git commit -m "test"  # Test hook (npm link is active, no reinstall needed)

5. Create PR

git push -u origin feature/new-functionality
claude-hooks analyze-diff main    # Generate PR metadata
claude-hooks create-pr main       # Or create PR directly on GitHub

CI/CD

No automated CI/CD (GitHub Actions pending). Manual verifications before merge:

  1. npm run lint passes
  2. npm run test — all tests pass
  3. Manual testing in test repo
  4. Peer code review
  5. CHANGELOG.md updated

Versioning

Follows Semantic Versioning (MAJOR.MINOR.PATCH):

  • MAJOR: Breaking changes (config format, CLI arguments)
  • MINOR: New features without breaking changes
  • PATCH: Bug fixes
npm version patch    # 2.6.1 → 2.6.2
npm version minor    # 2.6.1 → 2.7.0
npm version major    # 2.6.1 → 3.0.0
npm publish          # Publish to NPM

Conventional Commits

Format: <type>(<scope>): <subject>

| Type | Purpose | |------|---------| | feat | New functionality | | fix | Bug fix | | docs | Documentation only | | style | Formatting (no logic change) | | refactor | Refactoring without functional change | | test | Add or modify tests | | chore | Maintenance (deps, config) | | perf | Performance improvements |

Optional scopes: hooks, presets, github, cli, config, windows

feat(presets): add database preset for SQL analysis
fix(windows): resolve spawn ENOENT with .cmd files
docs: update CLAUDE.md with architecture details
chore(deps): upgrade @octokit/rest to v21

More information: see the source repository for your installation.