sivru
The comprehension layer for AI-written code.
Your agent just confidently broke something it didn't understand. sivru is the layer that remembers why your code is the way it is — and blocks the PR that breaks it.
npm install -g @sivru/cli
# Gate a PR on intent drift — exits non-zero when an agent's change breaks the
# test guarding an authored @sivru decision (or introduces a dependency cycle):
sivru explain --project --diff --gate --base=main
# Or just read the repo: the whole-repo map as one offline HTML file.
sivru explain --html --out=map.html
Code creation is becoming cheap. Code comprehension is becoming expensive — and as agents write more of every codebase, the gap shows up as incidents nobody can diagnose, refactors nobody dares start, and agents confidently "fixing" things that were deliberate.
Every coding tool produces code fast. None of them owns the question
that velocity creates: does anyone still understand this? Sivru
claims that question. It keeps a codebase comprehensible — to the
agents writing it and the humans accountable for it — by making
comprehension a durable, queryable asset of the repo itself: it records
why the code is the way it is, keeps that record current as the code
changes, and serves it at the moment it matters — the edit. The goal and
the test every release must pass: GOALS.md; how it's
positioned and described: POSITIONING.md.
Today the comprehension layer ships end-to-end:
- Search — agents call sivru via MCP and get ranked code chunks
back in milliseconds instead of looping through
ripgrep + Read. Hybrid BM25 + semantic + optional cross-encoder rerank. On how this squares with Anthropic's "agentic search wins for code" —WHY-SIVRU.md, the honest defense of one instrument. - Authored context —
@sivrublocks record a symbol's role, responsibility, invariants, and decisions in the source, with a lifetime and reliability checks (drift, staleness, invariant→test linkage, a cross-block graph).sivru explainserves that intent at the file/region level;sivru checkupcoaches against drift in CLAUDE.md / SKILL.md / agent files. - The codebase explainer —
sivru explain --projectprojects the whole repo into a System → Module → Package → Symbol model;sivru explain --htmlrenders it as one self-contained, offline HTML map. Its feedback loop (sivru feedback apply) writes a reader's corrections straight back to the@sivrublock in source, so understanding compounds in the repo instead of evaporating in a chat. - The architectural diff + gate —
sivru explain --project --diffdiffs the model across a change and reports what it did to the architecture: new cross-module edges, new dependency cycles,@sivruauthored-intent changes, the added surface area, and the touched hot spots.--gateexits non-zero on a regression worth blocking a PR on (a new cycle, or a broken@sivruinvariant→test linkage), with a.sivru/gate-allowlistescape hatch. Runs on every PR, not just at onboarding. - Observe + self-benchmark — reads your Claude Code session history, shows what the agent is actually doing, surfaces authored blocks in a Blocks tab, and benchmarks embedders + rerankers on YOUR repos.
What's next builds on this spine: the agent's working map — the same
model served to any coding agent over MCP, so it orients on the
architecture before it edits (DESIGN-0024).
See ROADMAP.md and docs/design/.
Status: 0.14.0. Engine, CLI, MCP server (8 tools), observe-ui, and the architectural diff + drift gate (
explain --project --diff [--gate]) ship end-to-end. SeeARCHITECTURE.mdfor how it's built andCHANGELOG.mdfor what's in.
The map sivru holds
Everything above — explain, the HTML view, the diff, the gate — serves one
artifact: a single map of your whole repo, built by parsing the code (tree-sitter,
the same parsers editors use), not by asking an AI. It's the ExplainerModel.
It's a four-level tree. Every node is one of these, nested:
System the whole repo
└─ Module a top-level package / workspace dir (e.g. @sivru/search)
└─ Package a source subdir (e.g. src/block)
└─ Symbol a load-bearing export (e.g. the buildIndex function)
Each node carries three layers of truth:
- Structure — what it exports, and its dependency edges: which other modules/packages it imports from. That's the wiring diagram — the arrows between the boxes, and (read the other way) the blast radius of a change.
- Authored intent — the
@sivrublock a human wrote in the source, when there is one: the symbol's role, responsibility, invariants ("this must always hold"), decisions ("we chose X because Y"), and theenforced-bylink to the test that guards each invariant. - Health —
churn(how often it changes),hotScore(churn × coupling — where change meets connectivity, i.e. where bugs cluster), whether it sits in a dependency cycle, and whether an invariant's guard test has gone missing (drift).
The one rule that makes it trustworthy: it is a projection of facts, never a
generation. Structure comes from the parser, churn from git history, intent from
text a human actually wrote. sivru never invents an explanation it can't trace to
something in your repo. That's why the same map can drive a human's onboarding
(--html), block a regression on a PR (--diff --gate), and — next — orient any
coding agent before it edits (the agent map, DESIGN-0024).
What's here
| Package | What it does |
|---|---|
@sivru/search |
Engine. Walker → chunker → BM25 + cosine + RRF → optional cross-encoder rerank. Pluggable embedders (Model2Vec, Transformers.js, OpenAI-compatible HTTP) with asymmetric query encoding for BGE / Nomic / E5. On-disk cache + mid-session refreshStale(). |
sivru (CLI) |
search, index, from-git, mcp, observe, session, bench personal, bench models, config, doctor, skill; explain (file/region, --project, --html, --diff); feedback apply (write authored-intent corrections back to source); block (validate / extract / staleness / graph / check-enforcement / init); checkup (coach-loop drift). Persistent embedder + reranker via sivru config. |
@sivru/observe |
Reads Claude Code's ~/.claude/projects/*.jsonl, normalizes events, runs a localhost Hono HTTP server. Ships token + dollar savings estimator and offline counterfactual replay. Hosts the coach loop (@sivru/observe/coach) that surfaces drift in CLAUDE.md / SKILL.md / agent files, plus the authored-context read/write surface (sivru mcp --writable). No network egress, ever — enforced by lint rule + runtime fetch spy. |
@sivru/observe-ui |
React + Tailwind dashboard. Tabs: Sessions / Checkup / Blocks / Replay / Costs / Bench. Dark-only. |
benchmarks/ |
NDCG@10, agent-task token economy, perf gate. Raw data committed; see BENCHMARKS.md. |
Numbers
Three benches. Each measures one thing. Full methodology + raw data: BENCHMARKS.md.
Token economy (sivru vs ripgrep + Read on agent tasks)
| Corpus | Mean saved | Median saved | Recall@3 |
|---|---|---|---|
| Labeled (zod / requests / gson, 20 tasks) | 57.7% (44–70%) | 63.5% | 65% sivru vs 15% baseline |
| Real-world (vitest, 178k LOC, 10 tasks) | 78.7% (74–83%) | 79.9% | n/a (unlabeled) |
Retrieval quality (NDCG@10 on 60 labeled queries — pnpm bench)
| Mode | NDCG@10 | Cold-start (16k chunks) |
|---|---|---|
| BM25 + signals | 0.5933 | n/a |
| Hybrid · Model2Vec (default) | 0.6013 | ~30 s |
| Hybrid · Transformers.js MiniLM | 0.6601 | ~10–15 min on CPU |
Benchmark sivru on your own code
Don't trust the numbers above? Run the same methodology on YOUR Claude Code sessions and YOUR repos. (Requires install — see below.)
sivru bench personal # interactive picker
sivru bench personal --models bm25,potion,jina-code
sivru bench personal --models potion --rerank=ms-marco-minilm
What you get back per model:
- Recall@5 — of the files the agent actually edited after each query in your sessions, how many appear in sivru's top 5?
- MRR — rank of the first relevant file (1.0 = always at rank 1).
- Tokens saved — vs. a windowed
ripgrep + Readbaseline. - Bootstrap 90% CIs on every metric so "model A beats model B" has to clear the noise floor.
Ground truth comes from the files the agent actually edited or read after each query in your jsonl session files. No labels needed — sivru derives them from the session itself.
Past runs persist to ~/.cache/sivru/bench-history/<iso>.json and render
in the Bench tab of sivru observe. Full methodology, how to add
custom queries, and what to do when ground truth is sparse:
BENCHMARKS.md §Benchmark 3.
Install
From npm (recommended)
# Install the CLI globally:
npm install -g @sivru/cli
sivru version # → sivru 0.13.0
# Or run without installing:
npx -y @sivru/cli help
The package on npm is @sivru/cli; the binary it installs is
sivru. The rest of this README assumes the global install (or
npx -y @sivru/cli for one-off invocations).
Wire into Claude Code
claude mcp add sivru -s user -- npx -y @sivru/cli mcp
Restart Claude Code. The agent now has eight mcp__sivru__* tools
alongside Grep / Read: search, find_related, explain, and
checkup (read-only). Four more — block_autofix, block_acknowledge,
feedback_read, feedback_append — let the agent maintain authored
context and are gated behind sivru mcp --writable.
Install the routing skill
The MCP tools give the agent the capability. The skill gives it the
policy — when to reach for sivru.search versus grep, and when to
run find_related after an edit:
sivru skill install # ~/.claude/skills/sivru/SKILL.md
sivru skill install --project # or <repo>/.claude/skills/sivru/
The installed SKILL.md is the canonical routing policy — read or edit
it at packages/cli/SKILL.md. sivru skill uninstall removes it.
From source (hacking on sivru)
If you want to read or modify the source, run a local build, and have Claude Code (or your shell) use that local build:
git clone https://github.com/sivru/sivru.git
cd sivru
# pnpm 9.x is required (we don't use corepack):
npm install -g [email protected]
# Install + build all packages:
pnpm install
pnpm build
# Expose the local build as the global `sivru` command:
pnpm --filter @sivru/cli link --global
# Verify — should print the version AND show the path to YOUR local build:
sivru version
which sivru # …/sivru/packages/cli/dist/index.js (your local path, not npm)
If sivru isn't on PATH after the link, run pnpm setup once
(adds pnpm's global bin dir to your shell startup file), then open a
new shell.
Claude Code with a local build
Use the linked sivru directly — don't use npx -y @sivru/cli, that
would fetch from npm and bypass your local build:
claude mcp add sivru -s user -- sivru mcp
Iterating
After every change, rebuild the affected package:
pnpm --filter @sivru/cli build # if you touched packages/cli/
pnpm build # if you touched any of search / observe
The global sivru command picks up the change automatically (the link
points at packages/cli/dist/).
Unlink later
pnpm --filter @sivru/cli unlink --global
Search a repo
# Default = hybrid (BM25 + semantic) using the Model2Vec static embedder
# (potion-retrieval-32M). First run downloads ~129 MB to
# ~/.cache/sivru/models/ once; subsequent runs are sub-second.
sivru search "where do we sign requests" /path/to/repo
sivru search "websocket reconnect" . --top=3 --json | jq
# --bm25: skip embeddings entirely (still indexes everything via BM25).
sivru search "AuthFilter authenticate jwt" . --bm25
# Pick any catalog embedder by short name, or any HF model via hf:owner/model.
# `sivru bench models` prints the full list with size / RAM / cold-start.
sivru search "where do we sign requests" . --embed=jina-code
sivru search "where do we sign requests" . --embed=hf:Xenova/bge-small-en-v1.5
# Layer a cross-encoder reranker on top — BM25⊕embed retrieves top-50
# candidates, cross-encoder rescores them, top-K returned. Lifts
# recall@5 / NDCG@10 by 5–15% at the cost of ~100 ms / query.
sivru search "websocket reconnect" . --rerank=ms-marco-minilm
sivru search "websocket reconnect" . --rerank=bge-reranker-base # stronger, ~5× slower
# Persist a default embedder + reranker so the MCP server picks them up.
sivru config set embedder jina-code
sivru config set reranker ms-marco-minilm
sivru index . # walk + chunk + index, print stats
sivru from-git https://github.com/owner/repo # depth=1 clone, cached + indexed
sivru bench models # registered embedders + rerankers
See what your agent is doing
sivru session list # 20 most recent Claude Code sessions
sivru session show <id-prefix> # event-by-event replay in the terminal
sivru observe # localhost web UI on http://127.0.0.1:7676
# Counterfactual analytics — zero API cost, runs on your existing sessions:
sivru observe replay <id-prefix> # one-session "what if sivru had been here?" table
sivru observe costs --since=7 # weekly rollup: tokens used vs estimated saved
sivru observe costs --since=7 --json # same, machine-readable
→ The web UI: sessions sidebar / event timeline / inspector pane. Estimated tokens and dollars saved per session, derived from your live Claude Code session log via the same counterfactual engine the costs CLI uses. Strictly local — no telemetry, no network egress, ever.
Explain a codebase (and correct it)
# Authored intent for one file or symbol — role, public API, callers,
# callees, churn, ownership, attached @sivru blocks. --diff scopes it
# to what changed.
sivru explain packages/search/src/rank.ts
sivru explain "packages/search/src/rank.ts::rankResults"
# Project the WHOLE repo into a System → Module → Package → Symbol model,
# then render it as one self-contained, offline HTML file you can open or
# email — no server, no build step.
sivru explain --project --repo=/path/to/repo # the model as JSON
sivru explain --html --repo=/path/to/repo --out=map.html
# Diff the architecture across a change, and gate a PR on regressions.
sivru explain --project --diff --base=main # the delta (text)
sivru explain --project --diff --format=github # a PR-comment body
sivru explain --project --diff --html # the delta as a page
sivru explain --project --diff --gate --base=main # exit 1 on a regression
The HTML map has a feedback mode: toggle it on, then edit a block's
role/responsibility/collaborators, author a new @sivru block on an
un-annotated symbol, suggest the system narrative, or leave a note.
Export downloads a patch.json; sivru feedback apply writes it back to
the @sivru block in source — deterministically, never corrupting it.
sivru feedback apply patch.json --dry-run # preview the per-block diff
sivru feedback apply patch.json # write it back to source
A correction made while reading the map lands where the truth lives, so
the next sivru explain reflects it for everyone. See
DESIGN-0018.
Pluggable embedding providers
import { buildIndex, createTransformersProvider, createHttpEmbeddingProvider } from "@sivru/search";
// Default: Xenova/all-MiniLM-L6-v2 (384-dim)
const idx = await buildIndex("./repo", { embed: { provider: createTransformersProvider() } });
// Swap to any HF model that supports the feature-extraction pipeline
createTransformersProvider({ model: "Xenova/bge-small-en-v1.5" });
// Or any OpenAI-compatible service
createHttpEmbeddingProvider({
url: "https://api.openai.com/v1/embeddings",
model: "text-embedding-3-small",
dim: 1536,
headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}` },
});
// Or local Ollama
createHttpEmbeddingProvider({
url: "http://localhost:11434/api/embeddings",
model: "nomic-embed-text",
dim: 768,
shape: "ollama",
});
EmbeddingProvider is two methods ({ dim, embed } plus optional embedBatch) — drop in any model you can run.
Roadmap
v0.13.0 ships the codebase explainer + feedback loop. Next up: drift + hot spots + a PR-diff CI gate, and an agent-facing model slice over MCP (DESIGN-0022). Long-term direction (coaching + platform) and what's explicitly out of scope: ROADMAP.md.
Contributing
Sivru is pre-1.0 — this is the moment to influence the surface. PRs welcome.
- Path from clone to merged PR:
CONTRIBUTING.md(30-minute walkthrough). - 30,000-foot system diagram + per-package map:
ARCHITECTURE.md. - Three benchmarks, methodology, raw data:
BENCHMARKS.md. - Why this exists when Anthropic chose grep + Read:
WHY-SIVRU.md. - Recipes:
Got a question that isn't answered above? Open an issue with the dx_feedback label — those go to the front of the queue.
License
MIT — see LICENSE.
No comments yet
Be the first to share your take.