--- name: require-plan-file description: PreToolUse hook that blocks ExitPlanMode unless a *-PLAN.md file exists in the current project root type: reference --- # script: require-plan-file **Location:** `hooks/require-plan-file.sh` **Symlinked to:** `~/.claude/hooks/require-plan-file.sh` ## Purpose Enforces the plan-file convention: Claude cannot exit plan mode until it has written a `[MILESTONE]-[PURPOSE]-PLAN.md` file in the project root. ## How it works Fires as a `PreToolUse` hook on `ExitPlanMode`. Reads `cwd` from the JSON input on stdin, checks for any `*-PLAN.md` file in that directory: - **File found** → exits 0 (allows ExitPlanMode to proceed) - **No file found** → exits 2 (blocks ExitPlanMode, stderr message injected into Claude's context) The exit 2 message tells Claude exactly what to do, so it self-corrects and writes the file before retrying. ## Settings.json config ```json "PreToolUse": [ { "matcher": "ExitPlanMode", "hooks": [{ "type": "command", "command": "~/.claude/hooks/require-plan-file.sh" }] } ] ``` ## Naming convention `[MILESTONE]-[PURPOSE]-PLAN.md` — e.g. `M2-auth-PLAN.md`, `M3-monitoring-PLAN.md`, `initial-setup-PLAN.md` Plan files are committed to the project repo as a persistent record of planning decisions. ## Gotchas - `cwd` in the hook input is the Claude session's working directory, not necessarily the repo root — works correctly as long as Claude is `cd`'d into the project root (the standard pattern). - If `cwd` cannot be parsed from stdin, the hook exits 0 (fails open) to avoid blocking legitimate use.