CLAUDE.md@plugins/itp-hooks · git:20261102.8a57940 · 2026-11-02 · sha256 4df77fb52162802e

CLAUDE.md@plugins/itp-hooks git:20261102.8a57940A

Immutable. This exact content never changes and is served at /api/v1/blob/4df77fb52162802e.

# itp-hooks Plugin

> Claude Code hooks for ITP workflow enforcement, code correctness, and commit validation.

**Hub**: [Root CLAUDE.md](../../CLAUDE.md) | **Sibling**: [gh-tools CLAUDE.md](../gh-tools/CLAUDE.md) | **Spoke index**: [docs/spoke-index.md](./docs/spoke-index.md)

## Invariants — read before editing

1. **Keep this file a slim hub.** The size guard warns at 36k and Claude Code stops fully loading a `CLAUDE.md` over **40,000 characters** (counted in UTF-16 code units, not bytes — see `hooks/posttooluse-claude-md-size-budget-reminder.ts`). Prettier repads every cell in a table to its widest row, so one long cell inflates the whole table; **keep every Purpose cell to a short clause** and put the narrative in the hook's own spoke. Measure after formatting, never before.
2. **`hooks.json` is the SSoT for registration**, not this file. A hook listed here but unregistered there does not run.
3. **`pretooluse-pueue-wrap-guard.ts` MUST stay the LAST PreToolUse entry** in `hooks.json` (audited by `tasks/hook-lint/pueue-wrap-last.sh`) — it auto-wraps long-running commands, so any guard after it never sees the unwrapped command. Details: [pueue-wrap-guard](./docs/pretooluse-bash-guard-orchestrator.md#pueue-wrap-guard).
4. **A new Bash guard goes into `BASH_GUARD_REGISTRY`** in `hooks/pretooluse-bash-guard-orchestrator.ts`, not into `hooks.json` (#111). Export its `main()` and gate the top-level call on `import.meta.main`. The exception is a guard that rewrites the command through `updatedInput`, which stays a separate entry.
5. **No full-table snapshot docs.** A spoke owns one subject; a doc that mirrors these tables drifts out of sync with the spokes. [docs/spoke-index.md](./docs/spoke-index.md) is an index of subjects, not a snapshot of hook rows.
6. **TypeScript/Bun is preferred for new hooks** (per `lifecycle-reference.md`); bash is acceptable only for simple pattern matching.

## Hooks

Registration lives in `hooks/hooks.json`. Each row is one clause; the spoke is the SSoT for that hook.

### PreToolUse

Orchestrator arc: [pretooluse-write-edit-orchestrator.md](./docs/pretooluse-write-edit-orchestrator.md). "Write\|Edit orch." in the Matcher column means the hook runs as a subhook of that orchestrator rather than as its own process. "Bash orch." means the hook runs inside [`pretooluse-bash-guard-orchestrator.ts`](./docs/pretooluse-bash-guard-orchestrator.md) rather than as its own process.

| Hook                                                  | Matcher                  | Purpose                                       | Spoke                                                              |
| ----------------------------------------------------- | ------------------------ | --------------------------------------------- | ------------------------------------------------------------------ |
| `pretooluse-version-guard.ts`                         | Write\|Edit orch.        | Hardcoded-version blocker for markdown        | [→](./docs/version-guard.md)                                       |
| `pretooluse-process-storm-guard.mjs`                  | Bash orch. + Write\|Edit | Blocks fork-bomb patterns                     | [→](./docs/process-storm-guard.md)                                 |
| `pretooluse-cwd-deletion-guard.ts`                    | Bash orch.               | Blocks deleting the CWD                       | [→](./docs/cwd-deletion-guard.md)                                  |
| `pretooluse-git-worktree-guard.ts`                    | Bash orch.               | Enforces worktree-per-branch                  | [→](./docs/git-worktree-guard.md)                                  |
| `pretooluse-vale-claude-md-guard.ts`                  | Write\|Edit orch.        | Rejects CLAUDE.md edits with vale findings    | [→](./docs/vale-terminology-enforcement.md)                        |
| `pretooluse-hoisted-deps-guard.ts`                    | Write\|Edit orch.        | pyproject.toml hoisting/path-escape policy    | [→](./docs/hoisted-deps-guard.md)                                  |
| `pretooluse-gpu-optimization-guard.ts`                | Write\|Edit orch.        | GPU optimization enforcement (6 checks)       | [→](./docs/gpu-optimization-guard.md)                              |
| `pretooluse-file-size-guard.ts`                       | Write\|Edit orch.        | Per-extension file-size bloat prevention      | [→](./docs/file-size-guard.md)                                     |
| `pretooluse-write-edit-orchestrator.ts`               | Write\|Edit              | Runs the 11 Write\|Edit subhooks in-process   | [→](./docs/pretooluse-write-edit-orchestrator.md)                  |
| `pretooluse-native-binary-guard.ts`                   | Write\|Edit orch.        | Launchd services must be native binaries      | [→](./docs/native-binary-guard.md)                                 |
| `pretooluse-html-measure-guard.ts`                    | Write\|Edit orch. + Bash orch. | Denies HTML/CSS that fixes text width  | [→](./docs/html-measure-guard.md)                                  |
| `pretooluse-pyi-stub-guard.ts`                        | Write\|Edit orch.        | Blocks top-level defs in Python `__init__`    | [→](./docs/pyi-stub-guard.md)                                      |
| `pretooluse-uv-enforcement-guard.ts`                  | Bash orch.               | Blocks non-UV Python package operations       | [→](./docs/uv-enforcement-guard.md)                                |
| `pretooluse-pueue-local-guard.ts`                     | Bash orch.               | Pueue commands must target the local daemon   | [→](./docs/pueue-local-guard.md)                                   |
| `pretooluse-cargo-tty-guard.ts`                       | Bash (in pueue-wrap)     | Backgrounded cargo to PUEUE (via pueue-wrap)  | [→](./docs/cargo-tty-guard.md)                                     |
| `pretooluse-skill-plugin-root-guard.ts`               | Write\|Edit orch.        | Skills must use `cc-plugin-root`              | [→](./docs/skill-plugin-root-guard.md)                             |
| `pretooluse-bash-guard-orchestrator.ts`               | Bash                     | Runs the 26 Bash guards in one bun process    | [→](./docs/pretooluse-bash-guard-orchestrator.md)                  |
| `pretooluse-pueue-wrap-guard.ts`                      | Bash                     | Auto-wraps long-running commands (see #3)     | [→](./docs/pretooluse-bash-guard-orchestrator.md#pueue-wrap-guard) |
| `pretooluse-webfetch-fallback-guard.ts`               | WebFetch                 | Denies built-in WebFetch; no escape hatch     | `~/.claude/webfetch-fallback-CLAUDE.md`                            |
| `pretooluse-release-notes-extensiveness-guard.ts`     | Bash orch.               | Hard-blocks releases with thin notes          | [→](./docs/release-notes-extensiveness-guard.md)                   |
| `pretooluse-gmail-body-guard.ts`                      | Bash orch.               | Blocks bad-rendering `gmail draft` bodies     | [→](./docs/gmail-body-guard.md)                                    |
| `pretooluse-markdown-commit-hard-wrap-guard.ts`       | Bash orch.               | Blocks a `git commit` adding `.md` hard wraps | [→](./docs/markdown-hard-wrap-reminder.md)                         |
| `pretooluse-secret-exposure-guard.ts`                 | Write\|Edit              | Hard-blocks live credentials in new content   | [→](./docs/secret-and-pii-exposure-guard.md)                       |
| `pretooluse-headless-claude-p-guard.ts`               | Bash orch.               | Blocks unworkable headless `claude -p` calls  | [→](./docs/headless-claude-p.md)                                   |
| `pretooluse-askuserquestion-line-terminator-guard.ts` | AskUserQuestion          | Blocks newlines in option label/description   | [→](./docs/askuserquestion-option-line-terminator-guard.md)        |
| `pretooluse-pkill-option-after-pattern-guard.ts`      | Bash orch.               | Blocks pkill/pgrep options after the pattern  | [→](./docs/pkill-option-after-pattern-guard.md)                    |
| `pretooluse-orca-worktree-agent-guard.ts`             | Bash orch.               | Blocks `orca worktree create` without `--agent` | [→](./docs/orca-worktree-agent-guard.md)                           |
| `pretooluse-broad-process-signal-guard.ts`            | Bash orch. + Write, Edit | Blocks broad kill/pkill/killall (+ scripts)   | [→](./docs/broad-process-signal-guard.md)                          |
| `pretooluse-old-git-guard.ts`                         | Bash orch.               | Blocks hook-firing git below 2.54             | [→](./docs/old-git-guard.md)                                       |
| `pretooluse-long-runtime-haiku-monitor-reminder.ts`   | Bash orch.               | Long run: start a `haiku` health monitor      | [→](./docs/long-runtime-haiku-monitor-reminder.md)                 |

### PostToolUse

Orchestrator arc: [posttooluse-write-edit-orchestrator.md](./docs/posttooluse-write-edit-orchestrator.md). "PostToolUse orch." in the Matcher column means the hook runs inside that orchestrator.

| Hook                                              | Matcher           | Purpose                                       | Spoke                                                                         |
| ------------------------------------------------- | ----------------- | --------------------------------------------- | ----------------------------------------------------------------------------- |
| `posttooluse-reminder.ts`                         | Bash\|Write\|Edit | Context-aware reminders (UV, Pueue, ADR, …)   | [→](./docs/posttooluse-reminder.md)                                           |
| `code-correctness-guard.sh`                       | Bash\|Write\|Edit | Silent-failure detection ONLY                 | [→](./docs/code-correctness-philosophy.md)                                    |
| `posttooluse-pushover-budget-reminder.ts`         | Bash\|Write\|Edit | Pushover message-budget nudge + limits SSoT   | [→](./docs/pushover-budget-reminder.md)                                       |
| `posttooluse-invented-fallback-reminder.ts`       | Bash\|Write\|Edit | Official-values nudge on invented fallbacks   | [→](./docs/invented-fallback-reminder.md)                                     |
| `posttooluse-vale-claude-md.ts`                   | PostToolUse orch. | Informational vale check on CLAUDE.md edits   | [→](./docs/vale-terminology-enforcement.md)                                   |
| `posttooluse-glossary-sync.ts`                    | Write\|Edit       | Auto-sync GLOSSARY.md to Vale vocabulary      | [→](./docs/vale-terminology-enforcement.md)                                   |
| `posttooluse-terminology-sync.ts`                 | Write\|Edit       | CLAUDE.md → GLOSSARY.md sync + dupe detection | [→](./docs/vale-terminology-enforcement.md)                                   |
| `posttooluse-readme-pypi-links.ts`                | Write\|Edit       | PyPI badge/link consistency in READMEs        | [→](./docs/readme-pypi-links.md)                                              |
| `posttooluse-markdown-table-guard.ts`             | Write\|Edit       | Per-edit GFM table structural guard           | [→](./docs/markdown-table-guard.md)                                           |
| `posttooluse-ssot-principles.ts`                  | PostToolUse orch. | SSoT/DI reminder with ast-grep detection      | [→](./docs/ssot-principles.md)                                                |
| `posttooluse-memory-efficiency-reminder.ts`       | PostToolUse orch. | Once-per-session memory-efficiency reminder   | [→](./docs/posttooluse-write-edit-orchestrator.md#memory-efficiency-reminder) |
| `posttooluse-ty-type-check.ts`                    | PostToolUse orch. | ty type check on .py/.pyi edits               | [→](./docs/ty-type-checker.md)                                                |
| `posttooluse-write-edit-orchestrator.ts`          | Write\|Edit       | PostToolUse multi-aggregation orchestrator    | [→](./docs/posttooluse-write-edit-orchestrator.md)                            |
| `posttooluse-tsc-type-check.ts`                   | PostToolUse orch. | tsc project-scoped check on .ts/.tsx edits    | [→](./docs/tsc-type-check.md)                                                 |
| `posttooluse-oxlint-check.ts`                     | PostToolUse orch. | oxlint correctness+suspicious on JS/TS        | [→](./docs/js-ts-lint.md)                                                     |
| `posttooluse-biome-lint.ts`                       | PostToolUse orch. | biome complementary-to-oxlint JS/TS lint      | [→](./docs/js-ts-lint.md)                                                     |
| `posttooluse-python-preference-nudge.ts`          | PostToolUse orch. | Language-preference reminder on `.py` edits   | [→](./docs/python-preference-nudge.md)                                        |
| `posttooluse-pii-exposure-reminder.ts`            | Write\|Edit       | Reminder on third-party email/phone on disk   | [→](./docs/secret-and-pii-exposure-guard.md)                                  |
| `posttooluse-markdown-hard-wrap-reminder.ts`      | PostToolUse orch. | Reminds on net-new hard-wrapped `.md` prose   | [→](./docs/markdown-hard-wrap-reminder.md)                                    |
| `posttooluse-bash-markdown-hard-wrap-reminder.ts` | Bash              | Same, for `.md` written by a shell command    | [→](./docs/markdown-hard-wrap-reminder.md)                                    |
| `posttooluse-claude-md-size-budget-reminder.ts`   | PostToolUse orch. | CLAUDE.md character-budget reminder (see #1)  | [→](./docs/posttooluse-write-edit-orchestrator.md)                            |

### SessionStart

| Hook                                | Purpose                                          | Spoke                                  |
| ----------------------------------- | ------------------------------------------------ | -------------------------------------- |
| `sessionstart-proto-floor-check.sh` | Warns when proto is too old for bare `bun` hooks | [→](./scripts/proto-floor.sh) (header) |
| `sessionstart-git-version-check.sh` | Warns when the git on PATH is below 2.54         | [→](./docs/old-git-guard.md)           |

### Stop

| Hook                         | Purpose                                            | Spoke                          |
| ---------------------------- | -------------------------------------------------- | ------------------------------ |
| `stop-hook-error-summary.ts` | Summarizes session hook errors on Claude exit      | [→](./docs/stop-hooks.md)      |
| `stop-ty-project-check.ts`   | Project-wide ty check on exit (only if .py edited) | [→](./docs/ty-type-checker.md) |

## Escape hatches

Every escape marker, its consumer hook, case and window rules and reason length: [docs/marketplace-escape-hatch-marker-reference.md](../../docs/marketplace-escape-hatch-marker-reference.md), generated from `hooks/lib/escape-hatch-marker-registry-iter111.ts` (add a marker there, then `bash tasks/hook-lint/marker-reference-doc.sh`). Not markers, so not in the registry: the command-prefix assignments `ALLOW_BARE_BRANCH=1` (git worktree guard), `ALLOW_UMBRELLA_REPO=1` (umbrella no-repo guard), `PR_BLOCKING_REVIEW_OK=1` (PR review-invitation guard) and `ALLOW_LEGACY_TS=1` (TypeScript install-command guard), plus the lowercase comment `# gpu-optimization-bypass: <reason>` (GPU optimization guard, exact spelling with `#` and colon).

`pretooluse-webfetch-fallback-guard.ts` has **no** escape hatch, by design.

## Environment variables (hook context)

Set by Claude Code when a hook fires — hooks read them, users do not set them.

| Variable                 | Description                                                         |
| ------------------------ | ------------------------------------------------------------------- |
| `CLAUDE_SESSION_ID`      | Session UUID; per-session gate files and session-scoped caches      |
| `CLAUDE_CONVERSATION_ID` | Conversation UUID (alias surfaced by some hook events)              |
| `CLAUDE_PROJECT_DIR`     | Project root Claude is working in; resolves `.claude/` config       |
| `CLAUDE_HOOK_SPAWNED`    | `1` when running via a wrapper; guards against recursive invocation |

## Skills

- [hooks-development](./skills/hooks-development/SKILL.md)
- [setup](./skills/setup/SKILL.md)

## References

- [docs/spoke-index.md](./docs/spoke-index.md) — annotated index of all spokes in [`docs/`](./docs/)
- [lifecycle-reference.md](skills/hooks-development/references/lifecycle-reference.md) — hook lifecycle and best practices
- [bootstrap-monorepo.md](../itp/skills/bootstrap-monorepo/references/bootstrap-monorepo.md) — monorepo scaffolding patterns