# Agent Hooks

Coding agents finish and push work nobody has checked; hooks run Bumpkit inside the agent's own loop, for developers and teams who use Claude Code, Cursor, Codex, Gemini CLI, Windsurf or Cline.

> **Beta, early access.** A workspace without access gets `403 FEATURE_EARLY_ACCESS` and a link to request it. Flag: `agent_guard`.

The Codex, Gemini CLI, Windsurf and Cline hooks also need the `agent_hooks_extended` flag (Beta).

Agent hooks put Bumpkit inside your coding agent's loop:

- **When a session starts**, `bumpkit recall` loads what your team and agents saved about the repository (approved swarm lessons, decisions, pitfalls, incidents) and what recent releases were flagged for.
- **When the agent finishes**, `bumpkit guard` checks its work against your `bumpkit.yml` policy. If it finds proven problems, it sends the agent back once to fix them. If a human approval is needed, it tells the agent to say so instead of working around it.
- **Before a push**, a git pre-push hook runs the same guard for any agent or person.

To get verified Claude Code sessions with nothing installed on developer machines, see [Agent Telemetry](/docs/agent-telemetry): your admin enables it once for the whole org.

You need the `bumpkit` CLI on your `PATH` and a key, from `bumpkit login` or `BUMPKIT_API_KEY`. See [Getting Started](/docs/).

## Supported agents

| Agent | Install | Session start | Finish check | Flags (all Beta) |
|-------|---------|---------------|--------------|------------------|
| Claude Code | `bumpkit hooks install --claude` | `SessionStart` | `Stop` | `agent_guard`. Also installs the [pause hook](#pause-risky-commands) (`agent_pause`). |
| Cursor | `bumpkit hooks install --cursor` | `sessionStart` | `stop` | `agent_guard`. Also installs the [pause hook](#pause-risky-commands) (`agent_pause`). |
| git | `bumpkit hooks install --git` | | `pre-push` | `agent_guard` |
| OpenAI Codex | `bumpkit hooks install --codex` | `SessionStart` | `Stop` | `agent_guard`, `agent_hooks_extended`. Also installs the [pause hook](#pause-risky-commands) (`agent_pause`). |
| Gemini CLI | `bumpkit hooks install --gemini` | `SessionStart` | `AfterAgent` | `agent_guard`, `agent_hooks_extended`. Also installs the [pause hook](#pause-risky-commands) (`agent_pause`). |
| GitHub Copilot | `bumpkit hooks install --copilot` | | | `agent_pause` |
| OpenHands | `bumpkit hooks install --openhands` | | `stop` | `agent_guard`, `agent_pause` |
| Devin | `bumpkit hooks install --devin` | | `Stop` | `agent_guard`, `agent_pause` |
| Amp | `bumpkit hooks install --amp` | | | `agent_pause` |
| Aider | `bumpkit hooks install --aider` | | `pre-push` | `agent_guard` |
| Windsurf | `bumpkit hooks install --windsurf` | | `pre_run_command` before `git push`, and `pre-push` | `agent_guard`, `agent_hooks_extended` |
| Cline | `bumpkit hooks install --cline` | `TaskStart` | `PreToolUse` on `attempt_completion`, and `pre-push` | `agent_guard`, `agent_hooks_extended` |

The session start hooks also need `codebase_memory` or `swarm_lessons`. The git `pre-push` hook that `--windsurf` and `--cline` add needs only `agent_guard`.

Running `bumpkit hooks install` with no flags installs the Cursor hooks and the git pre-push hook, plus the Claude Code hooks when the repository has a `.claude/` directory or a `CLAUDE.md`. `--windsurf`, `--cline` and `--aider` also install the git pre-push hook, and `--claude`, `--codex`, `--gemini`, `--windsurf` and `--cline` add the [MCP server](/docs/mcp) to that agent's config. Every installer merges into existing config: it keeps your other hooks and skips an entry whose command is already there, so running it twice is safe.

## What the guard does

`bumpkit guard` compares your working tree, including uncommitted changes, with where your branch left the default branch. It tries `origin/HEAD`, `origin/main`, `origin/master`, `main` and `master`. When you're already on the default branch, with nothing committed past `origin`, the base is `HEAD` itself: guard checks only your uncommitted changes and passes quietly when there are none, so commits already merged aren't flagged again. Without an `origin` ref, on a local `main` or `master` itself or with none of these refs, it falls back to the latest tag. Pass `--base REF` to choose the ref yourself.

It applies `bumpkit.yml` (or `.bumpkit.yml`) as it is at that base, or the default policy, and runs a fast release gate:

| Outcome | What happens |
|---------|--------------|
| `pass` | Nothing. The agent finishes. |
| `fail` | The agent is told to fix each proven, high-severity finding, with its file and line, or explain a false positive in its final message. |
| `needs_approval` | The agent is told which rules need a human reviewer and not to work around them. |

The guard never blocks on its own failure. If you are not signed in, the workspace doesn't have `agent_guard` (or `agent_hooks_extended` for the Codex, Gemini CLI, Windsurf and Cline hooks), or Bumpkit is unreachable, it prints a note to stderr and exits `0`. When there is no diff, it exits `0` without a note. The exception is a change too large to check in full: the guard blocks the hook, or exits `2` without `--hook`, with "Bumpkit could not check the full change".

Run without `--hook`, as in the git hook, it prints the message to stderr and exits `1` when the outcome is `fail` or fix tasks are open. A change that only needs approval prints which approval it needs and exits `0`. With `--hook`, it exits `0` with the reply that agent expects, except the Windsurf hook, which blocks by printing the message to stderr and exiting `2`. See [Agent guard](/docs/agent-controls#agent-guard) for each reply.

With Close the loop on (Beta, flag `close_the_loop`), the guard also blocks while [fix tasks](/docs/agent-swarms#fix-tasks) are open on the current branch, even when the gate passes.

```bash
bumpkit guard
bumpkit guard --base origin/main
```

The guard sends an agent back only once per stop: Claude Code skips it when `stop_hook_active` is set, and Cursor runs it only on the first loop of a stop with status `completed`.

## What recall does

> **Beta, early access.** A workspace without access gets `403 FEATURE_EARLY_ACCESS` and a link to request it. Flag: `codebase_memory`.

`bumpkit recall` prints the approved [swarm lessons](/docs/agent-swarms#swarm-lessons) when `swarm_lessons` is on, then the memories saved for the repository (from the `origin` remote) or for one path, with their kind, author and id, plus the finding kinds recent releases there were flagged for. As a hook, it hands that text to the agent as session context.

```bash
bumpkit recall
bumpkit recall --path services/auth
```

It exits `0` with a note on stderr when both `codebase_memory` and `swarm_lessons` are off, when a Codex, Gemini CLI or Cline hook runs without `agent_hooks_extended`, or when the directory has no `origin` remote. Manage memories with `bumpkit memory add`, `bumpkit memory list` and `bumpkit memory forget`, or the `remember`, `recall` and `forget` [MCP tools](/docs/mcp).

## Claude Code

```bash
bumpkit hooks install --claude
```

This adds three hooks to `.claude/settings.json`, the project settings your team shares, and keeps your other settings, permissions and hooks:

```json
{
  "hooks": {
    "SessionStart": [
      { "hooks": [{ "type": "command", "command": "bumpkit recall --hook claude", "timeout": 20 }] }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash|Read|Write|Edit|MultiEdit|NotebookEdit",
        "hooks": [{ "type": "command", "command": "bumpkit pause --hook claude", "timeout": 150 }]
      }
    ],
    "Stop": [
      { "hooks": [{ "type": "command", "command": "bumpkit guard --hook claude", "timeout": 60 }] }
    ]
  }
}
```

| Hook | What it does |
|------|--------------|
| `SessionStart` | Runs `bumpkit recall --hook claude` (timeout 20 s) |
| `PreToolUse` | Runs `bumpkit pause --hook claude` (timeout 150 s) before shell commands, reads and writes. See [Pause risky commands](#pause-risky-commands). Needs `agent_pause`. |
| `Stop` | Runs `bumpkit guard --hook claude` (timeout 60 s) |

It also adds the [MCP server](/docs/mcp) to `.mcp.json` in the repository, so the agent can call `release_gate`, `recall` and `remember` itself. An existing `bumpkit` server there is kept. Claude Code asks you to approve project MCP servers the first time it starts one; review the hooks with `/hooks`.

The hooks use the key from `bumpkit login` or `BUMPKIT_API_KEY`. When the guard finds a problem it replies `{"decision": "block", "reason": "..."}`, which sends Claude back to work with the reason. Recall replies with `hookSpecificOutput.additionalContext`.

To add the hooks for every project instead, put the same entries in `~/.claude/settings.json` and run `claude mcp add bumpkit -- bumpkit mcp`.

## Cursor

```bash
bumpkit hooks install --cursor
```

This writes `.cursor/hooks.json` in the repository root:

```json
{
  "version": 1,
  "hooks": {
    "sessionStart": [
      { "command": "bumpkit recall --hook cursor", "timeout": 20 }
    ],
    "stop": [
      { "command": "bumpkit guard --hook cursor", "timeout": 60 }
    ],
    "beforeShellExecution": [
      { "command": "bumpkit pause --hook cursor", "timeout": 150 }
    ]
  }
}
```

The guard replies with `followup_message`, which Cursor sends back to the agent. Recall replies with `additional_context`. The `beforeShellExecution` hook is the [pause hook](#pause-risky-commands).

To remove the hooks, delete the three `bumpkit` entries from `.cursor/hooks.json`.

## Git pre-push

```bash
bumpkit hooks install --git
```

This writes a `pre-push` hook in the repository's hooks directory (`git rev-parse --git-path hooks`, so it respects `core.hooksPath`):

```bash
#!/bin/sh
exec bumpkit guard
```

A push with proven problems stops with the guard's message. A push that only needs approval goes through: approval belongs on the pull request, which can't exist until the branch is pushed. The guard prints which approval the pull request will need, the dashboard link where a reviewer approves it, and the workspace it checked, and the pull request check and the merge stay blocked until a reviewer approves. With a clean working tree it checks the exact commit you push, so an approval already recorded for that commit counts. The installer never overwrites a `pre-push` hook you already have: if one exists without `bumpkit guard`, it stops and asks you to add the line yourself.

To remove it, delete the `pre-push` file, or the `bumpkit guard` line from your own hook. To push once without it, use `git push --no-verify`.

## OpenAI Codex

```bash
bumpkit hooks install --codex
```

This writes `.codex/hooks.json` in the repository:

| Hook | What it does |
|------|--------------|
| `SessionStart` | Runs `bumpkit recall --hook codex` (timeout 20) |
| `Stop` | Runs `bumpkit guard --hook codex` (timeout 120) |
| `PreToolUse` | Runs `bumpkit pause --hook codex` (timeout 150) before every `Bash` or `apply_patch` call. See [Pause risky commands](#pause-risky-commands). Needs `agent_pause`. |

It also adds `[mcp_servers.bumpkit]` to `.codex/config.toml`. Trust the project in Codex and review the hooks with `/hooks` before they run.

## Gemini CLI

```bash
bumpkit hooks install --gemini
```

This adds three hooks and the Bumpkit MCP server to `.gemini/settings.json`: `SessionStart` runs `bumpkit recall --hook gemini`, `BeforeTool` runs `bumpkit pause --hook gemini` before every `run_shell_command`, `read_file`, `write_file` or `replace` call, and `AfterAgent` runs `bumpkit guard --hook gemini` after each agent turn. Gemini asks you to trust new project hooks the first time they run.

## Windsurf

```bash
bumpkit hooks install --windsurf
```

This adds a `pre_run_command` hook that runs `bumpkit guard --hook windsurf` before Cascade runs `git push`, in `.windsurf/hooks.json` (or `.devin/hooks.json` when that file exists). Cascade has no blocking hook when it finishes, so the installer also adds the git pre-push hook as the backstop. The Bumpkit MCP server goes in your user MCP config. Windsurf has no recall hook.

## Cline

```bash
bumpkit hooks install --cline
```

This writes hook scripts to `.clinerules/hooks`: `TaskStart` runs `bumpkit recall --hook cline`, and `PreToolUse` runs `bumpkit guard --hook cline` before `attempt_completion`. It also adds the git pre-push hook, and the Bumpkit MCP server to the Cline CLI settings; in VS Code, add the server under MCP Servers > Configure. Turn on Enable Hooks in Cline's Feature Settings. If a `TaskStart` or `PreToolUse` script that isn't Bumpkit's already exists, the installer stops and asks you to add the command yourself.

## GitHub Copilot

```bash
bumpkit hooks install --copilot
```

This writes `.github/hooks/bumpkit.json` with a `PreToolUse` hook that runs `bumpkit pause --hook copilot` (timeout 150 seconds) before each tool call, so risky shell commands and file access wait for a human. The Copilot coding agent runs in GitHub's cloud: install `bumpkit` and set `BUMPKIT_API_KEY` from a repository secret in `.github/workflows/copilot-setup-steps.yml` so the hook can run.

## OpenHands

```bash
bumpkit hooks install --openhands
```

This writes `.openhands/hooks.json`: `pre_tool_use` runs `bumpkit pause --hook openhands` before every tool call, and `stop` runs `bumpkit guard --hook openhands` before the agent finishes. Install `bumpkit` in the sandbox from `.openhands/setup.sh` and give it a key with `BUMPKIT_API_KEY`.

## Devin

```bash
bumpkit hooks install --devin
```

This writes `.devin/hooks.v1.json`: `PreToolUse` runs `bumpkit pause --hook devin` before `exec`, `read`, `write`, `edit` and `apply_patch`, and `Stop` runs `bumpkit guard --hook devin` before Devin finishes. Install `bumpkit` and set `BUMPKIT_API_KEY` in Devin's machine setup.

## Amp

```bash
bumpkit hooks install --amp
```

This writes the plugin `.amp/plugins/bumpkit.ts`, which sends each tool call to `bumpkit pause --hook amp` before it runs and follows its answer. Run **plugins: reload** from Amp's command palette to load it. The installer keeps a plugin that's already there.

## Aider

```bash
bumpkit hooks install --aider
```

Aider has no hooks of its own, so this installs the [pre-push hook](#git-pre-push): every push of Aider's work runs `bumpkit guard` first.

## Company-wide agent policy

> **Beta, early access.** A workspace without access gets `403 FEATURE_EARLY_ACCESS` and a link to request it. Flag: `org_policies`.

Owners and admins set one locked agent policy for the whole workspace, and every hook above enforces it. It has an `agent:` section like `bumpkit.yml` (`ask`, `deny`, `allow`, `protected_branches`, `remote`, `timeout`, `files_deny`, `network_allow`, `egress`) and a `locked:` list of keys repositories may only tighten.

```yaml
locked: [deny, files_deny]
agent:
  deny: ["terraform destroy"]
  files_deny: [".env"]
```

```bash
bumpkit agent policy set agent-policy.yml --message "Keep agents off production hosts"
bumpkit agent policy show
bumpkit agent policy show --effective
bumpkit agent policy history
bumpkit agent policy diff 1
```

`set` shows the diff and asks before saving. `show --effective` applies the policy to this repository's `bumpkit.yml` and shows each key's value, where it came from and whether it's locked. Every version is kept and audited. On the dashboard, the **Agent policy** section of the **Policy** page shows the current version, what changed in each version and the history, and owners and admins save new versions there. From an agent, use the `agent_policy_show`, `agent_policy_set`, `agent_policy_history` and `agent_policy_diff` MCP tools.

Hooks fetch the policy signed by Bumpkit and cache it for up to 24 hours. A cached copy that was changed on disk fails its signature check and is fetched again.

## Add the hooks with a pull request

> **Beta, early access.** A workspace without access gets `403 FEATURE_EARLY_ACCESS` and a link to request it. Flag: `agent_hooks_pr`.

Owners, admins and policy admins can add the hooks for the whole team in one pull request. On the **Repositories** page, each connected repository has **Add agent hooks**; or run:

```bash
bumpkit hooks pr --repo acme/api
```

Bumpkit opens **Add Bumpkit agent hooks** through its GitHub App, on the branch `bumpkit/agent-hooks`. It adds the Claude Code, Cursor, Codex, Gemini CLI, GitHub Copilot, OpenHands, Devin and Amp hooks with [provenance](#record-ai-change-provenance) (no prompt summaries) and the MCP servers:

| File | Adds |
|------|------|
| `.claude/settings.json` | `recall`, `pause`, `guard` and provenance hooks |
| `.mcp.json` | The Bumpkit MCP server |
| `.cursor/hooks.json` | `recall`, `pause`, `guard` and provenance hooks |
| `.codex/hooks.json` | `recall`, `pause`, `guard` and provenance hooks |
| `.codex/config.toml` | The Bumpkit MCP server |
| `.gemini/settings.json` | `recall`, `pause`, `guard` and provenance hooks, and the Bumpkit MCP server |
| `.github/hooks/bumpkit.json` | The GitHub Copilot `pause` hook |
| `.openhands/hooks.json` | The OpenHands `pause` and `guard` hooks |
| `.devin/hooks.v1.json` | The Devin `pause` and `guard` hooks |
| `.amp/plugins/bumpkit.ts` | The Amp `pause` plugin |

The files are the ones `bumpkit hooks install --claude --cursor --codex --gemini --copilot --openhands --devin --amp --provenance` writes, merged into what is already on the default branch. Asking again returns the open pull request, and nothing is opened when the default branch already has every hook. The App needs contents and pull requests write access. Agents read the state with the `agent_hooks_status` MCP tool, and the API is `GET /v1/repositories/{owner}/{repo}/agent-hooks` and `POST /v1/repositories/{owner}/{repo}/agent-hooks`.

## Record AI change provenance

> **Beta, early access.** A workspace without access gets `403 FEATURE_EARLY_ACCESS` and a link to request it. Flag: `change_provenance`.

Provenance hooks record which agent, model and session made a change, and the tools it used, so each release shows where its code came from. They are opt-in. Add them while installing:

```bash
bumpkit hooks install --claude --provenance
bumpkit hooks install --cursor --provenance
bumpkit hooks install --codex --provenance --prompts
```

Or turn them on and off for every agent whose hooks are already in the repository:

```bash
bumpkit provenance enable
bumpkit provenance enable --prompts
bumpkit provenance disable
```

Each event runs `bumpkit provenance record --hook <agent>`. For Claude Code that's `SessionStart`, `UserPromptSubmit`, `SessionEnd`, and `PostToolUse` on `Bash`, `Edit`, `MultiEdit`, `Write`, `NotebookEdit` and MCP tools. Installing again with or without `--prompts` replaces the Claude Code provenance hooks instead of adding more. `--prompts` also sends a redacted summary of each prompt. `bumpkit provenance enable` adds the hooks to `.claude/settings.json` (creating it if `.claude/` exists), `.cursor/hooks.json`, `.codex/hooks.json`, `.gemini/settings.json`, the Windsurf `hooks.json` and Cline's `.clinerules/hooks`, wherever they are already installed; `disable` removes only the provenance hooks. See [Compliance Evidence](/docs/compliance).

## Pause risky commands

> **Beta, early access.** A workspace without access gets `403 FEATURE_EARLY_ACCESS` and a link to request it. Flag: `agent_pause`.

The hooks also run `bumpkit pause` before a tool or shell command runs, which allows it, asks you, or denies it under the `agent:` section of `bumpkit.yml`:

| Agent | Hook |
|-------|------|
| Claude Code (`--claude`) | `PreToolUse` with matcher `Bash\|Read\|Write\|Edit\|MultiEdit\|NotebookEdit` runs `bumpkit pause --hook claude` (timeout 150 s) |
| Cursor (`--cursor`) | `beforeShellExecution` runs `bumpkit pause --hook cursor` (timeout 150) |
| Codex (`--codex`) | `PreToolUse` with matcher `^(Bash\|apply_patch)$` runs `bumpkit pause --hook codex` (timeout 150) |

See [Agent Controls](/docs/agent-controls).

## Uninstall

There is no uninstall command. Remove what the installer added:

| What | How to remove |
|------|---------------|
| Claude Code | Delete the `bumpkit` entries in `.claude/settings.json` and `bumpkit` in `.mcp.json` |
| Cursor | Delete the `bumpkit` entries in `.cursor/hooks.json` |
| git | Delete `pre-push` in your hooks directory, or its `bumpkit guard` line |
| Codex | Delete the `bumpkit` entries in `.codex/hooks.json` and `[mcp_servers.bumpkit]` in `.codex/config.toml` |
| Gemini CLI | Delete the `bumpkit` entries in `.gemini/settings.json` |
| Windsurf | Delete the `bumpkit` entry in the Windsurf `hooks.json`, and `bumpkit` in its MCP config |
| Cline | Delete the Bumpkit scripts in `.clinerules/hooks`, and `bumpkit` in the Cline MCP settings |
| Provenance hooks | `bumpkit provenance disable` |
