Reference
Hook events
How each agent's native hook events map to Comity events, what is sent, timeouts, and how answers are rendered.
Every agent integration runs comity hook --tool <tool> --event <Event> with the host's hook JSON on stdin (the omp extension calls the same code in-process). The CLI maps the native event to a Comity event, sends it to POST /v1/hooks/evaluate, and prints the host's native hook output.
Event mapping
| Comity event | Claude Code / Copilot CLI | Codex | Cursor (via Claude hooks) | omp |
|---|---|---|---|---|
session_start |
SessionStart |
SessionStart |
sessionStart |
session_start |
prompt |
UserPromptSubmit |
UserPromptSubmit |
beforeSubmitPrompt |
before_agent_start |
plan |
PreToolUse on ExitPlanMode |
– | – | – |
pre_edit |
PreToolUse on an edit tool |
PreToolUse on apply_patch / edit |
preToolUse on an edit tool |
tool_call on edit, apply_patch, write |
pre_shell |
PreToolUse on Bash |
PreToolUse on a shell command |
preToolUse on Shell |
tool_call on bash, eval, ast_edit |
post_edit |
PostToolUse on an edit tool or Bash |
PostToolUse |
postToolUse |
tool_result on the same tools |
stop |
Stop |
Stop |
stop |
session_stop |
session_end |
SessionEnd |
SessionEnd |
sessionEnd |
session_shutdown |
- Edit tools:
Edit,Write,MultiEdit,NotebookEdit(andDeletewhere a host has it). Host-specific names are normalized:create/write→Write,edit/str_replace_editor→Edit,Shell/bash/powershell/shell/exec_command→Bash. - Codex
apply_patch: paths come from the patch envelope (*** Update File: …). A shell command containing*** Begin Patchis treated as an edit of those files. - Other tools (reads, searches, web) are ignored and never leave the machine.
- The matchers
comity initwrites areEdit|Write|MultiEdit|NotebookEdit|Bash|ExitPlanModeonPreToolUseandEdit|Write|MultiEdit|NotebookEdit|BashonPostToolUse(Claude Code), andapply_patch|Edit|Write|Bash(Codex). Hooks written by CLI 0.4.0 or older lackExitPlanMode, so they never sendplan; they keep working otherwise, andcomity doctorshows "update available" until you reruncomity init. Codex has no plan event. pre_pushexists in the protocol but no integration sends it and the server doesn't act on it.
What each event sends
| Event | Extra fields |
|---|---|
session_start |
Workspace packages (repo.packages, up to 200) |
prompt |
prompt_excerpt: first 2,000 characters of the prompt |
plan |
plan_text (up to 32,768 characters) |
pre_edit |
paths: repo-relative paths about to change (up to 500) |
pre_shell |
shell.command (up to 4,000 characters); paths the command visibly writes (>, >>, tee) |
post_edit |
paths changed (for shell commands: the working-tree diff before/after); analysis: per-file symbols, signature hashes, compatibility, new references |
stop |
status: {excerpt (≤500 chars of the last assistant message), files (touched this turn)}, unless COMITY_SHARE_STATUS=0 |
Every request also carries session (external_id, tool, model, surface, parent_external_id for subagents), client (cli_version, os, tool_version, machine_id_hash), repo (remote_fingerprints, branch, head_sha, base_sha, worktree_hash, cwd_path), and a dedupe_key so a retried event is evaluated once.
Hooks only run in git repositories with at least one remote. In a folder that contains several repositories (not itself a repo), the CLI sends each file's event to the repo it belongs to, and merges the briefings for up to 8 recently active repos at session start.
Response
{
"decision": "warn",
"reason": "1 coordination warning(s): …",
"inject_context": "## Comity update — system-generated for `acme/api`\n…",
"conflicts": [{ "number": 9, "ref": "CF-9", "kind": "symbol_overlap", "severity": "warn" }],
"intent": { "number": 14, "ref": "INT-14", "status": "active" },
"session_id": "0192f0c4-7d1e-7a8b-9c2d-3e4f5a6b7c8d",
"index_version": 412
}How the CLI renders it for the host:
| Result | Before a tool call (PreToolUse) |
Other events |
|---|---|---|
block |
{"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "<reason>"}} |
Never happens |
warn / context |
Codex, omp: additionalContext. Claude Code, Cursor, Copilot CLI: queued and added to the next PostToolUse or prompt |
{"hookSpecificOutput": {"hookEventName": "<Event>", "additionalContext": "<text>"}} on SessionStart, UserPromptSubmit, PostToolUse |
allow, nothing to say |
No output | No output |
Comity never outputs a native "allow" decision, so the host's own permission prompts still apply. Added context is capped at 6,000 characters per event. The hook always exits 0.
Timeouts
| CLI waits for the API | Host hook timeout in init config |
|
|---|---|---|
pre_edit, pre_shell |
400 ms | 5 s |
| Other events | 1.5 s | 5 s (SessionStart, UserPromptSubmit), 10 s (PostToolUse, Stop, SessionEnd; Codex SessionEnd 3 s) |
| omp extension | 600 ms per event, then allows | – |
If the API doesn't answer in time, errors, or returns an unexpected shape, the hook prints nothing (the agent proceeds) and appends a fail-open line to hook.log in the CLI config folder.
Host detection
Cursor and Copilot CLI run the Claude Code hooks, so --tool claude_code is only a hint. The CLI decides from the payload and environment:
| Host | Recognized by |
|---|---|
| Cursor | cursor_version or conversation_id in the payload, or CURSOR_VERSION set |
| Copilot CLI | sessionId / toolName / toolArgs in the payload, or the VS Code–compatible payload (ISO timestamp, no transcript_path) |
| Codex | --tool codex or turn_id in the payload |
| omp | --tool omp (only the omp extension sets it) |
| Claude Code | otherwise |
If the detected host has its own Comity hook config (for example a .cursor/hooks.json or .github/hooks/*.json that calls comity hook), the invocation from the Claude Code config steps aside so each event is evaluated once.