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.
When your agent reaches for it
Section titled “When your agent reaches for it”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.
Parameters
Section titled “Parameters”| Parameter | Type | Required | Description |
|---|---|---|---|
session_id | string | no | Optional 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.
Request and response
Section titled “Request and response”{ "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. Callctx_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.
What fills the buffer
Section titled “What fills the buffer”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.
Lifecycle and expiry
Section titled “Lifecycle and expiry”- 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 theirsession_idexplicitly to reach one. - Archival.
ctx_capture_sessionnever archives. The buffer is moved to_pending/_archive/<session-id>.jsonlonly byctx_pushwithdistill_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 turnwrite in that project. Nothing else garbage-collects them.
To see what is currently on disk:
No pending capture buffers.Errors
Section titled “Errors”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.
See also
Section titled “See also”ctx_write_page— the call that turns the template into a pagectx_push— the automatic version of this handshake, at push timectx capture—ctx capture status, and the hiddenturnsubcommand the hooks runctx hooks— install or remove the capture hooks per agent
