Trace what a C# codebase actually runs.

Text search stops at the interface. csmesh compiles your solution 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 hard cap on how many tokens come back.

curl -fsSL https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.sh | sh
Read the source
.NET 10Native AOTRoslynzero idle contextMIT
$ csmesh trace PaymentController.Post --budget 600 exit 0118 tokens96 ms

Colour is information here, not decoration: amber is the implementation the container registered, violet is a mediator dispatch, teal is an HTTP entrypoint.

The loop this replaces

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.

grep, then read, then grep again

  1. grep for the interface12 hits: mocks, fakes, an XML doc comment — ~600 tokens
  2. open PaymentService.csfinds interface dispatch, not the body — ~800 tokens
  3. grep Program.cs for the registrationsifts through test fixtures — ~1,200 tokens
  4. open the handler, hit another Send()and the chain starts over — ~1,500 tokens

4 turns spent, roughly 4,100 tokens burned, still no answer

or ask the graph once

csmesh trace PaymentController.Post --budget 600

The 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

Three things ripgrep will never resolve

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.

services.AddScoped<IStore, SqlStore>();

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.

await _mediator.Send(cmd);

The dispatch

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.

[HttpPost("/payments")]

The entrypoint

Attribute routes, MassTransit consumers, hosted services. Tagged as entrypoints, so a blast radius tells you which HTTP calls actually break — not which files mention the word.

Six commands, real output

Pick one. Every answer is capped by --budget; when the answer is genuinely bigger than the cap, the process exits 2 with a hint instead of flooding the window.

$

Measured on a production backend

A multi-project .NET solution, roughly 1,600 nodes and 3,000 edges. The same questions asked two ways, recorded by the tool's own usage telemetry.

96msmedian query

Against three to five seconds of grep, file reads and model round trips.

85%less context

Around a hundred tokens returned where the file-hopping loop spent four thousand.

1shell command

Chainable with &&, so two questions still cost one turn.

Metricgrep and file readscsmeshDifference
Query latency3,000–5,200 ms94–111 ms35–50× faster
Agent turns2–4 turns1 commandup to 75% fewer
Context spent3,500–4,800 tokens73–125 tokens~85% reduction
DI resolutionguessworkdeterministicreads the registration
False positivesmocks, comments, logsnonecompiler symbols only

Exit codes an agent can branch on

No text parsing, no heuristics. The process says what happened and what to do next.

0ok

Complete answer, within budget. Use it.

1not-found

No such symbol here. Check the spelling or the namespace.

2over-budget

The answer exists but is bigger than the cap. Narrow --depth rather than raising the budget.

3ambiguous

Several symbols match. Re-run with Type.Member.

4no-index

No graph on disk yet. Run csmesh index.

64usage-error

Bad flags or arguments. Run the command with --help.

Teaches your assistant to use it

One command writes the skill and rule files each tool expects, in the repository or machine-wide with --global. Shared files like AGENTS.md get a tagged block, so rules you wrote yourself survive the install.

csmesh skill --install
Claude Code.claude/skills/csmesh/SKILL.md
Cursor.cursor/rules/csmesh.mdc
Google Antigravity.agents/skills + .agents/rules
Windsurf.windsurfrules
Cline and Roo Code.clinerules/csmesh.md
GitHub Copilot.github/copilot-instructions.md
Kilo Code.kilocode/rules/csmesh.md
MiMo Code.mimocode/skills + AGENTS.md
Codex CLI and KimiAGENTS.md
Gemini CLIGEMINI.md
Anything reading AGENTS.mdopen agent standard block
A human in a terminalcsmesh --help

Install

Two paths. The prebuilt Native AOT binary needs nothing installed and starts in under 100 ms; the global tool needs the .NET SDK and updates through NuGet.

Standalone binary

curl -fsSL https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.sh | sh

Falls back to dotnet tool automatically when no release asset matches your architecture.

.NET global tool

dotnet tool install --global CsMesh.Cli
dotnet tool update --global CsMesh.Cli

Then, in any repository with a .sln, .slnx or .csproj: run csmesh index once, and csmesh doctor whenever an answer looks wrong.