# What are agent hooks (Stop hooks)?

Agent hooks are scripts a coding agent runs at set points in its loop, e.g. a Stop hook that runs the tests before the agent can end its turn.

Last updated September 29, 2026, 9 min read

## Learning objectives

After reading this article you will be able to:

-   Define agent hooks and Stop hooks
-   Explain how hooks put checks inside the agent loop
-   Compare agent hooks with Git hooks

## Related content

-   [What is CI/CD?](https://specstory.com/learning/ci-cd/ci-cd)
-   [What is a pre-commit hook?](https://specstory.com/learning/ci-cd/pre-commit-hook)
-   [What is the difference between pre-commit, pre-push, and CI checks?](https://specstory.com/learning/ci-cd/pre-commit-vs-pre-push-vs-ci)

## What are agent hooks (Stop hooks)?

An agent hook is a script that a [coding agent](https://specstory.com/learning/ai-coding/coding-agent)'s [harness](https://specstory.com/learning/ai-coding/agent-harness) runs at a fixed point in the agent's loop. A Stop hook is an agent hook that runs when the agent tries to end its turn. A hook can let the step go ahead, block it, or send the agent a message to act on.

Hooks belong to the harness, not to the model, so each coding agent defines its own set of hook events. The [Claude Code hooks reference](https://code.claude.com/docs/en/hooks) describes hooks as handlers that "execute automatically at specific points in Claude Code's lifecycle." Each of these points is a hook event, e.g. `Stop`.

Hooks put checks inside the loop, before control returns to the developer. A [pre-commit hook](https://specstory.com/learning/ci-cd/pre-commit-hook) runs only if the agent commits, and a continuous integration and delivery ([CI/CD](https://specstory.com/learning/ci-cd/ci-cd)) pipeline usually runs after a push. In Claude Code, a Stop hook can run the tests each time the agent tries to stop. When a test fails, the hook exits with code 2, and the agent receives the failure and keeps working.

## How do agent hooks work?

Each hook pairs an event with a handler, which is usually a shell command. A command hook works in six steps:

1.  A developer adds the hook to a settings file with an event, an optional matcher, and the command. The matcher limits the hook to some tools, e.g. `Bash`.
2.  The harness reaches the event, e.g. the model requests a [tool call](https://specstory.com/learning/glossary#tool-calling) that edits a file.
3.  The harness starts the command and passes it a JSON description of the event on standard input.
4.  The command runs its check and exits with a code. It can also print JSON with a decision.
5.  The harness reads the result. In Claude Code, exit code 2 blocks a tool call or a stop, and the model receives the command's error output.
6.  The model reads that message as its next input and continues from it.

Diagram: Where hooks run in the agent loop

The PreToolUse and PostToolUse hooks run on each matching tool call. The Stop hook runs once per final answer, so a slow check there adds less wait to the loop.

Claude Code and Codex share the names of these four events:

-   **Before a tool call.** A `PreToolUse` hook reads the tool's input and can block the call.
-   **After a tool call.** A `PostToolUse` hook runs after the tool runs, e.g. to format an edited file. It cannot undo the call. Claude Code runs it only after the tool succeeds.
-   **When a prompt arrives.** A `UserPromptSubmit` hook runs before the model reads the prompt and can add context or block it.
-   **When the agent stops.** A `Stop` hook runs when the agent finishes its response and can send it back to work.

Besides shell commands, Claude Code can use an HTTP endpoint, a [Model Context Protocol (MCP)](https://specstory.com/learning/ai-coding/model-context-protocol) tool, a model prompt, or a subagent as a handler. Its documentation calls the subagent type an "agent hook," a narrower meaning than this page's, and marks it experimental. A hook in a user's own settings applies to every project. A project's settings file can be committed and shared with the team.

## What is an example of an agent hook?

Here is an illustrative example. Acme Co. sells furniture online. A developer at Acme asks a coding agent, e.g. Claude Code, to "Let customers edit their delivery address during checkout." The web store's repository has this Stop hook in `.claude/settings.json`:

```json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/run-tests.sh",
            "args": []
          }
        ]
      }
    ]
  }
}
```

The hook runs this script, which is marked executable with `chmod +x` so the harness can start it. It checks for uncommitted changes and then runs the unit tests:

```bash
#!/bin/bash
# .claude/hooks/run-tests.sh
if [ -z "$(git status --porcelain)" ]; then
  exit 0  # no uncommitted changes, so the agent may stop
fi
if ! npm test > /tmp/acme-tests.log 2>&1; then
  echo "Unit tests failed. Read /tmp/acme-tests.log and fix the code." >&2
  exit 2  # block the stop and send this line to the agent
fi
exit 0
```

The turn then runs in six steps:

1.  The agent edits `checkout.js` and `checkout.test.js`, and ends its final message with "Done."
2.  The harness fires the `Stop` event and runs `run-tests.sh`.
3.  The script finds 2 changed files with `git status --porcelain`, so it runs `npm test`.
4.  One cart test fails. The address saved, but the cart emptied.
5.  The script exits with code 2. The harness keeps the turn open and sends the script's error line to the model.
6.  The agent reads `/tmp/acme-tests.log`, fixes `checkout.js`, and tries to stop again. The tests pass, the script exits 0, and the turn ends.

This example is simplified. A real hook would also test commits the agent made during the turn, which `git status --porcelain` does not list.

## What is a Stop hook?

A Stop hook is an agent hook that runs when the agent finishes its response, before control returns to the developer. In Claude Code, the hook blocks the stop by exiting with code 2, or by printing JSON with `"decision": "block"` and a `reason`. The model receives the reason and keeps working. Codex accepts the same exit code and JSON, and sends the reason to the model as the next prompt.

In Claude Code, a Stop hook runs after each response, not only at the end of the task, e.g. when the agent stops to ask a question. It does not run when the developer interrupts the agent. A `PostToolUse` hook can run the tests after each file edit instead, which reports a failure sooner but makes each edit wait for a test run. A hook that runs in the background avoids that wait, but it cannot block.

A Stop hook turns part of a team's [definition of done](https://specstory.com/learning/verification/definition-of-done-for-coding-agents) into a check that runs, e.g. "the unit tests pass." It answers a ["done" claim](https://specstory.com/learning/verification/coding-agent-done-claims) with a test run, not with the agent's own summary.

A Stop hook that blocks on a condition the agent cannot meet keeps the turn running. Claude Code sets a `stop_hook_active` field to true when a Stop hook already continued the turn, so a hook can read it and stop blocking. Claude Code also ends the turn after 8 blocks in a row by default. Cursor gives each Stop hook a loop limit for the same reason.

## What are the limits of agent hooks?

Agent hooks have these limits:

-   **A hook checks only what its command checks.** A passing Stop hook shows that the suite passed, not that the feature works.
-   **The agent can change what the hook runs.** The agent can edit the tests so they pass, which is [test tampering](https://specstory.com/learning/verification/test-tampering). It can also edit the hook's settings, but in Claude Code a write to the `.claude` settings folder needs approval unless permission checks are turned off.
-   **A broken hook usually lets the step through.** In Claude Code, only exit code 2 blocks on its own for most events. A script that exits 1 without a JSON decision does not block, and neither does a mistyped script path.
-   **Hooks add time to the loop.** The harness waits for a hook to finish. A slow check on each tool call repeats that wait many times per turn.
-   **A hook that blocks commands is not a hard rule.** A `PreToolUse` hook that matches command text can miss a command written another way. Claude Code's documentation recommends permission rules, not hooks, for a hard allow or deny. A [sandbox](https://specstory.com/learning/environments/ai-sandbox) limits what a command can reach when a hook misses it.

## How are agent hooks different from Git hooks?

Both are [hooks](https://specstory.com/learning/ci-cd/git-hooks), which are scripts that a tool runs at set points in its workflow. A Git hook runs when someone runs a Git command, e.g. `git commit`. An agent hook runs inside the agent's loop, even before any commit exists, and no flag the agent adds to a command, e.g. `--no-verify`, turns it off. When an agent runs `git commit`, the Git hook still runs, and a `PreToolUse` hook can block a `git commit --no-verify` that would skip it. Outside the agent's loop, the choice between a pre-commit hook, a [pre-push hook](https://specstory.com/learning/ci-cd/pre-commit-vs-pre-push-vs-ci), and CI depends on how long each check takes and whether it can be skipped.

## FAQs

### What are Claude Code hooks?

Claude Code hooks are the agent hooks that Claude Code runs at named events in its loop, e.g. when the agent tries to stop. Each hook runs a handler, usually a shell command. A command hook can block a tool call or a stop by exiting with code 2.

### Where are agent hooks configured?

Agent hooks are configured in the coding agent's settings files. In Claude Code, a hook in a user's own settings applies to every project. A hook in a project's settings file can be committed and shared with the whole team.

### Can hooks slow down a coding agent?

Hooks can slow down a coding agent, because the harness waits for each hook to finish unless it runs in the background. A slow check on each tool call repeats that wait many times per turn. A matcher that limits the hook to the tools it needs keeps the wait short.

### Can an agent skip its own hooks?

An agent cannot turn off its own hooks with a flag on a command it runs, because the harness runs them, not the model. An agent can still weaken a hook by editing the tests it runs or the hook's settings. In Claude Code, a write to the settings folder needs approval unless permission checks are turned off.

---

Source: [Agent hooks | Run tests with Claude Code hooks | SpecStory](https://specstory.com/learning/ci-cd/agent-hooks)
