In your agent
Agent Controls
Check coding agents' work before they finish, pause risky commands, share codebase memory and record which agent made each change.
A single coding agent can run risky commands, forget what the team learned and leave no record of what it did; agent controls fix all three, for teams using AI coding agents.
Agent controls put Bumpkit inside a coding agent's loop. The agent's work is checked before it finishes, risky shell commands wait for a person, what the team learned about the code reaches every new session, and each change records which agent, model and session produced it.
Most of these run as agent hooks. To install the hooks for Claude Code, Cursor, Codex, Gemini CLI, Windsurf and Cline, see Agent Hooks. Every command below is also listed in the CLI Reference, and every endpoint in the API Reference.
| Feature | Flag | Commands | MCP tools | Endpoints |
|---|---|---|---|---|
| Agent guard | agent_guard |
bumpkit guard |
guard |
none |
| Codebase memory | codebase_memory |
bumpkit memory, bumpkit recall |
recall, remember, forget |
/v1/memories |
| Pause risky commands | agent_pause |
bumpkit pause |
pause |
/v1/agent/decisions |
| Memory approval | memory_approval |
bumpkit memory pending, approve, reject |
memory_pending, memory_approve, memory_reject |
/v1/memories/pending |
| Agent forensics | agent_forensics |
bumpkit provenance show |
provenance_show |
/v1/checks/{id}/provenance |
| AI change provenance | change_provenance |
bumpkit provenance |
provenance_show, provenance_attest |
/v1/provenance/events, /v1/checks/{id}/provenance |
| Agent scorecards | agent_scorecards |
bumpkit scorecards |
agent_scorecards |
/v1/scorecards |
Agent guard
Beta, early access. A workspace without access gets
403 FEATURE_EARLY_ACCESSand a link to request it. Flag:agent_guard.
bumpkit guard runs the Release Gate on the agent's uncommitted and committed changes before the agent finishes or pushes. When the gate fails or needs approval, the agent is sent back with the reasons.
bumpkit guard
bumpkit guard --base origin/main| Flag | Default | Meaning |
|---|---|---|
--base |
Where this branch left the default branch | The ref to compare against |
--hook |
none | claude, cursor, codex, gemini, windsurf or cline: run as that agent's finish hook |
What it does:
- Finds the base: the merge base of
HEADwithorigin/HEAD,origin/main,origin/master,mainormaster. If the branch hasn't left the default branch, it uses the latest tag. - Takes the diff from the base to your working tree, including uncommitted changes. An empty diff passes without a message.
- Runs a fast gate with the
bumpkit.ymlfrom the base ref, so an agent can't loosen the policy in the change it is checking. - On a pass, it exits 0. Run directly, it prints nothing. As a Codex hook it prints
{}, and as a Cline hook{"cancel":false}.
When the gate fails, the message lists only the proven (deterministic) high-severity findings, with where each one is, and tells the agent to explain any false positive in its final message. When the gate needs approval, it lists each rule that needs a person and tells the agent not to work around it.
Run directly, bumpkit guard prints the message to stderr and exits 1 when the gate fails or fix tasks are open. When the change only needs approval, it prints which approval the push will need and exits 0. With --hook, it prints the reply that agent expects. Every hook exits 0 except Windsurf's, which blocks by exiting 2:
| Hook | Reply | Exit code |
|---|---|---|
--hook claude |
{"decision":"block","reason":"..."} |
0 |
--hook cursor |
{"followup_message":"..."} |
0 |
--hook codex |
{"decision":"block","reason":"..."} |
0 |
--hook gemini |
{"decision":"deny","reason":"..."} |
0 |
--hook cline |
{"cancel":true,"errorMessage":"...","contextModification":"..."} |
0 |
--hook windsurf |
The message on stderr | 2 |
See Agent Hooks for where each hook runs.
In hook mode, the guard runs once per stop: it skips when Claude Code or Codex reports stop_hook_active, when Cursor's loop_count is above 0 or its status isn't completed, and when Gemini reports stop_hook_active. The Windsurf hook runs only before a git push, and the Cline hook only before attempt_completion. If there is no API key, Bumpkit is unreachable or the feature is off, the guard prints a note to stderr and exits 0, so it never blocks an agent on its own failure. The Codex, Gemini, Windsurf and Cline hooks also need the agent_hooks_extended flag (Beta); without it they print a note and let the agent finish.
With Close the loop on (Beta, flag close_the_loop), the guard also sends the current branch. While fix tasks are open on that branch, it sends the agent back with each task, its places and pull requests, even when the gate passes.
The git pre-push hook from bumpkit hooks install --git runs bumpkit guard, so proven problems stop a push from any agent or person. See Agent Hooks.
Codebase memory
Beta, early access. A workspace without access gets
403 FEATURE_EARLY_ACCESSand a link to request it. Flag:codebase_memory.
Codebase memory stores what agents and people learned about a repository, by path: decisions, pitfalls, incidents and notes. Agents recall it when they start work in an area, together with the recent releases that changed that area.
Save a memory
bumpkit memory add "Webhook handlers must stay idempotent; GitHub retries on timeout." \
--kind decision --path services/webhooks/github.go| Flag | Default | Meaning |
|---|---|---|
--kind |
note |
note, decision, pitfall or incident |
--path |
The whole repository | The file or directory it's about |
--repository |
The origin remote | The repository URL |
Rules for a memory:
- The body is required and at most 2000 characters.
- Duplicates are merged. Saving the same text again for the same repository, path and kind (ignoring case and whitespace) doesn't create a second memory. It refreshes the existing one's date and author instead.
- Provenance. Each memory keeps who saved it (
author, such asclior the agent's name) and when.
Recall memories
bumpkit memory list services/api
bumpkit recall --path services/apibumpkit memory list [PATH] prints a table of IDs, kinds, paths and text. bumpkit recall prints the same memories as text an agent can read: approved swarm lessons first when swarm_lessons is on, then the memories with their kind, author and ID, then the five finding kinds recent releases there were flagged for most.
Flag (bumpkit recall) |
Default | Meaning |
|---|---|---|
--path |
The whole repository | A file or directory |
--hook |
none | claude, cursor, codex, gemini or cline: run as that agent's session start hook. codex, gemini and cline also need agent_hooks_extended |
Recall for a path returns memories saved for that path, for any parent directory, for anything under it, and for the whole repository. Recall is trimmed to fit in an agent's context.
Memories are ordered decisions first, then pitfalls, incidents and notes, newest first within each kind. The API and the recall MCP tool also return the last 10 releases that changed the path, what they were flagged for, and which agents wrote them. The bumpkit recall text includes only the flagged finding kinds.
With --hook claude or --hook gemini, bumpkit recall prints a SessionStart reply with the text as additionalContext. With --hook cursor, it prints {"additional_context":"..."}, with --hook cline {"cancel":false,"contextModification":"..."}, and with --hook codex the plain text. The text ends by telling the agent to respect the decisions and pitfalls, call recall before changing an area, save what the next agent should know with remember, and forget memories that are no longer true.
Forget a memory
bumpkit memory forget 3f2c9a1e-8b7d-4c2a-9e1f-6a5b4c3d2e1fUse it when the code changed and a decision or pitfall no longer applies. The memory is deleted.
MCP tools
The MCP server adds these tools when codebase_memory is on:
| Tool | Arguments | What it does |
|---|---|---|
recall |
path, repository |
Memories and recent releases for a path |
remember |
body (required), path, kind, author, repository |
Saves a memory |
forget |
id (required), confirm |
Deletes a memory by the ID recall returned; nothing is deleted until you pass confirm: true after the user agrees |
repository is owner/name and defaults to the origin remote of the current directory.
API
| Endpoint | What it does |
|---|---|
POST /v1/memories |
Save a memory: repository, path, kind, body, author. Returns 201 |
GET /v1/memories?repository=...&path=... |
Recall memories, releases, flagged finding kinds and agents |
DELETE /v1/memories/{id} |
Forget a memory. Returns 204, or 404 MEMORY_NOT_FOUND |
Pause risky commands
Beta, early access. A workspace without access gets
403 FEATURE_EARLY_ACCESSand a link to request it. Flag:agent_pause.
bumpkit pause checks each shell command or file access before the agent runs it. It allows it, asks a person to confirm, or denies it with a reason and advice on what to do instead.
How the hook works
The pause hook runs before a tool call:
| Agent | Hook event | What it checks |
|---|---|---|
| Claude Code | PreToolUse, matcher Bash|Read|Write|Edit|MultiEdit|NotebookEdit |
Shell commands and the file paths of reads and writes |
| Cursor | beforeShellExecution |
Shell commands |
| Codex | PreToolUse, matcher ^(Bash|apply_patch)$ |
Shell commands and the files a patch adds, updates, deletes or moves |
Install it with bumpkit hooks install (see Agent Hooks). For each call:
- Every part of the command, including pipelines,
&&chains andsh -cstrings, is checked against the built-in rules and youragent:policy. - If everything is allowed, the hook returns at once.
- Otherwise the decision is recorded in Bumpkit with the command redacted. With
agent.remote: true, anaskwaits for a teammate to approve or deny it in Bumpkit. - The hook replies with
allow,askordenyand the reason.
| Hook | Reply |
|---|---|
--hook claude |
hookSpecificOutput with permissionDecision and permissionDecisionReason |
--hook cursor |
{"permission":"...","user_message":"...","agent_message":"..."} |
--hook codex |
permissionDecision: deny with the reason. Codex hooks can't ask, so an ask is stopped and the agent is told to ask the user or to have it approved in Bumpkit with agent.remote |
The policy comes from bumpkit.yml on the default branch (origin/HEAD, then origin/main, origin/master, then HEAD), never from the working copy, so an agent can't loosen it by editing the file. The pause hook never allows everything: when there is no API key, Bumpkit is unreachable or the feature is off for your workspace, it checks with the built-in rules plus your agent: section, prints a note to stderr, and records nothing in Bumpkit. If bumpkit.yml is invalid, the default rules apply.
With agent budgets and scopes on (Beta, flag agent_budgets), bumpkit pause --hook claude also denies a Write, Edit, MultiEdit or NotebookEdit call on a file outside the agent's paths_allow, inside its paths_deny, or in an area its areas_deny lists, with the reason shown to the agent. The agent is matched by BUMPKIT_AGENT_ID (or BUMPKIT_AGENT) and as claude-code. This check needs Bumpkit to be reachable.
Check a command by hand
bumpkit pause git push --force origin mainIt prints allow and exits 0, or prints ask: <reason> or deny: <reason> and exits 1. It works the same without an API key, using the built-in rules.
What counts as risky
| Rule | Default | Matches |
|---|---|---|
rm_rf |
ask | rm -r on a path outside a temporary or build directory |
rm_rf_root |
deny | rm -r on /, the home directory, the repository root or a system directory |
force_push |
deny | git push --force or a branch delete on a protected branch |
git_reset_hard |
ask | git reset --hard, which throws away uncommitted work |
git_clean |
ask | git clean -f, which deletes untracked files |
sql_drop |
ask | DROP, TRUNCATE or an unfiltered DELETE sent to a database client |
infra_apply |
ask | terraform, tofu or pulumi apply and destroy |
kubectl_delete |
ask | kubectl delete or drain, helm uninstall |
pipe_to_shell |
ask | A downloaded or decoded script piped into a shell or interpreter |
chmod_777 |
ask | chmod -R that makes files world-writable |
secret_write |
ask | A write to .env, a key or a secrets file |
credential_file |
ask | Reading or copying a credential file such as .env, ~/.ssh or ~/.aws |
package_publish |
ask | Publishing a package or pushing an image |
prod_database |
ask | A database URL whose host isn't local |
self_approval |
deny | An agent approving or rejecting Bumpkit memories, lessons or Approvals items |
agent_scope |
deny | An agent writing outside the paths and areas agents: gives it |
too_complex |
ask | A command nested too deeply to check |
Protected branches default to main, master, trunk, production, prod, release/* and releases/*.
Policy keys
agent:
deny: [infra_apply, "npm publish *"]
ask: ["make deploy*"]
allow: [git_reset_hard]
protected_branches: [main, "release/*"]
remote: true
timeout: 60s| Key | Default | Meaning |
|---|---|---|
deny |
none | Rule IDs to deny, or command patterns |
ask |
none | Rule IDs to ask about, or command patterns |
allow |
none | Rule IDs to allow, or command patterns |
protected_branches |
The list above | Branch names or globs force_push protects |
remote |
false |
Let a teammate approve an ask in Bumpkit while the agent waits |
timeout |
30s |
How long to wait for a remote approval, between 5s and 120s |
Each entry is a rule ID from the table above or a command pattern where * matches anything and ? one character. A bare word that isn't a rule ID is rejected, so write a pattern with a space or *, like "deploy *". A pattern in deny beats everything. A pattern in allow allows the command unless a rule it hits is listed in deny. See bumpkit.yml: agent for the full schema.
Remote approval
With remote: true, an ask is recorded as pending and the hook waits up to timeout. A teammate approves or denies it on the Approvals page in the dashboard. If no one decides in time, the agent gets ask and the human at the terminal decides.
| Endpoint | What it does |
|---|---|
POST /v1/agent/decisions |
Record a decision: repository, agent, session, tool, command, command_hash, rules, reason, decision, remote, timeout_seconds. Rate limited to 240 per minute per key |
GET /v1/agent/decisions/{id} |
A decision's status: pending, approved, denied or expired |
Memory approval
Beta, early access. A workspace without access gets
403 FEATURE_EARLY_ACCESSand a link to request it. Flag:memory_approval. Needscodebase_memory.
With memory approval on, memories saved through the API wait as pending until a person approves them. Only approved memories are recalled.
Turn it on for the whole workspace:
bumpkit settings set --memory-approval onOr for one repository, on its default branch:
memory:
require_approval: trueBumpkit reads the repository's default-branch bumpkit.yml through the GitHub App. Without the App, only the workspace setting applies. See bumpkit.yml: memory.
Review pending memories:
bumpkit memory pending
bumpkit memory approve 3f2c9a1e-8b7d-4c2a-9e1f-6a5b4c3d2e1f
bumpkit memory reject 3f2c9a1e-8b7d-4c2a-9e1f-6a5b4c3d2e1fA rejected memory is never recalled. A key can't review a memory saved with a key of the same person, or with a key that was since deleted, so review your own agent's memories in the dashboard, or ask a teammate to use their key. The self_approval pause rule denies an agent that tries to run these commands. You can also review memories on the Approvals page in the dashboard.
| Endpoint | What it does |
|---|---|
GET /v1/memories/pending |
Pending memories, optionally for one repository |
POST /v1/memories/{id}/approve |
Approve a pending memory |
POST /v1/memories/{id}/reject |
Reject a pending memory |
Agent forensics
Beta, early access. A workspace without access gets the provenance page without this section. Flag:
agent_forensics.
Agent forensics answers what an agent did on a change. It adds a timeline to bumpkit provenance show CHECK_ID, the provenance_show MCP tool, GET /v1/checks/{id}/provenance and a release check's provenance page: agent sessions, what the guard allowed or refused, the check, the gate decision and approvals, and what happened in production.
Each entry says where it came from. Reported by the agent came from its hooks, so a compromised agent could leave it out or change it. Recorded by Bumpkit came from Bumpkit's own check and gate, on a diff it fetched itself. Sent by a client, from its own diff came through bumpkit gate, the API or MCP, and Bumpkit can't confirm that diff matches the commit.
The timeline also lists what it observed that deserves a look. These never block a release on their own:
| Signal | What it means |
|---|---|
no_session |
The repository reports agent sessions, but none matches this change. A person may have written it, or an agent ran without hooks |
denied_actions |
Bumpkit or a person denied some of the agent's actions while it worked on this change |
unauthenticated_session |
A session didn't come from an authenticated reporter |
AI change provenance
Beta, early access. A workspace without access gets
403 FEATURE_EARLY_ACCESSand a link to request it. Flag:change_provenance.
Provenance records, for each release check, which agent made the change: its version and model, the session, the tools it used, the human sponsor, optional redacted prompt summaries, the approvals and the verification evidence.
Record provenance
Install agent hooks first (see Agent Hooks), then turn on recording in the repository:
bumpkit provenance enable
bumpkit provenance enable --prompts
bumpkit provenance disableenable adds bumpkit provenance record --hook AGENT to each agent hook file it finds. --prompts also sends a redacted summary of each prompt; it is off by default. bumpkit hooks install --provenance [--prompts] does the same while installing.
bumpkit provenance record --hook AGENT reads the hook payload on stdin. AGENT is claude, cursor, codex, gemini, windsurf or cline. Each event is sent with the session ID, the agent version and model when the agent reports them, and the repository, branch and head commit. The sponsor comes from the API key, never from the event: a key tied to a person records that account, shown with its current email and marked verified, and a key tied to no person records key:<id>, never verified. A session stays bound to the account or key that started it. An event for it from any other account or key gets 409 PROVENANCE_SESSION_CONFLICT, and viewers can't record events. The agent name, tools and prompts are reported by the agent and aren't verified:
| Event | Sent when |
|---|---|
start |
A session or task starts or resumes |
tool |
A tool, shell command, file edit or MCP tool ran (MCP tools as mcp:server/tool) |
prompt |
You submit a prompt. The text is sent only with --prompts, with secrets redacted and cut to 280 characters |
end |
The session or task ends |
Recording never blocks the agent.
How sessions link to a release
When a release is checked, Bumpkit links the agent sessions that made it.
Name the agent, model, session or sponsor yourself with these commit trailers (case-insensitive):
| Trailer | Recorded as |
|---|---|
Bumpkit-Agent, Agent, AI-Agent, Generated-By |
Agent |
Bumpkit-Model, Agent-Model, AI-Model, Model |
Model |
Bumpkit-Session, Agent-Session, Session-Id |
Session |
Bumpkit-Sponsor, Sponsored-By, Human-Sponsor |
Sponsor |
Co-Authored-By |
Co-author |
Signed-Off-By |
Sign-off |
Reviewed-By, Approved-By, Acked-By, Bumpkit-Reviewer |
Reviewer |
View and attest
bumpkit provenance show CHECK_ID
bumpkit provenance attest CHECK_IDshow prints the provenance record as JSON, including the agent forensics timeline when that flag is on. attest prints an in-toto statement (https://in-toto.io/Statement/v1) with predicate type https://bumpkit.dev/attestation/change-provenance/v1. Each release in the dashboard has a provenance view at /checks/{id}/provenance, and the compliance evidence export includes the attestations.
| Endpoint | What it does |
|---|---|
POST /v1/provenance/events |
Record an event: agent, session_id, event, tool, prompt, model, agent_version, repository, branch, head_sha. Rate limited to 600 per minute per key |
GET /v1/checks/{id}/provenance |
The provenance record for a release check |
GET /v1/checks/{id}/attestation |
The in-toto attestation |
GET /v1/provenance/key |
Whether attestations are signed, and the Ed25519 public key and key ID when they are |
Agent scorecards
Beta, early access. A workspace without access gets
403 FEATURE_EARLY_ACCESSand a link to request it. Flag:agent_scorecards.
Scorecards show how each coding agent's releases fared: how many shipped clean, were blocked or needed approval, how many proven high-severity problems they carried, and what they were flagged for most. Releases with no agent detected show as agent none.
bumpkit scorecards --days 90--days defaults to 30. The same data is on the Reports tab of Insights in the dashboard, next to the committed by and written by matrix, at GET /v1/scorecards?days=N, and in the agent_scorecards MCP tool (days, at most 365).