Code graph
Index every repo in the hall into one local graph, and let agents ask it for source, callers and blast radius instead of grepping and reading file by file.
ivar graph builds a code graph of every repo in the hall and keeps it on disk
at .ivar/memory.db, a local SQLite file. Agents query it through an MCP server
or the CLI. Nothing leaves the machine.
What goes in the graph
Files are parsed with tree-sitter. Rust, TypeScript and JavaScript sources yield the detailed structure:
- Symbols: functions, methods, classes, structs, traits and their signatures.
- Calls, imports and type references between them.
- HTTP routes declared by a server.
- Cross-repo edges: a package imported from another repo in the hall, a CLI invoked by name, an HTTP client request matched to the route that serves it.
The cross-repo edges are what a per-repo index cannot give you. A change to an API route shows the web client that calls it, even though the two live in different repositories.
Build the index
ivar graph indexThe first run indexes every repo declared in ivar.json. Extraction runs in
parallel. Later runs are incremental: ivar diffs each repo against the commit
it last indexed and checks file size and modification time, so only changed
files are parsed again. On a hall of about 29,000 files the cold index took 77 s
and a rerun with no changes took 0.17 s.
Index one repo, or force a rebuild:
ivar graph index --repo api
ivar graph index --fullivar graph stats prints how many repos, files, symbols and edges the database
holds.
Feature sessions see the feature's code
Several feature sessions often run at the same time, each on its own branch. One index per checkout would mean indexing the same repo many times, so the graph is split in two:
- A base index of each repo's default branch, shared by every session.
- A feature layer per feature, holding only the files that feature changed, committed or not.
A query from a feature session reads the layer first and falls back to the base for everything else, so the agent sees its own edits and not another feature's. A discovery session has no feature bound and reads the base.
While an agent has ivar graph mcp running, one of those servers is the
watcher leader. It watches every default-branch worktree and every live
feature session's worktree, and reindexes a repo or layer about 150 ms after
its files or branch change. Commits, pulls and edits reach the graph without
ivar sync or ivar graph index.
A query from a feature session waits, at most 2 seconds, until the leader has
indexed its pending edits, then answers without running git. When no leader is
running, or the wait runs out, ivar checks the layer against the worktree
itself and reindexes what changed, as before. Base-view queries never wait.
Stale answers fail loudly
If the layer cannot be refreshed, the MCP call returns an error. It does not fall back to answering from the base, because code that no longer matches the worktree is worse than no answer. This also applies when the watcher's wait runs out and the direct check fails.
Deleting or cleaning up a feature drops its layer. To remove one by hand:
ivar graph clean --feature billing-currencyUse it from an agent
Over MCP
ivar graph index registers the graph server in ivar.json as a
local MCP server the first time it runs, unless a server
running ivar graph mcp is already declared:
{
"mcp": [
{
"name": "graph",
"type": "local",
"command": "ivar",
"args": ["graph", "mcp"]
}
]
}Pass --no-mcp to skip that. If a server named graph already runs something
else, the index leaves ivar.json alone and warns; declare the entry above under
another name by hand. Then write the provider configs:
ivar syncBy default the server advertises one tool, graph_explore. Start the server
with --tools all to advertise the rest; the
reference lists them.
graph_explore takes symbol names, file or directory paths, or a short intent,
several at once. One answer carries:
- the flow between the symbols you named,
- the line-numbered source of the most relevant files, within a size budget,
- the blast radius of each definition: its callers and type uses,
- a ready
Next:call withpathsfor the files that did not fit.
Passing paths returns up to 12 whole files in one call, which is cheaper than
reading them one at a time. The tool description tells the agent to treat
returned source as already read.
From the CLI
Some providers do not pass MCP servers to subagents; omp is one. A subagent can still run the CLI:
ivar graph explore renderInvoice
ivar graph callers formatAmount --cross-repo
ivar graph affected --stdinEvery subcommand takes --json, and --compact for pipe-delimited records with
a schema header when output size matters.
In a browser
ivar graph view --symbol renderInvoiceview serves an interactive viewer on a loopback port. ivar graph viz writes
a standalone HTML file instead.
Keep it fresh
- A running
ivar graph mcpkeeps the base index and feature layers current on its own. The first server to start leads; if it exits, the next tool call from another server takes over and catches up through git. ivar syncrefreshes the base index of an existing graph along with the rest of the hall. It does not create a graph that was never built.ivar doctorreports repos whose indexed commit is behind the worktree HEAD, a database whose schema version does not match the binary, and watcher scopes that failed to reindex or were left behind with no leader running. It also shows the leader's pid. Each finding names the command that fixes it.
Limits
- Calls, imports and type references are extracted for Rust, TypeScript and JavaScript. Code in other languages does not get that structure.
- Edges come from static extraction. Dynamic dispatch, reflection and computed
URLs can hide a caller; each edge carries a confidence score, and
callerstakes--min-confidenceto filter. - The database grows with the hall. The 29,000-file hall above produced a 370 MB index with 144,000 symbols and 1.9 million edges.
- Treat graph answers as evidence, not proof. When a query comes back empty for something you expect to exist, search the source.
Authentication
Complete end-to-end guide to MCP OAuth authentication, credential separation, provider flows, and token lifecycle across Claude Code, OpenCode, and OMP.
Planning
The three approval gates and the stable R-*, N-* and OP-* identifiers that make an approved Plan a checkable execution boundary.