Claude Code Function Hooks: CLAUDE.md Is Obsolete

Claude Code Just Made CLAUDE.md Feel Obsolete

🎬 Ray Amjad 📅 Sep 4, 2026 ⏱ 16:53
Claude Code function hooks middleware plugins security

🎯 What Are Function Hooks

Anthropic released function hooks — which Ray calls "the best feature in Claude Code yet." They take the existing shell-hooks system to the next level, making Claude Code far more hackable and customizable, while solving the core problems with hooks. 0:00

Why hooks exist at all: to add deterministic control to Claude Code. A rule in your CLAUDE.md (like "never run destructive Supabase commands") can fade over time as context fills up, or get skipped on a lazy prompt. Hooks enforce the rule mechanically instead of hoping the model remembers it.

🔒 The Limits of Old Hooks

Existing shell hooks were useful but couldn't do six things. Function hooks solve all six. 1:49

CapabilityShell hooksFunction hooks
Rewrite the prompt / input
Append context (e.g. company knowledge base)
Draw UI (buttons, status rows)
Ask user questions
Add tools / edit tool descriptions
Memory across hooks & sessions
Enable with: CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 claude. This unlocks the built-in /plugin-authoring skill ("write or debug a Claude Code plugin made of function hooks").

🧩 The Express.js Analogy

Ray's mental model: function hooks are Express.js middleware for Claude Code. On any tool call, you match against a tool and optionally a regex, then block, rewrite, or short-circuit. 2:17

Express.jsFunction hooks
Block requests missing an auth header, else next()On any tool call, match the Bash tool; if it matches a destructive regex, block it
Middleware can rewrite the requestRewrite input — e.g. replace npm with pnpm install to prevent accidental npm use
Middleware can short-circuit with a cached responseWeb fetch: check the store first, return the cached copy if the URL was already fetched
Two stores: a variable store (visible to the next hook and next turn, in-session) and a persistent store (survives sessions and restarts — use for non-secret state).
Overriding default tools: Claude Code's built-in web search is weak, so Ray uses Exa MCP. With a function hook he intercepts the web search tool → if an Exa API key is set, call Exa's endpoint; on failure, fall back to web search. He can now uninstall the Exa MCP server entirely and still get Exa behind the scenes. Same trick can route the web fetch tool through your own proxy.

🤐 Example 1: The Secret Redactor

The security killer-app: intercept secrets before they ever enter the session transcript. 5:00

The problem: Claude runs a Bash command that loads an API key → the secret is now in the transcript → you must delete the session or rotate the key. Same risk with emails and IP addresses.
The fix (auto-generated by /plugin-authoring): a ~300-line hook (transcript_redactor.json + redact.ts) that:
  1. Measures entropy to detect secrets, plus regex for emails and IPs
  2. Redacts the secret as soon as you hit enter — replaces it with an ID
  3. Stores the secret in-memory, so Claude uses the ID, never the secret
  4. Rewrites it back to the real secret only at request time
The demo: paste an Anthropic API key → ask for a story → the key is redacted to an ID, stored, and swapped back in only when the actual request fires. Secret never touches the transcript.
"We added security by never allowing secrets to enter the transcript — and second, allowing it to actually use secrets on our behalf." This is the same model as Agent Proxy by Infisical.

🖥️ Example 2: Vercel Deploy UI

Function hooks can draw custom UI rows in Claude Code — the feature Ray is most excited about. 7:54

The demo: a hook that shows the Vercel deploy stage (queued → building → ready) and elapsed time in a status row next to the prompt, with a hide/show button. Each plugin gets a live data panel. He triggers a deploy → watches the row tick through stages → "ready, 5m 50s."
The authoring pattern: /plugin-authoring → describe the hook → tell it to "interview me, give me prototypes to play with before coding" → it asks clarifying questions → builds it.

🔧 More Hook Patterns

The rest of the video is a rapid-fire catalog of patterns — the "hundreds of examples" Ray says are now possible. 11:29

PatternWhat it does
Dry runsBlock real commands until a dry-run has run first — combined with a big red "you're in production / dry mode" UI row
Refactor gateEvery time an edited file exceeds 1,000 lines, ask "refactor into smaller files?" (models still love 2,000–3,000-line files)
Speak on turn endPass a summary to a Haiku model ($model), then speak it via built-in TTS
Audit trailSend every event to your own log store — compliance for healthcare/payments
Newsletter guardBlock sending an email until the ask tool confirms you actually want it sent
Knowledge-base injectionGenerate keywords from the prompt, query your company KB via $http, inject context into the session
PR quizBefore opening a PR, Claude generates a quiz to confirm you understand the changes
Time guardIf a turn exceeds 10 minutes, save the result to a separate file so nothing is lost
"Point /plugin-authoring at your CLAUDE.md files and say: which hooks can we make here for more reliable deterministic behavior? Everything you've been putting in CLAUDE.md, start moving into well-defined hooks.json."

🔗 Shell Hooks Explained (Ray's blog) · Anthropic's official announcement (X)

💡 Key Takeaways

  1. Function hooks are deterministic control — rules in CLAUDE.md fade; hooks enforce mechanically, every time.
  2. They're Express.js middleware — block, rewrite, or short-circuit any tool call by matching tool + regex.
  3. They solve all six limits of shell hooks — rewrite, append context, draw UI, ask questions, add tools, and memory.
  4. Secrets never hit the transcript — the redactor swaps secrets for IDs and stores them in-memory, swapping back only at request time.
  5. You can override built-in tools — intercept web search to use Exa behind the scenes, no MCP server needed.
  6. Custom UI rows — live deploy status, dry-run warnings, per-plugin data panels with hide/show buttons.
  7. The ask + memory primitives — gate destructive actions behind a user question, and persist state across turns and sessions.
  8. Migrate CLAUDE.md → hooks.json — and share them as plugins via a shared GitHub repo for the whole team.

📍 Timestamp Index

0:00 Intro — the best feature yet
0:50 Why hooks (deterministic control)
1:49 The limits of old hooks
2:17 Middleware + rewrite + store
3:28 Override web search (Exa)
5:00 Secret redactor demo
7:54 Vercel deploy UI
11:29 Dry runs, refactor gate, TTS, audit
14:30 TTS + $model + knowledge-base injection
☰ View all