The binding
Grep finds twelve types implementing IStore — mocks, fakes, a legacy adapter. Exactly one is registered. csmesh tags it [di-bound] and ranks it first.
Text search stops at the interface. csmesh compiles your solution's projects with Roslyn into a frozen symbol graph and prints the resolved path — which implementation the container injects, which handler a Send() reaches, which endpoints break if you touch a property — with a fixed cap on how much comes back, and a confidence score on every edge it draws.
curl -fsSL https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.sh | sh
Colour is information here, not decoration: amber is the implementation the container registered, violet is a mediator dispatch, teal is an HTTP entrypoint. The 28 ms is a warm query on the measured NativeAOT win-x64 channel (csmesh 0.6.0, 2026-09-21).
Ask an agent where a payment ends up in a layered .NET solution and it starts hopping files. Every hop costs a turn, and the context window pays for all of them.
4 turns spent, roughly 4,100 tokens burned, still no answer
csmesh trace PaymentController.Post --budget 600The container binding, the mediator hop, the concrete repository and the DbContext underneath it — resolved from compiler symbols, ordered so the code that actually runs comes first.
1 turn, 118 tokens, exit 0
Every layered .NET app is held together by indirection that exists only at compile time or at container-build time. Lexical search cannot follow any of it.
Grep finds twelve types implementing IStore — mocks, fakes, a legacy adapter. Exactly one is registered. csmesh tags it [di-bound] and ranks it first.
The handler sits in another project with no textual link back to the caller. csmesh matches the request type to its IRequestHandler and draws the edge across the boundary.
Attribute routes, Blazor @page endpoints, MassTransit consumers, hosted services. Tagged as entrypoints, so a blast radius tells you which HTTP calls actually break — not which files mention the word.
A two-argument AddScoped is read off the compiler’s symbol table. A Scrutor assembly scan says a family of types is wired, not which pair. Both belong in the graph. Only one is a fact, and an engine that flattens the difference is one an agent goes back to grep to double-check.
1.0 when the compiler bound the symbol. 0.75 for a filtered assembly scan, 0.55 for an unfiltered one. The trust threshold is 0.8 — below it an edge is a lead to verify, and it never outranks an explicit registration in impl.
roslyn-symbol, semantic-registration, semantic-request, factory-lambda, assembly-scan, short-name-match. The reasoning that produced the edge, not just its endpoints.
The file and line of the registration, or of the Send() call. The class’s own location is already on the node; this is the other half, so “now change the binding” doesn’t start with a search.
IStore -- 2 implementation(s) SqlStore [di:scoped, ?0.75 assembly-scan] src/Data/SqlStore.cs:12 @ src/Api/Startup.cs:41 InMemoryStore [test] tests/Fakes/InMemoryStore.cs:8
The scan-derived binding is still ranked first, still tagged — and still marked as a guess, with the score and the reason that produced it.
A graph that answers “none” for every question it failed at reads like a graph that understood everything. csmesh unresolved --kind di lists the registrations that produced no edge and why each one failed. csmesh silence explains why a symbol has no callers. csmesh doctor reports index health, reference count, stale generated sources and version drift — run it before trusting an answer that surprises you.
Pick one. Every answer is capped by --budget, counted as roughly four characters per token — an estimate to size a reply, not a model’s tokenizer. Pass --heal to auto-refresh stale nodes on the fly. When the answer is bigger than the cap, the process exits 2 with a hint.
Benchmarked across a private 29-project .NET solution (1,945 symbols, 5,328 edges; measured 2026-09-23 on csmesh 0.7.0). Comparing standard AI agent exploration (Ripgrep + sequential file reads) against single-command csmesh queries.
Median of 20 warm runs on a NativeAOT win-x64 build, csmesh 0.6.0, 2026-09-21 — bypasses multi-hop model reasoning latency.
Measured ~93–94% less context in the two scenarios with a token baseline; the rest return csmesh token counts against qualitative baselines, not percentages.
Replaces 3 to 7 exploratory turns into a single invocation that cannot overflow the budget it was given.
| Workflow Scenario | grep & sequential reads | csmesh (single command) | Turn & Token Savings |
|---|---|---|---|
| DI binding (e.g. IOrderRepository) | grep + read, ~1,500 tokens | csmesh impl IOrderRepository — 27.6 ms median, 97 tokens | ~94% token reduction |
| Call chain trace (OrderEndpoints.CreateOrderAsync, depth 2) | 5–7 turns, ~4,000 tokens | csmesh trace OrderEndpoints.CreateOrderAsync --depth 2 — 27.8 ms median, 288 tokens | ~93% token reduction |
| Blast radius (OrderService.UpdateAsync) | 4–6 turns, 24+ noisy hits (no token baseline) | csmesh blast-radius OrderService.UpdateAsync — 27.4 ms median, 105 tokens | Callers, not text matches; no percentage |
| Path finding (OrderEndpoints.CreateOrderAsync → OrderWriter) | Impossible with grep (no token baseline) | csmesh path OrderEndpoints.CreateOrderAsync OrderWriter — 29.7 ms median, 115 tokens | 1 deterministic step; no percentage |
| Entrypoint & worker discovery | Multiple greps + manual parsing (no token baseline) | csmesh entrypoints — 24.8 ms median, 738 tokens | Every routing form it knows; no percentage |
| Type signature (OrderRecord) | Locate + read whole file (no token baseline) | csmesh context OrderRecord — 27.7 ms median, 478 tokens | No percentage |
| Architecture mapping (29 projects) | Read .slnx + 29 .csproj files (no token baseline) | csmesh map — 28.8 ms median, 766 tokens | No percentage |
Symbol names above are placeholders; the numbers were measured on the real codebase with symbols of the same shape. Median of 20 warm runs (graph pre-indexed and held in the OS file cache) on a NativeAOT win-x64 build of csmesh 0.6.0, 2026-09-21, on a 13th Gen Intel Core i7-13620H (10 cores / 16 threads, 48 GB RAM, NVMe SSD). Token counts use csmesh's own estimator at roughly four characters per token.
No text parsing, no heuristics. The process says what happened and what to do next.
Complete answer, within budget. Use it.
No such symbol here. Check the spelling or run csmesh where to discover symbols.
The answer exists but is bigger than the cap. Narrow --depth rather than raising the budget.
Several symbols match, including the same name declared in more than one project. Each candidate prints its project; re-run with --project <path> taken from that list, or with Type.Member. Two overloads in one project defeat --project; use the parameter list each candidate prints, e.g. Type.Member(int, string).
No usable graph: none on disk, or (for review) one that predates HEAD. Run csmesh index.
review only: unaccepted structural change vs. the base revision. Fix it, or csmesh review --accept.
Bad flags or arguments, including review --accept while the index predates HEAD. Run the command with --help.
csmesh itself failed. Re-run with --debug; that is a bug, not your query.
The index file is held by another process and nothing was written. Wait briefly and re-run.
One command writes the skill and rule files each tool expects, in the repository or machine-wide with --global. Pass --mcp or --all to configure MCP server integration automatically. Shared files like AGENTS.md get a tagged block, so rules you wrote yourself survive the install.
csmesh installTwo paths. The prebuilt Native AOT binary needs nothing installed and, on the measured NativeAOT win-x64 channel, answers a warm query in ~28 ms median (csmesh 0.6.0, 2026-09-21). The global tool needs the .NET SDK, and from 0.6.1 it fetches the same native binary on win-x64, win-arm64, linux-x64, linux-arm64, osx-arm64 and osx-x64, falling back to the framework-dependent build elsewhere.
curl -fsSL https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.sh | sh
irm https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.ps1 | iex
The scripts download the prebuilt Native AOT binary (win-x64, win-arm64, linux-x64, linux-arm64, osx-arm64, osx-x64) and fall back to dotnet tool automatically when no release asset matches your architecture.
dotnet tool install --global CsMeshdotnet tool update --global CsMeshFrom 0.6.1 this is a RID-specific package: on win-x64, win-arm64, linux-x64, linux-arm64, osx-arm64 and osx-x64 it delivers the Native AOT binary; elsewhere it falls back to the framework-dependent build. Then, in any repository with a .sln, .slnx or .csproj: restore first (dotnet restore) so package references are on disk, then run csmesh index; when the code uses source generators, build with dotnet build --no-incremental -p:EmitCompilerGeneratedFiles=true so their output is on disk too. A cold checkout resolves less completely than a restored one. Use --heal on any query or rerun csmesh index when files change.