# Configure Development Hooks for This Project Use this prompt to set up Claude Code hooks tailored to a project's tech stack. Run it after `/tech-plan` has produced architecture specs (or after you've manually chosen your stack) and before `/init-project` or first feature work. --- ## Prompt Analyze this project's tech stack and configure Claude Code hooks that prevent dangerous actions and protect sensitive files. Also recommend a pre-commit hook setup for code quality. The output is a working `.claude/settings.json` (or updates to an existing one) plus any hook scripts the configuration references. ### Process (7 steps) **Step 1: Load Tech Stack Context** Locate the project's technology decisions in this order: - `docs/specs/architecture.md` — tech stack, languages, frameworks - `CLAUDE.md` — any existing conventions or tool preferences - `package.json`, `pyproject.toml`, `Cargo.toml`, `go.mod`, or equivalent — actual dependencies - `.claude/settings.json` — any existing hooks to preserve If no tech stack is identifiable, ask the user to specify: primary language, framework, package manager, test runner, and linter/formatter. **Step 2: Identify Applicable Hook Categories** For the detected stack, determine which hook categories apply. Present the list to the user with recommendations marked. | Category | Purpose | Mechanism | |----------|---------|-----------| | **Safety Guards** | Block dangerous shell commands before execution | Claude Code hook (PreToolUse → Bash) | | **File Protection** | Prevent modification of sensitive/generated files | Claude Code hook (PreToolUse → Edit\|Write) | | **Dependency Safety** | Guard against risky package operations | Claude Code hook (PreToolUse → Bash) | | **Code Quality** | Formatting and linting on commit | Git pre-commit hook (not a Claude Code hook) | Safety Guards and File Protection are non-negotiable. Ask the user about the others. **Step 3: Configure Safety Hooks (PreToolUse)** These are the most important hooks. They use `PreToolUse` with matcher `Bash` to inspect commands before execution and block dangerous ones. **Mandatory patterns to block** (adapt regex to the project's stack): | Pattern | Why | Regex | |---------|-----|-------| | Destructive file ops | Prevent mass deletion | `rm\s+(-rf\|--recursive)` on paths outside the project | | Database destruction | Prevent data loss | `DROP\s+(TABLE\|DATABASE\|SCHEMA)`, `TRUNCATE`, `DELETE\s+FROM\s+\w+\s*;` (no WHERE) | | Git force operations | Prevent history rewrite | `git\s+push\s+.*--force(?!-with-lease)`, `git\s+reset\s+--hard` | | Env/secrets exposure | Prevent credential leaks | `cat\s+.*\.env`, `echo\s+.*\$(.*API_KEY\|SECRET\|TOKEN\|PASSWORD)` | | System-level commands | Prevent system damage | `sudo\s+`, `chmod\s+777`, `chown`, commands writing outside project root | | Package registry publish | Prevent accidental publish | `npm\s+publish`, `pip\s+upload`, `cargo\s+publish`, `twine\s+upload` | | Process killing | Prevent collateral damage | `kill\s+-9`, `killall`, `pkill` | | Network exfiltration | Prevent data leaks | `curl\s+.*-d\|--data`, `wget\s+.*--post` sending to unknown hosts | **Stack-specific patterns to add:** - **Node/JS**: Block `npx` with unknown packages, `npm link` to system - **Python**: Block `pip install` without `--target` or venv, `python -c` with eval/exec on external input - **Docker**: Block `docker rm -f`, `docker system prune`, `docker push` to non-project registries - **Database (any)**: Block `migrate` or `seed` commands against production connection strings For each blocked pattern: 1. Exit code 2 with stderr message explaining what was blocked and why 2. The stderr message should suggest the safe alternative **Step 4: Configure File Protection Hooks (PreToolUse)** Create a `PreToolUse` hook with matcher `Edit|Write` that prevents modification of: | File Pattern | Why | |-------------|-----| | `.env*` | Secrets — should never be modified by automation | | `*.lock` / `*-lock.*` | Lock files — only package managers should touch these | | `.git/*` | Git internals | | `dist/` / `build/` / `out/` | Generated output — edit source, not artifacts | | `node_modules/` / `venv/` / `target/` | Dependencies — never edit directly | | Files matching `.gitignore` patterns | Anything git ignores is probably generated or sensitive | Let the user add project-specific protected paths (e.g., migration files, generated API clients). **Step 5: Write Hook Scripts** Create all hook scripts in `.claude/hooks/` with this structure: ``` .claude/hooks/ ├── block-dangerous-cmds.sh # PreToolUse: Bash → safety guard └── protect-files.sh # PreToolUse: Edit|Write → file protection ``` Each script must: - Read JSON from stdin using `jq` - Be executable (`chmod +x`) - Handle missing fields gracefully (not all tool calls have all fields) - Exit 0 for success/pass-through, exit 2 for block - Include a comment header explaining what it does Guard against shell profile noise — hook scripts should not source `.bashrc`/`.zshrc`. Use `#!/usr/bin/env bash` with explicit PATH if tools need to be found. **Step 6: Assemble settings.json and Pre-commit Config** **Claude Code hooks** — write `.claude/settings.json` merging any existing settings with: ```json { "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": ".claude/hooks/block-dangerous-cmds.sh", "timeout": 10, "statusMessage": "Checking command safety..." } ] }, { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": ".claude/hooks/protect-files.sh", "timeout": 5, "statusMessage": "Checking file protection..." } ] } ] } } ``` **Git pre-commit hook for code quality** — set up formatting and linting as a git pre-commit hook instead of a Claude Code hook. This runs once at commit time rather than on every edit, avoiding wasted tokens. Use the `pre-commit` framework (`https://pre-commit.com`). Write a `.pre-commit-config.yaml` appropriate to the stack: | Stack | Formatter Hook | Linter Hook | |-------|---------------|-------------| | Python | `ruff format` via `ruff-pre-commit` | `ruff check --fix` via `ruff-pre-commit` | | TypeScript/Node | `prettier` via `mirrors-prettier` | `eslint` via local hook | | Rust | `rustfmt` via local hook | `clippy` via local hook | | Go | `gofmt` via local hook | `golangci-lint` via local hook | Example for Python: ```yaml repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.9.10 # check for latest version hooks: - id: ruff args: [check, --fix] - id: ruff-format ``` Install with `pre-commit install` and document in CLAUDE.md so Claude knows the project uses pre-commit hooks. **Step 7: Output Summary** ``` ## Hooks Configured: [Project Name] ### Safety Hooks (Claude Code — PreToolUse) - block-dangerous-cmds.sh → Bash — [N] dangerous patterns covered - [list key patterns blocked] - protect-files.sh → Edit|Write — [N] protected patterns - [list protected paths] ### Code Quality (Git Pre-commit) - [formatter]: runs on commit via pre-commit framework - [linter]: runs on commit via pre-commit framework ### Files Created - .claude/settings.json — [created/updated] - .claude/hooks/block-dangerous-cmds.sh - .claude/hooks/protect-files.sh - .pre-commit-config.yaml ### Testing Your Hooks To verify safety hooks work, try these (they should be blocked): - `[example dangerous command for this stack]` - `[example protected file edit for this stack]` ### What's NOT Covered - [Any categories the user declined] - [Any limitations of the current setup] ### Suggested Next Steps - `/establish-patterns` — prove architecture patterns - `/init-project` — scaffold the repo - Review blocked-command list and add project-specific patterns ``` --- ## Hook Design Reference ### Exit Code Behavior | Exit Code | Meaning | |-----------|---------| | `0` | Success — JSON stdout parsed, execution continues | | `2` | Block — stderr shown to Claude, action prevented | | Other | Non-blocking error — logged in debug mode only | ### Reading Input in Hook Scripts All hook scripts receive JSON on stdin. Key fields: ```bash #!/usr/bin/env bash INPUT=$(cat) # For Bash commands (PreToolUse, matcher: Bash) COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command') # For file operations (PreToolUse, matcher: Edit|Write) FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty') ``` ### Blocking with Explanation (PreToolUse) ```bash # Block and tell Claude why + what to do instead jq -n --arg reason "DROP TABLE blocked. Use migrations to modify schema." '{ hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: $reason } }' ``` ### Performance Considerations - Keep hook timeouts short (5-10s for safety checks) - Use file extension checks early to skip irrelevant files fast --- ## After Running This Prompt The project will have: - `.claude/settings.json` with safety and file protection hooks - `.claude/hooks/` directory with executable scripts - `.pre-commit-config.yaml` for formatting/linting at commit time - Safety guards that prevent dangerous commands regardless of permission mode Commit `.claude/settings.json`, `.claude/hooks/`, and `.pre-commit-config.yaml` to the repo so the entire team benefits.