https://media.licdn.com/dms/document/media/v2/D4D1FAQGtvK5tUnN0EQ/feedshare-document-url-metadata-scrapper-pdf/B4DaEgDW2kKUA4-/0/1791539116721?e=1792170000&v=beta&t=6lNyWkJparrDrHu4bE6lW0AGmrORP_M9VmFbuMKjk98
A LinkedIn-hosted PDF guide to Claude Code automation. It explains hook configuration in .claude/settings.json (matchers, JSON stdin payloads, exit code 2 to block) and the hook events: PreToolUse, PostToolUse, Notification, Stop, SubagentStop, SessionStart, UserPromptSubmit and PreCompact. Worked examples include sound and TTS alerts with pyttsx3, a regex guard against rm -rf and other dangerous Bash commands, TDD enforcement, auto-formatting with black, ruff and prettier, and session context loading. It adds troubleshooting and a cheat sheet, and its table of contents lists sections on multi-agent observability, slash commands, MCP tools, sub-agents and professional development patterns. The later sections are cut off in the fetched text. It is useful as deterministic guardrails and automation for a non-deterministic coding agent.
What it claims
This is a tutorial guide, not a spec. Its central idea is that hooks add deterministic guardrails to Claude Code. A hook is a shell command attached to a lifecycle event. It receives a JSON payload on stdin, and its exit code decides whether a tool call goes ahead. The useful material is the event contract (which events can block and which fields each one receives) and a set of copy-pasteable scripts.
How it works
Config locations
- Project hooks go in
.claude/settings.json. - User-global hooks go in
~/.claude/settings.json. - Settings load at startup, so you must restart Claude Code after editing them.
Matchers
""matches all tools.- A tool name such as
"Bash"matches that tool only. - Regex alternation works, for example
"Edit|MultiEdit|Write".
Exit codes
0is normal operation.2blocks the action, and stderr is fed back to Claude.- The guide warns that an accidental non-zero exit can block unintentionally. It recommends wrapping logic in
try/exceptand always ending withsys.exit(0).
Events, as listed in the cheat sheet:
| Event | Can block? | Key fields |
|---|---|---|
| PreToolUse | Yes (exit 2) | tool_name, tool_input |
| PostToolUse | No | tool_response (also tool_name, tool_input) |
| SubagentStop | Yes (exit 2) | stop_hook_active |
| Stop | No | transcript_path |
| Notification | No | message |
| SessionStart | No | session_id, source |
| UserPromptSubmit | No (described as "modify user prompts") | prompt |
| PreCompact | No | cut off (trigβ¦) |
Every payload carries hook_event_name.
Per-hook options
"timeout": 5limits how long a hook may run.- Appending
&to the command runs a non-critical hook in the background. - Hooks are synchronous, so the guide says to keep them fast.
Writing context into the session The SessionStart script prints its output to stdout. That output is git status, the last 5 commits, and up to 500 characters of TODO: grep results.
How to use it
Log the raw payloads first, before writing any logic:
{"hooks": {"PreToolUse": [{"matcher": "", "hooks": [{"type": "command", "command": "jq '.' >> .claude/hooks/log.jsonl"}]}]}}Format edited files after each edit. This relies on a $CLAUDE_FILE_PATHS environment variable:
if [[ "$CLAUDE_FILE_PATHS" =~ \.(py)$ ]]; then black $CLAUDE_FILE_PATHS && ruff check --fix $CLAUDE_FILE_PATHS; fiOther practical advice from the guide:
- Run hook scripts that have dependencies with
uv run my_script.py. - Use absolute script paths.
- Make scripts executable with
chmod +x .claude/hooks/*.py. - Validate your settings file with
jq '.' .claude/settings.json.
The advanced Bash guard (PreToolUse, matcher Bash) blocks five pattern families:
rm -[rf]chmod 777curl β¦ | shnpm install β¦ --globaldocker β¦ --privileged
It emits a JSON error with the risks and a suggestion on stderr, then exits with code 2.
Limits
- Truncated text. The fetched text cuts off midway through the TDD example and at the PreCompact row. Sections 9β16 are absent: workflows, security, multi-agent observability, slash commands, MCP, sub-agents and patterns.
- Guard over-matches. In the advanced guard,
rm\s+-[^\s]*[rf]matches plainrm -fas well asrm -rf. - Guard can be bypassed. Regex guards of this kind can be sidestepped by aliases, variables or other interpreters. The guide does not discuss this.
- Unverified details. Several details are the guide's own assertions and are not sourced here: the "can block" column,
$CLAUDE_FILE_PATHSand thetimeoutfield. Check them against current Claude Code documentation before relying on a hook as a security control.
Organisations named here
- Astral
- Anthropic
- Claude Code
- Cursor
Technologies named here
- Claude Code
- Claude Code hooks
- MCP tools
- Custom slash commands
- Subagents
- pyttsx3
- uv
- jq
- black
- ruff
- prettier
- tsc
- Cursor
- Model Context Protocol
- TypeScript
- Python
Techniques named here
- PreToolUse blocking hook
- Payload logging for debugging
- Formatter hooks on PostToolUse
- Session context loading
- TDD enforcement hook
- Voice and sound notifications
Related in coding-agents
