lurp 1.4.0
dotnet tool install --global lurp --version 1.4.0
dotnet new tool-manifest
dotnet tool install --local lurp --version 1.4.0
#tool dotnet:?package=lurp&version=1.4.0
nuke :add-package lurp --version 1.4.0
Lurp: a Roslyn semantic map for .NET agents
Lurp indexes a .NET solution into SQLite with Roslyn, so an agent gets a small, sufficient code neighborhood instead of re-grepping and re-parsing the whole thing for every question. It loads the solution through the compiler and stores symbols, typed relationships, source spans, and provenance in one database, then serves retrieval, semantic diffs, impact paths, and token-bounded context capsules. Index once, query as many times as you want, and get back exact source with evidence levels each time.
What the model sees
An interactive map of how Lurp structures an eCommerce codebase for agent consumption: symbols, relationships, evidence levels, and capsule boundaries as the model receives them.
Why this exists
An agent working a C# codebase today loops search → read → guess, reopening and re-parsing the whole solution for every question. Context windows fill up with irrelevant source, and the agent ends up rediscovering the same call graph on every turn.
Lurp flips that cost around. A one-time index builds a snapshot-bound semantic
graph. After that, every query just reads persisted facts: no Roslyn reload, no
re-grep. Capsules return the smallest neighborhood that's actually sufficient
for the task, each fact states its provenance (compiler_proved →
runtime_unknown), and any omitted tier is named so you can fetch it
separately.
The mental model
| Command | What it does |
|---|---|
context |
Assemble a bounded capsule of relevant code from a symbol or source location. |
impact |
Follow typed relationships outward and explain each path. |
diff |
Show semantic changes between two snapshots. |
search |
Full-text search over source and symbols. |
grep |
Literal/exact-text search over source content with line numbers. |
find-symbol |
Resolve a symbol by its fully-qualified name. |
navigate |
Resolve an indexed declaration by file and line. |
get-symbol |
Look up symbol metadata (signature, provenance, declaration spans). |
get-source |
Retrieve source text for a document by relative path. |
index |
Build or update the snapshot-bound map in index.db. |
pin-snapshot |
Pin which snapshot reads default to when --snapshot= is omitted, without deleting or rewriting any snapshot. |
annotate / get-annotations / retract-annotation |
Attach and retrieve user-authored annotations on symbols; retract (by annotation_id) any annotation regardless of provenance. |
status |
Report whether the indexed snapshot still matches the workspace. |
timings |
Per-step performance data for a snapshot. |
outline |
List declarations in a document with line spans. |
diagnostics |
List compiler diagnostics captured at index time. |
dead-candidates |
List dead-code candidates: no incoming LIVE edge, after a suppression ladder that keeps public surface, EF/serialization conventions, process entry points, and generated/test code out of the default view. |
Worked example
Index a solution, then build a context capsule from a source location:
lurp --mode=index --solution=MySolution.slnx --output-dir=./out
lurp --mode=context --file=src/Services/OrderService.cs --line=42 --output-dir=./out --output=summary
--output=summary prints the handoff facts instead of the full JSON capsule:
capsule OrderService.CreateAsync (Method)
snapshot: f3bff523b103462be239655c9b753be3 intent: inspect maxHops: 3
content tokens: 283/8000 (estimatedTokens: the budget basis)
delivery tokens: ~571 (estimatedArtifactTokens: whole emitted file; size the context window from this)
truncated: true
omitted: direct_callers (budget_exhausted) : fetch with --tier=direct_callers
omitted: relevant_tests (budget_exhausted) : fetch with --tier=relevant_tests
When a tier is budget_exhausted, fetch it on its own with no budget applied:
lurp --mode=context --file=src/Services/OrderService.cs --line=42 --output-dir=./out --tier=direct_callers
Install
dotnet tool install --global lurp --version 1.4.0
lurp --mode=index --solution=path/to/Your.slnx --output-dir=./out
<details> <summary>Build from source & environment variables</summary>
dotnet build Lurp.slnx
dotnet run --project src -- --mode=index --solution=path/to/Your.slnx --output-dir=./out
Environment variables LURP_SOLUTION_PATH and LURP_OUTPUT_DIR are equivalent to
--solution= and --output-dir=. Requires .NET 10 SDK 10.0.301 (pinned via
src/global.json rollForward=latestMajor; Roslyn 5.6 requires net10.0).
Installing a local build as the global tool: if you pack a local build and its
version number matches the version already on nuget.org, dotnet tool install --global --add-source <path> lurp can silently
install the nuget.org copy instead of yours. --add-source only appends a source;
it does not remove nuget.org, and when two sources offer the same version, NuGet is
free to pick either one. Use --source <path> instead — it replaces every other
source, so only your local build is visible. Confirm afterward with
lurp --version, which prints the schema/extractor/CLI-MCP-contract versions the
installed binary was built with — compare that against the docs you're reading; a
mismatch means dotnet tool install pulled an older published build than the repo
this doc came from. This will bite again on every future local build that reuses
an already-published version number; bump the local package version before packing, or
always install with --source, never --add-source.
</details>
Common recipes
Task-first lookup for things you already know Lurp can do but not which mode does it:
| Task | Command |
|---|---|
Find unused using directives |
lurp --mode=diagnostics --severity=hidden --id=CS8019 --output-dir=./out |
| Confirm the installed build matches these docs | lurp --version |
| Find dead code, excluding public API and tests | lurp --mode=dead-candidates --output-dir=./out |
| Search source text literally (not symbol search) | lurp --mode=grep --query=<text> --output-dir=./out |
| See what changed between two indexing runs | lurp --mode=diff --from-snapshot=<id> --to-snapshot=<id> --output-dir=./out |
| Pull just the code relevant to a change | lurp --mode=context --file=<path> --line=<n> --output-dir=./out |
| Find every caller of a symbol | lurp --mode=impact --symbol=<id> --direction=upstream --output-dir=./out |
Framework adapters
Lurp models framework-mediated relationships through six adapters that emit ordinary typed facts into the shared model. Each fact retains its evidence level; see ARCHITECTURE.md for the ladder.
| Adapter | Facts emitted |
|---|---|
| ASP.NET Core | RoutesTo (route → controller action) |
| Dependency Injection | Registers (service → implementation) |
| MediatR | request/notification → handler chains |
| EF Core | entity, DbSet, and configuration relationships |
| Serialization | DTO/property contract participation |
| Test | TestedBy (production symbol → covering test) |
Limitations
- Single active TFM/configuration: one snapshot per index run.
- Source generators not executed:
GeneratedTreesIncluded=false; generated files underobj/are path-filtered out. - Reflection string-literal candidates are
name_candidate, notcompiler_proved. - 3-snapshot retention: older snapshots and their document versions are pruned automatically, except a snapshot pinned via
pin-snapshot, which pruning always skips. - Workspace must be restorable:
MSBuildWorkspacerequires a successful restore; no index without it.
Performance
| Measurement | Value |
|---|---|
| eNoteV2 (402 docs) full index | ~48 s |
| eNoteV2 incremental (no changes) | ~11 s |
| Capsule token estimates | estimated_tokens (content) vs estimated_artifact_tokens (delivery) |
| Incremental↔full convergence | 5 cycles; 0 changed docs after cycle 1 |
Status & roadmap
Shipped 1.1.0 as a global tool (dotnet tool install lurp); the source tree
currently carries 1.4.0, pending publish. Schema v29, extractor
1.6.0. windows-latest CI plus a self-hosted real-parity gate on FIT-RS2-2026 +
eNoteV2 (opt-in via real-parity PR label). Roadmap: multi-TFM and richer DI
parameter-type matching are postponed by design (see
DeclaredBoundaries).
Documentation & license
- ARCHITECTURE.md: product model, storage, pipeline, rules.
- CLI_REFERENCE.md: commands, options, output shapes, snapshot lifecycle, MCP.
- MIT license, see LICENSE.
Also MCP: --mode=serve exposes 18 tools (lurp_context, lurp_get_source,
lurp_outline, lurp_navigate, lurp_find_symbol, lurp_search, lurp_grep,
lurp_impact, lurp_diff, lurp_get_symbol, lurp_get_annotations, lurp_retract_annotation,
lurp_diagnostics, lurp_status, lurp_timings, lurp_refresh, lurp_index,
lurp_dead_candidates) over stdio; all are read-only except lurp_index and lurp_retract_annotation
(background re-index). Index first, then serve. See
CLI_REFERENCE.md#mcp.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.