{
  "markdown": "<!-- mcp-name: io.github.pro-target/ai-r -->\n# ai-r\n\n[![CI](https://github.com/pro-target/ai-r/workflows/CI/badge.svg)](https://github.com/pro-target/ai-r/actions)\n[![coverage](https://img.shields.io/badge/coverage-92%25-brightgreen.svg)](https://github.com/pro-target/ai-r/actions)\n[![tests](https://img.shields.io/badge/tests-1300+-brightgreen.svg)](https://github.com/pro-target/ai-r/actions)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)\n[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)\n\n[English](README.md) | [Русский](README.ru.md) | [中文](README.zh-CN.md) | [日本語](README.ja.md) | [Español](README.es.md)\n\n**An agent reported \"done.\" There's nothing to check it against.**\n\n`ai-r` reads the session history of any of the five coding agents and lets a\nfresh agent cold-check what `git` can't answer:\n\n- did it lie, did it break anything — did it keep its word, did it run anything\n  dangerous (and roll it back if it did), what it actually changed, what it cost;\n- why it went that way — under which plan, with what intent, and whose hand was\n  behind the edit.\n\n> Across our own corpus — 1600+ sessions of five agents in 20+ projects — that's\n> how we found 312 risky commands (`rm -rf`, `curl|sh`, `git push --force`): the\n> agent caught and rolled back two itself; the other 310 ran silently — `git`\n> won't show them.\n\n`git` shows **what** made it into the code; `ai-r` shows whether you can trust\n**how** the agent got there. Read-only: no LLM calls, no network.\n\n## Quick example — an agent asks about history\n\nThe primary mode is **MCP**: an agent (Claude, Codex, …) calls `ai-r` directly\nand asks about history in plain language. For example — pull the plan the\nprevious agent settled on, drafts discarded:\n\n```\nShow me the plan from the last session — final only, no intermediate revisions.\n→ plan(session=…, kind=\"final\")  →  get_body(id, shallow=true)\n\n  plan:            \"Migrate auth to JWT: 1) extract the check…\"\n  dropped_drafts:  2   ← two drafts the agent threw away along the way\n  session:         a3f… (claude)\n```\n\nFast edit attribution — one terminal command, across every agent at once:\n\n```bash\nai-r find-file-edits auth.py --since 2026-06-01\n```\n```\n2026-06-03  codex   auth.py  \"add a refresh token\"                 edit\n2026-06-07  claude  auth.py  \"extract the check into middleware\"   edit\n```\n\n## What hurts\n\n- \"Done, I did X per plan Y\" — with nothing to check it against: the agent keeps\n  the plan in one shape, the edits in another.\n- You switched agents mid-task and lost the thread. There's nowhere to ask \"what\n  did the *other* agent already try?\"\n- An edit shows up in a file — and it's unclear **which** agent made it, and on\n  what request.\n\nOne cause: every agent writes its history **its own way** — Claude and Codex in\nJSONL, OpenCode in SQLite, Antigravity in \"brain\" directories, Pi in\nper-project JSONL. Five formats, five layouts — together they don't reconcile.\n\n## The promise\n\n`ai-r` folds all five into **one read-only interface**. Point any agent — or a\nscript, or yourself — at any session, no matter which tool recorded it. One\nquery shape per agent; format differences are normalized inside the parsers.\n\nEven with a **single** agent it works: you audit your own Claude history (or\nCodex…). The five formats are so your history doesn't break when you switch\ntools — not a requirement to have all five.\n\n### As a source for RAG\n\nIn an \"LLM + external data source\" setup (RAG), `ai-r` is the **source** — more\nprecisely, a retrieval layer over agent sessions. For a query it returns not a\nslice of log but parsed entities: the plan, the intent, the authorship of an\nedit — with a reference to the body the agent can pull if it needs it.\n\nIt **doesn't replace** your RAG over code and docs; it adds a source the others\ncan't reach. The usual sources you retrieve from: documentation, commit history,\nStack Overflow, internal wikis, code bases, bug reports. Agent sessions aren't on\nthat list — even though only there is it recorded **why** an edit happened at\nall.\n\nRetrieval is BM25 (ranked keyword search), with optional semantic re-ranking. No\nvector database, no second LLM: all local, results reproducible. BM25 here isn't\na shortcut — GitHub lists it alongside vector retrievers: [\"Common retrievers\ninclude sparse methods like BM25 and dense vector retrievers using neural\nnetworks.\"](https://github.com/resources/articles/software-development-with-retrieval-augmentation-generation-rag)\n\n## Key features\n\nEach item is a trust question from the first screen and the verb that answers it:\n\n- **Did it keep its word — plan vs. reality.** Pulls the final plan (separate\n  from the discarded `dropped_drafts`) and checks it against what actually made\n  it into the edits — catching \"did X per plan Y\" where Y is no longer that\n  plan. (`plan`, `session_diff`)\n- **Did it run anything dangerous — and roll it back.** Flags risky commands\n  (`rm -rf`, `curl|sh`, `git push --force`) and, from the turns that follow,\n  sees whether the agent caught it and rolled back — or it passed silently.\n  (`incidents`, `query tool_kind=bash`)\n- **What it actually changed, and by whose hand.** Any edit or call → the agent\n  that made it, plus the request that triggered it; including edits made through\n  the shell (`> file` under codex) that a plain diff misses.\n  (`find-file-edits`, `find-tool-calls`)\n- **What it cost.** Tokens and cost per session — exact where the format\n  recorded the usage, an honest estimate where it didn't, never invented.\n  (`session_stats with_tokens`, `aggregate group_by=model`)\n- **Why it went that way.** The intent behind an edit (the request *before* it),\n  under which plan, on which model — \"why\", not just \"what\". (`query with_intent`)\n- **Small answer, body on demand.** A record carries a reference to the content\n  (hash + length); the full text comes as a separate request. A reader, not a\n  guard: read-only, it runs nothing and writes nothing to an agent's history.\n\n## How ai-r knows\n\nDeterministically, with no second LLM guessing — and honest about the edges:\n\n- **dangerous command** — a pattern over the call string (`rm -rf`, `curl|sh`,\n  `git push --force`, …). Anything obfuscated (`exec(input())`) the pattern\n  won't catch — that's a declared boundary, not a silent miss.\n- **rollback** — marked \"confirmed\" ONLY when a regret/apology marker from the\n  agent sits nearby (within the window of following turns; the marker itself is a\n  bilingual ru/en pattern, not an LLM sentiment call). No marker → it stays an\n  unconfirmed candidate: `ai-r` **won't infer a silent rollback**, it honestly\n  says \"not confirmed\".\n- **lied about the plan** — `ai-r` doesn't decide for you. It lays the plan\n  entity next to the session's reconstructed edits (`session_diff`) — the\n  mismatch is visible to you or a reviewing agent. That's evidence assembly, not\n  a semantic verdict.\n\nZero LLM calls, read-only — the numbers are reproducible and \"confirmed\" is\nnever guessed.\n\n## What you use it for\n\n- **Audit sessions with a fresh pair of eyes.** A new agent with an empty\n  context coldly checks past sessions on three axes: were promises and\n  requirements met; are the decisions sound and well-judged; how deeply was the\n  question explored — what the agent missed. This catches agents that finished\n  the task **but misled on the planning** — something a live chat hides, and that\n  steers you into wrong decisions.\n- **Continue past a spent context — without losing detail.** `/compact` erases\n  the specifics. Instead, open a fresh session: it reads the previous session's\n  **logs** and continues from its conclusions, without re-burning context on\n  what's already been worked out. The original session stays intact — for audit\n  and search. The new session can run in **any** agent: the history reconciles\n  regardless of the tool.\n- **Feeds your memory system.** Keeping memory and summaries à la Karpathy, or\n  your own method? `ai-r` gives you, for AI chats, what you already do with\n  message history — parsed entities to build a lasting memory of the details\n  that matter.\n- **Recall what you did and why.** Why was this file edited? Why was this rule\n  added? Find the session where the file changed and read the request *before*\n  the edit.\n\n## How it differs from session-search tools\n\nA handful of cross-agent tools now read more than one agent's history\n(`jazzyalex/agent-sessions`, `Dicklesworthstone/coding_agent_session_search`,\n`hacktivist123/agent-session-resume`). Almost all are about **search and\ntimeline**: find a *session*, scroll the history.\n\n`ai-r` goes deeper: it extracts the **plan, intent, and authorship as ready-made\nentities** you build memory on. Search finds text — `ai-r` answers **why**.\nTechnically a search tool could also dig a plan out of a session's text, but it\ndoesn't hand it back parsed into a single, normalized shape — with `ai-r` that's\nthe primary surface.\n\n| Capability | Single-agent viewers | Cross-agent search tools | `ai-r` |\n|---|---|---|---|\n| Reads >1 agent's logs | No | Yes | Yes — Claude, Codex, OpenCode, Antigravity, Pi |\n| Programmatic surface | Mostly GUI/TUI | Mostly TUI/CLI/app | **MCP + CLI + Python SDK** |\n| Attribution (edit/command → agent + intent) | — | Partial | Yes — `find-file-edits` / `find-tool-calls` |\n| Audit replay (reconstruct a session's changes, no git) | — | Rarely | Yes — `session_diff` |\n| Plan extraction (final vs draft, normalized) | — | — | Yes — `plan` |\n| Scope | Viewer | Search / resume / memory | **Read-only extraction core** |\n\n*Competitor columns reflect their public docs as of 2026-07; where a capability\nis unclear we under-state rather than over-claim.*\n\nWe deliberately **don't** compete on agent breadth, speed, or TUI richness.\n`ai-r`'s wedge is extracting the \"why\" and structured entities for machine\nconsumption.\n\n## Proven in practice\n\n`ai-r` already reads its own development history — across all five agents. Real\ntools run on it (they live separately, on top of its read-only API):\n\n- **auditor** — a fresh agent coldly checks what the previous one actually did\n  and decided. This caught agents that quietly fibbed about the plan.\n- **summarizer** (`export rounds`) — renders a session into a ready handoff doc.\n- **ai-local-reader** — a read-only skill: audits past sessions from disk across\n  all agents.\n\nThese tools are workflow-side, outside this repo. `ai-r` itself only reads and\nreturns data.\n\n## Supported agents\n\n| Agent | Storage | Parser |\n|---|---|---|\n| Claude Code | `~/.claude/projects/` | JSONL |\n| Codex | `~/.codex/sessions/` | JSONL |\n| OpenCode | `~/.local/share/opencode/opencode.db` | SQLite (snap/flatpak auto-detect) |\n| Antigravity | `~/.gemini/antigravity/brain/` | JSON / markdown brain directories |\n| Pi | `~/.pi/agent/sessions/<encoded-cwd>/*.jsonl` | JSONL |\n\nNot your agent? Adding a sixth is **one parser module**; the read-only pattern\nports to any tool in minutes. See [CONTRIBUTING.md](./CONTRIBUTING.md).\n\n## Surfaces\n\n`ai-r` gives the same reading power three ways:\n\n- **MCP server** (`ai-r-mcp`) — 15 tools over JSON-RPC, so any MCP agent\n  calls it directly (recommended). Default is **stdio**; optionally a **shared\n  http server** (one warm process for all agents instead of a per-agent stdio\n  swarm), see the `http` extra under Quick start. Registration — see\n  [docs/mcp-registration.md](./docs/mcp-registration.md).\n- **CLI** (`ai-r`) — subcommands for scripts and manual use (`list` / `read` /\n  `search` / `find-file-edits` / `find-tool-calls` / `file-frequency` /\n  `detect-agent` / `export rounds`). Search operators —\n  [docs/search-operators.md](./docs/search-operators.md).\n- **Python SDK** (`from ai_r.parsers import ...`) — parsers, typed\n  `Session`/message models, and the event verbs, to build your own tools.\n\n### Method vocabulary\n\nThe full dictionary of public verbs and presets (signatures, parameters, behaviour) lives in its own file: [`docs/methods.md`](./docs/methods.md).\n\n### Event core\n\nThe verbs above are new: one **event core** replaces a pile of one-off tools.\nEach parser reads one agent's logs and emits typed models, normalized into a\nsingle agent-neutral stream — `user_turn` / `assistant_turn` / `tool_call(...)`\n/ `plan_event`. A small set of verbs filters, aggregates, and diffs that stream;\nagent differences (`ExitPlanMode` vs `update_plan` vs `implementation_plan.md`)\nstay hidden inside the parsers — the caller sees one shape.\n\nAn honest boundary: this is **extraction of entities only** — turns, tool calls,\nplans, intents, reactions. It is **not** a graph and **not** a memory store.\nWhat you do next (knowledge graph, Obsidian, persistent memory) is on your side,\noutside this repo. For the full layering and the MCP tool list, see\n[docs/architecture.md](./docs/architecture.md).\n\n## Quick start\n\n**Try it without installing** — if you have [uv](https://docs.astral.sh/uv/):\n\n```bash\nuvx --from agent-session-reader ai-r list          # CLI: list sessions\nuvx --from agent-session-reader ai-r-mcp           # MCP server (stdio)\n```\n\nNothing lands on your system: `uvx` downloads the package into a temporary cache\nand runs it. Good for looking at your sessions right now, or for wiring\n`ai-r-mcp` into an agent's MCP config by hand.\n\n**Full install (1 command)** — also patches your configs:\n\nRequirements: Python 3.11+ with `venv` or `pip`, and `jq` (used to auto-patch\nthe Claude and Antigravity MCP configs — the others don't need `jq`).\n\n```bash\ngit clone https://github.com/pro-target/ai-r.git ~/dev/ai-r\ncd ~/dev/ai-r && bash install.sh\n```\n\nThe installer creates a venv, installs the runtime package, patches MCP configs\nfor **Claude**, **Codex**, **OpenCode**, **Antigravity** (where the configs\nexist), installs the **Pi** CLI skill, and runs smoke tests. That auto-patch is\nexactly what `uvx` doesn't do — there you edit the configs yourself.\n\nOptional extra — `tokens`: `AI_R_EXTRAS=tokens bash install.sh` (or\n`pip install \"ai-r[tokens]\"`) adds [tiktoken](https://github.com/openai/tiktoken)\nfor better token **estimates** on sessions whose format stores no exact usage\nnumbers. Fully optional: without it exact numbers still come straight from the\nsession files where recorded, and the fallback estimate degrades to a rough\nchars/4 heuristic, honestly labeled `estimate` — never a crash.\n\nOptional extra — `semantic`: `AI_R_EXTRAS=semantic bash install.sh` (or\n`pip install \"ai-r[semantic]\"` + a one-time model download the installer does\nfor you) enables `sort=\"semantic\"` on text search (`query`, `search_sessions`) —\nthe BM25 top-50 candidates are re-ranked by **meaning**.\n\n- **Model.** A local multilingual embedding model,\n  [intfloat/multilingual-e5-small](https://huggingface.co/intfloat/multilingual-e5-small)\n  (int8 ONNX, ~118 MB, MIT), run directly via\n  [onnxruntime](https://onnxruntime.ai) + [tokenizers](https://github.com/huggingface/tokenizers) + [numpy](https://numpy.org),\n  no torch, no persistent index. Chosen for strong cross-lingual retrieval\n  (a Russian query finds an English session and vice versa) at a small size.\n- **How the score works.** BM25 picks the 50 best word-matches (a cost budget,\n  not a quality cut-off — there is deliberately *no* similarity threshold,\n  because this model family scores even unrelated texts ≈0.7). Within that pool\n  the final score is **75 % meaning + 25 % word match** — meaning dominates,\n  while the word share keeps exact-term hits from being drowned and breaks ties.\n- **Fail-soft.** Without the packages or model files, `sort=\"semantic\"` honestly\n  falls back to the BM25 order and the response says why\n  (`semantic: {active: false, reason, fallback: \"bm25\"}`) — never a crash.\n\nTwo knobs keep the model well-behaved inside a long-lived MCP process (both\nenv-tunable, both degrading to the default on blank/invalid input — never a\ncrash): `AI_R_SEMANTIC_THREADS` caps how many CPU threads onnxruntime may use\nper inference (default `2`, never more than the machine's core count — so it\ndoes not grab every core and fight the server for CPU), and\n`AI_R_SEMANTIC_IDLE_SEC` frees the loaded model's ~118 MB of RAM after that\nmany idle seconds (default `300`); the next request transparently re-loads it.\n\nOptional extra — `http`: `AI_R_EXTRAS=http bash install.sh` (or\n`pip install \"ai-r[http]\"`) adds [uvicorn](https://www.uvicorn.org) and enables\na **shared streamable-http transport** (requires `mcp>=1.9.0`).\n\n- **Why.** By default every agent spawns its own `ai-r-mcp` over stdio — under\n  multi-agent fan-out that is N processes, each with a cold cache, re-scanning\n  the corpus (the measured cause of RAM exhaustion). With\n  `AI_R_MCP_TRANSPORT=http` a single **warm server** on localhost (default\n  `127.0.0.1:8756`) is shared by every agent instead of a swarm; the systemd\n  units in `packaging/systemd/` add socket-activation with idle self-exit.\n- **Security (fail-closed).** The bind is loopback-only. Browser-based attacks\n  (DNS rebinding) are cut off by the SDK's Origin/Host allowlist (always on for\n  loopback). Remote access requires `AI_R_MCP_ALLOW_REMOTE=1` **and** an\n  `AI_R_HTTP_TOKEN` — without the token it refuses to start (transcripts carry\n  secrets). On loopback the token is optional (protection against another local\n  user on a shared box); the client sends an `Authorization: Bearer <token>`\n  header.\n- **Knobs (env):**\n  - `AI_R_MCP_PORT` — port (default `8756`).\n  - `AI_R_MCP_IDLE_SEC` — idle self-exit threshold.\n  - `AI_R_MCP_HOST` / `AI_R_MCP_ALLOW_REMOTE` — bind host / allow non-loopback.\n  - `AI_R_HTTP_TOKEN` — bearer token (required for a remote bind).\n  - `AI_R_HAYSTACK_CACHE_MAX` — search cache ceiling by entry count.\n  - `AI_R_HAYSTACK_CACHE_CHARS_MAX` — by total size (an RSS safeguard for a\n    long-lived server).\n\nBoth extras are fully optional: without them stdio mode and the BM25 order work\nas before.\n\n## Boundaries: a reader, not a guard\n\n- **Read-only.** It never runs an agent's code and never writes to its history —\n  it reads and returns.\n- **No graph, no memory.** It extracts entities (turns, calls, plans, intents).\n  Building a knowledge graph or memory out of them is your job, not its.\n- **Not an access-control layer — except the http transport.** Anyone who can\n  reach the CLI, MCP over stdio, or the package reads any session: it's the same\n  local user, so an authorization check in front of the parsers would guard\n  nothing. The exception is the shared http transport: it's reachable over a\n  socket, so it carries an Origin allowlist and an optional bearer token\n  (required for a remote bind, see the `http` extra above). Either way, keep the\n  data where untrusted local processes can't reach.\n- **Session content is data, not commands.** Whoever reads (auditor, summarizer)\n  must treat session text as data, not instructions. See\n  [Security](docs/security.md).\n\n## Acceptance (end-to-end scenarios)\n\nThe public surface is covered by end-to-end scenarios an LLM agent runs against the live MCP (complementing pytest). Full list — [`docs/scenarios.md`](./docs/scenarios.md).\n\n<!-- gallery:start -->\n## Example: ai-r in action\n\nA 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`](./docs/examples/showcase-gallery.md).\n<!-- gallery:end -->\n\n## Next — documentation\n\n- Method vocabulary (verbs + presets) — [`docs/methods.md`](./docs/methods.md)\n  (English SSOT) · [`docs/methods.ru.md`](./docs/methods.ru.md) (Russian mirror)\n- Acceptance scenarios (104 e2e) — [`docs/scenarios.md`](./docs/scenarios.md)\n- Architecture & layering — [`docs/architecture.md`](./docs/architecture.md)\n- Search operators — [`docs/search-operators.md`](./docs/search-operators.md)\n- Per-agent MCP registration — [`docs/mcp-registration.md`](./docs/mcp-registration.md)\n- Parser coverage & limitations — [`docs/parsers.md`](./docs/parsers.md)\n- Security (untrusted content) — [`docs/security.md`](./docs/security.md)\n- Add a sixth agent — [`CONTRIBUTING.md`](./CONTRIBUTING.md)\n\n## Development\n\n```bash\ngit clone https://github.com/pro-target/ai-r.git\ncd ai-r\npip install -e \".[dev]\"\npytest --cov=src/ai_r\n```\n\n- 1300+ tests, CI requires ≥85% coverage\n- Versioning: [SemVer](https://semver.org); while on `0.x`, a minor release may\n  break compatibility — where possible a migration path is given (a loud\n  deprecation warning before removal); changes land in\n  [CHANGELOG.md](./CHANGELOG.md)\n- Conventional Commits (`feat:`, `fix:`, `docs:`, …)\n- On adding new agents, see [CONTRIBUTING.md](./CONTRIBUTING.md) and\n  [docs/parsers.md](./docs/parsers.md)\n\n<details>\n<summary>Keywords</summary>\n\nclaude code session reader · claude code session parser · codex session parser ·\nopencode session reader · antigravity brain parser · pi agent session reader ·\nrag over agent sessions · bm25 retriever · retrieval layer for ai agents ·\ngrounding · mcp server · structured context ·\ncross-agent attribution · ai coding agent audit · ai agent session history ·\nmcp session tools · read-only session reader · agent session replay ·\nresume agent session · agent handoff · plan extraction · tool-call audit ·\nfile edit attribution · multi-agent coding · claude codex opencode antigravity pi\n\n</details>\n\n## License\n\nMIT — see [LICENSE](./LICENSE).\n\n---\n\n**Get started:** `uvx --from agent-session-reader ai-r list` — see your sessions\nright now; or clone + `bash install.sh` for the full install with MCP-config\nauto-patching ([docs/mcp-registration.md](./docs/mcp-registration.md)). One\nread-only surface over every agent's history.\n",
  "bytes": 21778,
  "sha": "fc35ae6ffaccc5749ea1073723f3a444f258bf82ffca2aed7cc20a1ac9f4fcfa",
  "repo_slug": "pro-target/ai-r",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_pro_target_ai_r_594885ef/readme"
}