Project Guardian: A Claude Code Hooks Tutorial
Project Guardian: A Claude Code Hooks Tutorial
This tutorial walks you through building Project Guardian — a safety and observability layer that intercepts, inspects, and controls everything Claude Code does. By the end, you will have a working set of ten hooks covering audit logging, command blocking, credential protection, session reporting, and more. You will also understand where hooks fit in a real security posture and where they do not.
Every lesson builds on the previous one. Start at Lesson 01 and work forward. The code is already written and running — your job is to understand it, then modify it.
What Is Project Guardian?
Project Guardian is a pre-configured Claude Code hook system. It runs alongside Claude Code, intercepting every tool call, prompt, and session event. You do not change how you use Claude — you just get a layer of visibility and control underneath it.
Ten hooks work together as a single deployed agent:
- A
PreToolUsehook logs every tool call before it runs - A second
PreToolUsehook blocks dangerous shell commands - A third blocks access to hidden files (
.env,.ssh/,.aws/) - A fourth rewrites
rmcommands into safe previews instead of blocking them - A
UserPromptSubmithook intercepts each message before Claude sees it - A
PostToolUsehook scans command output for exposed credentials - A second
PostToolUsehook enriches command results with execution metadata - A third records every tool call to a structured ledger file
- A
SessionStarthook greets you and injects session context into Claude - A
SessionEndhook reports a session activity summary when you exit
None of these require changes to how you work. They activate when Claude Code opens and run silently in the background.
Prerequisites
- Claude Code installed and working (
claude --versionshould return a version) - Python 3 available (
python3 --versionshould return 3.8 or higher) - Basic terminal familiarity: navigating directories, reading files, running commands
No Python packages beyond the standard library are required.
How to Use This Tutorial
- Open Claude Code from this directory — not from the repo root:
bash
cd /path/to/hooks-pretooluse
claude
This matters. Claude Code discovers .claude/settings.json by walking up from the launch directory. Opening from this directory scopes all hooks to this project only.
-
Follow the lessons in order. Each lesson introduces a new hook and builds on the concepts from the previous one.
-
Each lesson has three sections:
- A walkthrough explaining the code line by line
- A Try it section with hands-on steps to observe the hook working
- An Exercise to extend the code yourself
-
A Deeper dive for experienced users who want more
-
The code is already registered and running. You will be reading, testing, and modifying it — not writing it from scratch.
Lesson Index
| Lesson | Title | Hook Type | What You Will Build |
|---|---|---|---|
| 01 | How Hooks Work | All | Understand the hook system before writing any code |
| 02 | Audit Logging | PreToolUse | Log every tool call to a file |
| 03 | Blocking Dangerous Commands | PreToolUse | Block shell commands before they run |
| 04 | Protecting Hidden Files | PreToolUse | Guard credentials and config files |
| 05 | Input Mutation | PreToolUse | Rewrite commands instead of blocking them |
| 06 | User Prompt Hooks | UserPromptSubmit | Intercept and validate messages before Claude sees them |
| 07 | Scanning Outputs for Secrets | PostToolUse | Detect credentials in command output |
| 08 | Enriching Command Output | PostToolUse | Add metadata to tool results |
| 09 | Usage Tracking | PostToolUse + SessionEnd | Record every tool call and summarize sessions |
| 10 | Session Lifecycle | SessionStart + SessionEnd | Context injection and session reports |
| 11 | Project Guardian | All | Assemble all hooks into a deployable agent |
| 12 | Security Deep Dive | All | Understand the vulnerabilities and mitigations |
File Structure
hooks-pretooluse/
.claude/
settings.json — Hook configuration: all registered hooks and matchers
lessons/ — Tutorial lessons in order
01-how-hooks-work.md
02-audit-logging.md
03-blocking-commands.md
04-protecting-files.md
05-input-mutation.md
06-user-prompt-hooks.md
07-post-scanning.md
08-post-enhancement.md
09-usage-tracking.md
10-session-lifecycle.md
11-project-guardian.md
12-security.md
demos/ — Standalone demonstration scripts (not active by default)
inject_as_message.py — Shows prompt injection via file contents (intentionally insecure)
error_demo.py — Shows what a crashing hook looks like
notify_external.py — Shows how to send hook events to an external service
log_hook.py — Audit logging: appends every tool call to tool_calls.log
block_dangerous.py — Blocks Bash commands matching a danger pattern list
block_hidden_files.py — Blocks Read/Write/Bash access to hidden files and directories
mutate_dryrun.py — Rewrites rm commands into echo previews
userprompt_hook.py — Logs and optionally blocks user messages before Claude sees them
post_secret_scan.py — Scans Bash output for credential patterns
post_enhance.py — Adds duration, status, and line-count metadata to Bash results
post_usage_ledger.py — Appends one JSON record per tool call to usage_ledger.jsonl
session_start.py — Greets user at session open, injects context into Claude
session_end_summary.py — Reads usage_ledger.jsonl, prints session report, saves summary
print_file.py — Helper script: reads a file and prints its contents (used by inject_as_message.py demo)
hooks-summary.md — Reference summary of all hooks, matchers, and behaviors
vulnerabilities.md — Running record of security issues discovered during development
tool_calls.log — Runtime: audit log written by log_hook.py
prompt_log.txt — Runtime: prompt log written by userprompt_hook.py
usage_ledger.jsonl — Runtime: per-call records written by post_usage_ledger.py
usage_summary.jsonl — Runtime: per-session summaries written by session_end_summary.py
Quick Start
Three steps to verify the hooks are active:
Step 1: Open Claude Code from this directory.
claude
Step 2: Look for the Guardian greeting.
Immediately after Claude Code opens, before any prompt, you should see:
[Guardian] New session started | HH:MM:SS
If this appears, the SessionStart hook fired. All other hooks are also active.
Step 3: Ask Claude to list the files, then check the log.
In the Claude Code session:
list the files in this directory
Then, in a separate terminal:
tail -5 tool_calls.log
You should see a JSON entry for the tool call Claude just made. If the log is growing, the PreToolUse audit hook is running.
From here, proceed to Lesson 01.
Want to explore more?
Explore all tutorials →