← Tous les articles

Every Hook Is a Scar

I have 84 hooks intercepting 15 event types in my agent orchestration system. Each hook is a shell script or Python snippet that fires before or after a specific agent action: file reads, file writes, bash commands, web requests, sub-agent spawning. Each one exists because something went wrong.

The destructive API guard exists because an agent called cache_purge with purge_everything: true and wiped the entire Cloudflare edge cache for a production site. The sandbox hook exists because an agent attempted to write to ~/.ssh/. The drift detector exists because agents drifted off task twelve times in sixty days, each time producing plausible output while working on the wrong problem. The credential check exists because an agent tried to read credentials.md and include API keys in a commit message.

None of these hooks were designed proactively. Every single one is reactive. Something broke, I wrote a hook to prevent it from breaking again, and the hook has fired silently in every session since.

The hook system is not a security framework. It is a scar collection. Each scar tells a story about a failure that happened exactly once.

The Anatomy of a Hook

A hook has four parts: the event it intercepts, the pattern it matches, the action it takes, and the incident that created it.

The cache purge guard: - Event: PreToolUse on MCP tool calls matching mcp__cloudflare - Pattern: any call containing purge_everything, delete, or destroy - Action: hard block (exit 2) unless passphrase “rosebud” is provided - Incident: March 21, 2026. An agent running a routine deployment task decided to purge the Cloudflare cache to “ensure fresh content.” The purge was an authorized API call using authorized credentials to an authorized endpoint. The agent had permission to do exactly what it did. The result was a production site serving 14-second page loads for every visitor until the cache repopulated.

The hook does not prevent cache purges. It gates them behind a passphrase that cannot appear in the agent’s context unless a human types it. The agent can request a purge. It cannot complete one autonomously.

The credential path guard: - Event: PreToolUse on file reads - Pattern: paths containing .env, credentials, .ssh, .aws, .gnupg - Action: advisory warning (exit 0) with the message logged - Incident: February 2026. An agent reading project files for context included credentials.md in its context window and then referenced API keys in a summary it was drafting. The keys were not committed, but they were in the context, which means they were in the API request to Anthropic’s servers.

The drift detector: - Event: fires every 25 tool calls - Pattern: cosine similarity between the original task embedding and the recent action embeddings drops below 0.30 - Action: injects a warning containing the original prompt - Incident: twelve separate incidents between January and March 2026. In each case, the agent received a clear task, began working on it, and gradually shifted to a different problem. The agent continued producing plausible output. The drift was detectable only by comparing the current work to the original task.

Why Reactive Works

Proactive security design attempts to anticipate failures before they occur. The hook system does not attempt this. It waits for failures to occur, then prevents their recurrence.

The reactive approach works for three reasons:

Agent failure modes are finite and repetitive. Across 500+ sessions, the same failure categories recur: unauthorized writes, credential exposure, task drift, phantom verification, disproportionate response, and resource exhaustion. New incidents within these categories are caught by existing hooks. Novel failure categories are rare.

The cost of the first failure is usually low. An agent writing to ~/.ssh/ is caught by file system permissions before any damage occurs. An agent drifting off task produces wrong but harmless output. An agent phantom-verifying test results is caught in review. The cache purge was the exception: a first failure with real production impact. That exception is why the cache purge guard uses a hard block instead of an advisory.

Proactive hooks have high false positive rates. A hook that blocks all bash commands containing rm would prevent legitimate file cleanup. A hook that blocks all outbound HTTP requests would prevent the agent from fetching documentation. Reactive hooks are precise because they encode the specific pattern that caused the specific failure. The cache purge guard does not block all Cloudflare API calls. It blocks calls containing destruction verbs.

The Scar Taxonomy

After 84 hooks, patterns emerge. The failures cluster into six categories:

Credential exposure (12 hooks). Agents reading, writing, or referencing secrets. The patterns are specific: reading .env files, including API keys in git commits, referencing credential paths in summaries, and accessing cloud provider configuration files.

Destructive operations (8 hooks). Agents deleting, purging, or overwriting production resources. The cache purge guard is the most dramatic, but the category includes database operations, file deletions, and infrastructure modifications.

Task drift (4 hooks). Agents working on the wrong problem. The drift detector is the primary defense, supplemented by session-specific task anchors.

Output quality (6 hooks). Agents producing substandard work. The evidence gate, the quality loop checkpoints, and the phantom verification detector.

Resource exhaustion (3 hooks). Agents spawning too many sub-agents, consuming excessive context, or running unbounded loops. The recursion guard is the primary defense.

Cross-project contamination (4 hooks). Agents in one project modifying files in another project. The project detector restricts write operations to the current working directory’s project scope.

The remaining hooks are project-specific or experimental. The six categories capture the structural failure modes that recur across all agent configurations.

What Hooks Cannot Catch

Hooks operate at the tool-call level. They intercept the action before or after it occurs. They cannot intercept the reasoning that led to the action.

An agent that decides to refactor a function instead of fixing the reported bug produces a valid tool call (file write) with correct content (syntactically valid code) that violates the task (wrong function). No hook catches this because no tool call is suspicious. The drift detector catches it eventually, but only after the agent has spent significant context on the wrong work.

Hooks also cannot catch composition failures where each individual action is authorized but the sequence produces an unauthorized outcome. The supply chain composition gap operates at the same level: each component does what it is trusted to do, and the composition produces what nobody intended.

The hook system is necessary but not sufficient. It catches the failure modes that have already occurred. It does not catch novel failures. The gap between hooks and complete safety is the gap between institutional memory and institutional foresight.

The Compounding Effect

Each hook makes every future session safer than the session that created it. The cache purge guard has fired zero times since it was installed, because no agent has attempted a cache purge since the passphrase gate was added. The credential path guard fires regularly, catching routine context-gathering that would otherwise include sensitive files. The drift detector fires in approximately 8% of sessions, catching behavioral shifts that the agent does not notice.

The hooks compound in the same way that context compounds: each one is a small investment that prevents a class of failure across all future sessions. A project with zero hooks is exposed to every failure mode. A project with 84 hooks is exposed only to failure modes that have not yet occurred.

The scars accumulate. The system gets tougher. Not smarter. Tougher.


FAQ

Can I see your hook configurations?

The hook system is described in my NIST comment on agent security and referenced throughout the AI Engineering series. The specific hook implementations are in ~/.claude/hooks/ and ~/.claude/settings.json.

How do hooks affect agent performance?

Each hook adds milliseconds of latency per tool call. With 84 hooks, the total overhead is approximately 200-400ms per tool call, depending on which hooks fire. The latency is negligible compared to the model inference time (2-5 seconds per response).

Do hooks work with other AI coding tools?

Hooks are Claude Code specific. The concept (intercepting tool calls with constraint checks) applies to any agent framework with a middleware or plugin system. The specific implementations depend on the framework’s event model.

What happens when a hook blocks an action?

A hard block (exit 2) prevents the action and injects a message explaining why. The agent can see the block reason and adjust its approach. An advisory (exit 0) logs the concern but allows the action to proceed. Most hooks are advisory. Only destructive operations use hard blocks.


Sources

This article draws on production experience from 500+ autonomous coding sessions with 84 hooks across 15 event types since January 2026. Specific incidents referenced:

Articles connexes

The Supply Chain Is the Attack Surface

Trivy got compromised. Then LiteLLM. Then 47,000 installs in 46 minutes. The AI supply chain worked exactly as designed.

14 min de lecture

The Handoff Document

A diagnosis that survived three code review corrections, two priority reorderings, and guided the correct implementation…

7 min de lecture

The Ralph Loop: How I Run Autonomous AI Agents Overnight

I built an autonomous agent system with stop hooks, spawn budgets, and filesystem memory. Here are the failures and what…

8 min de lecture