Skip to main content
Glama

ai-r

CI coverage tests License: MIT Python 3.11+

English | Русский | 中文 | 日本語 | Español

An agent reported "done." There's nothing to check it against.

ai-r reads the session history of any of the five coding agents and lets a fresh agent cold-check what git can't answer:

  • did it lie, did it break anything — did it keep its word, did it run anything dangerous (and roll it back if it did), what it actually changed, what it cost;

  • why it went that way — under which plan, with what intent, and whose hand was behind the edit.

Across our own corpus — 1600+ sessions of five agents in 20+ projects — that's how we found 312 risky commands (rm -rf, curl|sh, git push --force): the agent caught and rolled back two itself; the other 310 ran silently — git won't show them.

git shows what made it into the code; ai-r shows whether you can trust how the agent got there. Read-only: no LLM calls, no network.

Quick example — an agent asks about history

The primary mode is MCP: an agent (Claude, Codex, …) calls ai-r directly and asks about history in plain language. For example — pull the plan the previous agent settled on, drafts discarded:

Show me the plan from the last session — final only, no intermediate revisions.
→ plan(session=…, kind="final")  →  get_body(id, shallow=true)

  plan:            "Migrate auth to JWT: 1) extract the check…"
  dropped_drafts:  2   ← two drafts the agent threw away along the way
  session:         a3f… (claude)

Fast edit attribution — one terminal command, across every agent at once:

ai-r find-file-edits auth.py --since 2026-06-01
2026-06-03  codex   auth.py  "add a refresh token"                 edit
2026-06-07  claude  auth.py  "extract the check into middleware"   edit

Related MCP server: claude-sessions-mcp

What hurts

  • "Done, I did X per plan Y" — with nothing to check it against: the agent keeps the plan in one shape, the edits in another.

  • You switched agents mid-task and lost the thread. There's nowhere to ask "what did the other agent already try?"

  • An edit shows up in a file — and it's unclear which agent made it, and on what request.

One cause: every agent writes its history its own way — Claude and Codex in JSONL, OpenCode in SQLite, Antigravity in "brain" directories, Pi in per-project JSONL. Five formats, five layouts — together they don't reconcile.

The promise

ai-r folds all five into one read-only interface. Point any agent — or a script, or yourself — at any session, no matter which tool recorded it. One query shape per agent; format differences are normalized inside the parsers.

Even with a single agent it works: you audit your own Claude history (or Codex…). The five formats are so your history doesn't break when you switch tools — not a requirement to have all five.

As a source for RAG

In an "LLM + external data source" setup (RAG), ai-r is the source — more precisely, a retrieval layer over agent sessions. For a query it returns not a slice of log but parsed entities: the plan, the intent, the authorship of an edit — with a reference to the body the agent can pull if it needs it.

It doesn't replace your RAG over code and docs; it adds a source the others can't reach. The usual sources you retrieve from: documentation, commit history, Stack Overflow, internal wikis, code bases, bug reports. Agent sessions aren't on that list — even though only there is it recorded why an edit happened at all.

Retrieval is BM25 (ranked keyword search), with optional semantic re-ranking. No vector database, no second LLM: all local, results reproducible. BM25 here isn't a shortcut — GitHub lists it alongside vector retrievers: "Common retrievers include sparse methods like BM25 and dense vector retrievers using neural networks."

Key features

Each item is a trust question from the first screen and the verb that answers it:

  • Did it keep its word — plan vs. reality. Pulls the final plan (separate from the discarded dropped_drafts) and checks it against what actually made it into the edits — catching "did X per plan Y" where Y is no longer that plan. (plan, session_diff)

  • Did it run anything dangerous — and roll it back. Flags risky commands (rm -rf, curl|sh, git push --force) and, from the turns that follow, sees whether the agent caught it and rolled back — or it passed silently. (incidents, query tool_kind=bash)

  • What it actually changed, and by whose hand. Any edit or call → the agent that made it, plus the request that triggered it; including edits made through the shell (> file under codex) that a plain diff misses. (find-file-edits, find-tool-calls)

  • What it cost. Tokens and cost per session — exact where the format recorded the usage, an honest estimate where it didn't, never invented. (session_stats with_tokens, aggregate group_by=model)

  • Why it went that way. The intent behind an edit (the request before it), under which plan, on which model — "why", not just "what". (query with_intent)

  • Small answer, body on demand. A record carries a reference to the content (hash + length); the full text comes as a separate request. A reader, not a guard: read-only, it runs nothing and writes nothing to an agent's history.

How ai-r knows

Deterministically, with no second LLM guessing — and honest about the edges:

  • dangerous command — a pattern over the call string (rm -rf, curl|sh, git push --force, …). Anything obfuscated (exec(input())) the pattern won't catch — that's a declared boundary, not a silent miss.

  • rollback — marked "confirmed" ONLY when a regret/apology marker from the agent sits nearby (within the window of following turns; the marker itself is a bilingual ru/en pattern, not an LLM sentiment call). No marker → it stays an unconfirmed candidate: ai-r won't infer a silent rollback, it honestly says "not confirmed".

  • lied about the planai-r doesn't decide for you. It lays the plan entity next to the session's reconstructed edits (session_diff) — the mismatch is visible to you or a reviewing agent. That's evidence assembly, not a semantic verdict.

Zero LLM calls, read-only — the numbers are reproducible and "confirmed" is never guessed.

What you use it for

  • Audit sessions with a fresh pair of eyes. A new agent with an empty context coldly checks past sessions on three axes: were promises and requirements met; are the decisions sound and well-judged; how deeply was the question explored — what the agent missed. This catches agents that finished the task but misled on the planning — something a live chat hides, and that steers you into wrong decisions.

  • Continue past a spent context — without losing detail. /compact erases the specifics. Instead, open a fresh session: it reads the previous session's logs and continues from its conclusions, without re-burning context on what's already been worked out. The original session stays intact — for audit and search. The new session can run in any agent: the history reconciles regardless of the tool.

  • Feeds your memory system. Keeping memory and summaries à la Karpathy, or your own method? ai-r gives you, for AI chats, what you already do with message history — parsed entities to build a lasting memory of the details that matter.

  • Recall what you did and why. Why was this file edited? Why was this rule added? Find the session where the file changed and read the request before the edit.

How it differs from session-search tools

A handful of cross-agent tools now read more than one agent's history (jazzyalex/agent-sessions, Dicklesworthstone/coding_agent_session_search, hacktivist123/agent-session-resume). Almost all are about search and timeline: find a session, scroll the history.

ai-r goes deeper: it extracts the plan, intent, and authorship as ready-made entities you build memory on. Search finds text — ai-r answers why. Technically a search tool could also dig a plan out of a session's text, but it doesn't hand it back parsed into a single, normalized shape — with ai-r that's the primary surface.

Capability

Single-agent viewers

Cross-agent search tools

ai-r

Reads >1 agent's logs

No

Yes

Yes — Claude, Codex, OpenCode, Antigravity, Pi

Programmatic surface

Mostly GUI/TUI

Mostly TUI/CLI/app

MCP + CLI + Python SDK

Attribution (edit/command → agent + intent)

Partial

Yes — find-file-edits / find-tool-calls

Audit replay (reconstruct a session's changes, no git)

Rarely

Yes — session_diff

Plan extraction (final vs draft, normalized)

Yes — plan

Scope

Viewer

Search / resume / memory

Read-only extraction core

Competitor columns reflect their public docs as of 2026-07; where a capability is unclear we under-state rather than over-claim.

We deliberately don't compete on agent breadth, speed, or TUI richness. ai-r's wedge is extracting the "why" and structured entities for machine consumption.

Proven in practice

ai-r already reads its own development history — across all five agents. Real tools run on it (they live separately, on top of its read-only API):

  • auditor — a fresh agent coldly checks what the previous one actually did and decided. This caught agents that quietly fibbed about the plan.

  • summarizer (export rounds) — renders a session into a ready handoff doc.

  • ai-local-reader — a read-only skill: audits past sessions from disk across all agents.

These tools are workflow-side, outside this repo. ai-r itself only reads and returns data.

Supported agents

Agent

Storage

Parser

Claude Code

~/.claude/projects/

JSONL

Codex

~/.codex/sessions/

JSONL

OpenCode

~/.local/share/opencode/opencode.db

SQLite (snap/flatpak auto-detect)

Antigravity

~/.gemini/antigravity/brain/

JSON / markdown brain directories

Pi

~/.pi/agent/sessions/<encoded-cwd>/*.jsonl

JSONL

Not your agent? Adding a sixth is one parser module; the read-only pattern ports to any tool in minutes. See CONTRIBUTING.md.

Surfaces

ai-r gives the same reading power three ways:

  • MCP server (ai-r-mcp) — 15 tools over JSON-RPC, so any MCP agent calls it directly (recommended). Default is stdio; optionally a shared http server (one warm process for all agents instead of a per-agent stdio swarm), see the http extra under Quick start. Registration — see docs/mcp-registration.md.

  • CLI (ai-r) — subcommands for scripts and manual use (list / read / search / find-file-edits / find-tool-calls / file-frequency / detect-agent / export rounds). Search operators — docs/search-operators.md.

  • Python SDK (from ai_r.parsers import ...) — parsers, typed Session/message models, and the event verbs, to build your own tools.

Method vocabulary

The full dictionary of public verbs and presets (signatures, parameters, behaviour) lives in its own file: docs/methods.md.

Event core

The verbs above are new: one event core replaces a pile of one-off tools. Each parser reads one agent's logs and emits typed models, normalized into a single agent-neutral stream — user_turn / assistant_turn / tool_call(...) / plan_event. A small set of verbs filters, aggregates, and diffs that stream; agent differences (ExitPlanMode vs update_plan vs implementation_plan.md) stay hidden inside the parsers — the caller sees one shape.

An honest boundary: this is extraction of entities only — turns, tool calls, plans, intents, reactions. It is not a graph and not a memory store. What you do next (knowledge graph, Obsidian, persistent memory) is on your side, outside this repo. For the full layering and the MCP tool list, see docs/architecture.md.

Quick start

Try it without installing — if you have uv:

uvx --from agent-session-reader ai-r list          # CLI: list sessions
uvx --from agent-session-reader ai-r-mcp           # MCP server (stdio)

Nothing lands on your system: uvx downloads the package into a temporary cache and runs it. Good for looking at your sessions right now, or for wiring ai-r-mcp into an agent's MCP config by hand.

Full install (1 command) — also patches your configs:

Requirements: Python 3.11+ with venv or pip, and jq (used to auto-patch the Claude and Antigravity MCP configs — the others don't need jq).

git clone https://github.com/pro-target/ai-r.git ~/dev/ai-r
cd ~/dev/ai-r && bash install.sh

The installer creates a venv, installs the runtime package, patches MCP configs for Claude, Codex, OpenCode, Antigravity (where the configs exist), installs the Pi CLI skill, and runs smoke tests. That auto-patch is exactly what uvx doesn't do — there you edit the configs yourself.

Optional extra — tokens: AI_R_EXTRAS=tokens bash install.sh (or pip install "ai-r[tokens]") adds tiktoken for better token estimates on sessions whose format stores no exact usage numbers. Fully optional: without it exact numbers still come straight from the session files where recorded, and the fallback estimate degrades to a rough chars/4 heuristic, honestly labeled estimate — never a crash.

Optional extra — semantic: AI_R_EXTRAS=semantic bash install.sh (or pip install "ai-r[semantic]" + a one-time model download the installer does for you) enables sort="semantic" on text search (query, search_sessions) — the BM25 top-50 candidates are re-ranked by meaning.

  • Model. A local multilingual embedding model, intfloat/multilingual-e5-small (int8 ONNX, ~118 MB, MIT), run directly via onnxruntime + tokenizers + numpy, no torch, no persistent index. Chosen for strong cross-lingual retrieval (a Russian query finds an English session and vice versa) at a small size.

  • How the score works. BM25 picks the 50 best word-matches (a cost budget, not a quality cut-off — there is deliberately no similarity threshold, because this model family scores even unrelated texts ≈0.7). Within that pool the final score is 75 % meaning + 25 % word match — meaning dominates, while the word share keeps exact-term hits from being drowned and breaks ties.

  • Fail-soft. Without the packages or model files, sort="semantic" honestly falls back to the BM25 order and the response says why (semantic: {active: false, reason, fallback: "bm25"}) — never a crash.

Two knobs keep the model well-behaved inside a long-lived MCP process (both env-tunable, both degrading to the default on blank/invalid input — never a crash): AI_R_SEMANTIC_THREADS caps how many CPU threads onnxruntime may use per inference (default 2, never more than the machine's core count — so it does not grab every core and fight the server for CPU), and AI_R_SEMANTIC_IDLE_SEC frees the loaded model's ~118 MB of RAM after that many idle seconds (default 300); the next request transparently re-loads it.

Optional extra — http: AI_R_EXTRAS=http bash install.sh (or pip install "ai-r[http]") adds uvicorn and enables a shared streamable-http transport (requires mcp>=1.9.0).

  • Why. By default every agent spawns its own ai-r-mcp over stdio — under multi-agent fan-out that is N processes, each with a cold cache, re-scanning the corpus (the measured cause of RAM exhaustion). With AI_R_MCP_TRANSPORT=http a single warm server on localhost (default 127.0.0.1:8756) is shared by every agent instead of a swarm; the systemd units in packaging/systemd/ add socket-activation with idle self-exit.

  • Security (fail-closed). The bind is loopback-only. Browser-based attacks (DNS rebinding) are cut off by the SDK's Origin/Host allowlist (always on for loopback). Remote access requires AI_R_MCP_ALLOW_REMOTE=1 and an AI_R_HTTP_TOKEN — without the token it refuses to start (transcripts carry secrets). On loopback the token is optional (protection against another local user on a shared box); the client sends an Authorization: Bearer <token> header.

  • Knobs (env):

    • AI_R_MCP_PORT — port (default 8756).

    • AI_R_MCP_IDLE_SEC — idle self-exit threshold.

    • AI_R_MCP_HOST / AI_R_MCP_ALLOW_REMOTE — bind host / allow non-loopback.

    • AI_R_HTTP_TOKEN — bearer token (required for a remote bind).

    • AI_R_HAYSTACK_CACHE_MAX — search cache ceiling by entry count.

    • AI_R_HAYSTACK_CACHE_CHARS_MAX — by total size (an RSS safeguard for a long-lived server).

Both extras are fully optional: without them stdio mode and the BM25 order work as before.

Boundaries: a reader, not a guard

  • Read-only. It never runs an agent's code and never writes to its history — it reads and returns.

  • No graph, no memory. It extracts entities (turns, calls, plans, intents). Building a knowledge graph or memory out of them is your job, not its.

  • Not an access-control layer — except the http transport. Anyone who can reach the CLI, MCP over stdio, or the package reads any session: it's the same local user, so an authorization check in front of the parsers would guard nothing. The exception is the shared http transport: it's reachable over a socket, so it carries an Origin allowlist and an optional bearer token (required for a remote bind, see the http extra above). Either way, keep the data where untrusted local processes can't reach.

  • Session content is data, not commands. Whoever reads (auditor, summarizer) must treat session text as data, not instructions. See Security.

Acceptance (end-to-end scenarios)

The public surface is covered by end-to-end scenarios an LLM agent runs against the live MCP (complementing pytest). Full list — docs/scenarios.md.

Example: ai-r in action

A gallery of real examples — one per capability (error analysis, dangerous commands, network trail, token burn, plan comments, commit phantom-check, cross-agent file history, cross-lingual search, zombie subagents, git-less diff): docs/examples/showcase-gallery.md.

Next — documentation

Development

git clone https://github.com/pro-target/ai-r.git
cd ai-r
pip install -e ".[dev]"
pytest --cov=src/ai_r
  • 1300+ tests, CI requires ≥85% coverage

  • Versioning: SemVer; while on 0.x, a minor release may break compatibility — where possible a migration path is given (a loud deprecation warning before removal); changes land in CHANGELOG.md

  • Conventional Commits (feat:, fix:, docs:, …)

  • On adding new agents, see CONTRIBUTING.md and docs/parsers.md

claude code session reader · claude code session parser · codex session parser · opencode session reader · antigravity brain parser · pi agent session reader · rag over agent sessions · bm25 retriever · retrieval layer for ai agents · grounding · mcp server · structured context · cross-agent attribution · ai coding agent audit · ai agent session history · mcp session tools · read-only session reader · agent session replay · resume agent session · agent handoff · plan extraction · tool-call audit · file edit attribution · multi-agent coding · claude codex opencode antigravity pi

License

MIT — see LICENSE.


Get started: uvx --from agent-session-reader ai-r list — see your sessions right now; or clone + bash install.sh for the full install with MCP-config auto-patching (docs/mcp-registration.md). One read-only surface over every agent's history.

Available Tools

18 tools
aggregateA

Roll a list of row dicts up by group_by — the generic stats verb.

Reproduces session_stats (group_byagent/dir/date/ kind over a session inventory) and file_frequency (group_by="file" over a find_file_edits record stream) as a pure fold over already-materialized rows — no re-parsing. session_stats is now a thin preset over this verb (rank_by="stats" + kind_split).

Args: rows: The row dicts to fold (query output, find_file_edits records, or a session inventory). group_by: The bucket key — a row field name (agent / dir / date / kind / file / model — query rows carry the producing model where the format records one / …). Missing/empty values bucket under "(unknown)". metrics: Which numbers each bucket carries. One or more of count / sessions / edits / intents / agents / messages / files / tokens / component_tokens. Defaults to ["count"]. tokens (F3.3) folds per-row tokens blocks (the shape session_stats(with_tokens=True) rows carry, or a bare int total) into {input, output, reasoning, cache_read, cache_write, total, exact, estimated, unknown} — sums over rows that carry each field (null when none does) plus honest provenance counters (exact + estimated + unknown == len(rows)). component_tokens (F3.3) folds per-row component_tokens blocks (the shape :func:ai_r.tokens.component_tokens produces, as read_session(with_tokens=True) attaches) into summed event-taxonomy components (user_turn / assistant_turn / thinking / plan and a tool_call per-kind sub-dict) + total + provenance counters (estimated / unknown; never exact — always an estimate). A component/kind no row carried stays absent (never a fabricated 0). rank_by: Group ordering — "default" (edits→sessions→count→label, the file_frequency order) or "stats" (sessions→edits→label, the session_stats order). kind_split: When True, add the session_stats RISK-4 fields (kind_split_available + a degenerate-split note).

Returns: {"group_by", "groups": [...], "totals": {...}} (plus kind_split_available/note when kind_split) or the standard {"error": ..., "message": ...} dict on an unknown metric/rank_by.

ParametersJSON Schema
NameRequiredDescriptionDefault
rowsYes
metricsNo
rank_byNodefault
group_byYes
kind_splitNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full responsibility. It is exceptionally transparent: it states it is a 'pure fold' with 'no re-parsing', details how missing/empty group_by values bucket under '(unknown)', explains the exact folding behavior for tokens and component_tokens including provenance counters and the rule that absent components stay absent (never fabricated 0). It also describes the error return format. This goes far beyond what annotations would typically provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Although lengthy, every sentence earns its place. The description is front-loaded with purpose, then uses a structured Args/Returns layout. The detailed explanations of metrics are necessary for correct usage and are not redundant. The structure is logical and the density is appropriate for the tool's complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (5 parameters, two complex metric types, multiple ordering options) and the fact that an output schema exists, the description is remarkably complete. It covers return format, edge cases, parameter constraints, and error conditions. It even specifies the ordering of groups for each rank_by option. There are no gaps that would leave an agent guessing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate, and it does thoroughly. It explains rows (what counts as valid input), group_by (valid values and unknown handling), metrics (allowed values, default, and detailed behavior for nested token/component_tokens structures), rank_by (both options and their ordering), and kind_split (what happens when True). This provides full semantic clarity for all 5 parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Roll a list of row dicts up by group_by — the generic stats verb', which clearly states the action (rolling up rows) and resource (row dicts). It further distinguishes itself by noting it reproduces session_stats and file_frequency, making its purpose distinct from sibling tools. The purpose is specific and well-differentiated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context on when to use the tool: it operates on already-materialized rows from query output, find_file_edits records, or a session inventory, and avoids re-parsing. It references session_stats as a thin preset, implying a relationship. However, it does not explicitly state when not to use this tool or name alternative tools outside of session_stats/file_frequency, so it lacks explicit exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

audit_briefA

Token-lean, budgeted session digest for auditors — the audit_brief preset.

One call answers "what happened in this session, verbatim where it matters", inside a hard character budget. A preset over the existing core, not a second engine (project preset rule): ONE query scan over the session's events supplies the user turns (VERBATIM — the auditor's ground truth) and the tool/file footprint (folded by aggregate(group_by="tool_kind") + the edit/write rows' existing file refs); the plan/plan_feedback projections supply the decision trail; :mod:ai_r.tokens (the same SSOT behind session_stats(with_tokens) / read_session(with_tokens)) supplies the token breakdown.

Deterministic budget algorithm: build the full digest, then tighten in a FIXED ladder until the serialized JSON fits budget_chars (default 15000; 0 = unlimited) — (1) drop tool-call error details, (2) drop the per-file edit list, (3) drop plan bodies + feedback quote/comment texts (counts/references always stay; bodies on-demand via get_body). User turns are NEVER truncated: if they alone exceed the budget the response carries budget.over_budget: true + a note naming the full projections — never a silently clipped ground truth.

session accepts the full uuid or a unique id prefix (e.g. the 8-hex head), resolved through the SAME id-prefix matching locate uses — the digest's session.uuid echoes the full resolved id; an ambiguous prefix is invalid_argument naming the candidates (capped), zero matches is not_found with closest-title suggestions. agent is an optional hint (None = the id resolves across every parser, like read_session). redact=true (default) masks secrets in the emitted title / user texts / plan bodies / feedback pairs. The response is section-structured (session / user_turns / plans / tools / files / tokens / component_tokens / budget); the CLI mirror is ai-r audit-brief <uuid> (markdown, --json for this dict).

Thin wrapper over :func:ai_r.audit_brief.audit_brief: a ValueError becomes {"error": "invalid_argument"}, an unknown session id {"error": "not_found"}.

ParametersJSON Schema
NameRequiredDescriptionDefault
agentNo
redactNo
sessionYes
budget_charsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full behavioral burden and succeeds: it discloses the deterministic budget algorithm, the fixed truncation ladder, that user turns are NEVER truncated, error handling for invalid/ambiguous prefixes, redaction behavior, and the response structure. This is far beyond basic expectations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but front-loaded with a clear purpose and well-organized into sections with bullets. Every sentence provides useful detail, though there is slight redundancy (e.g., mentioning both 'preset' and 'thin wrapper') that could be trimmed without losing meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity, the description is remarkably complete: it covers all parameters, behavioral edge cases, error mapping, output sections, and even the CLI mirror. The presence of an output schema doesn't reduce the need for this context because the tool's behavior around budgets and redaction is essential for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description thoroughly explains all four parameters: session accepts full UUID or prefix, agent is an optional hint, redact masks secrets, and budget_chars drives the truncation algorithm. It adds operational meaning well beyond the bare schema definitions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose as a 'Token-lean, budgeted session digest for auditors' and explains it answers 'what happened in this session, verbatim where it matters'. It distinguishes itself from siblings by labeling itself a preset over the core, not a second engine, and by detailing its specific output structure.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description specifies the intended use case ('for auditors') and clarifies it is a 'preset over the existing core' with a budget algorithm. However, it does not explicitly state when to prefer this over alternatives like read_session or session_stats, nor does it provide exclusions or alternative guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

detect_currentA

Return the current runtime identity (session + agent) from env/fs.

NOT a session-query — this reads the runtime environment (env vars + per-session flag files), reusing the exact cascade behind the ai-r detect-agent / ai-r detect-session CLI subcommands.

Args: agent: Optional hint (accepted for symmetry with the CLI's deprecated --agent flag); the cascade scans all agents.

Returns: {"session_id", "agent", "model", "resume_command", "candidates": [...], "verified", "self"} where session_id / agent describe the highest-priority candidate, model is the current session's model — the LAST assistant model recorded in its transcript (null when identity is incomplete or the format records no model signal — never guessed) — resume_command is the ready-to-run shell one-liner that reopens the detected session in its agent's CLI (F2.2, text only, never executed; null when no real command exists) — and candidates is the full cascade for disambiguation. Returns {"error": ..., "message": ...} on an unknown agent hint.

ParametersJSON Schema
NameRequiredDescriptionDefault
agentNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden and does so thoroughly. It explains the data sources (env vars + flag files), the candidate cascade, and the 'never guessed' behavior for model, and clarifies that resume_command is text-only and never executed. It also discloses error behavior for unknown agent hints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with Args and Returns sections. Every sentence contributes: it defines the tool, contrasts with session queries, explains the parameter, enumerates return fields, and documents error cases. There is no filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having an output schema, the description independently lists every return field and their semantics, including null cases and the error response. It gives enough context for the agent to invoke the tool correctly and interpret results without further lookup.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description fully explains the single 'agent' parameter: it's an optional hint, accepted for symmetry with a deprecated CLI flag, and the cascade scans all agents. This adds meaning beyond the bare schema and leaves no ambiguity.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource: 'Return the current runtime identity (session + agent) from env/fs.' It clearly distinguishes itself by stating 'NOT a session-query,' which differentiates it from sibling tools like list_sessions and read_session.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly states when not to use it ('NOT a session-query') and clarifies the underlying mechanism ('reads the runtime environment (env vars + per-session flag files)'), which tells the agent this is for runtime detection rather than persistent session queries. It also references CLI subcommands, aiding alignment with existing patterns.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

diffA

Stitch edit rows into a per-file chronological diff — the diff verb.

Reproduces the synthesis of session_diff: given the edit events of a session (query(type="tool_call(edit)", session=…) — plus write / shell-redirect events), group them per file in chronological order and render a stitched, readable diff. Bodies are fetched on demand (via each event's stored message_index), never inlined on the row.

Args: rows: Edit-event dicts (query output). Each must carry an id and a refs list with a file entry; unresolvable rows skip. per_file: Group by file (the only mode today). format: "unified" (the only rendering today). redact: When True (default) secrets in the stitched output are masked as [REDACTED_<TYPE>] and the result carries a redactions type→count dict when any replacement happened; False returns raw content.

Returns: {"files": [{"file", "edits", "diff", "hunks"}], "count", "caveats"} (same shape + caveats as session_diff, size-bounded the same way: capped fields named in the per-file truncated_fields, byte budget → output_truncated) or the standard {"error": ..., "message": ...} dict on an unsupported format.

ParametersJSON Schema
NameRequiredDescriptionDefault
rowsYes
formatNounified
redactNo
per_fileNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so thoroughly. It discloses that bodies are fetched on demand via message_index, unresolvable rows are skipped, and redaction behavior includes masking as [REDACTED_<TYPE>] and returning a redactions dict. It also describes return structure, truncation, and error handling, offering deep insight into the tool's behavior beyond mere input/output.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a summary sentence, followed by detailed argument explanations and a clear Returns section. While somewhat long, every sentence provides essential information, and the front-loaded first sentence gives the core purpose immediately. It avoids fluff and earns its length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity and the absence of annotations, the description covers all necessary aspects: input requirements, processing behavior, output shape, edge cases (unresolvable rows, unsupported format), and constraints (size-bounded, truncated_fields). It also references session_diff for known caveats, making it complete for an agent to use correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides only titles with no descriptions (0% coverage), but the description explains each parameter in detail: rows must contain id and refs with a file entry, per_file is the only mode, format supports only 'unified', and redact controls secret masking. This fully compensates for the schema's lack of documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Stitch edit rows into a per-file chronological diff — the diff verb.' It clearly distinguishes from session_diff by explaining that it reproduces the synthesis from provided edit-event rows rather than querying directly. The purpose is unambiguous and aligns with the tool name.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides clear context: use this when you have edit-event rows from a query and want a per-file diff, as opposed to session_diff which likely queries the session directly. It also notes that per_file and format are the only modes today, implying no alternatives within the tool. However, it does not explicitly list alternative tools or state when not to use it, though the contrast with session_diff gives implicit guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_file_editsA

Find every file edit across sessions, cross-agent by default.

redact=True (default) masks secrets in emitted record fields as [REDACTED_<TYPE>] and adds a redactions type→count dict when any replacement happened; redact=False returns raw content.

Reference-by-default: to keep an audit listing small, each record does not inline the full edit body. Instead it carries a light-weight reference — input_sha256 (hash of the body) and input_chars (its length) — so you can see a body exists and how big it is. Fetch the body on demand with get_body / read_session (keyed by session_uuid

  • message_index). Pass include_input=True to inline the full body under input instead.

Size-bounded output: over-long intent / assistant fields are cut with a …[truncated] marker (named in the per-record truncated_fields) and emission stops at a total byte budget (output_truncated — distinct from the count-based truncated).

Default time window: a call with NO narrowing filter at all (no agent / since / until) is scoped to the last 7 days instead of the whole corpus; the response then carries default_since (the applied bound) plus a note saying so. Any explicit scope disables the default — pass e.g. since="1970-01-01" to deliberately scan the full history.

Thin wrapper over :func:ai_r.find_file_edits.find_file_edits that translates the core ValueError contract into the {"error": "invalid_argument", "message": str(exc)} shape the MCP client expects.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes
agentNo
limitNo
sinceNo
untilNo
redactNo
include_inputNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so impressively. It discloses redaction behavior, reference-by-default semantics, size-bounded output with truncation markers, the default 7-day time window, and the error contract translation—far exceeding minimal disclosure expectations and providing rich behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but every sentence earns its place, organized by labeled behavioral aspects (redact, reference, truncation, default window, wrapper). It is front-loaded with the core purpose and uses bolded inline terms to make scanning easy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity and the presence of an output schema, the description covers all major behavioral areas: redaction, reference-by-default, truncation, default time window, and error mapping. It leaves no significant gap for an agent to misuse the tool, and the output schema handles return-value details.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate, and it explains redact, include_input, since/until, agent, and the distinction between output_truncated and count-based truncation. However, the 'limit' parameter is not explicitly tied to record-count behavior; while 'count-based truncated' hints at it, the direct semantic of limit remains implicit rather than stated.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence, 'Find every file edit across sessions, cross-agent by default,' uses a specific verb ('Find') and resource ('file edit across sessions'), and the phrase 'cross-agent by default' immediately distinguishes it from sibling tools like find_tool_calls or session_diff. It is immediately clear what the tool does and how it is scoped.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly explains when to fetch bodies on demand via get_body/read_session and when to pass include_input=True, giving practical alternatives. However, it does not explicitly state when not to use find_file_edits versus other sibling tools, relying more on implicit context than direct exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_tool_callsA

Find every tool call across sessions, cross-agent by default.

redact=True (default) masks secrets in emitted record fields as [REDACTED_<TYPE>] and adds a redactions type→count dict when any replacement happened; redact=False returns raw content. Filters always match the RAW, pre-redaction text.

session scopes the scan to a single session uuid (or a list of uuids) — same semantics as the query facet. None = every session; a wide since/until with NO session therefore surfaces calls from unrelated sessions, so pin it when auditing one conversation.

Exactly one of tool_name (exact, case-insensitive) or tool_name_pattern (substring, case-insensitive) must be set.

Optional filters combine with AND: input_contains / output_contains (case-insensitive substring on the full, pre-cap input/output), output_excludes (drop records whose output contains it) and is_error (tri-state: None all, True failures only, False successes only). output_mode selects output truncation — "head"/"tail"/"smart"; None is adaptive ("smart" on errors, "head" otherwise). Each record also carries is_error_reliable (True only for Claude/OpenCode) plus the wrapper-aware classification: tool_kind (edit/write/read/bash/task/skill/mcp/ web/other) and tool_resolved — the real name under a Skill/Task/MCP wrapper (subagent type, skill name, or "<server>:<tool>"); None when there is no wrapper or the input carries no name signal.

A record whose call has a correlated result also carries tool_use_id — the join key back to a spawned subagent's own session (the child stores it as extra.spawn_tool_use_id). On a spawn (tool_kind="task") it additionally carries subagent: what the child COST — model (the model it actually resolved to, which may be a cheaper pinned tier than the parent's), agent_type (persona), tokens (EXACT billed usage, source="exact", full token-block shape), status, duration_ms, tool_uses. Honest gaps: a background spawn (status="async_launched", sidecar written before the run exists) reports its model with no tokens key — never a fabricated zero; its real cost and persona come from read_session(include_subagents=True)subagent_rollup.children. A record carrying several tool results drops the sidecar rather than billing it to the wrong subagent.

with_subagent_cost=True (opt-in) recovers exactly that for the spawn records here: each subagent sidecar is JOINED to the spawned child's own files, adding the persona (agent_type) from the child's agent-*.meta.json, the models it ran on, its EXACT billed tokens (source="exact", an estimate is never merged into the billing field) and child_uuid. So a background spawn — anonymous and price-less in the launch-time sidecar — becomes a named, priced row. The child is preferred over the sidecar, which stays the fallback for a child that cannot be joined (not yet on disk, meta corrupt): its tokens are then left absent, never zeroed. Default False reads no per-spawn child file (a cross-corpus scan does not pay the join).

Thin wrapper over :func:ai_r.find_tool_calls.find_tool_calls that translates the core ValueError contract into the {"error": "invalid_argument", "message": str(exc)} shape the MCP client expects.

ParametersJSON Schema
NameRequiredDescriptionDefault
agentNo
limitNo
sinceNo
untilNo
redactNo
sessionNo
is_errorNo
tool_nameNo
output_modeNo
input_containsNo
output_containsNo
output_excludesNo
tool_name_patternNo
with_subagent_costNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Despite no annotations, the description discloses extensive behavioral traits: redaction masking with [REDACTED_<TYPE>] placeholders, filters matching raw pre-redaction text, tri-state is_error semantics, output_mode adaptive behavior, wrapper-aware classification, and honest subagent cost fallback gaps. This far exceeds typical transparency and fully describes edge cases without contradicting any structured metadata.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but each paragraph addresses a coherent behavioral aspect, and technical details are interwoven with usage rationale. It front-loads the core purpose and then organizes by parameter and edge case, making it navigable. Some length is justified given the tool's 14-parameter complexity, though a few sentences could be tightened.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is self-contained, covering error translation, subagent cost join mechanics, fallback behaviors, and the presence of an output schema. It answers 'what happens if' for background spawns, corrupted metadata, and multi-result records. This goes beyond a typical tool description and fully prepares an agent to use the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, and the description adds deep meaning to most parameters: redact, session, tool_name/tool_name_pattern, input_contains/output_contains/output_excludes, is_error, output_mode, and with_subagent_cost. It even explains session semantics relative to since/until and hints at agent scope with 'cross-agent by default'. While 'limit' and 'agent' are not explicitly detailed, the description compensates overwhelmingly for the schema's silence.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence uses a specific verb 'Find' and resource 'every tool call across sessions, cross-agent by default', clearly establishing the tool's scope. It distinguishes itself from siblings by focusing on tool calls and cross-agent scanning, which is not obvious from navigation-based tools like read_session or search_sessions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear when-to-use context, such as pinning the session when auditing one conversation and opting into with_subagent_cost for subagent billing recovery. It does not explicitly name alternative tools or state when not to use this tool, but the context and filters give strong practical guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_bodyA

Return the on-demand body for an event / plan id.

For a plan_event id: the full plan text and/or Codex steps (bodies are deliberately kept off the event stream so callers pay for them only when needed). For a user_turn / assistant_turn id: the turn text.

shallow=True (plans only) returns just the final plan of the id's task, dropping the bodies of superseded draft revisions — the S6 case where a subagent receives one plan without the draft noise (dropped_drafts lists the ids that were elided).

max_chars bounds the returned body/text (default 500_000, generous enough that ordinary bodies are never cut; pass 0 to disable). When it trips, the field is sliced with a …[truncated] marker and body_truncated: true is set.

redact=True (default) masks secrets in the emitted text/body/title/steps as [REDACTED_<TYPE>] and adds a redactions type→count dict when any replacement happened; redact=False returns the raw content.

include_thinking=True (turn ids only): attach the model's reasoning (message.thinking) as a separate thinking field on the returned body, re-read from the hosting message. Default False leaves the body byte-identical to the historical shape (no thinking key). Fail-soft: a turn without reasoning never carries the key.

Returns the body dict, or {"error": ..., "message": ...} on a bad id.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYes
redactNo
shallowNo
max_charsNo
include_thinkingNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full behavioral disclosure. It covers return format, truncation behavior with markers, redaction semantics and defaults, the fail-soft behavior of include_thinking, and error responses—all beyond what annotations would typically convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Though long, the description is densely informative and well-structured: main purpose first, then parameter explanations, then return behavior. Every sentence adds operational value, and the examples (S6 case, fail-soft) clarify edge cases without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has 5 parameters, a complex combination of behaviors, and no annotations. The description covers all parameter semantics, edge cases, defaults, and error handling. The presence of an output schema means return-value details are not required, but the description still states the return shape, making it complete for an agent to invoke correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 0% description coverage, so the description must explain all parameters. It does so thoroughly: id type and meaning, shallow's draft-skipping behavior, max_chars truncation with 0 to disable, redact's masking behavior, and include_thinking's conditional field. This fully compensates for the absent schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Return') and identifies the exact resource ('on-demand body for an event / plan id'). It distinguishes between plan_event and user_turn/assistant_turn id types, making the tool's scope clear and differentiating it from sibling tools that handle sessions or audits.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains when to use the tool (for on-demand body retrieval, deliberately off the event stream) and provides detailed guidance on which id types apply. It does not explicitly name alternatives among sibling tools, but the contextual cues ('bodies are deliberately kept off the event stream') imply when this tool is appropriate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

incidentsA

Dangerous shell commands + regret reactions — the incidents preset.

One call answers "where did an agent run something destructive — and did it then apologise?". A preset over the existing core, not a second engine: ONE query scan (type="tool_call", tool_kind="bash") supplies the candidates, a deterministic danger dictionary (harvested from public agent-guardrail rule sets, calibrated on real history) selects the dangerous commands, and a bilingual (ru + en) regret dictionary scans the next reaction_window messages (default 6) for an apology/rollback reaction — the two-step check behind the confirmed flag. Zero LLM, zero guessing: no dictionary hit → no incident; no reaction → confirmed: false, never inferred.

Filters (all parameters): agent, session (uuid or list of uuids), since/until (ISO bounds on the call ts), category (fs/git/db/net — unknown values fail loud), confirmed (include default | only | exclude), noise and project_dir (session-level, same semantics as query).

Each incident record carries the query event id (walk its context via query(relative_to=...) / read_session), the matched patterns + categories, a char-capped command fragment centred on the hit (token budget — full context stays on-demand), is_error (null when the agent's format has no correlated outcome signal — honest, cross-agent), confirmed and reaction (message_index/offset/role/marker labels/capped preview; null when unconfirmed). count/confirmed_count/ by_pattern always reflect the FULL match set; limit (default 50, 0 = no cap) bounds only the emitted records (truncated).

Dictionary caveat (documented, not hidden): patterns are a deterministic dictionary, not a shell interpreter — a command that merely mentions a dangerous string (e.g. echo "rm -rf /") can still match. Matching runs on the extracted command field (a Bash description alone never fires) and always on the RAW stored text; redact=true (default) masks secrets only in the emitted session_title/command/reaction.preview fields (redactions type→count dict when anything was masked). When count == 0 the response carries diagnostics so an empty result is explainable (missing source dir vs all-excluding filter vs a genuinely clean history).

Thin wrapper over :func:ai_r.incidents.incidents that translates the core ValueError contract into the {"error": "invalid_argument", "message": str(exc)} shape the MCP client expects.

ParametersJSON Schema
NameRequiredDescriptionDefault
agentNo
limitNo
noiseNoinclude
sinceNo
untilNo
redactNo
sessionNo
categoryNo
confirmedNoinclude
project_dirNo
reaction_windowNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden, and it delivers: discloses deterministic dictionaries (no LLM), false-positive potential (echo "rm -rf /"), redaction behavior, is_error null when no correlated outcome, count/truncated semantics, diagnostics on empty results, and the error contract. This is exemplary transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but dense and front-loaded with the purpose in the first sentence. It is organized into logical paragraphs (purpose/mechanism, filters, output, caveats, wrapper). A 5 would require tighter structure (e.g., bullets), but every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 11 parameters, no annotations, and no schema descriptions, the description is remarkably complete. It covers output fields (id, patterns, categories, command fragment, is_error, confirmed, reaction, count, confirmed_count, by_pattern, truncated, diagnostics), cross-references to query/read_session, and error handling. Nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description compensates by explaining every parameter with semantics: filters (agent, session, since/until, category, confirmed, noise, project_dir), limit default/cap, redact masking, reaction_window default, and category 'unknown values fail loud'. This fully covers all 11 parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Dangerous shell commands + regret reactions' and states the one-call question: 'where did an agent run something destructive — and did it then apologise?'. This is a specific verb+resource scope and clearly distinguishes it from raw query or tool-call siblings by framing it as a preset over the core.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clear context is provided: 'One call answers...' and the internal mechanism (one query scan, dictionaries, reaction_window) helps the agent decide when to use it. However, it does not explicitly state when not to use it or name alternative sibling tools, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_sessionsA

List discoverable sessions, optionally filtered by agent.

Results are sorted by date (newest first) and paginated with limit/offset so the payload stays small. The default limit guards against dumping an unbounded number of sessions.

Each summary carries kind ("agent" for a top-level session, "subagent" for a spawned subagent/sidechain) and parent_uuid (the parent session's uuid for subagents, else None). Subagent detection covers Claude, OpenCode, Codex and Pi; Antigravity's format has no parent signal, so it always reports kind="agent".

Each summary also carries the F1.4 origin fields, None when the source format has no signal (never fabricated):

  • project_dir — the project directory the session ran in (Claude: transcript cwd / Desktop metadata / verified slug decode; Codex: session_meta.cwd; OpenCode: session.directory; Pi: header cwd; Antigravity: no signal).

  • launch_surface — where the session was driven from (Claude: "claude-cli" | "claude-desktop"; Codex: the raw originator, e.g. "codex_vscode"; Antigravity: "antigravity-ide" | "antigravity-cli"; OpenCode/Pi: no signal).

Each summary also carries models — the unique model ids observed in the session, in order of first appearance (Claude: assistant message.model; Codex: turn_context.model; OpenCode: message.data.modelID; Pi: assistant message.model; Antigravity records no model signal). [] when the format carries no signal — honest absence, never fabricated.

Each summary also carries the A3 recency signal, measured against a single wall-clock now sampled once for the whole call:

  • last_activity — the last-activity timestamp as an explicit ISO string (same instant as date; date is kept for backward compatibility);

  • age_sec — whole seconds since last_activity (clamped at 0 when a future timestamp implies writer/reader clock skew);

  • activity"fresh" if age_sec is at or under the AI_R_STALL_SEC threshold (default 600 s = 10 min), "stale" if past it.

Honest contract (F1.1): activity describes only the recency of the last written record. It is not a claim about process liveness — a session file cannot show whether its producer is still running. "Running but silent" vs. "crashed" is a consumer-side inference (correlate activity == "stale" with an OS pid-alive check); ai-r does not fabricate it.

Args: agent: One of claude, codex, opencode, antigravity, pi. When omitted, every supported agent is queried. limit: Max sessions in this page. 0 means no cap (use with care: may return a very large payload). Defaults to 100. offset: Zero-based index of the first session to return. Use with limit to page through total. kind: Optional filter. "agent" returns only top-level sessions, "subagent" returns only subagent sessions. When omitted (default), both kinds are returned. noise: Noise filter — a session is noise when it is a spawned subagent (kind == "subagent" or parent_uuid set). "include" (default) returns everything, "exclude" drops noise sessions, "only" returns only noise sessions. kind and noise compose (AND). project_dir: Keep only sessions whose project_dir equals this path or is a descendant of it (path-boundary aware: /a/b matches /a/b and /a/b/sub, never /a/bc); trailing slashes ignored. Sessions without a project_dir signal never match. Composes with the other filters (AND). redact: When True (default) secrets in emitted title / extra values are masked as [REDACTED_<TYPE>] and the response carries a redactions type→count dict when any replacement happened; False returns raw titles.

Returns: {"sessions": [...], "total": int, "offset": int, "limit": int, "truncated": bool}. total is the full count matching the agent (and kind/noise) filter; truncated is True when more sessions remain beyond this page. When total == 0 the dict additionally carries diagnostics (scanned agents + session counts, source-dir presence, cause hints) so an empty inventory is explainable.

ParametersJSON Schema
NameRequiredDescriptionDefault
kindNo
agentNo
limitNo
noiseNoinclude
offsetNo
redactNo
project_dirNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full responsibility. It is exceptionally transparent: explains sorting and pagination, subagent detection per source, origin field mappings, recency semantics with clock-skew handling, redaction behavior, and the 'honest contract' warning about liveness. This goes far beyond basic expectations and discloses caveats clearly.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Though the description is long, it is densely informative. It front-loads the core purpose, then systematically details behavior, parameters, and return contract. Each section adds value; there is no filler or tautology. The structure with Args/Returns mirrors schema for easy scanning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is complete for a tool of this complexity. It covers all 7 parameters, return fields with edge cases (truncated, diagnostics), cross-source format differences, and even the liveness caveat. The existing output schema is enriched with semantic explanations, and the description leaves no critical gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema has 0% description coverage, but the description compensates fully. Every parameter is explained with semantic detail: agent values, limit=0 meaning no cap, offset pagination, kind/noise composition, project_dir path-boundary awareness, and redaction behavior. This adds significant meaning beyond the bare schema fields.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource combination: "List discoverable sessions, optionally filtered by agent." It clearly identifies the tool's scope (listing discoverable sessions) and differentiates from siblings by emphasizing enumeration and discoverability rather than search or detailed read operations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for how to use the tool (filters, pagination, defaults) but does not explicitly name alternatives or state when not to use it. Sibling tools like search_sessions exist, but the description never contrasts this listing tool against them. Use-cases are implied rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

locateA

Find a session across all agents by uuid / id-prefix / title — locate.

One call answers "I remember a session — where does it live and how do I read it?". needle is a full uuid, an id prefix (e.g. the 8-hex head), or a case-insensitive title substring. A thin preset over the existing per-parser inventory (the same list_sessions walk — zero new scanning code) with a deterministic algorithm inside: prefix-match on uuid/path-stem OR substring-match on title, ranked by last activity (mtime) descending. Each match carries where it lives (path / agent / project_dir / date / size_bytes), the honest local-content claim readable (false for a reference-only stub whose transcript is not on this machine), and the ready-to-run commands: read_command (ai-r read <uuid> --agent <agent>) + resume_command (F2.2 — text only, never executed).

limit bounds the emitted list (0 = no cap; count keeps the full total, truncated flags the cut). Zero matches → an honest empty with closest-title suggestions + diagnostics — never a fabricated match.

web=true (v1, honest scope) adds web sessions KNOWN LOCALLY only: materialized hook-export files ($SW_HOME/web-sessions, default ~/.session-watch/web-sessions) and ~/.claude.json → projects[*].lastSessionId teleport stubs (id known, transcript NOT local — content_local: false). The fuller per-repo teleport-picker sweep needs a PTY and is a documented follow-up, not guessed here.

Thin wrapper over :func:ai_r.locate.locate (ValueError{"error": "invalid_argument"}).

ParametersJSON Schema
NameRequiredDescriptionDefault
webNo
agentNo
limitNo
needleYes
redactNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full transparency burden and exceeds expectations. It discloses the deterministic matching algorithm, ranking by last activity, the exact match fields (path, agent, project_dir, date, size_bytes), the honest 'readable' flag, the non-executed resume_command, limit/count/truncated behavior, zero-match suggestions instead of fabricated results, web=true's "honest scope", and the ValueError-to-error mapping.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but every sentence adds value: algorithm, result fields, command generation, limit semantics, empty-result behavior, web scope, and error mapping. It is front-loaded with the core purpose and then systematically expands into necessary edge-case detail without fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter tool with no annotations and no schema descriptions, the description is remarkably complete. It covers search semantics, result structure, command generation, output limiting, zero-match handling, web mode limitations, and exception mapping. The only minor omission is the semantics of 'agent' and 'redact', but the overall context is sufficient for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description richly explains needle (full uuid, id-prefix, case-insensitive title substring), limit (0 = no cap, count/truncated flags), and web (local-only known entries, hook files, teleport stubs with content_local). However, 'agent' and 'redact' parameters are not explained anywhere, leaving a clear gap despite the otherwise strong compensation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening line states the tool's exact purpose: "Find a session across all agents by uuid / id-prefix / title". It distinguishes itself from siblings like list_sessions and read_session by promising to answer where a session lives and how to read it, while returning ready-to-run commands.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description frames the core use case: "I remember a session — where does it live and how do I read it?". It explicitly positions the tool as a preset over the existing list_sessions walk and clarifies current limitations (e.g., the fuller teleport-picker sweep requires a PTY and is a documented follow-up), providing clear when-to-use and scope boundaries.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

networkA

Network-egress audit — the network preset (F4.3).

One call answers "where did an agent reach out to the network — and how risky did those requests look?". A preset over the existing core, not a second engine: ONE query scan (type="tool_call", tool_kind="web") supplies the candidates — Claude WebFetch/WebSearch, OpenCode webfetch, Codex web_search (surfaced from web_search_call rollout records), Gemini/Antigravity web_fetch/google_web_search; Pi records no web tool (honest absence). The request target (url/query) is extracted from each call's own input and assessed with a deterministic risk dictionary: plain_http, credentials_in_url, secret_in_url / secret_in_query (the redaction patterns double as the detector), ip_literal_host, private_or_local_host, punycode_host. Zero LLM, zero guessing: no extractable target → honest null fields; a risk fires only on parse/regex evidence.

Filters (all parameters): agent, session (uuid or list of uuids), since/until (ISO bounds on the call ts), kind (fetch|search — derived from the extracted fields, unknown values fail loud), risk (include default | only | exclude), domain (host equals-or-subdomain match), noise and project_dir (session-level, same semantics as query).

Each request record carries the query event id (walk its context via query(relative_to=...) / read_session), the derived kind, char-capped url/query (token budget — full context stays on-demand), domain, the risks labels and tri-state is_error (null when the agent's format has no correlated outcome signal — honest, cross-agent). count/risky_count/ by_domain/by_risk always reflect the FULL match set; limit (default 50, 0 = no cap) bounds only the emitted records (truncated).

Honesty caveats (documented, not hidden): risk labels are a deterministic dictionary, not a threat oracle; MCP-mediated network access (browser-automation servers etc.) stays under tool_kind="mcp" — a name alone cannot prove an MCP server touches the network, so it is never guessed into this audit. Risk assessment runs on the RAW stored strings; redact=true (default) masks secrets only in the emitted url/query/session_title fields (redactions type→count dict when anything was masked). When count == 0 the response carries diagnostics so an empty result is explainable.

Thin wrapper over :func:ai_r.network.network that translates the core ValueError contract into the {"error": "invalid_argument", "message": str(exc)} shape the MCP client expects.

ParametersJSON Schema
NameRequiredDescriptionDefault
kindNo
riskNoinclude
agentNo
limitNo
noiseNoinclude
sinceNo
untilNo
domainNo
redactNo
sessionNo
project_dirNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It exhaustively details the deterministic risk dictionary, the zero-LLM/zero-guessing policy, the handling of missing targets (null fields), risk firing only on parse/regex evidence, the redact behavior, limit bounds with truncated flag, tri-state is_error semantics, and the error contract mapping. Honesty caveats are explicitly documented, such as risk labels not being a threat oracle.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but every sentence earns its place for an 11-parameter audit tool. It is front-loaded with a clear one-sentence summary, then structured into how it works, filters, output, and honesty caveats. No filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (11 parameters, 0% schema description coverage, no annotations) and the presence of an output schema, the description is remarkably complete. It covers the full output shape (count, risky_count, by_domain, by_risk, truncated, diagnostics), edge cases (empty results, missing targets), and error handling. An agent has everything needed to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description adds meaningful semantics for every parameter: agent, session (uuid or list), since/until (ISO bounds on call ts), kind (fetch|search with fail-loud on unknown values), risk (include only/exclude), domain (equals-or-subdomain match), noise and project_dir (session-level semantics), limit (default 50, 0 = no cap), and redact. This goes far beyond the raw schema types and defaults.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool performs a Network-egress audit, answering 'where did an agent reach out to the network — and how risky did those requests look?'. It distinguishes itself from siblings by explaining it is a preset over the existing core (not a second engine) and focuses specifically on web tool calls (WebFetch, WebSearch, webfetch, web_search, etc.).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit when-to-use context: one call answers network egress and risk. It also gives clear when-not-to-use guidance, noting MCP-mediated network access stays under tool_kind='mcp' and is never guessed into this audit, and that Pi records no web tool (honest absence). It references query/read_session for walking context, effectively suggesting alternatives for further investigation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

planA

Normalized plan atoms for a session — final vs drafts, grouped by task.

Wraps query(type="plan_event", …) and normalizes every agent's plan signal (Claude ExitPlanMode / Write plans/*.md, Codex update_plan, Antigravity implementation_plan.md) into a single :class:~ai_r.events.Plan shape — the per-agent signal is an internal detail, never surfaced.

Plans are grouped by task keyed on each plan's task_key — the plan-file slug when the agent has one (Claude plans/<slug>.md, Antigravity implementation_plan.md path), falling back to the normalized title only when no plan file exists (Codex update_plan). Within a task the latest plan is final and earlier revisions are draft; plans of earlier completed tasks are completed_major.

F3.4 default schema (measured ≈×3.7 cheaper than "everything inlined"): the final plan's full text is inlined (body + body_source"approval_edited_by_user" when the user's approval carried an edited plan, which is the AUTHORITATIVE text and overrides the signal/file body, else "plan_signal"); drafts stay references (bodies via get_body); every «plan quote → user comment» pair extracted from the user's plan responses is returned under feedback, each with a ref ("<session>:pf<N>") that get_body resolves to the FULL raw response. Only agents with an interactive plan-approval flow have the feedback signal (today: Claude — an ExitPlanMode verdict or a rejected plan-file Write); others honestly contribute nothing. Technical failures and bare no-comment rejections are filtered out.

F3.4 v2 additions: every plan atom carries version — its 1-based revision number within the task group, chronological (drafts are v1…vN-1, the final is vN); every feedback pair carries plan_version (the answered revision's number), round (1-based feedback-round number within the session — one round per user response that produced pairs) and section — the heading of the plan section the quote anchors to. Quotes are selected from the RENDERED plan, so the anchor match strips markdown markup from both sides; a quote that matches no section — or more than one — gets an honest null anchor, never a nearest guess.

Args: session: Restrict to one session uuid (recommended). kind: Optional filter — draft | final | completed_major. group: Grouping strategy; only "task" is supported. agent: Optional agent filter (claude/codex/opencode/antigravity/pi). redact: When True (default) secrets in the emitted plan/feedback fields (title/steps/body/quote/comment…) are masked as [REDACTED_<TYPE>] and the response carries a redactions type→count dict when any replacement happened; False returns raw content. bodies: "final" (default) inlines the final plan's full text; "none" returns reference-only atoms. feedback: True (default) adds the feedback pair list + feedback_count; False omits both (historical shape). rounds: "all" (default) returns every feedback round; "last" keeps only each session's final round (v2). Any other value fails loud.

Returns: {"plans": [...], "count": N, "feedback": [...], "feedback_count": M} — each plan carries id/session_id/agent/title/task_id/kind/version/path/steps/status/ refs/sha256 (+ body/body_source on the final when bodies="final"); each feedback pair carries session_id/agent/plan_id/plan_version/verdict/round/quote/comment/ section/ref/ts (verdictrejected | stay_in_plan_mode; quote is null for a free-text comment; plan_version/ section are null without a signal). Draft bodies and raw responses stay on-demand via :func:get_body. Standard {"error": ..., "message": ...} dict on invalid arguments.

ParametersJSON Schema
NameRequiredDescriptionDefault
kindNo
agentNo
groupNotask
bodiesNofinal
redactNo
roundsNoall
sessionNo
feedbackNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully discloses behavioral traits: normalization of signals from different agents, grouping logic, versioning, redaction defaults, filtering of technical failures, and the precise semantics of feedback anchors ('never a nearest guess'). It also explains what output to expect and how parameters change behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but exceptionally well-structured: an introductory summary, followed by detailed schema explanations, then parameter and return specifications. Every sentence adds substantive information, and the structure makes it easy to navigate. It is front-loaded with the core purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 8 parameters, an output schema, and complex normalization logic, the description is exhaustive. It covers all input options, output structure, edge cases, and internal behaviors, leaving no ambiguity. The presence of an output schema doesn't reduce the need for this detail, and the description provides it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the full burden. The 'Args' section explains every parameter (session, kind, group, agent, redact, bodies, feedback, rounds) with defaults, allowed values, and behavioral effects, fully compensating for the bare schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states the exact function: 'Normalized plan atoms for a session — final vs drafts, grouped by task.' It clearly identifies the resource (plan events) and the action (normalization), and distinguishes itself from siblings like get_body (draft bodies on demand) and query (the underlying raw call).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use it (to get normalized plan data grouped by task) and references alternatives: it 'wraps query(type=...)' and notes that 'Draft bodies and raw responses stay on-demand via get_body.' It also provides parameter-level guidance (e.g., 'session: Restrict to one session uuid (recommended)') and explains the behavior of edge cases like 'rounds' failing loud.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

queryA

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:

  • typeuser_turn | assistant_turn | tool_call | tool_call(edit|write|read|bash|other) | plan_event. Bare tool_call matches 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 a search_sessions / list_sessions result). Duplicates collapse; an unknown uuid contributes nothing. An empty list or a non-string item is a fail-loud invalid_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) — so tool="commit" also finds the Skill call that ran the commit skill.

  • tool_kind — exact match against the wrapper-aware classification of a tool call: edit / write / read / bash / task (subagent spawn) / skill / mcp / web / other. Every tool_call event carries tool_kind (in refs and as a top-level field); wrappers whose input names the real actor also carry tool_resolved — the subagent type under Task/Agent/ spawn_agent, the skill name under Skill/SlashCommand, or "<server>:<tool>" for a Claude-style mcp__<server>__<tool> call. No signal → no tool_resolved (never guessed). An unknown tool_kind value is a fail-loud invalid_argument.

  • model — exact, case-insensitive match against the model that produced the event's message: an assistant_turn / tool_call / plan_event inherits the model of the assistant message behind it and carries it as a top-level model field (absent without a signal — user turns, Antigravity — so aggregate(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-loud invalid_argument.

  • user_ref — filter user_turn events 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 combining user_ref with a non-user_turn type yields an honest empty result.

  • has_thinking — filter by whether the event's message carried model reasoning (Event.has_thinking). True keeps only events with reasoning, False only those without; unset (None, default) does not filter. Note the reasoning text itself is never inlined — this only gates on its presence (fetch it with get_body(id, include_thinking=True)).

  • text — substring matched against event text. With sort="relevance" survivors are BM25-ranked using the same scorer as search_sessions; sort="semantic" (F5.1, optional ai-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 a semantic dict reporting either the active ranking (active: true, model, candidate count, blend weight) or the honest degradation (active: false + plain-words reason + 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, default 1, 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 the previous_user_intent used by find_file_edits to both directions and any count. step_type chooses which event type to collect (default user_turn). When relative_to is 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.

ParametersJSON Schema
NameRequiredDescriptionDefault
nNo
fileNo
kindNo
sortNodate
textNo
toolNo
typeNo
agentNo
groupNo
limitNo
modelNo
noiseNoinclude
sinceNo
untilNo
parentNo
redactNo
sessionNo
user_refNo
directionNoprev
step_typeNouser_turn
tool_kindNo
project_dirNo
relative_toNo
with_intentNo
has_thinkingNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and excels: it discloses fail-loud invalid_argument cases, relative_to ignoring other facets, emission-time redaction, ~160-char preview truncation, semantic search degradation with fallback, and diagnostics on empty results. This level of edge-case disclosure is exceptional.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with bold facet names and a front-loaded purpose, but it is verbose and repeats phrases like 'honest empty result' and 'Ignored on the relative_to walk, like every other filter facet' multiple times. The length is mostly justified by 25 parameters and zero schema descriptions, but tighter editing would improve it.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's high complexity, no annotations, and zero schema descriptions, this description is remarkably complete. It covers all parameters, return shapes, error behavior, redaction, truncation, filtering precedence, and corner cases, leaving little to guess.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the description fully compensates by explaining every facet: type values, session union semantics, tool/tool_kind/tool_resolved matching, model inheritance, user_ref special values, has_thinking gating, sort modes, relative_to walk, noise/project_dir/parent filters, group, redact, and the kind tombstone. It adds far more meaning than the sparse schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource: 'Filter/search the unified session **event** stream', and immediately clarifies the normalized event types. It differentiates from siblings by positioning itself as the event-stream workhorse and referencing related tools like search_sessions and find_file_edits, making the scope clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides clear context: this is the primary tool for filtering/searching the unified event stream, 'all behaviour is parameters, never hard-wired variants', and it mentions related tools like search_sessions and find_file_edits for shared concepts. However, it never explicitly states when to use this tool versus a sibling, nor lists exclusions or alternatives, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

quotesA

User quotes of prior in-session content — the quotes preset.

One call answers "where did the user quote something the agent said, and what did they say about it?". When a user selects a chunk of a prior message and comments on it (the "attach selection as context" flow), the quoted text is embedded VERBATIM in their turn — no agent records it as a structured field — so it is recovered by matching the user turn against the text before it. A preset over the existing core, not a second engine: query scans supply user turns + assistant turns, the reviewed text is normalized (_normalize_rendered_text, reused from the plan-feedback anchorer) and :func:difflib.SequenceMatcher finds the longest verbatim run; a run below the minimum is not a quote (honest null), and text pasted from OUTSIDE the session matches nothing (never fabricated).

This is the cross-agent, chat-wide generalization of plan(feedback) (which surfaces «plan quote → user comment» only for Claude's plan-approval flow): quotes surfaces «any prior message quote → user comment» for every agent, operating on the normalized event stream, not client markup.

Filters (all parameters): agent, session (uuid or list), since/until (ISO bounds on the user turn's ts), source_kind (currently assistant — a user quoting the agent's prose; unknown values fail loud), noise and project_dir (session-level, same as query).

Each record carries the user_turn event id (context on-demand via query(relative_to=...)), source_id (the quoted assistant turn), source_kind, quote_chars, and the char-capped quote + comment (the user's turn with the quote elided). count/by_source_kind reflect the FULL matched set; limit (default 50, 0 = no cap) bounds only the emitted records (truncated).

Caveat (documented): v1 sources are assistant prose (the common case — quoting a tool's raw output is a future extension); the emitted quote/comment come from the NORMALIZED text (markdown stripped), so they are readable but not byte-identical to the raw turn (raw bodies stay reachable via the event ids). redact=true (default) masks secrets only in the emitted session_title/quote/comment. When count == 0 the response carries diagnostics so an empty result is explainable.

Thin wrapper over :func:ai_r.quotes.quotes that translates the core ValueError contract into the {"error": "invalid_argument", "message": str(exc)} shape the MCP client expects.

ParametersJSON Schema
NameRequiredDescriptionDefault
agentNo
limitNo
noiseNoinclude
sinceNo
untilNo
redactNo
sessionNo
project_dirNo
source_kindNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and excels. It discloses the matching mechanism (normalization + SequenceMatcher), the honest null for runs below minimum, the no-fabrication guarantee, normalization caveats (markdown stripped, not byte-identical), redact behavior, limit/truncation semantics, and diagnostics on empty results.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Though lengthy, the description is front-loaded with the core purpose and every sentence adds essential operational detail. It is well-structured into focused paragraphs covering filters, output records, caveats, and error contract—no filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (9 params, no annotations, rich output schema), the description is remarkably complete. It documents all filters, result fields, output behaviors (count, limit, truncated), edge cases (count == 0 diagnostics), and the error translation to invalid_argument, leaving no major usage gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must fully compensate, and it does. Every parameter is explained with syntax and semantics: session accepts uuid or list, since/until are ISO bounds on user turn timestamp, noise and project_dir mirror query, source_kind values fail loud, limit default 50 with 0 meaning no cap, and redact defaults to true masking secrets.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource statement: 'User quotes of prior in-session content' and immediately answers the exact question the tool resolves. It explicitly distinguishes itself from sibling tools like plan(feedback), emphasizing it is the cross-agent generalization covering 'any prior message quote → user comment.'

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides direct when-to-use guidance: 'One call answers "where did the user quote something the agent said..."' and contrasts it with plan(feedback), which only covers Claude's plan-approval flow. It also gives clear parameter-driven usage context, such as source_kind currently only supporting assistant prose and failing loud on unknown values.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_sessionA

Read a single session by uuid; agent is an optional hint.

Args: uuid: Session identifier. agent: One of claude, codex, opencode, antigravity, pi. Optional: when omitted, the uuid is looked up across every parser (session ids are unique across agents in practice). If — rarely — the same id exists under several agents, a candidates list is returned (not an error) so the caller can re-ask with an explicit agent. offset: Zero-based index of the first message to return (applied to the projected {role, content} list). limit: Maximum number of messages to return. Defaults to :data:_MESSAGES_CAP (100). A non-positive value means "no upper bound". redact: When True (default) secrets in the emitted title, message content/intent/qa are masked as [REDACTED_<TYPE>] and the response carries a redactions type→count dict when any replacement happened (see ai_r.redact); False returns the raw content. with_tokens: When True (F3.3) attach token usage read at request time (nothing runs in the background):

    * ``summary["tokens"]`` — the session's flat
      :func:`ai_r.tokens.session_tokens` block (exact where the agent
      records usage, a labeled estimate otherwise, honest
      ``source=None`` without any signal);
    * ``summary["component_tokens"]`` — the
      :func:`ai_r.tokens.component_tokens` breakdown: the transcript's
      estimated token volume split across ai-r's event taxonomy
      (``user_turn`` / ``assistant_turn`` / ``thinking`` / ``plan``
      and a ``tool_call`` per-``tool_kind`` sub-dict), always
      ``source="estimate"`` (never merged with the exact tier),
      ``None`` on an empty transcript;
    * per-message ``tokens`` on projected entries that carry exact
      usage — Claude (deduplicated per streamed API call), OpenCode
      and Pi.  Codex / Antigravity / user turns carry **no**
      ``tokens`` key at all (absent, not ``null``).  The dedup/attach
      is decided on absolute message positions BEFORE pagination, so
      page boundaries never shift which record is "first" for a call.

    Default ``False``: output is byte-identical to the historical
    shape (no ``tokens`` / ``component_tokens`` key on the summary or
    any message).  The token blocks carry only integers and
    ai-r-authored labels (never raw session text), so they stay
    outside the F2.1 redaction pass by construction.
include_subagents: When ``True`` attach
    ``summary["subagent_rollup"]`` — the parent session's
    ``component_tokens`` block plus one per spawned subagent child
    (resolved via :func:`ai_r.session_stats.children_of` on
    ``parent_uuid``) and a ``total`` folding parent + children through
    the ``aggregate`` ``component_tokens`` metric.  Each child entry
    carries ``uuid`` / ``agent`` / ``component_tokens`` (the estimate)
    plus **what it actually cost**: ``tokens`` read from the child's own
    transcript on the honest three-tier ``source`` ladder — billed
    ``"exact"`` where the child's transcript records usage, a labeled
    ``"estimate"`` where it does not (a truncated / reference-only run),
    ``source=None`` without any signal (never a fabricated zero) —
    ``models`` (the model(s) it ran on — a persona pinned to a cheaper
    tier shows up here), ``subagent_type`` (its persona, from the
    child's own spawn metadata, falling back to the spawning call's
    sidecar) and ``status`` where the spawn recorded one
    (``"async_launched"`` for a background spawn).  A childless parent
    (or an agent like Antigravity that never records ``parent_uuid``)
    yields an empty ``children`` list and a ``total`` equal to the
    parent's own block — honest, not an error.  Independent of
    ``with_tokens``.  Default ``False``.
include_thinking: When ``True`` attach the model's reasoning
    (``message.thinking``) as a separate ``thinking`` string field on
    each projected message that carried it — kept OUT of ``content``
    so the historical text projection is unchanged.  Default
    ``False``: output is byte-identical to the historical shape (no
    ``thinking`` key on any message).  Reasoning is opt-in to save the
    caller's budget; ``Event.has_thinking`` / the presence of the key
    signals which messages have it.  Fail-soft: a message without
    reasoning never carries the key.

Returns: A dict with session metadata plus:

* ``messages`` — the projected ``{role, content}`` list, sliced
  to ``[offset:offset+limit]``.
* ``total`` — the full uncapped projected message count (the
  length the slice was taken from).
* ``offset`` / ``limit`` — the pagination echo values actually
  used.
* ``messages_truncated`` — True when the MCP hard cap stopped
  extraction before every projected message could be returned.
* ``outcome`` — session outcome classification (F2.3):
  ``{status: success|failure|mixed|unknown, signals, user_verdict,
  markers, tool_results, tool_errors, error_rate,
  error_rate_reliable}``.  ``status`` combines the tool-call
  error rate (real flag only for Claude/OpenCode —
  ``None`` elsewhere, never guessed) with a calibrated bilingual
  success/failure dictionary over the tail user turns;
  ``"unknown"`` when neither signal exists (SSOT
  :mod:`ai_r.outcome`).

On an id collision (agent omitted, several agents own the id):
``{"ambiguous": True, "uuid": ..., "candidates": [...],
"count": N, "message": ...}`` where each candidate is a session
summary carrying its ``agent``.

On a missing session, returns an ``error`` dict instead of
raising (``agents_scanned`` lists the parsers probed when the
agent was omitted).
ParametersJSON Schema
NameRequiredDescriptionDefault
uuidYes
agentNo
limitNo
offsetNo
redactNo
with_tokensNo
include_thinkingNo
include_subagentsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are present, so the description fully documents behavior. It covers pagination, redaction, token estimation, subagent rollup, thinking inclusion, and edge cases such as ambiguous ids returning candidates and missing sessions returning an error dict. This is transparent, honest disclosure of side effects and return shapes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The text is lengthy but structured: a one-line summary, then Args, Returns, and edge cases. Each section is purposeful, though some explanations (e.g., the detailed token source ladder) could be condensed without losing essential meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (8 parameters, no annotations, rich return structure), the description covers every parameter, details all return fields, and handles edge cases. It is a self-contained reference for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With an input schema that has 0% description coverage, this description thoroughly explains each parameter: uuid, agent, offset, limit, redact, with_tokens, include_subagents, include_thinking, including defaults and interactions. It fully compensates for the schema's lack of detail.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Read a single session by uuid', a specific verb and resource. It clearly differentiates from siblings like list_sessions and search_sessions by focusing on a single session identifier.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clear context is provided: use this tool with a known uuid, and optionally disambiguate with agent. The description explains what happens when agent is omitted and how to handle collisions. It does not explicitly mention alternative tools, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_sessionsA

Case-insensitive search across sessions.

Args: query: Search string. Supports: * Bare words: pwa manifest (AND default) * Quoted phrases: "exact phrase" * Negative prefix: -claude (Google-style, always excluded) agent: Optional agent filter (claude/codex/opencode/antigravity/pi). scope: Where to look. * "title" — only session.title (default, backward-compat) * "body" — message text + tool_use[*].input + tool_result[*].content * "all" — title OR body operator: How to combine positive terms. * "AND" — all positive terms must appear (default) * "OR" — at least one positive term must appear * "NOT" — no term (positive or negative) may appear Negative -term prefixes are always excluded regardless of operator. limit: Maximum number of results. 0 or negative = no limit. Applied after sorting, so it keeps the top-ranked matches. sort: Result ordering. * "relevance" — BM25 relevance over the matched text (default). Pure-stdlib scoring; ties keep newest-first. * "date" — newest-first by session date (the historical pre-ranking order). * "semantic" — F5.1 (optional ai-r[semantic]): the BM25 top-50 candidates re-ranked by meaning with a local multilingual embedding model (cross-lingual ru↔en, synonyms); the response carries a semantic dict — either the active ranking (active: true, model, candidate count, blend weight) or the honest degradation notice (active: false + plain-words reason + fallback: "bm25", order stays BM25 — never a crash). noise: Noise filter — a session is noise when it is a spawned subagent (kind == "subagent" or parent_uuid set). * "include" — no filtering (default). * "exclude" — search only top-level agent sessions. * "only" — search only subagent sessions. Applied before matching, so excluded sessions never pay the body-scan cost. redact: When True (default) secrets in the emitted title / snippet / extra fields are masked as [REDACTED_<TYPE>] and the response carries a redactions type→count dict when any replacement happened; False returns raw content. Matching always runs on the RAW stored text, so searching for a literal secret still finds its session — only the displayed snippet is masked. include_thinking: When True fold model reasoning (message.thinking) into the body/all search haystack so a search matches text that lives only in the model's thoughts. Default False: reasoning is excluded from matching to save the caller's budget (turn it on only when a query must reach into reasoning). No effect on scope="title". The two modes are cached under separate keys, so toggling never serves a stale haystack of the other mode.

Returns: A dict {"results": [...], "count": N} where results is the list of session summaries and count is their total. When scope is "body" or "all" and a match is found, each summary includes a "snippet" field with the first matching message excerpt (up to 200 chars) and may carry body_truncated. When a scan matches nothing (count == 0), the dict additionally carries diagnostics (scanned agents + session counts, corpus date bounds, cause hints) so an empty result is explainable. With sort="semantic" the dict also carries a semantic report (active ranking vs BM25 fallback + reason).

Errors are returned as a top-level {"error": ..., "message": ...} dict (matches the existing convention).

ParametersJSON Schema
NameRequiredDescriptionDefault
sortNorelevance
agentNo
limitNo
noiseNoinclude
queryYes
scopeNotitle
redactNo
operatorNoAND
include_thinkingNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully carries the transparency burden and does so excellently. It discloses case-insensitivity, search operators, negative-prefix behavior, noise filter semantics, redaction that still allows raw matching, include_thinking budget implications, caching behavior, and honest degradation for semantic sort. It even documents error return format. Exceptionally transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long, but it's a complex tool with 9 parameters and subtle behaviors. It is well-structured: opening line, Args block, Returns block, Errors note. Every sentence adds necessary detail; no filler. Slightly verbose for a quick read, but appropriate given the tool's complexity, so not a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is complete for a complex search tool. It defines the result dict, count, snippet field, body_truncated, diagnostics on empty results, and the semantic report. It covers edge cases, fallback behavior, and error convention. No critical behavioral aspect is left unexplained. Given the tool's complexity, this is fully complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has 0% description coverage, and the description thoroughly compensates. Every one of the 9 parameters is explained beyond type alone: query supports special syntax (quoted phrases, negative prefix), scope enumerates options with examples, operator explains AND/OR/NOT and negative-term interplay, limit describes post-sort application, sort details BM25 vs date vs semantic with fallback, noise defines 'noise' precisely, redact explains masking and raw-search behavior, include_thinking covers haystack modes and caching. This is exemplary parameter documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opening line is clear: 'Case-insensitive search across sessions.' Specific verb+resource. Does not explicitly differentiate from siblings like list_sessions or query, but the search semantics are apparent. Loses one point for not naming alternatives, but purpose itself is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool vs siblings. Does not mention list_sessions, query, find_tool_calls, etc., or provide any exclusionary context. The detailed Args section explains how to configure the search, but not when the tool should be preferred. Thus, only implied usage, no explicit decision framework.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

session_diffA

Reconstruct what the agent changed in one session — without git.

Stitches the session's own edit records (Edit/MultiEdit old_stringnew_string, Write content, codex shell-exec redirections) into a per-file, chronological diff. Returns {"files": [...], "count": N, "caveats": [...]}; each file carries its ordered edits (timestamp + intent + hunks) and a stitched, readable diff.

caveats always carries two honest blind spots: (1) this is a diff of the agent's actions, not the git outcome — manual edits / partial commits / merges are invisible; (2) RISK-3 — inherits the find_file_edits shell-redirect gap (tee / sed -i / cp / mv / heredoc writes are not detected and are silently skipped).

redact=True (default) masks secrets in the emitted diff/hunks/ intents as [REDACTED_<TYPE>] and adds a redactions type→count dict when any replacement happened; redact=False returns raw.

Size-bounded output (mirrors find_file_edits): over-long intent / hunk bodies / per-file diff text are cut with a …[truncated] marker and named in the per-file truncated_fields (indexed paths), and whole-file emission stops at a total byte budget (output_truncated; count keeps the true total). The full edit body stays reachable on demand via get_body / read_session.

Thin wrapper over :func:ai_r.session_diff.session_diff that translates the core ValueError contract into the {"error": "invalid_argument", "message": str(exc)} shape the MCP client expects.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathNo
agentYes
redactNo
session_uuidYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description fully carries the behavioral disclosure burden. It explicitly states two blind spots (actions vs. git outcome, and shell-redirect gap vulnerability), describes redaction behavior with redact=True/False, explains truncation and byte budgets (output_truncated, truncated_fields), and details error-shape translation. This is exceptionally transparent for a tool with zero annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and clearly structured across paragraphs. It contains a moderate amount of detail—caveats, redaction, truncation, error handling—but every sentence contributes useful information. It is not overly terse nor bloated, though it is longer than strictly necessary.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite an output schema being present, the description goes beyond and explains the return shape, caveats, truncation, redaction, and error handling. It is comprehensive for a complex tool. The only notable omission is the meaning of 'path', but the overall context and references to sibling tools make the tool's behavior clear enough for selection.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate for all four parameters. It only explicitly explains redact (default true, masks secrets). session_uuid and agent are inferable from names but not described, and path is not addressed at all despite being an optional parameter. The description does not provide semantics for a quarter of the parameters, leaving a significant gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource+scope: 'Reconstruct *what the agent changed* in one session — without git.' It clearly differentiates from siblings by mentioning find_file_edits, get_body, and read_session, and by emphasizing it builds a per-file chronological diff from edit records, not a git diff.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when this tool is appropriate: when you need a diff of the agent's actions without git, and it explicitly warns that manual edits, partial commits, and merges are invisible. It names alternatives for getting full edit bodies (get_body/read_session) and references find_file_edits for shell-redirect gaps, but it does not explicitly say 'use this instead of X' in a comparative form.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

session_statsA

Summarise sessions, grouped and ranked — the bird's-eye audit view.

Where find_file_edits / find_tool_calls return flat record streams, this rolls the sessions themselves up by one dimension so you can see how the work is distributed in a single call.

group_by is one of:

  • "agent" (default) — claude vs codex vs opencode vs ...

  • "dir" — by working directory / project (the normalized project_dir first — one real directory = one bucket across agents — then cwd for codex/pi / project slug for claude; "(unknown)" for agents without any signal).

  • "date" — by calendar day (YYYY-MM-DD).

  • "kind" — top-level agent sessions vs spawned subagent sessions.

  • "model" — by the model that produced the session. A session that mixed models buckets as "(mixed)" rather than being attributed to one of them; one whose transcript records no model is "(unknown)". Neither is guessed. Pair with with_tokens=True to see what each model actually cost.

Each group carries its session count plus enrichment from the shared find_file_edits core: edits (file edits attributed to the group's sessions), intents (distinct requests behind those edits), the distinct agents in the group, and total messages.

RISK-4 note: subagent detection is currently Claude-only. When no subagent sessions are in scope, a group_by="kind" result shows a single agent bucket — so the result always carries kind_split_available (False here) plus a note making clear that this is NOT a verified "no subagents", just an absent split.

with_tokens=True (F3.3) additionally reads every matched session's token usage at request time (nothing runs in the background) and adds a folded tokens block to each group and to totals: {input, output, reasoning, cache_read, cache_write, total, exact, estimated, unknown}. Per session the numbers are exact where the agent's own files record usage (Claude message.usage, Codex token_count, OpenCode message.data.tokens, Pi usage); a session without a recorded signal (e.g. Antigravity) gets a transcript-volume estimate — tokenized with the optional tiktoken dependency (pip install "ai-r[tokens]") when installed, else a rough chars/4 heuristic — and counts under estimated, never silently mixed in as exact; no signal at all counts under unknown. Sums that no session carried stay null (never a fabricated 0). The block contains only ai-r-computed integers and labels — no raw session text — so it is outside the redaction surface by construction. Default False: byte-identical historical output, no extra reads.

Scan guard (token_scan_limit): because with_tokens reads every matched session's files at request time, an unscoped run over a huge corpus is a multi-hour I/O storm. When with_tokens is set with no narrowing filter (agent/since/until) and more than token_scan_limit sessions match, the call returns {"error": "scope_required", ...} (naming the count and the limit) INSTEAD of scanning — the check runs on the cheap inventory count before any file is read. Narrow the scope, or raise token_scan_limit (0 disables the cap) to force the full scan. A permitted-but-large scan runs but carries a warning.

Thin wrapper over :func:ai_r.session_stats.session_stats that translates the core ValueError contract into the {"error": "invalid_argument", "message": str(exc)} shape the MCP client expects.

ParametersJSON Schema
NameRequiredDescriptionDefault
topNo
agentNo
sinceNo
untilNo
group_byNoagent
edit_pathNo/
with_tokensNo
token_scan_limitNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden and does so thoroughly. It discloses that with_tokens reads at request time (nothing in background), explains exact vs estimate vs unknown token accounting, states that sums with no data stay null (never fabricated), notes the redaction-safe nature, and details the scan guard's error/return behavior. This is exemplary transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but every paragraph earns its place: purpose, grouping options, token behavior, scan guard, and error mapping. It is well-structured with clear headers (RISK-4 note, group_by enumeration) and uses examples. No redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 8-parameter tool with no annotations and 0% schema description coverage, this description is exceptionally complete. It explains the output group fields (edits, intents, agents, messages), token block contents, totals behavior, error shapes, and the exact wrapper contract. The existing output schema plus this description leaves a well-rounded picture.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate. It thoroughly documents group_by (all five enum values with nuances like '(mixed)' and '(unknown)'), with_tokens (including sub-fields and exact/estimate/unknown semantics), and token_scan_limit (including 0 disables cap). However, top and edit_path are not explicitly explained, though their meanings are partially inferable. The gap prevents a 5 but is still strong overall.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Summarise sessions, grouped and ranked — the bird's-eye audit view,' which uses a specific verb and resource. It explicitly contrasts with siblings (find_file_edits / find_tool_calls return flat record streams) and explains the grouping/rollup distinction, so it clearly differentiates from alternatives.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides explicit when-to-use guidance: 'Where find_file_edits / find_tool_calls return flat record streams, this rolls the sessions themselves up by one dimension.' It also gives actionable tips (e.g., 'Pair with with_tokens=True to see what each model actually cost') and warns about the scan guard, including when to narrow scope or raise token_scan_limit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 18 tool updatesv0.4.2
    • First observedaggregate
    • First observedaudit_brief
    • First observeddetect_current
    • First observeddiff
    • First observedfind_file_edits
    • First observedfind_tool_calls
    • First observedget_body
    • First observedincidents
    • First observedlist_sessions
    • First observedlocate
    • First observednetwork
    • First observedplan
    • First observedquery
    • First observedquotes
    • First observedread_session
    • First observedsearch_sessions
    • First observedsession_diff
    • First observedsession_stats

TDQS

A4.1/5.0

Scored across 18 tools

Disambiguation2/5

Multiple tools serve overlapping purposes: list_sessions, locate, and search_sessions all find sessions; query, find_file_edits, and find_tool_calls all filter events; session_stats and aggregate largely duplicate each other; session_diff and diff are nearly identical. The descriptions are detailed but the boundaries are vague, making misselection likely.

Naming Consistency3/5

The set mixes verb_noun patterns (list_sessions, read_session, find_file_edits) with bare nouns (incidents, network, quotes) and noun_noun compounds (session_stats, session_diff). While each name is readable, the inconsistent conventions and generic verbs like query and aggregate reduce predictability.

Tool Count3/5

At 18 tools, the set is heavy, but many tools are explicitly presets over a core (audit_brief, incidents, network, quotes, plan, session_diff) so the count reflects a deliberate tradeoff between convenience and atomicity. The redundancy between aggregate/session_stats and query/find_* makes it feel over-scoped, but it is within the 16-25 heavy range.

Completeness4/5

The tool set covers the full audit lifecycle: discovery (list_sessions, locate, search_sessions, detect_current), reading (read_session, get_body), event search (query, find_*), aggregation (aggregate, session_stats), and specialized presets (audit_brief, incidents, network, quotes, plan). Minor gaps exist—e.g., no bulk export or cross-session diff—but the core domain is well covered.

Maintenance

ActivitySlowing
ResponsivenessUnresponsive

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Enables AI assistants to query and analyze past Claude Code sessions, providing structured insights like file changes, decisions, errors, and git history across projects.
    11
    30
    1
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Enables search, analytics, and visualization of Claude Code sessions with MCP tools for session management, recovery, and insights.
    10
    1
    MIT