Symbol-accurate code intelligence
A queryable index of every symbol in the repository, so the real consumers of a change can be found across package boundaries in under a second.
- What it is
- Tool — something you run.
- What it does
- A symbol index over the repository's source, so "who calls this" is a query rather than a text search that crosses package boundaries wrongly.
- Where it stops
- Building the index is expensive — a cold build was measured at roughly twelve and a half minutes.
A code-intelligence index of the whole repository is built into a binary artifact and converted into a queryable database, so a question like “what actually uses this type” is a sub-second query rather than a text search. The distinction that matters is package boundaries: a text search finds occurrences of a name, and an index finds references to a symbol, which is what a change across a package boundary needs.
The problem it solves
At a million lines and thirty-odd interlinked packages, the cost of a change is dominated by enumeration. Before renaming a type, reshaping a schema or moving a symbol between public entrypoints, you have to know every consumer, and getting that list wrong produces a regression that compiles.
Text search is the tool everyone reaches for and it fails in both directions here. It matches names that happen to coincide and misses references that resolve through a re-export, an alias or a published declaration. It is also quietly blind: the repository’s default search tool skips hidden directories, and one of the largest consumer trees in the repository lives under a dotted directory. An enumeration run that way returned fifteen files where the real number was thirty-five, and the list looked complete, which is the dangerous property.
What it does
A symbol index over the repository’s source, so “who calls this” is a query rather than a text search that crosses package boundaries wrongly.
An index is produced and converted into a queryable database, so a lookup is a query rather than a scan. It is safe to run alongside the compile watchers.
Concurrent runs are serialised by an atomic directory-creation lock — chosen because it needs no external tool and works on every platform the repository is developed on. That choice was made after the previous approach, guarded by a check for a tool that does not exist on one of those platforms, silently skipped the guard entirely: over two days the watcher logged ninety-four index starts, thirty-two completions and no skips at all, and the overlapping runs corrupted each other’s output while the reported state kept moving.
The lock distinguishes a live owner from a dead one and from a recycled process, and only breaks a lock once it is old enough that it cannot belong to a run still starting. Its self-test exercises each of those independently, neutralising the other check in each case, so a passing run can only be explained by the check it names.
A daemon watches sources and regenerates on save with a delay, so the index settles after activity rather than rebuilding on every keystroke. It can run in the foreground, in the background with a log, or start at login, and it reports its own state.
A routing document sits beside the tooling and decides which tool answers which question, because the index is not the right answer to all of them: a literal string in a comment is a text search, a structural pattern is a structural matcher, and an architectural dependency rule belongs in a dedicated check. One command wraps a symbol query with a classification of what the change crosses, so the answer arrives with the rules a developer should read before editing.
Limits
Building the index is expensive — a cold build was measured at roughly twelve and a half minutes. That is the reason for the daemon, and the reason a stale index is a real possibility rather than a theoretical one.
Both tools are installed non-fatally by the framework installer, so a developer whose install failed has no index and gets no error until they try to query it. The index tool has releases only for the platforms the installer selects, so elsewhere the whole capability is absent — and the installer says so and continues.
Neither the index nor the query path is part of a generated application. This is repository tooling for people and agents working on the framework.