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.

nspect focus <path> <project>

Visualize the dependency neighborhood of a single project: --up <N> hops of reverse refs (projects that depend on it) and --down <N> hops of forward refs (projects it depends on), each defaulting to 1. <project> matches by exact name, suffix, or unique substring. --format accepts dot / mermaid / json / text (default).

nspect focus ./my-repo Domain --up 2 --down 1 --format text

nspect init [path]

Bootstraps nspect in a repo: creates .nspect/gen/, adds /.nspect/gen/ and /.nspect/cache/ to .gitignore (the derived artifacts — spec/ is hand-authored and meant to be committed), seeds .nspect/spec/areas.yaml (and a rules stub), and populates gen/ with a full atlas (--check --references, source scan included). Run this once so nspect lookup has something to read. [path] defaults to the current directory.

nspect init ./my-repo

nspect lookup <names...>

Reports everything the .nspect/gen/ artifacts know about a type: declaring project, namespace, metrics (loc/members/complexity), and cross-project callers. Reads atlas.yaml / classes.yaml / metrics.yaml / references.yaml from --atlas-dir, or walks up from the current directory looking for .nspect/gen (as produced by nspect init) if omitted.

nspect lookup Customer OrderService
nspect lookup --file Customer.cs

Names may be simple (Customer) or fully-qualified (Acme.Domain.Customer); multiple names combine freely with --file (repeatable, suffix match on the source path). --no-sig skips the tree-sitter re-parse that resolves method signatures (useful if the source tree has drifted); --min trims output to method names and line ranges only.

nspect install-skills

Installs the bundled Claude Code skill (SKILL.md) so agents know when and how to use nspect lookup. Installs to ~/.claude/skills/nspect/ by default, or .claude/skills/nspect/ in the current repo with --project.

nspect install-skills --project

nspect check-bindings <path>

Checks app.config / web.config / *.exe.config <bindingRedirect> entries for inverted redirects, cross-file inconsistencies, and in-file duplicates. Same checks as atlas --check, but standalone and much faster since it skips the project graph findings, package heuristics, and source scan.

nspect check-bindings ./my-repo --format yaml

Add --dlls <bin-dir> to also scan a built output directory (recursively) and cross-reference each assembly's AssemblyRef table against the redirects found — this shows which real on-disk reference actually needed each redirect. Opt-in, since unlike the rest of the command it requires binaries to have already been built. --format accepts text (default) / json / yaml; --compact emits single-line JSON.

nspect dlls <path>

Parses .dll/.exe build output and dumps each assembly's identity and AssemblyRef dependencies by reading ECMA-335 metadata directly — no dotnet/CLR/Mono involved. <path> is a single binary or a directory to scan recursively (typically a bin/ folder).

nspect dlls ./my-repo/Web.Api/bin/Debug/net48 --format yaml

--format accepts yaml (default) / json / text; --compact emits single-line JSON. Public key tokens are stripped by default (--pkt to keep them) since nearly every framework reference carries the same handful of well-known Microsoft tokens.

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

Metadata

Release files for nspect 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for nspect 0.3.0
File Actions
nspect-0.3.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details for nspect-0.3.0-py3-none-win_amd64.whl
nspect-0.3.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details for nspect-0.3.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
nspect-0.3.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details for nspect-0.3.0-py3-none-macosx_11_0_arm64.whl
nspect-0.3.0-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details for nspect-0.3.0-py3-none-macosx_10_12_x86_64.whl

Total release size: 11.3 MB

Release files / nspect-0.3.0-py3-none-win_amd64.whl

Download URL nspect-0.3.0-py3-none-win_amd64.whl
Size 2.9 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
8a98d15040599f20cf6f5d323925b149991855a89f87bc974d78b7dcbddb6bee
BLAKE2b-256 checksum
How to use checksums
efee4aca09d7d0ae0318b289e18599b1ceb5f2497f7e6777a790399998ec0d0d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release files / nspect-0.3.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL nspect-0.3.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 2.9 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
2c4ff73d330ec117dc6a0c88047f5ce8d8a2e86aff7004e53667fa71e87643aa
BLAKE2b-256 checksum
How to use checksums
b88c135e2dae7c114a32209aff34022ef77429ff0586311a41cff17dad37897e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release files / nspect-0.3.0-py3-none-macosx_11_0_arm64.whl

Download URL nspect-0.3.0-py3-none-macosx_11_0_arm64.whl
Size 2.7 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
d81a5cad013dfdd5ec5fae653a14d01603a1dc752e5f85643f2afc8cb33325b0
BLAKE2b-256 checksum
How to use checksums
135fd888a8c5592a6c676e224c6008d47cfed2422ef7b8ea8892ace2dd5d7756
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release files / nspect-0.3.0-py3-none-macosx_10_12_x86_64.whl

Download URL nspect-0.3.0-py3-none-macosx_10_12_x86_64.whl
Size 2.8 MB
Tags Python 3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
87db12bb812b187d309fa481f4521c6951bad9db42596545882aaabd95ee96bd
BLAKE2b-256 checksum
How to use checksums
85e2a44946690e1b841be4e2fa3c89243c999a1e8b3db7fe969c94a8da17ee34
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Security for nspect 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 4 files in this release have been uploaded with provenance metadata.

Select from 4 files

Attestation for nspect-0.3.0-py3-none-win_amd64.whl

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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