Skip to content

ctx hooks

ctx hooks manages the capture hook — the agent-side hook that appends each finished turn to this project’s local capture buffer, so a later ctx_push has a reasoning trail to distill into a source page.

ctx init already installs these: always for Claude Code, and for Codex and Cursor when it detects them. So you reach for ctx hooks when the agent arrived after init ran, when someone cleaned out .claude/settings.json, or when ctx_capture_session answers no recent capture buffer and you need to find out which of the three configs is actually missing. The thing to be clear about: the hook does no distilling. It buffers turns to disk, makes no LLM call and no network call — writing the knowledge page is still the agent’s job during ctx push. And for Claude Code the hook is read at session start, so a fresh install does nothing until you restart the agent.

Terminal window
ctx hooks install [--tool=claude|codex|cursor|all]
ctx hooks uninstall [--tool=claude|codex|cursor|all]
ctx hooks status [--tool=claude|codex|cursor|all]

All three targets are project-local — including Codex, whose MCP config is global. That asymmetry is deliberate: wiring an MCP server into ~/.codex affects every repo on the machine and so needs consent, while a capture hook in ./.codex/hooks.json only affects this project and can be installed silently.

Agent File Events Command written
Claude Code .claude/settings.json Stop ctx capture turn
Codex .codex/hooks.json Stop, UserPromptSubmit ctx capture turn --agent codex
Cursor .cursor/hooks.json beforeSubmitPrompt, afterAgentResponse ctx capture turn --agent cursor

One event is enough for Claude because its Stop payload points at a transcript file the command can parse. Codex and Cursor expose no transcript, so capture needs two events: the prompt-side hook stashes the user’s message, the response-side hook pairs it with the assistant’s reply. Cursor also uses a flatter schema than the other two, and requires a "version": 1 key, which Contexo adds when it creates the file.

Adds the capture hook to one agent’s config, or to every agent it can find.

Terminal window
ctx hooks install # claude, plus codex/cursor if detected
ctx hooks install --tool=cursor # just .cursor/hooks.json
FlagTypeDefaultDescription
--toolstringallagent: claude|codex|cursor|all
ctx hooks install --help
Install the Contexo capture hook for an agent (claude|codex|all)

Usage:
  ctx hooks install [flags]

Flags:
  -h, --help          help for install
      --tool string   agent: claude|codex|cursor|all (default "all")

Global Flags:
      --root string   project root directory (default: current directory)

Under --tool=all (the default), Claude Code is always wired, while Codex and Cursor are wired only when detected — Codex by the codex binary being on PATH, Cursor by ~/.cursor existing or cursor being on PATH. Naming a tool explicitly skips detection entirely: ctx hooks install --tool=codex writes .codex/hooks.json on a machine with no Codex at all. That’s the opposite of ctx mcp install --tool=codex, which errors without the binary — because MCP wiring has to shell out to codex, whereas hook wiring just writes a file in your project.

Every write is merge-safe: other hooks in the file are preserved, and re-running reports a no-op per agent (Stop hook already installed; nothing to do. for Claude, Codex capture hooks already installed; nothing to do. for Codex) rather than adding a duplicate entry.

The Claude Code entry carries a marker that the other two don’t:

{
"type": "command",
"command": "ctx capture turn",
"_contexo": "contexo-capture-turn"
}

install, status and uninstall all key off that _contexo marker, not off the command string. Copy the hook by hand into another settings file without the marker and Contexo will consider it absent — status reports not installed, install adds a second copy, and uninstall leaves yours alone. For Codex and Cursor the match is on the exact command string instead (ctx capture turn --agent codex / --agent cursor).

Removes the capture hook again.

Terminal window
ctx hooks uninstall --tool=claude
FlagTypeDefaultDescription
--toolstringallagent: claude|codex|cursor|all

Removal is surgical and unwinds cleanly: the matching hook entry goes, then any group it emptied, then the event key if that emptied, then — for the Codex/Cursor files, which Contexo created — the file itself once nothing but the husk remains (for Cursor, the "version": 1 key it added counts as husk). .claude/settings.json is never deleted; only the Stop entry and, if it becomes empty, the hooks block.

Nothing to remove is not an error — you get one line per agent, such as Stop hook not installed; nothing to do. Unlike install, this works outside a Contexo project.

Reports, per agent, whether the capture hook is present.

Terminal window
ctx hooks status
FlagTypeDefaultDescription
--toolstringallagent: claude|codex|cursor|all
ctx hooks status
claude: installed (.claude/settings.json)
codex:  not installed (.codex/hooks.json)
cursor: installed (.cursor/hooks.json)

Each line is a probe of one file, and each probe checks exactly one event: Claude’s Stop list for the _contexo marker, Codex’s Stop list for its capture command, Cursor’s afterAgentResponse list for its own. That last detail matters for the two-event agents — a config that somehow kept only UserPromptSubmit (Codex) or only beforeSubmitPrompt (Cursor) reports not installed, because half a pair captures nothing. Re-running ctx hooks install repairs it.

To see hook status alongside MCP wiring in one table, use ctx mcp status.

Message Cause and fix
hooks install: not a Contexo project (run 'ctx init' first) There’s no .contexo/ here. uninstall and status don’t have this check; install does.
unknown --tool "x" (want claude, codex, cursor, or all) Typo in --tool. The accepted set is claude, codex, cursor, all.
hooks: parse <path>: … (or agentwire: parse <path>: …) The agent’s settings/hooks file isn’t valid JSON. Contexo refuses to touch a file it can’t parse rather than overwrite it — fix the JSON, then re-run.
  • ctx capture — the buffer these hooks write into
  • ctx mcp — the other half of agent integration
  • ctx init — installs these hooks automatically
  • ctx push — where the buffered turns get distilled