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.
dotnet tool install -g dotnet-inspect
dotnet-inspect <command>Run without installing:
dnx dotnet-inspect -y -- <command>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 --versionIf 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 ReleaseIf 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 falseThen 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 ReleaseFor 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 ReleaseThat 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 listThe 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.
| 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 | 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 | 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 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 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.
These features are under active development. Their output shapes, section names, and signal sets may change between releases.
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.
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 (Full → Partial → StructuredOnly →
IlOnly → Failed) 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+0x5Default 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 1For 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.
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.NET 10.0 SDK or later.
dotnet-inspect is designed for LLM-driven development. The embedded skill (dotnet-inspect skill) is also distributed through the dotnet/skills marketplace.
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.
MIT