Skip to content

ctx_capture_session

Returns two things in one text block: a template for a source page, and the raw turn-by-turn buffer of the current session.

It does not write a file. It does not push. It does not call an LLM. The distillation is the agent’s job — this tool just puts the material and the shape in front of it, which is why the reasoning trail that lands in raw/sessions/ is a written summary rather than a dumped transcript.

Mid-session checkpoints: “capture what we’ve decided so far”. The end-of-session case is usually handled for you — ctx_push fires a PUSH_PAUSED handshake with the same buffer and a longer template whenever a push batch contains a concept or analysis page and a buffer exists from the last 6 hours. ctx_capture_session is the way to get that material on demand, without a push.

ParameterTypeRequiredDescription
session_idstringnoOptional Claude Code session id; defaults to the most recent buffer (within 6h)

session_id must be a single safe filename component — letters, digits, -, _, ., at most 200 characters, no .., no leading - or .. It is joined into a path, so anything else is rejected outright.

{
"method": "tools/call",
"params": {
"name": "ctx_capture_session",
"arguments": {}
}
}

The single text block the agent gets back:

<CAPTURE_TEMPLATE>
Author a 'source' page capturing the reasoning trail of this session. Call
ctx_write_page with:
type: "source"
slug: "2026-07-28-session-a1b2c3d4" (rename to reflect the topic)
reasoning_summary: one-line distillation (<= 100 chars)
body: follow the TEMPLATE below
TEMPLATE:
## Decision
## Why this approach
## Rejected alternatives
## Path of inquiry
## Dead-ends
## Open questions
## Sources
IMPORTANT: redact any API keys, tokens, passwords, or PII you encounter.
BUFFER (turn-by-turn summaries from this session, oldest first):
{"ts":"2026-07-28T09:03:11Z","turn":1,"user":"…","assistant":"…","tools":["Read","Edit"]}
{"ts":"2026-07-28T09:07:52Z","turn":2,"user":"…","assistant":"…","tools":["Bash"]}
</CAPTURE_TEMPLATE>

The suggested slug is <today>-session-<session-id>, truncated to 80 characters, and the template tells the agent to rename it. The next call is ctx_write_page with type: "source" — that is what actually creates .contexo/raw/sessions/<slug>.md — followed by ctx_push when you want it shared.

Per-turn capture hooks, installed by ctx init unless you pass --no-hooks — Claude Code’s unconditionally, Codex’s and Cursor’s when those agents are detected — or later by ctx hooks install. Each hook shells out to the hidden ctx capture turn command, which appends one JSON line to .contexo/raw/sessions/_pending/<session-id>.jsonl:

Agent Hooks Command How the turn is obtained
Claude Code Stop in .claude/settings.json ctx capture turn parses the session transcript
Codex UserPromptSubmit + Stop in .codex/hooks.json ctx capture turn --agent codex inline: prompt stashed, paired with last_assistant_message
Cursor beforeSubmitPrompt + afterAgentResponse in .cursor/hooks.json ctx capture turn --agent cursor inline: prompt stashed, paired with text

There is no daemon and no LLM in that path — it is one short-lived process per turn. Outside a .contexo/ project, or with CONTEXO_CAPTURE_DISABLE=1 set, it silently no-ops. Hook failures never fail the agent’s turn.

Each record holds a timestamp, a turn index, the user message, the assistant reply, and the tool names used. The buffer is deliberately bounded: user text truncated at 2 KB and assistant text at 4 KB per turn, a hard cap of 500 turns, after which the oldest 100 are dropped and replaced by a marker record:

{ "ts": "2026-07-28T09:11:02Z", "turn": 0, "truncated": { "dropped": 100, "reason": "buffer_cap" } }

What the tool inlines is bounded again, and separately: the first 10 and last 40 records, with a {"reason":"inline_window"} marker standing in for everything between. A long session gives the agent its beginning and its recent past, not its middle.

  • Selection. With no session_id, the tool takes the most recently modified buffer under _pending/ whose mtime is inside the last 24 hours. Older buffers are invisible to it, but still on disk — pass their session_id explicitly to reach one.
  • Archival. ctx_capture_session never archives. The buffer is moved to _pending/_archive/<session-id>.jsonl only by ctx_push with distill_done: true, at the end of the push handshake. So a mid-session checkpoint costs you nothing: the same buffer is still there for the end-of-session distill, with the later turns appended.
  • Pruning. Buffers older than 30 days are deleted by the next ctx capture turn write in that project. Nothing else garbage-collects them.

To see what is currently on disk:

ctx capture status
No pending capture buffers.

ctx_capture_session: no recent capture buffer (run 'ctx hooks install' once per project, then have a Claude Code session here) — nothing under _pending/ is younger than 24 hours. Either the hooks are not installed, or this session’s hooks have not fired yet (they fire per completed turn, so a session that has not finished a turn has no buffer).

ctx_capture_session: buffer is empty — the file exists but holds no parseable records.

ctx_capture_session: no buffer for session "…" — an explicit session_id with no matching file. Check ctx capture status for the ids that exist.

ctx_capture_session: invalid session_id "…" — the id failed the filename-component check.

  • ctx_write_page — the call that turns the template into a page
  • ctx_push — the automatic version of this handshake, at push time
  • ctx capturectx capture status, and the hidden turn subcommand the hooks run
  • ctx hooks — install or remove the capture hooks per agent