Skip to content

Hooks

Hooks run at agent lifecycle events (session start, before shell, after file edit, and more). You declare them once; capa translates each hook into the provider-specific config shape and tags its entries as capa:<id> so install/clean stay surgical.

Edit hooks in the capabilities file, or use the CLI:

Terminal window
capa add --hook --id audit-shell --on beforeShell --command 'date >> ~/.capa/audit.log'
capa add --hook --id greet --on sessionStart --type prompt --prompt 'Remember project conventions.'
capa install

See CLI: add for source flags (--source, --command, --prompt, --type).

FieldNotes
idStable id → capa:<id> in provider configs
onCanonical event (beforeShell, afterFileEdit, …) or provider-scoped (cursor:beforeShellExecution)
typecommand (default) or prompt
command / promptInline body when you do not use source
sourceinline, remote, github, gitlab, or local (path in the project)
matcher, timeout, failClosed, sequential, providersOptional controls; failClosed is Cursor-oriented today

Canonical events include sessionStart, sessionEnd, userPromptSubmit, beforeTool, afterTool, afterToolFailure, beforeShell, afterShell, beforeFileRead, afterFileEdit, beforeMcpCall, afterMcpCall, subagentStart, subagentStop, preCompact, and stop.

hooks:
- id: audit-shell
description: Timestamp every shell invocation
on: beforeShell
command: 'date >> ~/.capa/audit.log'
timeout: 5
- id: block-rm-rf
on: cursor:beforeShellExecution
matcher: 'rm -rf *'
failClosed: true
command: 'echo "blocked" && exit 1'
- id: log-bash-commands
on: beforeShell
source:
type: local
path: scripts/log-bash.sh

Non-local sources are materialized under ~/.capa/hooks/<projectId>/. source.type: local references your project file in place (no copy; capa clean will not delete it).

capa installs hooks only for providers that support them. Unsupported providers get a warning and are skipped: install does not fail.

ProviderConfig file
Claude Code.claude/settings.json → hooks
Codex.codex/config.toml → [hooks]
Cursor.cursor/hooks.json
Gemini CLI.gemini/settings.json → hooks

matcher is written in each provider’s native field: for Cursor that is matcher on the hook entry (use it, for example, to filter postToolUse to Write|Edit).

Re-installs and capa clean edit only entries tagged capa:<id>. If several capa hooks share one config file, capa still finds and removes each of its entries even after earlier ones were removed or moved, so no stale capa entries are left behind.