Skip to content

richlander/dotnet-inspect

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2,302 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dotnet-inspect

CLI tool for inspecting .NET libraries and NuGet packages. It is for .NET what docker inspect and kubectl describe are for container land: view package metadata, API surfaces, dependencies, source provenance, and version-to-version changes.

Install or run

dotnet tool install -g dotnet-inspect
dotnet-inspect <command>

Run without installing:

dnx dotnet-inspect -y -- <command>

Repository development SDK

Published tool users can install or run dotnet-inspect with the commands above. Contributors building this repository should use a .NET 11 daily SDK. The decompiler tracks compiler-produced C# shapes, and some correctness work needs daily compiler/runtime packs before the next public preview ships.

First check how dotnet is installed and which SDK it selects:

command -v dotnet
dotnet --version

If that already resolves to a dotnetup-managed .NET 11 daily SDK, use normal dotnet commands:

dotnet build dotnet-inspect.slnx -c Release
dotnet run --project src/ILInspector.Decompiler.Tests -c Release

If dotnet comes from a centrally managed location such as /usr/bin, /usr/local/share/dotnet, /snap, or C:\Program Files\dotnet, do not replace it or prepend another dotnet to PATH unless that is intentional for your machine. Use dotnetup in command-isolation mode, or ask your system administrator which setup is appropriate.

Install and track the daily SDK with dotnetup:

curl -fsSL --retry 3 https://aka.ms/dotnetup/get-dotnetup.sh -o /tmp/get-dotnetup.sh
bash /tmp/get-dotnetup.sh --install-dir "$HOME/.local/bin"
dotnetup sdk install 11.0-daily --interactive false

Then run repo commands through dotnetup when you want the nightly SDK without making it your shell default:

dotnetup dotnet build dotnet-inspect.slnx -c Release
dotnetup dotnet run --project src/ILInspector.Decompiler.Tests -c Release

For a temporary shell/process override, evaluate dotnetup's supported environment script before running repo commands:

eval "$(dotnetup print-env-script --shell bash)"
dotnet build dotnet-inspect.slnx -c Release

That affects only the current shell process and its children. It changes future shells only if you add the line to a startup file such as .bashrc, .profile, or .zshrc.

Verify the dotnet selected for commands run from this repository:

command -v dotnet
dotnet --version
dotnetup list

The Deep Inspect nightly lane uses the same acquisition model in an isolated workspace install. It restores with a temporary NuGet config that includes both the .NET 11 daily feed and nuget.org: most projects target the nightly net11.0 SDK, while a few fixture projects still target stable net10.0 packs.

What it inspects

Source Examples Notes
NuGet packages package System.Text.Json, type --package Markout Supports versions, custom sources, nuget.config, TFMs, package layout, dependencies, and vulnerabilities.
Restored projects type Command --project ./src/App, project ./src/App -S Skills --print Uses an existing project.assets.json as restored-assets context for API lookup, relationship search, and dependency package skills; restore/build first if dependencies changed. No restore/build/MSBuild evaluation is run.
Platform libraries library System.Private.CoreLib, library System.Text.Json --version 10.0.0, diff --platform System.Runtime@9.0.0..10.0.0 Resolves installed SDK/runtime assemblies, including runtime-only implementation assemblies with no NuGet package.
Local assets library ./bin/MyLib.dll, package ./pkg/MyLib.nupkg Useful for auditing builds before publishing.

Bare names are routed automatically: platform-looking names (System.*, Microsoft.AspNetCore.*) resolve to installed platform libraries; other names resolve as NuGet packages. In API commands, common CoreLib aliases and simple type names such as string, int, DateTime, and Guid resolve to System.Private.CoreLib. Use explicit commands and --package, --platform, or --library when you need a specific source.

For API and relationship commands, --project means an existing project.assets.json restored-assets context. Passing a .csproj or project directory only locates that file; dotnet-inspect does not restore or build, so restore/build first if dependencies changed. --bin remains the output directory context for copied DLLs. A future --deps source can represent runtime .deps.json context.

Capability inventory

Capability Commands Highlights
Package inventory package Metadata, versions, TFMs, file layout, dependency tree, metadata audit, vulnerability data, custom feeds, NuGet config support.
Project skills project Direct dependency Skills rows from package skills/**/SKILL.md files, plus version-resolved package README/PROJECT docs from restored projects.
Library audit library Assembly identity, public key token, trim/AOT metadata, unsafe/interoperability signals, OpenTelemetry support, symbols/PDBs, SourceLink and determinism audit, references, resources, async method classification.
API discovery type, member, find Type search, member tables, docs, overload selection, generics, obsolete-member markers, direct calls and callers, source/decompiled/IL drill-in. Add --project to resolve type/member queries in the project's restored dependency context.
API compatibility diff Version ranges, package or platform diffs, breaking/additive/potentially-breaking classification, type and member filters, plus opt-in decompiled C#/IL/checksum-verified authored Source evidence.
Relationships depends, extensions, implements Type hierarchies, package dependencies, library reference graphs, extension methods/properties, implementors and subclasses. Add --project to search project-referenced packages.
Source mapping type/library/package -S "Source Files", member -S "Source Locations" / "Original Source" SourceLink URLs, member file/line locations, source fetching, URL verification, token+IL-offset to source-line resolution.
Performance analysis (experimental) library/type/member -S "Top Leverage", "Performance Triage", "Resource Triage", "Call Graph", "Caller Graph" Whole-assembly call-graph leverage ranking — direct callers, root reach, fanout, depth, loop calls — with opt-in per-node cost signals (alloc, copy, unsafe, reflection, throw/exception, catch/finally), actionable rewrite-shape detection, and exception-path resource-lifecycle candidates.
Decompiler (experimental) member -S @Source (Decompiled Source, Annotated Source, Original Source, Source Diff, IL); member -S "Fidelity Causes" Raises method bodies to C#, interleaves IL and hidden-fact annotations, diffs SourceLink-backed source against decompiled source, and exposes typed DEC#### fidelity causes rather than emitting plausible-but-wrong source.
Agent-friendly output global flags Markdown by default, compact --table, normalized --tsv, --jsonl, --plaintext, --json, Mermaid diagrams, section/field projection, --count, table row limiting, built-in head/tail limiting.

Command inventory

Command Purpose
package X Inspect NuGet metadata, versions, dependencies, TFMs, layout, and vulnerabilities.
project [path] Inspect restored direct package references for skill files and package docs.
library X Inspect assembly metadata, symbols, SourceLink, references, resources, and async methods.
type X Discover types or render a single type shape.
member X Inspect members, docs, overloads, decompiled/lowered C#, SourceLink-backed original source, and IL.
find X Search for types across packages, frameworks, projects, and local assets.
diff X Compare API surfaces by default; opt into analysis or peer decompiled C#, IL, and checksum-verified authored Source implementation evidence.
extensions X Find extension methods and C# extension properties for a type.
implements X Find concrete implementors or subclasses.
depends X Walk type, package, or library dependency graphs; emits Mermaid diagrams.
cache Inspect or clear dotnet-inspect caches.
skill Print the base LLM skill; routes to focused skills (skill list, skill source, skill performance).

Single-type type X output is tree-shaped by default. Use -v:n or -v:d to grow that tree to overload leaves; use --markdown -v:q when you want the compact Markdown section view instead. When an exact type is not found, type treats the query as a best-effort namespace/type prefix browse within the resolved package, library, or platform scope.

Signals

Signals is an evidence report, not a safety certification. Select it with -S Signals. For libraries, Signals reports metadata/provenance observations and acquires a missing PDB when selected to resolve SourceLink. For packages, Signals reports package metadata/assets, dependencies, signature provenance, and NuGet registry observations. The per-source-file reachability pass (SourceLink Availability, SourceLink Missing Files) is selected explicitly with -S because its cost scales with source-file count. The slow, exhaustive content check (SourceLink Integrity) is opt-in only.

Command Scope Signals
library X -S Signals Metadata + provenance Library metadata/provenance signals; a missing library PDB is acquired to resolve SourceLink.
library X -S "Signals,SourceLink Availability,SourceLink Missing Files" Detailed SourceLink reachability Adds the opt-in per-file HEAD pass and reports embedded-source coverage.
library X -S "SourceLink Integrity" Content verification (slow, opt-in) Downloads every tracked source file and compares its hash to the PDB checksum; a mismatch exits non-zero. Never runs in a default flow.
package X -S Signals Full package signals Package and dependency signals, including known vulnerabilities, package age, dependency vulnerability/deprecation counts, and dependency age.

Vulnerability-service traffic is capability-gated. It runs only for detailed package inspection or an explicitly selected network-using package section; requests outside that scope are blocked at the shared HTTP handler. NuGet.org-wide statistics, verification, deprecation, and vulnerability metadata are queried only when api.nuget.org is among the configured package sources. RID companion-package verification follows the configured source list.

Integrations

Integrations is a library section for ecosystem support such as AI, ASP.NET Core, Aspire, Authentication, Configuration, Dependency Injection, Logging, Options, Hosting, Health Checks, HTTP Client, OpenAPI, and OpenTelemetry. It is a usability index, not a raw evidence report: focused integration sections list package-owned actionable types and starter APIs rather than assembly references.

Use package Foo --library to inspect one package DLL, or package Foo --all-libraries when the package contains multiple relevant libraries. In all-library mode, singular sections such as Library Info are rendered per library while aggregate sections such as @Integrations roll up rows across libraries and include library provenance when needed. Row formats (--table, --tsv, --jsonl) require one concrete section, such as Library Info, Integrations, Switches, or a focused integration section; use Markdown for category selectors such as @Integrations.

Switches is a peer library section for feature, compatibility, and runtime configuration switches such as FeatureSwitchDefinitionAttribute and AppContext switch names.

Experimental features

These features are under active development. Their output shapes, section names, and signal sets may change between releases.

Performance analysis

The whole-assembly call-graph analyzer ranks the members worth optimizing or hardening first. Select Top Leverage to rank members by direct callers, Root Reach (distinct entry points that transitively reach a member), fanout, depth, and loop calls; Performance Triage surfaces the highest-value allocation pay-dirt first — ranking in-loop (hot) and high-confidence opportunities ahead of raw leverage — across actionable rewrite shapes (small non-escaping arrays, temporary or span-to-array copies, capturing and instance method-group delegates, async state-machine setup, loop-invariant materialization, and value-type boxing) plus allocation-hotspot rows for methods that allocate heavily without matching a specific shape. Allocation rows also carry Weight, a coarse size x multiplicity x reach static prior that you can query or sort when choosing pre-profile instrumentation targets. Exact allocation and call-site rows also retain a Candidate id, their native Finding descriptor, Provenance=exact, Operation, and metadata Token. Aggregate rows are marked Provenance=aggregate; unmatched identifies an instruction-level row that could not be joined to a producer occurrence. Those fields let trace and version-diff tooling join a triage row to analysis.allocation or analysis.call-site evidence without parsing Evidence prose. Use --top, --loop, --min-confidence, and --triage-shape to ask the tool for the curated pay-dirt rows directly instead of post-processing. --top limits the ranked data before rendering; -n N --rows remains a renderer cap and is applied afterward if both are supplied. Drill candidates with Call Graph (bounded outbound tree) and Caller Graph (bounded reverse tree to entry points), and project per-node cost with --fields. Ranking rows carry a copyable Stable selector, Visibility, and Selector; add --all to drill non-public members.

CallerLoop, CallerLoopDepth, and CallerLoopWitness expose a separate cross-method repetition fact. CallerLoop=direct means a resolved invocation of the row's method occurs inside an upstream caller's loop. It does not change the allocation's local Loop, multiplicity, confidence, weight, or ranking, and it does not claim runtime heat. Function loads such as ldftn are not invocations and do not produce this evidence.

Resource Triage is an explicit library section for high-confidence exception-path pool-churn candidates. It currently reports ArrayPool<T> acquisitions whose exact def-use path reaches an external-input boundary before modeled cleanup. These are triage candidates, not permanent-memory-leak or memory-corruption accusations: the impact is pooled-array churn if the boundary throws, and static analysis does not establish runtime frequency. Each boundary is one row that retains its analysis.resource-lifecycle Finding, stable Candidate, exact acquire and boundary IL offsets, and resolved operation. Candidates with multiple boundaries repeat their candidate and acquisition fields so each operation remains paired with its own offset. Trusted in-memory transforms and unknown boundaries remain available to corpus measurement but are not exposed in this curated section.

dotnet-inspect library MyLib.dll -S "Top Leverage"
dotnet-inspect type MyType --library MyLib.dll --all -S "Top Leverage"
dotnet-inspect library MyLib.dll -S "Performance Triage"
dotnet-inspect library MyLib.dll -S "Resource Triage" --jsonl
dotnet-inspect library MyLib.dll --loop --min-confidence high --top 20 --tsv
dotnet-inspect library MyLib.dll --triage-shape scan-method-in-loop-call,linq-scan-in-loop,string-build-in-loop --top 20 --tsv
dotnet-inspect library MyLib.dll --triage-shape capturing-delegate --top 10 --jsonl
dotnet-inspect library MyLib.dll --triage-shape allocation-fanout \
  --order-by "OncePaths desc" --top 20 --tsv
dotnet-inspect library MyLib.dll --where "Finding=analysis.call-site" --jsonl
dotnet-inspect library MyLib.dll --where "CallerLoop=direct" --order-by "CallerLoopDepth desc" --jsonl
dotnet-inspect member MyType Method:1 --library MyLib.dll -S "Call Graph,Facts"
dotnet-inspect member MyType Method:1 --library MyLib.dll -S "Caller Graph" --fields "Throw,Catch,Finally"

allocation-fanout is an opt-in aggregate view for construction-heavy registries, pipelines, and object graphs that do not match a local rewrite shape. It counts direct allocation sites and composes repeated exact intra-assembly callsites into Once Paths, while keeping conditional, repeated, unknown, cached, and opaque paths separate. The counts describe IL-visible normal-return paths, not runtime bytes or workload frequency; virtual, external, delegate, recursive, and runtime-library effects remain opaque.

Common --triage-shape values include capturing-delegate, async-state-machine, box-value-type, small-array, linq-scan-in-loop, materialize-in-loop, string-build-in-loop, enumerator-allocation, and allocation-hotspot.

Decompiler

member -S @Source raises a method body to C# and shows the supporting evidence: Decompiled Source (raised C#), Annotated Source (C# with hidden-fact comments and interleaved IL), Original Source (SourceLink-backed), and IL. The decompiler is exception-safe by construction and degrades honestly: IL with no faithful C# spelling renders as a visible comment and lowers the result's fidelity level (FullPartialStructuredOnlyIlOnlyFailed) instead of emitting plausible-but-wrong source, with a stable DEC#### diagnostic on every degradation. If output looks wrong, capture all four sections; select Fidelity Causes for the typed cause census behind the grade. That section distinguishes Full fidelity, an absent method body, and inspection failure. Maintainers diagnose pipeline state with DecompilerHarness.

dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 -S @Source
dotnet-inspect member MyType Method:1 --library MyLib.dll -S "Decompiled Source"
dotnet-inspect member MyType Method:1 --library MyLib.dll -S "Annotated Source"
dotnet-inspect member MyType Method:1 --library MyLib.dll -S "Fidelity Causes"
dotnet-inspect library MyLib.dll --il-offset 0x06000001+0x5

Output and querying

Default output is Markdown. Use Markdown for evidence and narrative, --table for compact human scanning, --tsv for normalized tab-separated rows for agents and scripts, --jsonl for one JSON object per table row, and --json for structured object graphs. Use --plaintext for plain text, --bare for one undecorated payload without changing the selected shape, --value for one scalar, --urls for URL lists, --paths for path lists, --print to materialize one printable selected-section row (--row N chooses a printable row), --print-all to materialize every printable row with separators, --json-array to emit projected rows as one JSON array, --rows -n N to cap rendered table rows, --count to reduce a selected section/vector to a single row count, and --mermaid on depends for diagrams. Verbosity is -v:q, -v:m, -v:n, or -v:d. Markdown and JSON can represent multi-section documents; --table, --tsv, and --jsonl render one table/section at a time, so pair them with a specific -S selection when querying sectioned output.

Sections and fields are queryable without a template language:

dotnet-inspect library System.Net.Security -S "Async*"
dotnet-inspect member JsonSerializer --package System.Text.Json -D
dotnet-inspect member JsonSerializer --package System.Text.Json -D --schema
dotnet-inspect type --package System.Text.Json --columns Kind,Name
dotnet-inspect library System.Text.Json -S Symbols --fields "PDB*;SourceLink"
dotnet-inspect library System.Text.Json -S @Audit
dotnet-inspect library System.Text.Json -S "Async*" --count
dotnet-inspect package Microsoft.Extensions.Logging.Abstractions --library -S Integrations
dotnet-inspect library Microsoft.Extensions.Logging.Abstractions -S Integrations
dotnet-inspect library Microsoft.Extensions.Logging.Abstractions -S Logging
dotnet-inspect library System.Diagnostics.DiagnosticSource -S OpenTelemetry
dotnet-inspect library System.Text.Json -S Signals
dotnet-inspect package System.Text.Json --path @readme --content --frontmatter
dotnet-inspect package Newtonsoft.Json -S "Package Info" --fields Version --value
dotnet-inspect type Command --project ./src/App
dotnet-inspect member Command --project ./src/App --show-index
dotnet-inspect project ./src/App -S Skills --jsonl
dotnet-inspect project ./src/App -S Skills --paths
dotnet-inspect project ./src/App -S Skills --print --row 1
dotnet-inspect type JsonSerializer --platform System.Text.Json -S "Source Files" --urls --json-array
dotnet-inspect type JsonSerializer --platform System.Text.Json -S "Source Files" --print --row 1

For target-based queries, -D reports the effective schema by default: only sections and columns that can actually render for that query. Add --schema for the static schema. Bare -S renders @Default, a curated high-density view; type/member summaries use Method Groups, while member Type -m Name uses Methods overload rows. Lists for -S, --columns, and --fields accept commas or semicolons. Use -S @All to select all sections; it renders the default section first, then remaining sections alphabetically. Workflow categories such as @Source and @Audit expand to scenario-focused section groups.

Common examples

dotnet-inspect library System.Text.Json -S Signals
dotnet-inspect package Microsoft.Extensions.Logging.Abstractions --library -S Integrations
dotnet-inspect library Microsoft.Extensions.Logging.Abstractions -S Integrations
dotnet-inspect library System.Diagnostics.DiagnosticSource -S OpenTelemetry
dotnet-inspect library System.Text.Json -S "Signals,SourceLink Availability,SourceLink Missing Files"
dotnet-inspect library System.Text.Json -S "SourceLink Integrity"
dotnet-inspect package System.Text.Json -S Signals
dotnet-inspect package System.Text.Json --versions
dotnet-inspect package System.Text.Json@8.0.0..8.0.5 --versions
dotnet-inspect type JsonSerializer --package System.Text.Json@8.0.0..8.0.5 --at '#4'
dotnet-inspect member JsonSerializer Serialize --package System.Text.Json@8.0.0..8.0.5 --at 8.0.5
dotnet-inspect type Command --project ./src/App
dotnet-inspect member Command --project ./src/App --show-index
dotnet-inspect project ./src/App -S Skills
dotnet-inspect project ./src/App -S Skills --print --row 1
dotnet-inspect type JsonSerializer --platform System.Text.Json -S "Source Files" --print-all
dotnet-inspect type string --shape
dotnet-inspect type --package System.Text.Json --table
dotnet-inspect member JsonSerializer --package System.Text.Json -m Serialize
dotnet-inspect member JsonSerializer --package System.Text.Json -m Serialize -S "Member Index"
dotnet-inspect member JsonSerializer --package System.Text.Json -m Serialize -S "Source Locations"
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 -S @Source
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 -S Calls
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 -S Callers
dotnet-inspect member string IndexOf:7 -S Callers --caller-package System.Text.Json@9.0.0 --tfm net9.0
dotnet-inspect member MyApi.Helper Run:1 --library MyLib.dll --bin ./app/bin/Release/net10.0
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 -S "Call Graph"
dotnet-inspect member MyType MyMethod:1 --library MyLib.dll -S "Unsafe*"
dotnet-inspect library System.Text.Json --il-offset 0x06000004+0x15
dotnet-inspect diff --package System.Text.Json@9.0.0..10.0.0 --breaking
dotnet-inspect timeline --package System.Text.Json@8.0.0..9.0.0 --type System.Text.Json.JsonSerializer --members --at all
dotnet-inspect timeline --package MyLib@1.0.0..2.0.0 --type MyType --member Parse --finding analysis.unsafety --at all
dotnet-inspect diff --library old/Foo.dll..new/Foo.dll -S "Implementation Diff" --authored-source -m MyType.HotPath
dotnet-inspect depends Stream --markdown --mermaid
dotnet-inspect implements IEquatable --project ./src/App -v:q
dotnet-inspect extensions string --project ./src/App -v:n
dotnet-inspect depends Command --project ./src/App -v:q

Requirements

.NET 10.0 SDK or later.

LLM integration

dotnet-inspect is designed for LLM-driven development. The embedded skill (dotnet-inspect skill) is also distributed through the dotnet/skills marketplace.

Contributor and agent docs

Start with AGENTS.md for repository-wide engineering and workflow rules. It routes each change to the focused documentation that must be read. Use docs/overview.md when a change crosses subsystem ownership boundaries, and taste/skill-guidance.md when maintaining the embedded skill.

License

MIT

About

Tool to inspect .NET assets, like docker inspect and kubectl describe.

Resources

Stars

146 stars

Watchers

2 watching

Forks

Packages

 
 
 

Contributors

Languages