Welcome to session 49! Jyoti Pravat Senapati is back, this time on hooks — the part of the harness that turns a polite request into a rule the model cannot ignore.
Jyoti is a Product Manager at Enphase Energy in Bengaluru. He holds an MTech from IIT Madras and a PGP from the Indian School of Business. He last joined us for session 48 on self-improving skills.
Session overview
You control a coding agent in layers. A prompt is the loosest: you ask, and the model decides. A skill file or CLAUDE.md is firmer, but it is still text competing with other text in a long context — as Jyoti puts it, the model may follow all of it, one part of it, or none of it.
A hook is different. It is a script the harness runs at a fixed point in its own loop, and the harness will not take the next step until the script returns a verdict. The model does not get a vote.
That framing produced the line of the session: MCP is an opinion, hooks are a binding contract. An MCP tool is something the model might decide to call. A hook fires every time its event fires, guaranteed.
Both demos of the guardrails went wrong on camera, and the session is better for it. The rm -rf guard fired at the wrong trigger and the demo folder was deleted for real, live. Nobody edited that out.
Key takeaways
- Skills generate, hooks gate: A skill file creates output. A hook cannot create anything — it inspects what was produced and returns allow or deny. Neither replaces the other.
- A hook is a contract, an MCP call is an opinion: The model chooses whether an MCP tool is the right way to answer. It does not choose whether a
PreToolUsehook runs. - Claude Code exposes far more hook events than Codex:
PreToolUse,PostToolUse, tool failure, permission denied,Notification,UserPromptSubmit,SessionStart,Stopand more. Codex covers the common ones — pre/post tool use, pre/post compact, subagent start and stop. - Some "magic" features are just hooks: The desktop notification when a session is waiting on your permission ships built into Claude Code, but it is implemented as a hook. You can build the same class of feature yourself.
- A
SessionStarthook beats a growing CLAUDE.md: CLAUDE.md only ever gets appended to and loads in full every time. A hook that reads a backlog folder loads only what is still open, and works whether you are in Claude Code or Codex that day. - Hooks are evidence-driven: Write one when you have watched a specific failure happen, not in advance. Gating every turn costs more time than it saves.
- Hooks carry their own risk: A guard wired to the wrong trigger does nothing, and you will believe you are protected. Test them in a sandbox before they guard anything you cannot lose.
Topics covered
What a hook actually is
The four moving parts: the event that fires, the matcher that filters it, the script that runs, and the verdict it returns. When the script writes "permissionDecision": "deny", the harness stops. The model is not asked to agree.
Hooks versus skill files, and where MCP fits
An audience question on whether this is the same thing as a skill file opens the sharpest stretch of the session. Prompts drift because long context makes them undeterministic; a deterministic script does not drift. Then Vijay asks where to put a guardrail around an MCP tool layer that reads customer data, and Jyoti's answer is: before the tool call, not inside it.
Every hook event, side by side
A walk through the trigger list in Claude Code and the smaller set in Codex, with a use case for each — including PostToolUseFailure for tools that fail on permissions, and UserPromptSubmit for catching a password before it ever reaches the model.
Demo 1: a session that already knows your backlog
A fresh Claude session that opens already knowing the three features in flight, because a SessionStart hook reads a backlog folder. Jyoti then shows the real version on his own codebase: a tasks file that both Claude and Codex keep updated, with decisions recorded alongside status.
Demo 2: guarding against rm -rf, and watching it fail
The guard is configured, the prompt asks for the project to be deleted, and the folder goes anyway. The hook ran — it was attached to the wrong trigger. Bala and Jyoti debug it live, and the conversation turns to hooks as a governance layer on pull requests.
Bala's non-coding hooks
Three hooks with nothing to do with code: an audio cue so you know which of fifteen terminal tabs wants your attention, a Stop hook that summarises every session into a global wiki that outlives any one tool, and a SessionStart hook that asks what success looks like before any work starts. Bala's screen is blurred here — the terminal had client work on it.
Demo 3: secret scanning, and when not to use a hook
Blocking API keys before they land in a codebase, against the backdrop of 28 million leaked keys last year. Then the harder half: hooks cannot encode business logic, cannot judge tone, and should not sit on every turn.
Q&A highlights
- How can you be sure the model will follow the hook?
- Can one hook hold several different guardrails?
- Is a hook always better than a CLAUDE.md file?
- Can hooks regulate what the model says, not just what it does?
- Why can't the whole industry standardise on this?
- Is there any undo after
rm -rf? (No.)
Here's the entire recording of the session.