The 12 lifecycle hooks every team should install | Claude Code Toolkit
Deep dives

The 12 lifecycle hooks every team should install

Claude Code hooks are the most underrated part of the platform. These twelve turn team standards from "we should really enforce that" into invariants that get enforced automatically.

FA
Fatima A. August 20, 2026 · 14 min read

Lifecycle hooks are the least-discussed part of Claude Code. Slash commands and subagents get the attention — they're what you invoke, they're what does the work. Hooks feel like plumbing.

They are plumbing. They're also what separates "AI-assisted development that's mostly fine" from "AI-assisted development you can trust with production." A team without hooks has to remember to check for secrets, format code, verify commit messages, audit tool usage. A team with hooks doesn't have to remember any of that — it happens automatically.

This post covers the 12 hooks that make the biggest difference. Grouped by concern: safety, quality, git, observability. All 12 are in cctk's catalog, but the patterns apply whether you install cctk's versions or build your own.

Quick primer on hooks

Claude Code hooks run at lifecycle events: PreToolUse (before Claude runs a tool), PostToolUse (after), Stop (session ends), SessionStart, and a few others. Each hook is a script (shell, Python, whatever). If a PreToolUse hook exits non-zero, Claude aborts the tool call. That's the whole model.

Safety hooks (must-have)

Three hooks that prevent categories of disaster. If you install nothing else from this list, install these.

1. block-secrets

The block-secrets hook runs on PreToolUse before any Write or Edit operation. It scans the content being written for patterns that look like secrets — API keys, AWS credentials, private keys, Slack tokens, database URLs with passwords, JWT signing secrets. If it finds one, it blocks the write and prints what it found.

This exists because it's catastrophically easy for AI to accidentally commit a secret. You copy a config into a chat, Claude helps you refactor it, and now your .env contents are in a code file that gets committed. block-secrets catches this at the source.

Adding block-secrets to .claude/settings.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          { "type": "command", "command": ".claude/hooks/block-secrets.sh" }
        ]
      }
    ]
  }
}

2. block-dangerous-commands

Runs on PreToolUse for Bash calls. Blocks commands like rm -rf /, chmod -R 777, curl | bash, DROP TABLE, and anything piping unverified content to a shell. Not paranoia — Claude occasionally suggests dangerous commands with good intentions ("cleaning up temp files" that includes deleting a directory it shouldn't).

The hook uses a denylist plus pattern matching. You can add your own patterns for team-specific "don't ever do this" (like touching production DB directly).

3. path-guard

Prevents Claude from reading or writing outside the current project directory. Runs on any Read, Write, or Edit. This matters because "cd .. and read that other repo" is often not what you want — session-level permissions should be scoped to the project.

For monorepos, configure the allowed paths list to include sibling packages. For most projects, "just the current repo" is right.

Order matters

block-secrets should run before auto-format. Otherwise you'll auto-format a file containing a secret, then block the write — but the format has already modified the file. Order hooks so the "blocking" ones fire first.

Quality hooks (should-have)

These prevent code quality regressions before they can happen.

4. auto-format

Runs on PostToolUse after Write or Edit. Runs your project's formatter (Prettier, Ruff, gofmt, rustfmt) on the modified file. The file that's committed matches your team's formatting standard automatically.

This isn't new — many teams use pre-commit hooks or editor-integrated formatters. But Claude Code writes files outside the editor context; without this hook, formatting drifts. With it, formatting stays uniform whether the file was written by a human, by Claude, or by an agent session.

5. pre-commit-guard

Runs on PreToolUse for git commit commands. Enforces commit message conventions (Conventional Commits, team format, whatever). If the commit message doesn't match, blocks the commit and prints the required format.

This gets you a git history that's actually useful for changelog generation and blame archaeology. Without it, commit messages drift toward "fix stuff" as Claude generates whatever fits.

6. lint-on-write

Runs on PostToolUse for Write/Edit. Runs the project's linter (ESLint, Ruff, golangci-lint) on the file. Doesn't fix — just surfaces issues to Claude so it can address them in the next turn.

The subtle value: this makes Claude aware of lint failures immediately. Without it, Claude writes code that lint later flags; you spend a round trip. With it, Claude often fixes lint issues before you even see them.

Hooks turn "we should really do that consistently" into "that always happens." No enforcement effort required.

Git hooks (nice-to-have)

Git-specific safety and quality patterns.

7. commit-message-guide

On PreToolUse for git commit. When Claude is about to commit, it gets prompted with the team's commit message conventions (Conventional Commits type prefixes, scope naming, body format). Similar to pre-commit-guard but guides rather than blocks — useful for teams still transitioning to a convention.

8. no-force-push

On PreToolUse for git push. Blocks --force (unless --force-with-lease). Force-pushing overwrites shared history and is almost always a mistake when done from a Claude session (the AI usually doesn't have context on why the remote diverged).

For rare legitimate force-push cases, developers can bypass by running git directly instead of via Claude.

9. branch-protector

On PreToolUse for git push. Blocks direct pushes to main, master, or protected branches. Forces the workflow through PR review — which is where all the other tooling (pr-reviewer subagent, CI checks) applies.

Some teams enforce this at the git server level (GitHub branch protection). The hook adds a local layer for teams that don't.

Observability hooks (advanced)

For teams that want visibility into what Claude Code is actually doing.

10. tool-audit

On PostToolUse for every tool call. Logs the tool name, arguments, and outcome to a structured audit log. Useful for security review ("what did that session actually do?"), incident debugging ("Claude changed something 3 days ago, what?"), and understanding usage patterns.

The log format matches your existing structured-log stack (JSON to stdout, then aggregated by whatever picks that up — Datadog, Loki, CloudWatch).

11. cost-tracker

On Stop event (session end). Records the session's token usage and estimated cost. Aggregated over time, gives you a real answer to "how much are we spending on Claude Code?"

For teams on Pro/Team plans, this is directional (usage is bundled). For API-based usage, it's exact cost tracking. Either way, useful for showing ROI.

12. session-logger

On SessionStart and Stop. Records session metadata — who ran it, what project, when, what were the top-level goals (from the initial prompt). Useful for organizational visibility ("what is Claude Code being used for across the company").

Privacy note: this logs the initial prompt, not the entire conversation. Configure carefully if your prompts contain sensitive info.

Observability hook cautions

Log carefully. Logging the full conversation is convenient for debugging but a privacy/compliance risk (Claude sessions can contain personal data, secrets, customer info). Log metadata + first prompt by default; log full content only when you've reviewed the compliance implications.

Installing the whole set

The fastest way to install all 12: cctk's hook set.

Install the full safety + quality set
# Install all 12
cctk add --hook-set essentials

# Or individually
cctk add --hook block-secrets
cctk add --hook block-dangerous-commands
cctk add --hook path-guard
cctk add --hook auto-format
cctk add --hook pre-commit-guard
cctk add --hook lint-on-write
# ... etc

# See what's installed
cctk list --hooks

# Update to latest versions
cctk update --hooks

The hooks live in .claude/hooks/ and get registered in .claude/settings.json. Everything is versioned with your repo, so new team members get the same hooks on clone.

Writing your own hooks

The hook interface is simple. Each hook is a script that reads JSON from stdin (the event context: tool name, arguments, file path) and either exits 0 (allow) or non-zero (block). Exit code 1 = "block this action"; exit code 2 = "block and don't re-prompt" (rare).

Any language works. Our hooks are mostly Bash and Python. For hooks with complex logic (analyzing code for security issues, running linters), Python is nicer. For simple pattern matching, Bash is fine.

Minimal hook example
#!/usr/bin/env bash
# Block writes to files matching some pattern
input=$(cat)
file=$(echo "$input" | jq -r '.tool_input.file_path')

if [[ "$file" == *"/legacy/"* ]]; then
  echo "Cannot modify legacy/ — see MIGRATION.md" >&2
  exit 1
fi

exit 0

For inspiration, cctk's hooks are open source — read them, fork them, adapt them. Every hook in the catalog has a documented purpose, config example, and customization notes.

Why hooks matter more than they seem

The temptation with any AI coding tool is to trust the AI. And you can, mostly — Claude produces good code, follows conventions, catches its own mistakes. The problem isn't the median session; it's the tail. The 1-in-500 session where Claude, well-intentioned, does something the team really did not want.

Hooks are how you handle the tail. Instead of hoping the AI won't do X, you make X literally impossible. Not "the AI probably won't commit secrets" — secrets cannot be committed from this session. Not "we hope everyone follows commit conventions" — non-conforming commits get blocked.

This is what separates AI-assisted development you deploy to production from AI-assisted development you keep in a sandbox. The AI can be as smart as you want; the invariants are what keep things safe.

Install the 12 hooks. Adjust as needed. Stop worrying about the tail.

FA

Written by

Fatima A.

Fatima covers developer experience, tooling architecture, and how MCP-native workflows change day-to-day dev.

Get cctk running in one command

85 slash commands, 12 subagents, 12 MCP integrations, 12 hooks. All the patterns from this post are shipped in cctk.

npx cctk@latest init Get cctk v1.5.2 →

Share with