query
Filter and search the unified session event stream by type, session, tool, model, text, and other facets to locate specific actions, messages, or tool calls across coding agents.
Instructions
Filter/search the unified session event stream — the workhorse verb.
Every parser's messages + tool calls are normalized into one flat,
agent-neutral event stream (user_turn / assistant_turn /
tool_call(<sub>) / plan_event); this tool filters that stream
by facets — all behaviour is parameters, never hard-wired variants.
Facets:
type—user_turn|assistant_turn|tool_call|tool_call(edit|write|read|bash|other)|plan_event. Baretool_callmatches every subtype.agent— one of claude/codex/opencode/antigravity/pi (all if omitted).session— restrict to a single session uuid, OR a list of uuids (the union of those sessions' events in one call — e.g. the ids picked from asearch_sessions/list_sessionsresult). Duplicates collapse; an unknown uuid contributes nothing. An empty list or a non-string item is a fail-loudinvalid_argument— never a silent unfiltered scan.since/until— ISO-8601 bounds (inclusive) on the event ts.file— substring matched against an event's referenced file path.tool— substring (pattern) matched against the referenced tool name OR the resolved name under a wrapper (tool_resolved) — sotool="commit"also finds the Skill call that ran thecommitskill.tool_kind— exact match against the wrapper-aware classification of a tool call:edit/write/read/bash/task(subagent spawn) /skill/mcp/web/other. Everytool_callevent carriestool_kind(inrefsand as a top-level field); wrappers whose input names the real actor also carrytool_resolved— the subagent type under Task/Agent/ spawn_agent, the skill name under Skill/SlashCommand, or"<server>:<tool>"for a Claude-stylemcp__<server>__<tool>call. No signal → notool_resolved(never guessed). An unknowntool_kindvalue is a fail-loudinvalid_argument.model— exact, case-insensitive match against the model that produced the event's message: anassistant_turn/tool_call/plan_eventinherits the model of the assistant message behind it and carries it as a top-levelmodelfield (absent without a signal — user turns, Antigravity — soaggregate(group_by="model")buckets those under"(unknown)"). Model ids are agent-defined strings (no fixed vocabulary); events without a signal never match; an empty string is a fail-loudinvalid_argument.user_ref— filteruser_turnevents by the entity the user referenced. A string with special values:"any"matches every user turn that referenced some target; a bare kind (e.g."file"/"session") matches turns referencing that kind of target; any other string is a substring matched against the referenced target. Non-user events never match, so combininguser_refwith a non-user_turntypeyields an honest empty result.has_thinking— filter by whether the event's message carried model reasoning (Event.has_thinking).Truekeeps only events with reasoning,Falseonly those without; unset (None, default) does not filter. Note the reasoning text itself is never inlined — this only gates on its presence (fetch it withget_body(id, include_thinking=True)).text— substring matched against event text. Withsort="relevance"survivors are BM25-ranked using the same scorer assearch_sessions;sort="semantic"(F5.1, optionalai-r[semantic]) re-ranks the BM25 top-50 candidates by meaning with a local multilingual embedding model (cross-lingual ru↔en, synonyms) — the response carries asemanticdict reporting either the active ranking (active: true, model, candidate count, blend weight) or the honest degradation (active: false+ plain-wordsreason+fallback: "bm25"— the order is then plain BM25, never a crash);sort="date"(default) orders by timestamp ascending.relative_to(event id) +direction(prev|next) +n(a positive integer, default1, or"all") — the neighbouring-turn walk. A numeric string ("3") is deprecated and will be rejected in 0.6.0 — pass an int or"all". Generalises theprevious_user_intentused byfind_file_editsto both directions and any count.step_typechooses which event type to collect (defaultuser_turn). Whenrelative_tois set, other filter facets are ignored.
with_intent=True attaches a top-level intent (the request behind
the event, via the same previous_user_intent walk-back the legacy
tools use) to every returned event. Default False keeps the base
event shape unchanged.
noise filters at the session level before events are read — a
session is noise when it is a spawned subagent (kind == "subagent"
or parent_uuid set): "include" (default, no filtering),
"exclude" (top-level sessions only), "only" (subagent sessions
only). Ignored on the relative_to walk, like every other filter
facet.
project_dir also filters at the session level: keep only events
of sessions whose project_dir equals this path or is a
descendant of it (path-boundary aware, trailing slashes ignored) —
"events of this project". Sessions without a project_dir signal
never match. Ignored on the relative_to walk, like every other
filter facet.
parent also filters at the session level: keep only events of
sessions that are a descendant (transitively, any depth) of this
session uuid in the subagent parent_uuid tree — the whole spawned
subtree below parent (direct children plus nested). parent
itself is excluded (its own events are reachable via
session=<parent>). An unknown uuid matches nothing (honest empty
result). Ignored on the relative_to walk, like every other filter
facet.
group filters at the event level, plan_events only: keep only the
plan_events whose task_id (the plan-task grouping key — plan-file
slug or normalized title) equals this value. Non-plan events never
match when group is set, so combining group with a non-plan
type yields an honest empty result.
redact=True (default) masks secrets in the emitted text /
intent fields as [REDACTED_<TYPE>] and adds a top-level
redactions type→count dict when any replacement happened;
redact=False returns raw content. Redaction is emission-time only:
the text facet (and every other filter) matches the RAW stored text.
Events are reference-by-default: each emitted event's text is a
preview cut to ~160 chars (applied after redaction). A real cut is
marked with a trailing … and text_truncated: true (absent when
nothing was cut). id/refs/sha256 are untouched — fetch the
full body on demand with get_body(id).
kind was removed — it duplicated noise (noise="only" for
subagents, noise="exclude" for top-level). It is kept in the signature
only as a fail-loud tombstone: passing any value returns an
invalid_argument error pointing at noise rather than silently
ignoring it (the MCP transport would otherwise drop an unknown argument and
return an unfiltered result — a silent wrong answer).
Returns {"events": [...], "count": N} or the standard
{"error": ..., "message": ...} dict on invalid arguments. When
count == 0 the dict additionally carries diagnostics (scanned
agents + session counts, corpus date bounds, cause hints) so an empty
result is explainable.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| n | No | ||
| file | No | ||
| kind | No | ||
| sort | No | date | |
| text | No | ||
| tool | No | ||
| type | No | ||
| agent | No | ||
| group | No | ||
| limit | No | ||
| model | No | ||
| noise | No | include | |
| since | No | ||
| until | No | ||
| parent | No | ||
| redact | No | ||
| session | No | ||
| user_ref | No | ||
| direction | No | prev | |
| step_type | No | user_turn | |
| tool_kind | No | ||
| project_dir | No | ||
| relative_to | No | ||
| with_intent | No | ||
| has_thinking | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||