What exactly are hooks?
If you have been using Claude/Codex/ChatGPT often you may see subtext from the agents saying they are verifying with hooks. But what are they and how do they work?
They are rules that run on their own
A hook is a small script that the agent runs automatically when something specific happens. Before it runs a command. After it edits a file. When you send a message. When it thinks it is done. You write the rule once. The agent runs it every time without being asked.
That "verifying with hooks" line you see is the agent pausing while one of these scripts runs. Both Claude Code and Codex let a hook show a short status message while it works.
What a hook looks like
A hook is not a .md file. It is a few lines of JSON in a settings file, plus a small script that the JSON points to. Here is the "stop it from deleting things" hook from the examples below, as it looks in Claude Code:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-rm.sh"
}
]
}
]
}
}Read it as: before any tool runs (PreToolUse), if the tool is the shell (Bash), run this script. The script gets the command as JSON and decides:
#!/bin/bash
CMD=$(jq -r '.tool_input.command')
if echo "$CMD" | grep -q 'rm -rf'; then
echo "Blocked: no rm -rf in this repo" >&2
exit 2
fi
exit 0Exit 0 means go ahead. Exit 2 means stop, and the model reads the message and tries something else. Codex uses the same shape and the same event names.
The "command" type runs a script, and it is the most common. Claude Code supports four more.
- "http" sends the event to a URL, so a team can run one policy server for everyone.
- "mcp_tool" calls a tool on an MCP server you already have connected, like a security scanner.
- "prompt" asks a fast Claude model a yes or no question about the event, so you can write a rule in plain English with no script at all.
- "agent" starts a small helper agent that can read files before it decides, and is still experimental.
Codex only runs "command" and "mcp_tool" today.
Where they live and how the agent finds them
There is no search. Each tool reads hooks from a few fixed files every time a session starts. Where you put the file decides who it applies to.
- Global, every project on your machine: ~/.claude/settings.json for Claude Code, ~/.codex/hooks.json for Codex
- One project, shared with your team through git: .claude/settings.json or .codex/hooks.json in the repo
- One project, just for you: .claude/settings.local.json (Claude Code)
- Company wide: managed settings your admin pushes out, which you can't turn off
- Bundled: inside a plugin you install
They stack. A global hook and a project hook both run. Type /hooks in either tool to see what is loaded and which file each one came from. The ChatGPT desktop app runs Codex, so it reads the same Codex files.
So hooks are not tied to a session. Once the file is in place, every new session picks it up. The one exception is a hook written inside a skill or subagent. Those are .md files with the hook in the header, and the hook only switches on when that skill or agent runs. Codex also makes you approve each new or changed hook once before it will run it.
Why they exist
Instruction files like CLAUDE.md or AGENTS.md are suggestions. The model reads them and usually follows them. Usually is the problem. Ask it to run the formatter after every edit and it will do it nine times out of ten. Tell it never to touch the .env file and it will mostly listen.
Hooks are not suggestions. They are code. They run every time, whether the model remembers or not. That is the whole point. Anthropic shipped them in Claude Code in 2025 for exactly this reason. OpenAI then added the same idea to Codex with the same event names and the same config shape, so a hook written for one mostly works in the other.
Where they fire
Both tools fire hooks at the same kinds of moments:
- A session starts or ends
- You submit a prompt
- Before a tool runs (a shell command, a file edit, an MCP call)
- After a tool runs
- When the agent asks you for permission
- When the agent decides it is finished
A hook can do four things. Let the action through. Block it with a reason the model sees. Rewrite the input. Or add context the model reads on its next step.
Concrete examples
- Stop it from deleting things. Before any shell command, a hook checks for rm -rf, git push --force, or DROP TABLE and blocks it. The model sees why and picks another route. This is the first example in Anthropic's docs, and OpenAI's docs use the same one.
- Format every file it touches. After any edit, run Prettier or Black on that file. You never have to say "run the formatter" again, and you never get a PR full of whitespace diffs.
- Keep certain files off limits. Before any edit, if the path is .env, a lockfile, or a migrations folder, deny it.
- Catch pasted secrets. When you submit a prompt, a hook scans it for anything that looks like an API key and refuses the message before it leaves your machine.
- Don't let it quit early. When the agent says it is done, a hook runs the test suite. If tests fail, the hook blocks the stop and hands the failure back. The agent keeps working. This is how people run Claude Code for an hour unattended.
- Ping you when it needs you. When it is waiting on an approval, a hook sends a Slack message or a desktop notification so you can walk away from the terminal.
- Keep an audit trail. After every command, append the command and its output to a log file. If you work in a regulated industry, this is the difference between "trust me" and a record.
- Load context on start, save it on exit. On session start, inject the current branch and your open tickets. On session end, summarize the chat into a notes file so the next session picks up where you left off.
Do you have to write them yourself?
Mostly yes, but it is small. Neither tool ships with hooks turned on. A hook is one JSON entry in a settings file plus a short script, often ten lines of bash or Python. In Claude Code you can just ask Claude to write it for you. Codex makes you review and trust each hook before it runs, which is the right call since a hook is code running on your machine.
Three ways to skip writing from scratch: install a plugin that bundles hooks, copy one from the public collections on GitHub, or get them from your company's managed settings if your admin has set some up.
Can you use them in normal chat?
No. Hooks are tied to the agent loop. They fire when the agent calls tools, starts a turn, or finishes one. Plain chat in claude.ai or ChatGPT has none of that, so there is nothing to hook. You will only see them in Claude Code (terminal, IDE, desktop app, web) and in Codex (CLI, IDE extension, and the ChatGPT desktop app where Codex now runs).
If you only ever chat, you will never need one. The moment you let a model run commands and edit files on your behalf, you will want at least example one.
The short version
Hooks are the seatbelt for AI agents. Instructions tell the model what you want. Hooks make sure it happens.
Further reading: Claude Code hooks reference and Codex hooks docs.