"My agent already has a language server. Why a map?"
Because a language server answers one hop, on demand, inside a session — and the questions that stop an agent breaking your code are whole-graph questions, asked before the edit and diffed after it.
This page answers the objection properly, and every number on it points at a file you can regenerate. Nothing here is a criticism of language servers: codeweb runs beside yours and asks different questions.
The editor loop, one symbol at a time
Definitions, direct references, rename, hover — computed per request against a live session, tuned to answer in milliseconds while you type.
It is very good at that. It is not trying to be a whole-program artifact, because the editor loop never needs one.
The edit loop, one graph at a time
A deterministic call/import graph written to a single file: transitive impact, duplication with body evidence, dead code, hotspots, domain coupling.
Agents query it over MCP before they write. CI diffs two of them to decide whether a pull request made the structure worse.
Four questions a one-hop lookup is not built to answer
Each answer below is checked against an independent implementation, and each names the committed file that produced its number.
Transitive impact — "what breaks two hops away?"
Direct references stop at the first hop. An agent editing a function needs the closure: every symbol transitively affected, plus the domains they sit in.
codeweb_impact returns it in one call. Graded against an independent reverse-reachability walk over 121,913 symbol comparisons, it disagreed 0 times.
On sampled targets the mean blast radius was 21 symbols. One call injects 1,214 bytes of context; a simulated graph-assisted grep loop needed 7.2 rounds and 153,274 bytes to reach the same answer — a factor of 126.
Receipts: bench/results/correctness-query.json · bench/results/oracle-ab.json
Duplication — "does this already exist here?"
A reference lookup can only find code you already named. It cannot tell you the function you are about to write was written twice already, in two other domains.
codeweb body-confirms every candidate before reporting it. Against a name-matching baseline on planted clones, F1 was 1.0 (lower confidence bound 0.9977) versus 0.6667.
Renamed clones — identifiers changed, structure identical — are found by an identifier-normalized skeleton pass: recall 1.0 against 0.0 for a lexical baseline over 30 planted pairs.
Receipt: bench/results/detection-accuracy.json
Dead code — "is anything still using this?"
"Find references, see none" is a per-symbol question you have to know to ask. The graph inverts it: every uncalled, unexported symbol falls out of the same artifact at once.
Findings are confidence-tiered, because deleting something a test or an entry point still reaches is worse than missing it. The safe tier scored precision 1.0, lower bound 0.9771, against an independent reachability oracle.
Receipt: bench/results/detection-accuracy.json
Gating a pull request on the structure
This is the one a language server structurally cannot absorb, and it is the reason codeweb exists in CI.
A gate compares two states of the whole codebase. That needs a diffable snapshot — an artifact you can produce for the base commit, produce again for the head commit, and subtract.
A per-request lookup produces answers, not artifacts. There is nothing to diff, so there is nothing to fail a pull request on.
Receipt: bench/results/auxiliary.json (the gate's exit codes on a regression, a clean change, and a pure removal)
A snapshot is only diffable if it is deterministic
If the same code produced a slightly different graph each run, every gate verdict would be noise, and the whole approach would collapse into flaky CI.
It does not. Across 20 runs of each of the 6 pinned corpus repositories, the pipeline emitted one structural digest per repository — nodes, edges, domains, and overlaps identical every time. No model sits in the analysis path, so nothing drifts.
The pre-flight that predicts a verdict was checked the same way: 0 violations over 10,000 in-process operations plus 120 command-line trials.
Receipts: bench/results/determinism.json · bench/results/edit-safety.json
What the gate actually fails on
- A new dependency cycle.
- A new body-confirmed duplication.
- A symbol that lost every caller.
Pure removals pass these structural rules. No LLM is in the checks. A passing check does not prove the program works; unresolved dynamic relationships can remain.
Verified against independent implementations, not against ourselves
Cycles, impact, callers, callees, and context windows are each graded against a separate implementation written for the purpose — a Kosaraju SCC pass, a reverse-reachability walk, raw edge-set scans.
Across all five families that is 497,864 comparisons with 0 disagreements. The oracles are deliberately written to restate the rules rather than import them, so a change to the engine's definitions fails the oracle instead of moving in lock-step with it.
Receipt: bench/results/correctness-query.json · harness: bench/experiments/correctness-query.mjs · browse the raw data →
The two compose
Keep your language server for the editor loop. codeweb replaces the grep loop, not your language server — it is the artifact your agent consults before it writes, and the one CI diffs after.