Repository navigation
Releases: nRafinia/CsMesh
Release list
v0.11.0
csmesh 0.11.0
Upgrade note
The graph format moves to v15. An index built by 0.10.x is rejected on load (exit 4):
run csmesh index --full once. review baselines are invalidated the same way; run
csmesh review --accept after the first review on 0.11.0.
Freshness
- A file edited without changing its size, within two seconds of being indexed, was
treated as fresh. Under default heal, that meant a stale answer with no[STALE]
marker. Each stamp now carries a SHA-256 of the bytes that were parsed. Inside the
mtime tolerance, the hash decides. An exact mtime match still costs no file read. - Files are stamped before they are read, so a write that lands mid-index can no longer
hide behind a fresh-looking stamp.
Answers that say what they left out
INCOMPLETEnow states rows shown out of the total, e.g.12 of 95 reached member(s) shown, and suggests a budget that fits the whole answer. The old line
could say "nearly complete" with most rows missing, and suggest a budget that
overflowed again.contextreports members past the 20-row cap (… 14 more member(s)), with a
matchingwithheld_membersfield in--json.wherelabels a member that matches only through its type's name[container], and
ranks it below the type itself.
MCP
initializeinstructions now carry the prefer-csmesh-over-grep directive and the
"you are about to → run instead" table, from the same source as the installed skill.
This matters in repositories with no AGENTS.md: there, the server's instructions are
the only rules an agent sees.- Shared parameters (
project,heal,repo,budget,under,depth) are
described once.tools/listdrops from 5,059 to 2,899 tokens. Instructions plus
catalogue together go from 5,368 to 3,865 tokens resident per session.
Exit codes are unchanged.
📦 Installation & Upgrades
Global .NET Tool
dotnet tool update --global CsMeshAutomatic One-Line Install Script
Linux & macOS:
curl -fsSL https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.ps1 | iexwinget install nRafinia.CsMeshQuick Setup for AI Assistants
# Install skills and register MCP server in one command:
csmesh install -g --all
csmesh index --fullv0.10.1
0.10.1
Fixes for csmesh run outside a git repository.
- Root detection no longer stops at a
.csmeshfolder that holds no index. Before,
a stray.csmeshin a parent directory (for example the user home) became the root
for every unmarked folder beneath it, andindexthere could fail with exit 70. - Telemetry no longer creates a
.csmeshfolder. A failed command in a plain folder
used to leave one behind, which then triggered the problem above. - Indexing skips a directory it cannot read instead of failing the whole run.
- The MCP server picks a workspace root that holds an index or a C# project, not one
that only holds a stray.csmesh.
If you have a .csmesh folder in your home directory with no graph.json in it,
you can delete it.
📦 Installation & Upgrades
Global .NET Tool
dotnet tool update --global CsMeshAutomatic One-Line Install Script
Linux & macOS:
curl -fsSL https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.ps1 | iexQuick Setup for AI Assistants
# Install skills and register MCP server in one command:
csmesh install -g --all
csmesh index --fullv0.10.0
0.10.0
Stale rows now heal by default. A query that finds edited files rebinds them before
answering; --no-heal or CSMESH_AUTO_INDEX=0 opts out. The MCP query tools take a
heal argument (default true).
- A default heal never waits for the index lock. If another process holds it, the query
answers from the current graph with aheal skipped: index busynote, exit 0. - An explicit
--healwaits for the lock and exits 75 if it cannot take it. indexexits 75 when the lock stays held, instead of writing the graph unlocked after
the wait. Before this release two concurrent writers could both write.
📦 Installation & Upgrades
Global .NET Tool
dotnet tool update --global CsMeshAutomatic One-Line Install Script
Linux & macOS:
curl -fsSL https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.ps1 | iexQuick Setup for AI Assistants
# Install skills and register MCP server in one command:
csmesh install -g --all
csmesh index --fullv0.9.0
Changed
- Declarations print their full span. Every row that points at a declaration now reads
path:start-endinstead ofpath:line, so the next read can be exactly that range
instead of the whole file. A single-line declaration stayspath:line. Wiring sites
(@ Api/Registrations.cs:22) are still one line: they point at a call or a
registration, not a declaration. The cost is small: on a 29-project solution the
where,contextandblast-radiusanswers grew by 2, 13 and 25 tokens. - The skill text tells agents to read that range. Run
csmesh installafter upgrading
so the instruction blocks in your agent files pick it up.
Added
--jsonrows carryend_linenext toline. No field was renamed or removed, and exit
codes are unchanged.
Upgrade
dotnet tool update -g CsMesh
npm i -g @nrafinia/csmesh
csmesh install
The graph format is unchanged (v14); existing indexes load as they are.
📦 Installation & Upgrades
Global .NET Tool
dotnet tool update --global CsMeshAutomatic One-Line Install Script
Linux & macOS:
curl -fsSL https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.ps1 | iexQuick Setup for AI Assistants
# Install skills and register MCP server in one command:
csmesh install -g --all
csmesh index --fullv0.8.2
Added
-
Solution scope warning.
csmesh doctorandcsmesh indexnow say when a solution
file was found but did not fully decide which projects are indexed: some listed project
paths match nothing on disk, none do, the solution lists no project, or it cannot be read.
The line names the solution, how many of its paths matched, and the first one that did
not, as written in the file:solution App.slnx: 2 of 3 project path(s) matched on disk (first unmatched: src/Old/Old.csproj)When the result was a fallback to the ProjectReference closure, the line says so. Before
this, the fallback was silent.--jsoncarries the same data assolution_findingson
both reports; the field is new, no existing field changed, and exit codes are unchanged.
Fixed
- Spurious incremental run after the first index. In a repository where the solution
leaves some projects out of scope, the run after a first full index could come back
incrementalinstead ofcurrent. Two causes, both fixed: the index created its own
.csmesh/directory after stamping the repository root, so it moved the stamp it checks
next time; and the new-file check walked out-of-scope projects and reported their files as
new. Nothing out of scope ever entered the graph; the cost was one needless rebind.
Upgrade
dotnet tool update -g CsMesh
npm i -g @nrafinia/csmesh
The graph format is unchanged (v14); existing indexes load as they are.
📦 Installation & Upgrades
Global .NET Tool
dotnet tool update --global CsMeshAutomatic One-Line Install Script
Linux & macOS:
curl -fsSL https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.ps1 | iexQuick Setup for AI Assistants
# Install skills and register MCP server in one command:
csmesh install -g --all
csmesh index --fullv0.8.1
Fixed
- Solution scope on Linux and macOS. Project paths inside a
.slnuse backslashes
(Visual Studio anddotnet sln addwrite them that way on every OS). On Linux and macOS
they were combined with the solution directory unconverted, matched no project on disk,
and scope silently fell back to the ProjectReference closure. A project listed in the
solution but not reachable byProjectReferencefrom an executable or test project was
left out of the index. A.slnxwith backslash paths had the same problem. Windows was
not affected.
Check whether you were affected
Run csmesh doctor on the affected machine. Before this fix the scope line read
ProjectReference closure from N root(s) where it should name your solution file.
Upgrade
dotnet tool update -g CsMesh
npm i -g @nrafinia/csmesh
The graph format is unchanged (v14), so existing indexes still load. On Linux or macOS,
run csmesh index --full once after upgrading so the scope is decided again from the
solution file.
📦 Installation & Upgrades
Global .NET Tool
dotnet tool update --global CsMeshAutomatic One-Line Install Script
Linux & macOS:
curl -fsSL https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.ps1 | iexQuick Setup for AI Assistants
# Install skills and register MCP server in one command:
csmesh install -g --all
csmesh index --fullv0.8.0
CsMesh 0.8.0
Graph format is still v14. Existing indexes keep working; no reindex is required, with one
exception noted under doctor.
Upgrade
dotnet tool update -g CsMesh
npm install -g @nrafinia/csmesh
csmesh install # refreshes the generated agent instruction blocks
New: csmesh export
Renders the graph as Mermaid or DOT at three levels:
csmesh export --level project --format mermaid
csmesh export --level namespace --format dot --out docs/namespaces.dot
csmesh export --level neighbourhood "OrderService.Submit" --depth 1 --direction out
- Without
--out, the diagram goes to stdout under the budget (default 1500). If it does
not fit, the command exits 2 and names the remedy:--out, a coarser--level, or a
smaller--depth. - With
--out, the full diagram is written atomically and stdout carries only a short
summary: node and edge counts plus what was withheld. The path must be inside the
repository (exit 64 otherwise). - Node ids are derived from the symbol's identity, so a committed diagram changes only
where the code changed. - Call edges are plain arrows. Other kinds are labelled (
di,iface,override,
mediatr,construct,route,typeuse); write access is dashed. - By default, test code,
TypeUseedges, compiler-synthesized tuple and anonymous types,
and edges inside a single project or namespace are withheld and counted in the summary.
--include-testsand--all-edgesbring the first two back. - Namespace buckets use the namespace of the outermost containing type; nested types never
appear as namespaces. - Available over MCP as the
exporttool, which returns the summary.
Design and trade-offs: docs/adr/0004-csmesh-export.md.
Selecting one overload
When two overloads of a member live in the same project, --project cannot tell them
apart. Exit 3 now prints a selector for each candidate. Pass it back quoted:
csmesh trace "CheckoutService.Apply(int,string)"
The parameter list must match exactly: same arity, same ref/out/in. Short type
names, Int32/int style aliases and nullable value types are accepted. A selector
works wherever a symbol does (trace, impl, blast-radius, context, path,
silence). If no overload matches, silence with the same selector lists the ones that
exist. An unclosed ( is exit 64 with a reminder to quote.
doctor
Two new warnings, each naming the project and the fix:
- Source-generator output not on disk (CS8795). Members a generator would supply stay
unbound. SetEmitCompilerGeneratedFiles=trueand build. - PackageReference to a project in the same solution. That project's types are not
bound through the package. Use aProjectReference.
The generator warning reads diagnostics captured at index time. On a project with many
compiler errors, run csmesh index --full once so the index records it.
Smaller changes
csmesh where <term> --unrankedlists every match in stable order, without entrypoint
ranking.usage.jsonlrecords carryschema_version: 2. Lines without it read as version 1, and
lines written by 0.0.1 in PascalCase are read again instead of being dropped.reviewkeeps its five most recent base caches and drops caches for the same revision
built against an older reference set.- The release workflow passes dispatch inputs through environment variables instead of
interpolating them into scripts.
📦 Installation & Upgrades
Global .NET Tool
dotnet tool update --global CsMeshAutomatic One-Line Install Script
Linux & macOS:
curl -fsSL https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.ps1 | iexQuick Setup for AI Assistants
# Install skills and register MCP server in one command:
csmesh install -g --all
csmesh index --fullv0.7.1
0.7.1
Package types resolve from restore, not from whatever landed in bin/
Until now csmesh took package assemblies only from bin/. A class library does not copy its
PackageReference closure there, so on library-heavy solutions whether Refit.RestService or a
Hangfire type bound depended on which app project happened to copy it.
0.7.1 reads each in-scope project's obj/project.assets.json, the same resolved graph the compiler
uses, and gives every project its own reference list. On that solution, with bin/ still empty,
unbound call sites drop to 250. A restore is enough; a build is needed only for source-generator
output.
- Per-project references: a package referenced by one project no longer binds in another, and two
projects on different versions of a package each compile against their own. Previously every
compilation saw every assembly under everybin/. - Projects without an assets file (never restored) keep the old
bin/behaviour. - A restore now marks the index dirty: the next
csmesh indexruns a full pass instead of
reporting the tree current, and thereviewbase cache is keyed on the assets files too. - Design:
docs/adr/0003-package-assemblies-from-assets.md.
doctor
- The references line reports three sources: runtime, assets,
bin/. - Unrestored projects are counted and the advice is
dotnet restore. The "nothing from bin/, run
dotnet build" message fires only when neither source supplied packages. - The instruction-drift line prints ASCII; the previous arrow rendered as a control picture on the
Windows console.
skill --install
- Rewriting an existing file keeps its line endings. A CRLF
AGENTS.mdused to come back with LF
lines inside it. - The rules block renders as LF regardless of the checkout the binary was built from, so every
release binary writes the same bytes. - Each target path is written once per install.
AGENTS.md, shared by several agents, was written
three times.
📦 Installation & Upgrades
Global .NET Tool
dotnet tool update --global CsMeshAutomatic One-Line Install Script
Linux & macOS:
curl -fsSL https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.ps1 | iexQuick Setup for AI Assistants
# Install skills and register MCP server in one command:
csmesh install -g --all
csmesh index --fullv0.7.0
CsMesh 0.7.0
Breaking: graph format v14
Existing indexes are rejected with exit 4 until you rebuild them:
csmesh index --full
csmesh review baselines built by 0.6.x need one csmesh review --accept after the
upgrade.
Where is this written?
blast-radius --writes answers "who writes this property or field" instead of "who
touches it":
csmesh blast-radius Order.Status --writes --budget 800
Member-access edges now carry a role: Read, Write, Read|Write (compound
assignment, ++/--, ref arguments) or Subscribe (event +=/-=). Writes are
recorded for simple and compound assignment, object initializers, with expressions,
out and ref arguments, deconstruction targets, constructor writes to readonly
fields and init-only properties, and indexer setters. Bare field writes such as
_total = x, which produced no edge at all before, are now recorded.
- A write through an interface-typed receiver shows up on the implementation with
[via-interface]. It is one reverse hop, so it can include writers bound to another
implementation of the same interface member. - Events and indexers are graph nodes now.
--writeson an event returns no rows and
points you toblast-radius <event>for its subscribers. - Not recorded: writes to members declared only in referenced assemblies, and attribute
named arguments.
Roles live on the existing call edge, so default changes and review output does not
fill up with write findings after the upgrade. --calls does show a method that moved
from reading a member to writing it.
review: no more false exit 5 on a clean tree
The base revision used to be indexed in a checkout with no bin/. Package types went
unbound, edges dropped out, and review reported structural changes that did not
exist. The base is now compiled against the working tree's reference set.
- The base-graph cache is keyed on that reference set, so a stale thin base is rebuilt
instead of reused. - When a
.csproj,.props,.targets,Directory.Packages.props,
packages.lock.json,global.jsonor solution file changed in the reviewed range,
reviewprints a warning (reference_inputs_changedin JSON). The exit code does not
change.
Agent skill
The skill text teaches --writes, drops a repeated paragraph and uses a generic
nested-type example. Refresh installed copies with:
csmesh skill --install
Upgrade
dotnet tool update -g CsMesh
npm install -g @nrafinia/csmesh
then csmesh index --full in each indexed repository.
v0.6.1
CsMesh 0.6.1
No graph format change. A 0.6.0 index keeps working, so no re-index is needed.
dotnet tool install now delivers the native binary
Until now the NuGet tool was a framework-dependent build: every run compiled Roslyn through the JIT
from scratch. npx and the install scripts already shipped the Native AOT binary, so only NuGet
users paid for it. CsMesh is now a pointer package, and the .NET 10 SDK picks the native package
for your platform when you install or update.
Measured on the same 29-project solution and machine, in one session, with phase timing on:
| 0.6.0 dotnet tool | 0.6.1 dotnet tool | |
|---|---|---|
impl, warm median |
185.6 ms | 54.1 ms |
trace --depth 2, warm median |
204.8 ms | 47.8 ms |
index --full, warm |
12.8–15.3 s | 1.8–2.1 s |
first launch before Main |
1.6 s | about 0.05 s |
Native packages: win-x64, win-arm64, linux-x64, linux-arm64, osx-x64, osx-arm64. Any other
platform gets CsMesh.any, the framework-dependent build, so install and update keep working
there. Each native package is about 13 MB, against 4 MB for the old one.
dotnet tool update -g CsMesh
Updating from 0.6.0 was verified on win-x64.
More platforms
Release archives and the npm package now cover win-arm64, linux-arm64 and osx-x64 as well. Before,
npm exited on those platforms.
Phase timing
CSMESH_TIMINGS=1 writes one line per indexing phase to stderr, with the time from process start to
Main. Nothing reaches stdout, so JSON and MCP output are unaffected. Include it when you report a
slow run.
Docs
Every latency and startup figure now names the channel it was measured on.
📦 Installation & Upgrades
Global .NET Tool
dotnet tool update --global CsMeshAutomatic One-Line Install Script
Linux & macOS:
curl -fsSL https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/nRafinia/CsMesh/main/install.ps1 | iexQuick Setup for AI Assistants
# Install skills and register MCP server in one command:
csmesh install --all
csmesh index