Skip to main content

nspect

A Rust CLI that analyzes the structure of C# projects and solutions: dependency graphs, package references, version conflicts, structural metrics (LOC / members / cyclomatic complexity), and a best-effort cross-check between declared packages and what the source actually imports.

Not a compiler, not Roslyn. Fast, read-only, works from the filesystem — no NuGet restore, no MSBuild evaluation.

Install

From a release binary

Linux / macOS:

curl -fsSL https://github.com/vivainio/nspect/releases/latest/download/nspect-linux-x86_64-musl -o ~/.local/bin/nspect && chmod +x ~/.local/bin/nspect

macOS (Apple Silicon):

curl -fsSL https://github.com/vivainio/nspect/releases/latest/download/nspect-macos-aarch64 -o ~/.local/bin/nspect && chmod +x ~/.local/bin/nspect

Windows (PowerShell):

iwr https://github.com/vivainio/nspect/releases/latest/download/nspect-windows-x86_64.exe -OutFile ~/.local/bin/nspect.exe

Via pip

pip install nspect

From source

git clone https://github.com/vivainio/nspect
cd nspect
cargo install --path .

Commands

nspect scan <path>

List every project reachable from <path> (a repo root, a .sln, or a .csproj) with its SDK style, target framework(s), and package/project refs.

$ nspect scan ./my-repo
Found 12 project(s)

┌──────────────┬─────┬────────────────────────┬──────┬──────────┐
│ Project      │ SDK │ TargetFramework(s)     │ Pkgs │ ProjRefs │
╞══════════════╪═════╪════════════════════════╪══════╪══════════╡
│ Web.Api      │ sdk │ net8.0                 │ 14   │ 3        │
│ Domain       │ sdk │ net8.0, netstandard2.0 │ 2    │ 0        │
...

Add --format json for machine output.

nspect graph <path>

Emit a project-to-project dependency graph as DOT, Mermaid, JSON, or a text summary.

nspect graph ./my-repo --format dot      | dot -Tsvg > graph.svg
nspect graph ./my-repo --format mermaid  > graph.mmd
nspect graph ./my-repo --format text

Package nodes are off by default — on large monoliths they drown out the project structure. Add --packages to include them.

nspect atlas <path>

Emit a structural snapshot of the repo as YAML (default) or JSON: areas, projects with fan-in/fan-out/layer, and internal vs. external references.

nspect atlas ./my-repo                       # YAML to stdout
nspect atlas ./my-repo --format json         # JSON
nspect atlas ./my-repo --check               # embed findings (see below) under `findings:`
nspect atlas ./my-repo --output-dir ./out    # writes multiple artifacts (see below)

With --output-dir, the tree-sitter source scan runs and these artifacts are written side by side:

File Contents
atlas.yaml Project graph (areas, fan-in/fan-out, layers, refs). Each project also gains a weight: block with aggregate types, loc, members, complexity.
classes.yaml Declared types per project, grouped by namespace and bucketed by kind (class, interface, struct, record, record_struct, enum, delegate). Nested types keep a dotted local path (e.g. Outer.Inner).
metrics.yaml Same shape as classes.yaml but values are {loc, members, complexity, methods} per type, plus a per-project totals: block.
checks.yaml Only written with --check. The findings list (see below) as a standalone artifact.
tips.yaml Soft architectural suggestions (e.g. merge_candidates). Non-authoritative — meant for human review, not CI gates.

Without --output-dir, only the atlas itself is emitted (to stdout) and no source scan is performed — unless --check forces it to run the package-ref heuristics.

--check findings

When --check is on, atlas.yaml gains a findings: array (and with --output-dir, a sibling checks.yaml). CI gates can grep for error-severity kinds.

Finding Severity What it means
cycle error A project-to-project reference cycle.
version_conflict error Same package declared with different versions across projects.
unresolved_project_ref warning A <ProjectReference> that doesn't resolve on disk.
unused_package_ref warning A <PackageReference> whose namespaces never appear in any using of the project. Skips test runners, analyzers, and runtime shims by default.
undeclared_usage warning A using X.Y.Z; that doesn't match any declared package or project ref. Advisory only — noisy on legacy codebases that rely on transitive DLL discovery.
orphan_project info A project with no incoming or outgoing project refs.

nspect metrics <path>

Fast text summary of structural metrics — runs the tree-sitter pass, prints a per-project table plus the top methods by cyclomatic complexity. Scope is whatever csprojs live under <path>, so you can point it at a single .csproj, a subdirectory, or the whole repo:

$ nspect metrics tests/fixtures/sourcescan --top 5
project        types      loc  members  complexity
--------------------------------------------------
App                1        9        1           0
--------------------------------------------------
TOTAL              1        9        1           0

top 1 methods by complexity:
           0      6  App.Program.Main

When the scope contains more than one project, each method in the top-N section is prefixed with project:: to disambiguate.

Flags:

  • --top <N> — how many top methods to list (default 20, 0 disables the section)
  • --project <name> — restrict the methods section to a single project (exact, suffix, or substring match)

Metric definitions:

  • loc — source lines spanned by the type / method declaration.
  • members — direct methods, properties, fields, ctors, events, indexers. Nested types are not counted as members.
  • complexity — McCabe-ish branch count: if, while, for, foreach, do, case, catch, ternary ?:, when clauses. Logical && / || are currently not counted. Branches inside nested types count toward the enclosing type.

nspect ts-dump <file.cs>

Debug aid. Shows the extracted usings, top-level named children of the parse tree with line ranges, and (with --sexp) the full tree-sitter S-expression annotated with leaf source text:

(class_declaration
  (modifier "public")
  name:
  (identifier "Greeter")
  body:
  (declaration_list
    (method_declaration ...)))

Useful for writing new heuristics against the CST.

What it handles

  • SDK-style csproj<PackageReference>, <ProjectReference>, TargetFramework(s), AssemblyName
  • Legacy csproj<Reference> assembly refs are counted as namespace providers
  • .sln files — project list (the format is not XML; parsed directly)
  • Central Package Management — walks up for Directory.Packages.props and resolves version-less PackageReference entries
  • Multi-targeting — captures TargetFrameworks="net8.0;netstandard2.0" as a list
  • Malformed csprojs — skipped with a warning instead of aborting the scan

What it doesn't handle

  • MSBuild property evaluation. $(Foo) references are recorded as-is; nothing is expanded. Attempting to evaluate MSBuild correctly is a rabbit hole.
  • Directory.Build.props/targets. Presence is not currently merged into project metadata. Flagged for a future milestone.
  • Transitive DLL discovery via HintPath. Legacy .NET Framework monoliths rely on packages/*/lib/*.dll being found through a chain of HintPaths. The undeclared_usage finding does not trace these, which is why it's noisy on legacy codebases.
  • Type resolution. The source scan is textual. using Foo.Bar; produces the string "Foo.Bar"; whether that's a namespace or a static type is not determined.
  • NuGet restore. nspect analyzes what's declared, not what would resolve.

Performance

On a ~790-csproj monolith:

Command Time
nspect scan (parse all csprojs + CPM) ~0.3 s
nspect graph ~0.3 s
nspect atlas ~0.3 s
nspect atlas --check (tree-sitter across ~all .cs files) ~28 s
nspect atlas --output-dir ... (full source scan + per-type metrics) ~28 s

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

nspect-0.1.0-py3-none-win_amd64.whl (2.5 MB view details)

Uploaded Python 3Windows x86-64

nspect-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.6 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

nspect-0.1.0-py3-none-macosx_11_0_arm64.whl (2.4 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

nspect-0.1.0-py3-none-macosx_10_12_x86_64.whl (2.5 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file nspect-0.1.0-py3-none-win_amd64.whl.

File metadata

  • Download URL: nspect-0.1.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 2.5 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for nspect-0.1.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 ebf9422185dc17f6d2303a3a83f001e36d0ae88209ce5f9b76e0767d034b627b
MD5 d22457fe59b2aa782b1504cb4a14744e
BLAKE2b-256 fd87b7cd21f83108ed73b3bf2a8e2f26d3f35487d017ad8942c0490f159dcec8

See more details on using hashes here.

Provenance

The following attestation bundles were made for nspect-0.1.0-py3-none-win_amd64.whl:

Publisher: ci.yml on vivainio/nspect

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nspect-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for nspect-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 f7110b602cdcc5dac2ff70c228eb4c48021440cde84ef6b0923b29433fafc117
MD5 3be466e9369b4bc407d0785ec4a6604d
BLAKE2b-256 fa3d50c28b7241f1935afac0e594745887a7d6d7d79782892094439f70f8126e

See more details on using hashes here.

Provenance

The following attestation bundles were made for nspect-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: ci.yml on vivainio/nspect

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nspect-0.1.0-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for nspect-0.1.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 18a2f02f0839565237bf47877e3d61161cd265915147dc631ae34faca54603a2
MD5 92a1df0a46f7f87b23344a0a8ba91191
BLAKE2b-256 724df1764af0e5688161399599e94593df8d9bb6982166507043b51c0a6550c1

See more details on using hashes here.

Provenance

The following attestation bundles were made for nspect-0.1.0-py3-none-macosx_11_0_arm64.whl:

Publisher: ci.yml on vivainio/nspect

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nspect-0.1.0-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for nspect-0.1.0-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 da5a6f61f00a2ac2c6992ab008101e2fb2dfe73d597100e2ec4739cf184203ba
MD5 ea44a0f2f1da337129ac09ea1dcc40c0
BLAKE2b-256 e4350a4f194c03ce95718b97f6f87db9e53d7eb3a75fd01dceacb23d95b088c2

See more details on using hashes here.

Provenance

The following attestation bundles were made for nspect-0.1.0-py3-none-macosx_10_12_x86_64.whl:

Publisher: ci.yml on vivainio/nspect

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.3.0

4 files

0.2.1

4 files

0.2.0

4 files

This release

0.1.0 This release

4 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page