Text search answers structural questions by name.

The questions that matter about a codebase are structural: where is this used, what depends on it, what a change would touch. Text search answers them by name, and a name is not an identity. A function called parse and a variable called parse in an unrelated module read as one thing to a string match, and the answers come back wrong about scope and impact. symbol resolves the imports between files first, so a usage counts only when its chain leads back to the definition. That resolution step is the shape of every answer it gives.

A pure core, wrapped in adapters.

A single Rust crate built strictly inward: a pure domain wrapped in the layers that touch the world.

Anatomy symbol
01 Domain
Symbols, languages, import-resolution rules. The pure core: no I/O, no async.
02 Application
Orchestration behind port traits
03 Infrastructure
Language parsers · a compressed on-disk cache
04 Adapters
A CLI and a JSON-RPC MCP server over stdio
05 Coverage
Rust · Python · TypeScript · JavaScript · Svelte
06 Resolved query
Call sites joined to imports on the resolved path

Parse each file, then connect them. Resolution is the step that earns the answers.

A scan walks the project once and parses every recognised file on its own. The differentiating work is the join after: the imports between files are resolved, so a usage in one file is wired to its definition in another. What lands in the cache is not a list of names but a graph.

Source → answers symbol
The codebase git-aware walk · recognised files only
Per file · parse and extract
01 Parse
each file compiled to a syntax tree on its own
02 Extract
the symbols it defines, plus its imports, calls, and references
Across files · resolve
03 Resolve
follow each import chain so a usage connects to its true definition
04 Graph
the queryable graph, persisted and re-read incrementally
Structural answers where-used · blast radius · dead code, resolved not name-matched

One engine, a terminal and a machine.

What it does symbol
Extract
Five languages, parsed incrementally.
Resolve
Matched on the resolved graph, never by name.
Impact
Call-graph blast radius, to any depth.
Dead code
Defined, but referenced from nowhere.
Summaries
Per-file digests: coupling and cohesion.
Two front doors
2 A CLI and an MCP server, one cache.
Diff impact
A diff in, the review surface out.

A name match is a guess. A resolved reference is a fact.

What it changes symbol
Without it
A name match counts a same-named symbol elsewhere as a hit, so scope and impact come back wrong.
With symbol
A reference counts only when its import chain resolves to the definition.
work