Decide · infra SKILL.md
Claude Code hooks: Prettier, protect-files, Stop prompt, git if-filter
WhenUse when Prettier, protect-files, Stop prompt, or git if-filter must always run.
StopNever mix exit 2 and JSON in one hook. Never treat a hook as undoing work already done.
Steps
- Exit 0 — no objection via exit code.
- PreToolUse: does not approve the tool; the normal permission flow still applies.
- UserPromptSubmit, UserPromptExpansion, SessionStart, PostModelSwitch: stdout treated as plain text is added to context.
- Exit 2 — block the action. Write a reason to stderr. For PreToolUse it is fed to Claude as feedback. Some events cannot be blocked (SessionStart: stderr shown to the user, execution continues).
- Any other exit — usually a non-blocking error unless stdout is valid JSON that passes schema validation (then JSON alone decides).
- "ok": true: the action proceeds
- "ok": false: what happens depends on the event:
- Stop and SubagentStop: the reason is fed back to Claude so it keeps working, unless the response also sets "impossible": true to mark the condition as one that can never be satisfied, in which case Claude Code allows the stop and the turn ends
Load.claude/settings.json hooks. Shell. No send/pay/deploy from the hook itself.
--- name: Claude Code hooks: Prettier, protect-files, Stop prompt, git if-filter description: Use when Prettier, protect-files, Stop prompt, or git if-filter must always run. --- # Claude Code hooks: Prettier, protect-files, Stop prompt, git if-filter When: Use when Prettier, protect-files, Stop prompt, or git if-filter must always run. Stop: Never mix exit 2 and JSON in one hook. Never treat a hook as undoing work already done. 1. Exit 0 — no objection via exit code. 2. PreToolUse: does not approve the tool; the normal permission flow still applies. 3. UserPromptSubmit, UserPromptExpansion, SessionStart, PostModelSwitch: stdout treated as plain text is added to context. 4. Exit 2 — block the action. Write a reason to stderr. For PreToolUse it is fed to Claude as feedback. Some events cannot be blocked (SessionStart: stderr shown to the user, execution continues). 5. Any other exit — usually a non-blocking error unless stdout is valid JSON that passes schema validation (then JSON alone decides). 6. "ok": true: the action proceeds 7. "ok": false: what happens depends on the event: 8. Stop and SubagentStop: the reason is fed back to Claude so it keeps working, unless the response also sets "impossible": true to mark the condition as one that can never be satisfied, in which case Claude Code allows the stop and the turn ends Load: .claude/settings.json hooks. Shell. No send/pay/deploy from the hook itself.
