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.
When you’d reach for it
Section titled “When you’d reach for it”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.
Synopsis
Section titled “Synopsis”ctx hooks install [--tool=claude|codex|cursor|all]ctx hooks uninstall [--tool=claude|codex|cursor|all]ctx hooks status [--tool=claude|codex|cursor|all]What gets written
Section titled “What gets written”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.
ctx hooks install
Section titled “ctx hooks install”Adds the capture hook to one agent’s config, or to every agent it can find.
ctx hooks install # claude, plus codex/cursor if detectedctx hooks install --tool=cursor # just .cursor/hooks.json| Flag | Type | Default | Description |
|---|---|---|---|
--tool | string | all | agent: claude|codex|cursor|all |
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).
ctx hooks uninstall
Section titled “ctx hooks uninstall”Removes the capture hook again.
ctx hooks uninstall --tool=claude| Flag | Type | Default | Description |
|---|---|---|---|
--tool | string | all | agent: 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.
ctx hooks status
Section titled “ctx hooks status”Reports, per agent, whether the capture hook is present.
ctx hooks status| Flag | Type | Default | Description |
|---|---|---|---|
--tool | string | all | agent: claude|codex|cursor|all |
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.
Common errors
Section titled “Common errors”| 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. |
See also
Section titled “See also”ctx capture— the buffer these hooks write intoctx mcp— the other half of agent integrationctx init— installs these hooks automaticallyctx push— where the buffered turns get distilled
