Skip to content

Latest commit

 

History

History
2830 lines (2455 loc) · 153 KB

cli-reference.md

File metadata and controls

2830 lines (2455 loc) · 153 KB

dotnet-inspect CLI reference

A tool for inspecting .NET libraries and NuGet packages. It is for .NET what docker inspect and kubectl describe are for containers: view package metadata, API surfaces, dependencies, and source.

The .NET ecosystem uses a standardized binary format for managed assemblies (ECMA-335 .dll files). That's why NuGet packages primarily distribute binaries instead of source. That's where dotnet-inspect fits. It does for .NET binaries what LSP-based tools do for source. dotnet-inspect reads .NET binaries to answer basic questions about types and members and unlocks deeper insights, like call graphs and seeing what really changed across two binary versions

Install or run

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

Run without installing:

dnx dotnet-inspect -y -- <command>

Choose a Platform source

dotnet-inspect can load direct local libraries, packages from configured Package Sources, and Platform libraries. Platform requests prefer locally installed packs when dotnet-inspect has a usable .NET root and the requested version is installed. Otherwise, they use the package-backed Platform source.

A framework-dependent invocation may derive the root containing its current CoreCLR runtime; a NativeAOT invocation cannot. For a .NET installation outside that runtime-derived location, learn the root from machine provisioning or its tool manager, verify that it contains packs, and set process-scoped DOTNET_ROOT:

dotnet_root=/absolute/path/to/dotnet-root
test -d "$dotnet_root/packs" &&
  DOTNET_ROOT="$dotnet_root" dnx dotnet-inspect -y -- find JsonSerializer
$dotnetRoot = "C:\absolute\path\to\dotnet-root"
if (-not (Test-Path -Path (Join-Path $dotnetRoot "packs") -PathType Container)) {
    throw "The selected .NET root does not contain packs."
}
$env:DOTNET_ROOT = $dotnetRoot
dnx dotnet-inspect -y -- find JsonSerializer

DOTNET_ROOT is the installed-root override; dotnet-inspect does not infer it from PATH. Without a usable explicit or runtime-derived root, Platform requests use the package-backed source.

Repository development SDK

Published tool users can install or run dotnet-inspect with the commands above. Contributors building this repository should use .NET 11 RC1 SDK 11.0.100-rc.1.26425.128.

Check the selected SDK first:

command -v dotnet
dotnet --version

Build from source:

dotnet build dotnet-inspect.slnx -c Release

See AGENTS.md for launch guidance, Repository workflow for contributor rules, and Local development for targeted test commands.

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/DotnetInspect.Cli, project ./src/DotnetInspect.Cli -S Skills --print, project ./src/DotnetInspect.Cli -S README Uses an existing project.assets.json as restored-assets context for API lookup, relationship search, dependency package skills, and root package README files; restore/build first if dependencies changed. dotnet-inspect does not restore, build, or acquire missing packages.
Platform libraries library System.Private.CoreLib, library System.Text.Json --version 10.0.0, diff --platform System.Runtime@9.0.0..10.0.0 Prefers installed packs when the requested version is available; otherwise uses package-backed Platform packs.
Local assets library ./artifacts/obj/ILInspector.Metadata/release/ILInspector.Metadata.dll, package ./artifacts/MyLib.nupkg Useful for auditing local builds before publishing.

Platform packs have distinct package, Platform, and direct-library views. For example, package Microsoft.NETCore.App.Ref@10.0.0 inspects the targeting-pack container as an exact NuGet package, while library ./packs/Microsoft.NETCore.App.Ref/10.0.0/ref/net10.0/System.Runtime.dll inspects one manually downloaded or extracted DLL directly. A Platform selection unwraps authorized pack DLLs without publishing its source pack as a Package participant. These entry paths preserve different provenance and do not infer Platform identity from a package or file name.

Windows Metadata (.winmd) is not a supported input format, and rejection is only partially enforced. Directory and package scans select *.dll, so a .winmd beside them is skipped without comment. A native *.dll in a directory scan is also skipped; a directory with only native images is reported as a failed source. A .winmd named explicitly — library ./Foo.winmd, find --library ./Foo.winmd — is rejected rather than inspected, though not every surface names the reason: find reports "Windows Metadata is not a supported metadata format", while library reports only "Could not read library". Owners that have not yet adopted the admission contract do not classify at all. Treat any Windows Metadata result as unsupported output regardless of how confident it looks. Tracked by #5559.

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.

After exact Type and Member lookup misses, a dotted Platform name may resolve as an exact namespace in its longest namesake Library. For example:

dotnet-inspect System.Text.Json.Nodes

is equivalent to:

dotnet-inspect library System.Text.Json \
  --namespace System.Text.Json.Nodes

The Router confirms exact ordinal namespace membership before selecting this route. It does not use suffix or descendant matching, and broad inputs such as System.Text retain their existing Type-prefix browsing behavior.

find uses the same exact namespace meaning after direct Type lookup misses:

dotnet-inspect find System.Text.Json.Nodes

It returns the public Types declared directly in System.Text.Json.Nodes, such as JsonArray, JsonNode, and JsonObject. It does not include Types from System.Text.Json or descendant namespaces. The rows use the Namespace match classification. The default unscoped search uses the same House-realized Runtime and ASP.NET Core populations as other Type patterns. Explicit source options remain authoritative; for example, --platform System.Text.Json searches only that platform Library.

Add a terminal .* to include the named namespace and its descendants:

dotnet-inspect find 'System.Text.Json.Serialization.*'

This is namespace-aware rather than an ordinary Type glob. It includes Types from System.Text.Json.Serialization and System.Text.Json.Serialization.Metadata, classifies them as Namespace, and uses the same package and Platform source policy as exact namespace discovery. The literal dot is significant: System.Text.Json.Nodes.* excludes System.Text.Json.NodesExtra, while System.Text.Json.Nodes* remains the broader lexical Type glob with Glob classification.

find classifies each Type independently without requiring wildcard syntax:

dotnet-inspect find JsonSer       # Prefix and similar Types in discovery order
dotnet-inspect find Serializer    # Substring: XmlSerializer, JsonSerializer, ...
dotnet-inspect find AppendFormat  # Members: StringBuilder.AppendFormat overloads

Each candidate receives one Exact, Direct, Glob, Namespace, Prefix, Substring, or Partial classification. Exact and broader classes can mix; the rows retain source and declaration discovery order rather than sorting by name or similarity score. An undotted identifier without an Exact, Direct, Glob, Namespace, or Prefix Type may also search member names; Markdown shows those rows in a separate Members section. Plain --json and table formats keep Type rows only and note omitted member matches; --count rejects an answer that includes them. Use find .AppendFormat for member rows in every format.

-n N is also Find's maximum hit budget across its Type or Member patterns. For Type search, duplicate identity and per-candidate classification occur before the budget. Find keeps the Nth accepted candidate, then stops before the next Type, query participant, pattern group, source, or implicit broadened Member fallback. Use a leading dot or --members when Member rows are the requested bounded answer. If Type rows do not fill the budget, implicit Member fallback may still contribute and its rows precede weak Type rows in the presented answer. The current reverse-locator package route applies Head after its complete resident census; other compatibility and Platform routes stop metadata traversal directly.

A sole finite --rows A..B or --rows ..B similarly stops after accepted row B for explicit Member Find and for Type patterns that cannot enter implicit Member fallback, such as wildcard or dotted patterns. The strict window still fails when row B does not exist. Ordinary undotted Type patterns remain exhaustive because fallback Member rows can precede Type rows and suppress weak Type matches. --tail, open-ended windows, and multi-stage row selection also remain exhaustive.

Library Type hierarchy

A bare library command that resolves one Library renders its public-surface Type declarations as a Tree: the Library, its namespaces with declaration counts, and each declaration by name. Forwarded declarations are marked (forwarded). The Tree shows no Member counts; use type <Type> for a Type's Members.

dotnet-inspect library System.Text.Json
System.Text.Json 11.0.0.0
├─ System.Runtime.CompilerServices (3 types)
│  ├─ IsExternalInit (forwarded)
│  └─ …
├─ System.Text.Json (20 types)
│  ├─ enum JsonCommentHandling
│  ├─ class JsonDocument
│  └─ …
└─ …

--tree and -v:m select the same Tree, and --mermaid renders the same nodes as a Mermaid graph. Platform, package, and file sources are accepted, together with --framework, --version, --preview, one --tfm, --namesake-library, NuGet source options, and --verbose. A package that contributes more than one Library keeps the multi-Library view; explicit --tree or --mermaid on such a package fails and asks for the assembly within the package. Any other option, including -S, -v:n, -v:d, and every format option, keeps the sectioned Library view; combined with such an option, --tree and --mermaid keep their -S "Reference Hierarchy" requirement. A DOTNET_INSPECT_FORMAT default also keeps the sectioned view unless --tree, --mermaid, or -v:m is given explicitly. Library facts remain available as -S "Library Info".

A Library with no public Types renders its identity line marked (no public types). A Library whose Type population cannot be read completely fails with the reason instead of rendering a partial Tree.

Library namespace Type listings

An exact Library can list its public Type declarations from one exact namespace:

dotnet-inspect library System.Text.Json \
  --namespace System.Text.Json.Nodes

Add --children to include the named namespace and all namespaces beneath its dot-segment boundary:

dotnet-inspect library System.Text.Json \
  --namespace System.Text.Json \
  --children

This includes Types from System.Text.Json and System.Text.Json.Serialization, but not System.Text.Jsonish.

A leading dot selects an exhaustive namespace suffix within that same exact Library:

dotnet-inspect library ./MyLibrary.dll --namespace .Nodes

.Nodes matches Types declared in namespaces such as World.Blue.Nodes and World.Green.Nodes. It does not prepend the Library name, and it does not match Nodes, World.Blue.MyNodes, or World.Blue.Nodes.More. Markdown renders the matching declarations in Type tables without a separate count summary. --envelope exposes the same population's typed exact, exact-or-descendant, or suffix binding and continuation identity. Namesake source discovery belongs to Router, Spotlight, and find, not this exact-Library operation.

Use -D --schema to inspect the syntax-selected structural view without acquiring or loading the target. Package --library and --all-libraries queries expose their route-specific schemas before package resolution, while ambiguous commandless or dotted-member targets return separately labeled alternatives rather than a lookup-chosen union. A commandless <target> --all-libraries gesture always selects the package aggregate view.

Demo: query rendered C# body shapes

Discover the stable IDs accepted by body queries:

dnx dotnet-inspect -y -- explain vocabularies/csharp.body-kinds --depth 1

The depth-1 listing shows every value's exact Identity, such as ObjectCreationExpression or BreakStatement, which is the spelling queries accept; Name is a display label.

Then use one as a typed predicate. Kind=... auto-selects Body Shapes, while ordinary section query options still control columns and rows:

dnx dotnet-inspect -y -- library System.Text.Json \
  --where "Kind=ObjectCreationExpression" \
  --columns "Member;Token;Match" -n 3
# System.Text.Json.dll

## Body Shapes

| Member | Token | Match |
| ------ | ----- | ----- |
| `System.Text.Json.JsonDocument.RootElement~2810741072:1` | `0x06000260` | `new JsonElement(this, 0)` |
| `System.Text.Json.JsonDocumentOptions.CommentHandling~4fc3b6f99d:2` | `0x060002DC` | `new ArgumentOutOfRangeException("value", SR.JsonDocumentDoesNotSupportComments)` |
| `System.Text.Json.JsonElement.GetProperty~b07c7787dc` | `0x060002EA` | `new KeyNotFoundException(SR.Format(SR.Arg_KeyNotFoundWithKey, propertyName))` |

For an overview, explicitly select Body Shape Summary to group identical rendered matches with an occurrence count:

dnx dotnet-inspect -y -- type StringBuilder --platform System.Private.CoreLib \
  --where "Kind=ObjectCreationExpression" -S "Body Shape Summary" \
  --columns "Match;Count"

Body Shapes retains individual occurrences. Keep Member, Token, and the start/end line and column fields to locate each match in the method's rendered C# body; these coordinates are not IL offsets or original source locations. Hiding columns never groups rows. Summary row limits select groups without reducing their occurrence counts; --count counts the selected view's rows. Both views are available on library, type, and member.

Use --jsonl for one machine-readable row per match or --count for the row count. Bodies that cannot be reconstructed at full fidelity make the search incomplete: the observed rows and count still print, stderr reports how many bodies were not searched (--verbose lists them), and the command exits 1.

Capability inventory

Capability Commands Highlights
Package inventory package Metadata, versions, TFMs, file layout, direct dependencies, recognized ecosystem dependencies, rooted dependency hierarchy, vulnerability data, custom feeds, and NuGet config support.
Project package skills and docs project Section-driven direct-dependency rows from valid skills/**/SKILL.md files and root README.md files in the restored package cache. Use --print --row N to emit one selected document. Skill inventory values and complete documents that require containment become [Text omitted: required containment]; selected documents also report bounded code-point locations on stderr.
Query vocabulary explain vocabularies Product-owned stable values, accepted query inputs, maps, and defaults for rich queries.
Ecosystem catalog ecosystem Product-configured ecosystem packs, namespace hints, core/tool packages, demos, and known Integration bindings without package acquisition.
Library audit library Assembly identity, public key token, trim/AOT metadata, unsafe/interoperability signals, SourceLink, PDBs, references, resources, async methods, and body-shape search.
API discovery type, member, find Type search, exact namespace discovery, member tables, docs, overload selection, generics, direct calls/callers, source, decompiled C#, and IL. Unscoped find searches installed Platform populations and adds exact prune-authorized package observations for namespace hits; add other package APIs through explicit --package, restored --project, or patterned --package-prefix scope.
Package discovery package query Discover exact package IDs or terminal-star package-ID prefixes before inspecting a known package with package.
API compatibility diff Package, platform, and library diffs with breaking/additive classification plus opt-in C#/IL, selected-member authored-source, complexity, and structural-cohort context.
Timeline correlation timeline Correlate API or member-body Findings across a package version range, with evaluation and transition views.
Implementation matching match Identity-agnostic structural equivalence for two unambiguously named methods, plus --similar seeded discovery that ranks structural candidates for one seed.
Structural clone discovery library/type/member -S "Clone Candidates" Workspace-scoped structural candidate ranking for an exact Library, Type, or logical Member seed, with independent Breadth and Discovery facets.
Library vocabulary library -S "Name Families" Ranked one- and two-word Type-name suffix families, exact supporting Type evidence, and optional source-provenance populations.
Library dependency structure library -S "Dependency Structure" Internal namespace dependency graph with relationship counts, topological levels, and cycle membership.
Relationships graph, depends, extensions, type -S Implementers, type -S "Derived Types" Integration graphs, type hierarchies, explicit package/nuspec/library/restored-project dependency graphs, reference graphs, extension methods/properties, implementors, and subclasses.
Direct dependency evidence depends -S Dependencies depends combines explicit roots, traversal, and normalized declaration/restored evidence in one sectioned document.
Package pruning policy depends -S Pruning Explicitly compares source-authorized direct dependency candidates with an exact installed runtime or ASP.NET Core platform inventory, without changing graph traversal.
Source type/member -S Source / @Source, library/package -S "SourceLink: Files", type -S "Source Files", member -S "Source Locations" Source is authored-first and retains provider and fallback context. @Source adds forced PDB Source and Decompiled Source views plus Source Diff; SourceLink inventories remain separate.
Performance analysis (experimental) library -S "Library Metrics", library -S @Performance, library -S "Performance: Strings", type/member -S "Performance Triage", "Top Leverage", "Resource Triage", "Call Graph" Whole-library structural metrics, whole-assembly leverage ranking, exact string-materialization operations, actionable rewrite-shape detection, and exception-path resource-lifecycle candidates.
Decompiler (experimental) member -S @Decompiler, member -S "Fidelity Causes", member/type/library --where "Kind=<ID>" Decompiled C#, annotated source, IL, body-shape queries, and typed DEC#### fidelity causes.
Raw metadata library -S @Metadata, library address "#Strings:0x1a4" Decoded ECMA-335 metadata tables and heap addressing.
Workspace definition, inventory, and navigation workspace --package X --tfm TFM --share packet Author a durable format-3 Workspace definition without acquisition, or omit --share to realize and render typed top-level inventory. Repeat --package to compose Package Scope; add --register-library, --register-package-prefix, or --register-ecosystem for registration intent. --packet accepts a canonical Base64URL packet string. Add --active-ecosystem ID for a resource-free Ecosystem subject or --active-package N for structural Library, Type, Member, and lens descriptors.
Package Queries package query ID --where "library-literal=TEXT" --tfm TFM, workspace --root-request TOKEN AND-compose ordinary Package Query terms with an ordinal decoded-ldstr substring over each prequalified package's selected implementation libraries. Results remain package-grain and carry typed producing-Library context, complete occurrences, and exact Root reopening tokens.
Workspace sharing and editing workspace packet encode / decode, workspace component list, workspace package add / update / remove Convert canonical browser/CLI packets, discover stable component paths, and immutably derive edited Workspace packets.
Agent-friendly output global flags Markdown by default, compact --table, normalized --tsv, --jsonl, --json, Mermaid diagrams, section/field projection, --count, and row limiting.

Command inventory

Command Purpose
package X Inspect NuGet metadata, versions, dependencies, TFMs, layout, and vulnerabilities.
package query X Discover exact package IDs or terminal-star package-ID prefixes, with optional metadata, dependency, ecosystem, and selected-Library qualification.
package activity --ecosystem NAME Report bounded recent package activity for an ecosystem-selected package population, with source coverage and security evidence.
project [path] Inspect restored project package skills and package docs.
library X Inspect assembly metadata, symbols, SourceLink, references, resources, async methods, and rendered body shapes.
library query DIR Query a directory or --platform reference pack as a bounded Library population; references=NAME qualifies direct assembly references.
type X Discover types or render a single type shape.
member X Inspect members, docs, overloads, decompiled/lowered C#, rendered body shapes, checksum-verified PDB source, and IL.
find [X] Search for API types in installed .NET Runtime, ASP.NET Core, and .NET Standard populations by default. Add --members (or lead the query with ., such as .Serialize) to search member names; add package APIs through explicit --package, restored --project, or patterned --package-prefix scope. Use package query to discover package IDs.
diff X Compare API surfaces by default; opt into analysis or implementation evidence.
timeline X Correlate API or member-body Findings across a package version range.
graph integrations Induce extension, observed Integration, and Integration-opportunity relationships over an explicit package set; -n, --tail, and --rows select complete logical edges after graph construction.
graph calls TYPE MEMBER Explain one package member's supply-chain exits across its dependency graph, retaining highlighted boundaries and their shortest baseline connectors.
graph libraries Discover deterministic direct-use clusters and exact cross-library relationships between two local Libraries.
graph packages Discover deterministic direct-use clusters across the complete implementation-Library matrix of two exact Packages.
graph cluster N Inspect exact calls for one local-Library-pair or Package-pair Direct-Use Cluster ordinal; the local route also supports public-entrypoint paths.
depends [Type] With a positional type, walk its hierarchy inside --package, --library, --project, or platform search scopes. Without a positional type, combine repeatable explicit --package, --nuspec, --library, and --project roots, or exclusive --package-prefix, into one dependency graph and evidence document.
extensions X Find extension methods and C# extension properties for a type.
type X -S Implementers Find concrete implementors of an exact interface focus.
type X -S "Derived Types" Find subclasses of an exact base-type focus.
match A B Compare two unambiguous Type.Member names by identity-agnostic structural equivalence; add --body for decompiled C# and IL body differences.
match A --similar Rank structural candidates for one seed method, within a single assembly. Ranks candidates only; it establishes no relation.
explain vocabularies Explain product-owned query vocabularies such as api.accessibility, csharp.style-choices, and csharp.body-kinds. Add /<id> for one vocabulary, --depth 1 for all of its values, or /<id>/values/<value> for one value.
ecosystem [name] Inspect the ecosystem knowledge configured into this product build. Omit the name to list packs; use -S Integrations for configured Integration concepts, distinct from observations in a library.
workspace Render the typed top-level inventory of one ephemeral Workspace: committed ordered Package occurrences first, then inert Exact Library, Package Prefix, and Ecosystem registrations. Repeat --package ID@VERSION coordinates and supply --tfm; add --register-library PACKAGE@VERSION/ASSEMBLY@ASSEMBLY_VERSION, --register-package-prefix PREFIX, or --register-ecosystem ID; filter with repeatable --kind. Restore a current-format canonical Workspace packet with --packet PACKET, or use --root-request TOKEN to reopen the exact Package Root a package query --where "library-literal=..." result names. Add --active-ecosystem ID to activate the exact resource-free registration with Ecosystem Overview, or --active-package N to evaluate the exact Package occurrence and expose its Navigation hierarchy, Library asset IDs, Type and Member inventories, lenses, and diagnostics.
workspace packet encode / decode Convert validated Workspace JSON and canonical base64url packets; pass - for stdin or use --file.
skill Print the base LLM skill and route to focused built-in guidance (skill list, skill query, skill decompiler, skill relationships, and more).
demo [id] List or run product-home inspection demos backed by real section output.
cache Inspect or clear dotnet-inspect caches.

Bare type ... --count follows the resolved subject: a Library subject counts Types, while a Type subject counts Members. Add -S to count a particular section or category instead; several explicitly selected row sets retain their per-section count table.

Signals, integrations, and focused guidance

Signals is an evidence report, not a safety certification. Use -S Signals for a compact package or library overview, then opt into deeper audits only when you need them.

Observed integration support is exposed through one Integrations section. Use integration=<canonical-concept-id> to focus one concept, or ecosystem=<canonical-pack-id> to enable the Integration concepts registered to an ecosystem. The current Aspire registration enables the complete configured Integration catalog; only concepts observed in the inspected library produce rows. Add integration=... to narrow within that enabled set. @Integrations also includes the separate Integration Opportunities section.

Use ecosystem to inspect which ecosystem packs and Integration bindings are configured into this build. This is catalog knowledge, not evidence from an acquired library:

dotnet-inspect ecosystem
dotnet-inspect ecosystem aspire
dotnet-inspect ecosystem aspire -D
dotnet-inspect ecosystem aspire -S @Ecosystem
dotnet-inspect ecosystem aspire -S Integrations
dotnet-inspect ecosystem ai -S "Core Packages"
dotnet-inspect ecosystem aspire -S "Core Packages"
dotnet-inspect ecosystem blazor -S "Core Packages"
dotnet-inspect ecosystem maui -S "Core Packages"
dotnet-inspect ecosystem microsoft-extensions -S "Namespace Hints"
dotnet-inspect ecosystem runtime -S Pruning

Package Info and Library Info summarize ecosystems recognized from direct dependencies. Select Ecosystem Dependencies to see the dependency/ecosystem pairs, including one row per ecosystem when a dependency intentionally overlaps multiple packs:

dotnet-inspect package Microsoft.Extensions.Http@10.0.0 \
  -S "Package Info"
dotnet-inspect library --platform System.Text.Json \
  -S "Library Info"
dotnet-inspect library --platform System.Text.Json \
  -S "Ecosystem Dependencies" \
  --columns "Ecosystem,Kind,Dependency,Declared By"

Library recognition classifies the selected Library's declared assembly references. Package declarations use product-profile associations directly. Assembly references first match an authored exact or family association and then require a compatible same-name AssemblyDef from one exact shipped Package-asset evidence entry. Detail rows distinguish Profile match, Catalog-backed, and Candidate; catalog-backed rows name the exact Package asset. Candidates matched an ecosystem association without corroborating AssemblyDef evidence and therefore do not enter the compact Package or Library Info ecosystem rollup.

Recognition does not resolve or traverse assembly references. Unrecognized references do not become ecosystem rows, while JSON still reports recognition status as complete. Complete means every available direct observation was classified against the shipped profile; it does not claim runtime binding or high-confidence provenance.

Core Packages are inert registered package roots. Catalog inspection performs no source work; a later bounded operation that selects the ecosystem may resolve those concrete packages and follow their ordinary dependencies. Package-prefix matches remain discovery scope and are not substituted for those roots.

Use package activity --ecosystem to report package activity under one named ecosystem's recorded package prefixes (for example Aspire. for aspire). The ecosystem option selects where to look; ecosystem itself remains the acquisition-free catalog command. This network-backed query defaults to the interval (reference time - 42 days, reference time], reports the exact UTC bounds and source horizon, and overlays current GitHub-reviewed advisory context and evidenced security releases:

dotnet-inspect package activity --ecosystem aspire
dotnet-inspect package activity --ecosystem aspnetcore --security-only
dotnet-inspect package activity --ecosystem microsoft-extensions -n 25 --json
dotnet-inspect package activity --ecosystem aspire \
  --from 2026-02-01T00:00:00Z \
  --through 2026-03-01T00:00:00Z

--from is exclusive and --through is inclusive; specify both with explicit UTC offsets, and keep the interval at 42 days or less. --security-only keeps activity with positive current-advisory or exact security-release evidence. Unavailable evidence is not treated as a negative. Human output uses the shared report view; --json emits the lossless schema-versioned report, while --envelope emits the same report as Content with Share and diagnostics. --compact minifies either JSON boundary. Use --verbose for bounded acquisition progress on stderr. Single-table formats and catalog-only section projections are not available with package activity.

ecosystem runtime -S Pruning is the exception to "catalog knowledge": it reads the reference pack installed on this machine to list the package identities the platform target supplies, so a reference to one resolves to the platform rather than to the package. Kind separates a version that moves with the framework (live) from one pinned to a release the framework has passed (frozen).

All integrations are enabled by default. Discover the supported ecosystem predicate with library -Q Integrations, then narrow the ordinary result:

dotnet-inspect library -Q Integrations
dotnet-inspect library Aspire.Hosting.Redis@13.5.3 --tfm net8.0 \
  -S Integrations --where "ecosystem=ecosystem.aspire"
dotnet-inspect library ./MyLibrary.dll -S Integrations \
  --where "integration=integration.aspire" --jsonl

These facets filter Integration evidence and opportunities, not assembly-wide presence or Census. When both are supplied, they intersect. Other query families cannot be combined with either Integration facet.

For deeper how-to guidance, use the embedded skills instead of relying on a very long README:

dotnet-inspect skill list
dotnet-inspect skill query
dotnet-inspect skill signals
dotnet-inspect skill decompiler
dotnet-inspect skill performance
dotnet-inspect skill relationships

Experimental features

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

Performance analysis

Use library -S @Performance for a whole-assembly triage pass, Top Leverage for ranking, Resource Triage for exception-path pool-churn candidates, and Call Graph to drill one selected member. The performance skill covers the full workflow in more depth. Performance: Sync Calls in Async finds synchronous calls made by async methods when the declaring type offers a callable async sibling, including Dispose/DisposeAsync pairs.

dotnet-inspect library System.Text.Json -S @Performance
dotnet-inspect library System.Text.Json -S "Library Metrics"
dotnet-inspect library System.Text.Json -S @Performance --count
dotnet-inspect library System.Text.Json -S "Performance: Boxing" --json
dotnet-inspect library System.Text.Json -S "Performance: Strings" --json
dotnet-inspect library System.Text.Json -S "Performance: Sync Calls in Async"
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 -S "Call Graph"

Decompiler

Use member -S @Source for the authored-first source view, forced PDB and decompiled provider views, and their source diff. Use member -S @Decompiler for decompiled and annotated C#, IL, and related analysis evidence. Use Fidelity Causes when a body cannot be raised faithfully. In Inspect Web, All also reveals exact direct-call relationships at their source locations; these remain outside the default Finding set. Explore starts with one Relationships row per exact physical call, with explicit call-site inspection and Member or Source target actions. An opt-in Diagram groups repeated physical calls by their stable logical edge while keeping every exact call site available through the table. Selecting a recursive relationship shows its exact direct or mutual cycle witness and whether the bounded focus-graph census was complete. Selecting a framework Task.Wait, Task<T>.Result, or task-awaiter GetResult relationship also shows the exact synchronous-completion structure without claiming that runtime blocking was measured. Selecting a proven classic await explains its inline and suspension/resume paths, while selecting an exception-related allocation distinguishes a thrown value from an allocation inside a catch, filter, or fault handler. A relationship can also show a bounded direct-call path to a method containing an Analysis-proven local throw new, including its exception type and physical construction and throw offsets. These are compiled-structure claims only: they do not prove that a path ran, that a throw escapes, or that an exception propagates to the selected method.

dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 -S @Source
dotnet-inspect type JsonSerializer --package System.Text.Json -S Source
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 -S Source
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 -S "Fidelity Causes"
dotnet-inspect library address 0x060002EA+0x0 \
  --package System.Text.Json --library System.Text.Json.dll
dotnet-inspect library address --file coordinates.txt \
  --library ./MyLibrary.dll

Coordinate files accept up to 1,024 significant records. Blank and comment lines are ignored; valid and malformed records remain interleaved in source-file order so row windows select the same records the producer supplied.

ReadyToRun and raw metadata

ReadyToRun and metadata sections are opt-in only. Use @ReadyToRun for the validated image header and section directory. Use @Metadata to discover or render decoded ECMA-335 table rows, --metadata-root r2r-manifest to inspect the ReadyToRun manifest metadata instead of the default CLI root, and library address for one exact heap address in the selected root.

dotnet-inspect library System.Private.CoreLib -S @ReadyToRun
dotnet-inspect library ./artifacts/obj/ILInspector.Metadata/release/ILInspector.Metadata.dll -D @Metadata
dotnet-inspect library ./artifacts/obj/ILInspector.Metadata/release/ILInspector.Metadata.dll -S @Metadata --count
dotnet-inspect library ./artifacts/obj/ILInspector.Metadata/release/ILInspector.Metadata.dll -S "Metadata: TypeRef" --rows 20
dotnet-inspect library address "#Strings:0x1a4" \
  --library ./artifacts/obj/ILInspector.Metadata/release/ILInspector.Metadata.dll
dotnet-inspect library System.Private.CoreLib --metadata-root r2r-manifest -S "Metadata: Image"

Output and querying

Default output is Markdown. For compact human scanning use --table; for machine-friendly rows use --tsv or --jsonl; for structured graphs use --json; for plain text use --plaintext; and for diagrams use --mermaid. Tips are off by default. Member uses one dotted explanation-projection namespace at two placements: --explain replaces ordinary output with a primary result on stdout, while short-only -E preserves ordinary output and writes a companion to stderr. Bare selects the complete explanation; .tips, as a separate dotted token, selects up to three contextual suggestions:

dotnet-inspect member --explain
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize \
  --explain
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 \
  --explain
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize \
  --explain .tips
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize -E
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize \
  -E .tips

Command-level member --explain is acquisition-free. Subject-bearing --explain resolves exactly one semantic subject and writes its explanation as the terminal stdout document instead of ordinary inspection output. A bare ordinary method name is one MemberGroup subject regardless of overload count; an ordinal or digest selector is one exact Member subject. Singleton groups remain MemberGroups, and an overloaded group is not rejected as several subjects or reduced to its first overload. Resolved-subject --explain .tips writes only the headless plain-text suggestions to stdout; it does not produce ordinary Member Content. Command-level .tips requires a MemberGroup or exact Member because the command resource has no applicable gesture context. Resolved-subject bare -E preserves ordinary stdout byte-for-byte, flushes it, then writes the same explanation Content to stderr. --explain -E and --explain .tips -E .tips are duplicate projections and are rejected; different primary and companion projections compose. Bare -E remains reserved on other commands. Both .references placements remain reserved until reusable inspection references are available. Legacy -T and --tips, lowercase -e, undotted -E tips / -E references / --explain tips / --explain references, attached or inline -E.tips / -E=.tips / -E:.tips / --explain=.tips, unknown dotted children, and repeated placement options are invalid. An unrelated undotted token after either option remains positional. Option-like filenames and other required option values retain that option's ownership; for example, --out --tips names an output path rather than invoking the retired option. E suggests explain and can also remind users that the companion is written to the error stream; the latter is a mnemonic, not an error classification.

Positional depends <type>, ordinary single-Library API diff, package activity, Package Query, online package range-version population, and exact package-backed Type or Library API inspection support the presence-only --envelope service-output selector. It implies JSON. For depends, API Diff, Package Activity, Package Query, and exact Type or Library API inspection, unprojected --json emits the same Content without the service frame. Package version --json remains an explicit row projection; --envelope instead exposes the complete directed population Document, Share, and diagnostics. Asset-mode depends, other Diff modes, Discover, Count outside package population, projected output, other Type modes, and other commands have not adopted this transport.

Goal Flags
Discover available sections and fields -D, -D --schema
Add structural format, shape, and cardinality details -D --details, -D <exact-name> --details (library, package, type, member)
Discover query facets and operators -Q on library/type/member/package/find; e.g. library -Q @Performance or type -Q "Body Shapes"
Select sections or categories -S, wildcards such as -S "Async*", authored categories such as -S @Source or -S @Audit
Project columns/fields --columns, --fields
Limit semantic rows or rendered lines --rows, -n, --head, --tail, --lines, --tail-lines
Count results --count
Materialize one payload --print, --row, --value, --raw, --paths, package-file --roots, --urls, --json-array
Prefer browser views over fetchable URLs --prefer-rendered-urls (keeps the original URL when no mapping is available)
Control document verbosity -v:q, -v:m, -v:n, -v:d
Explain the Member command, one MemberGroup, or one exact Member member --explain, subject-bearing member ... --explain, or member ... -E
Show contextual tips Subject-bearing member ... --explain .tips on stdout or -E .tips on stderr
Control package sources --offline, --source, --add-source, --nugetconfig, --http-timeout

--offline is the only way to guarantee no network dependence. Without it, commands other than plain -D discovery may acquire packages and PDBs to answer the request. The network policy owns this rule and its adoption status.

--table, --tsv, and --jsonl render one section at a time, so pair them with a concrete -S when querying sectioned output. Markdown and JSON can represent multi-section documents.

--raw is itself a formatter. On package and project, do not combine it with --json, --jsonl, --tsv, --table, --markdown, --plaintext, or --mermaid; the command rejects those combinations before acquisition. Explicit --raw outranks DOTNET_INSPECT_FORMAT. The retired --bare spelling receives the ordinary unrecognized-input result.

Source URLs are fetchable by default. --prefer-rendered-urls prefers a browser view when supported; it changes neither --print acquisition nor undecorated --raw rendering. The former SourceLink URL-shape meaning of --raw is retired, and --blob is removed and unrecognized. Use no URL-shape flag for the default fetchable form.

-n N selects the command's items. It selects semantic rows when the active command or lens declares them; otherwise it selects the first N rendered lines. Add --tail for the last N items. --lines explicitly selects rendered lines on a semantic-row command, and --tail-lines selects rendered lines from the end. Rendered-line clipping is not available with JSON document output.

Useful discovery and projection patterns:

dotnet-inspect library System.Text.Json -D
dotnet-inspect library System.Text.Json -D --details
dotnet-inspect library System.Text.Json -D @Dependencies --details
dotnet-inspect library System.Text.Json -D "Reference Hierarchy" --details
dotnet-inspect library -Q
dotnet-inspect type -Q "Body Shapes"
dotnet-inspect library -Q "Performance: Arrays" --json
dotnet-inspect member JsonSerializer --package System.Text.Json -D --schema
dotnet-inspect explain vocabularies
dotnet-inspect explain vocabularies/csharp.body-kinds
dotnet-inspect explain vocabularies/csharp.body-kinds --depth 1
dotnet-inspect explain vocabularies/csharp.style-tiers/values/spelling
dotnet-inspect library System.Text.Json -S Signals
dotnet-inspect library System.Text.Json -S @Audit
dotnet-inspect library System.Text.Json -S References
dotnet-inspect library System.Text.Json -S "Reference Hierarchy" --tree
dotnet-inspect library Microsoft.Extensions.Logging.Abstractions -S Integrations
dotnet-inspect library Microsoft.Extensions.Logging.Abstractions \
  -S Integrations --where "integration=integration.logging"
dotnet-inspect library System.Diagnostics.DiagnosticSource \
  -S Integrations --where "integration=integration.opentelemetry"
dotnet-inspect package System.Text.Json --path @readme --content --frontmatter
dotnet-inspect package Newtonsoft.Json -S "Package Info" --fields Version --value
dotnet-inspect project ./src/DotnetInspect.Cli -S Skills --jsonl

Library, Package, Type, and Member -D --details are structural and do not acquire the target. They add the owner-issued section properties to the top-level catalog, or report one exact category or section in detail: Formats, and, where the owner declares them, Shape (table, hierarchy, or text, per Section shapes), Cardinality (scalar or inventory), and Terminals. Every owner declares all of them; Call Graph and Library Dependency Structure are graphs and declare no shape. A category reports the formats supported by its complete expansion plus the formats of each member; it never selects or drops members to satisfy a format. Use the result to choose an exact section before requesting a single-result projection such as --tree or --mermaid. explain <catalog>/sections/<section> reports the same shape and cardinality for one section, beside its formats and members. The catalogs are library, package, type (the type listing), member (one type's members), member-overload, and member-detail (one exact member).

For one library, its field-set records — Library Info, SourceLink: Availability, SourceLink: Integrity, Symbols, and Metadata: Image — are scalar: they have no rows to count or window. --count or --rows on one of them, on a selection of only them, or on the default overview fails before acquisition. An explicit selection that mixes them with inventories counts and windows the inventories alone, so library MyLib.dll -S @Metadata --count lists each metadata table without an image field count. Context: Source Location, Member, Instruction, Callsite, and Return Address count their one located row; Context: Exception, Allocation, Safety, and Cost count the regions or facts at the coordinate. library address ... -D --details reports these declarations for the coordinate sections.

The library command renders a lone explicitly selected section in its declared shape's native format when no format is named, per Section shapes: a Table streams its TSV rows (library MyLib.dll -S References, the Library Info record as field/value TSV, each metadata table, and each Context: section on library address) and Reference Hierarchy renders its tree; --markdown or --mermaid names another of its formats. Dependency Structure is a graph and keeps its current rendering. An explicit format, an environment default, --print, --row, --value, --urls, --paths, --tree, --count, a projection, an envelope, or discovery keeps its existing behavior, and selecting several sections composes Markdown as before, including a mixed selection whose scalar records leave a --rows window.

dotnet-inspect package System.Text.Json -D --details
dotnet-inspect package System.Text.Json -D Files --details --json
dotnet-inspect type System.String -D --details
dotnet-inspect member System.String.Trim:1 -D --details
dotnet-inspect explain package/sections/files
dotnet-inspect explain member-detail/sections/source

Common examples

Packages and feeds

dotnet-inspect package System.Text.Json
dotnet-inspect package System.Text.Json --version 10.0.0
dotnet-inspect package System.Text.Json --versions -n 1
dotnet-inspect package System.Text.Json@latest --versions
dotnet-inspect package System.Text.Json --versions -n 6
dotnet-inspect package System.Text.Json@8.0.0..8.0.5 --versions
dotnet-inspect package System.Text.Json@8.0.0..8.0.5 --versions --envelope
dotnet-inspect package System.Text.Json@8.0.0..8.0.5 --count
dotnet-inspect package System.Text.Json@8.0.0..8.0.5 --count --envelope
dotnet-inspect package Newtonsoft.Json@13.0.4 \
  --tfms -n 1 --tail --json
dotnet-inspect package System.Text.Json -S Signals
dotnet-inspect package System.Text.Json -S "Signals,Audit: Artifact Text"
dotnet-inspect package System.Text.Json -S "Signals,Audit: Findings"
dotnet-inspect package Newtonsoft.Json@13.0.4 \
  --files --tfm net6.0 -n 1 --tail --json
dotnet-inspect package Markout@0.35.2 \
  --path "skills/*/SKILL.md" -n 1 --tail --paths
dotnet-inspect package Markout@0.35.2 \
  --path skills/markout/SKILL.md --content --raw
dotnet-inspect package System.Text.Json --version 10.0.0 \
  --path README.md --content --raw
dotnet-inspect package Microsoft.Data.SqlClient@6.1.0 \
  --tfm net8.0 -S Files --paths
dotnet-inspect package Microsoft.Data.SqlClient@6.1.0 \
  --tfm net8.0 -S Files --roots
dotnet-inspect package Newtonsoft.Json@13.0.3 \
  -S "SourceLink: Files" -t JsonReader -n 1 --tail --urls
packet=$(dotnet-inspect workspace \
  --package System.Text.Json@10.0.0 \
  --tfm net10.0 \
  --share packet)
dotnet-inspect package System.Text.Json --workspace "$packet"
dotnet-inspect package System.Text.Json \
  --workspace "$packet" --share packet
dotnet-inspect package System.Text.Json@10.0.0 \
  --tfm netstandard2.0 -S "Dependency Hierarchy" --share url
dotnet-inspect package query 'Azure.AI*' --take 100 --tsv

Bare package ID[@VERSION] output and bare --tree render the Package's native children Tree. Ordinary packages list every Library in the selected compile population by identity without opening the Library binary or summarizing its Type population. --tfm selects an explicit target; otherwise the Package selection default chooses the target. Tool pointer packages list their RID packages, managed tool payloads list the entry-point Library before their dependencies, and native tool payloads state that they contain no managed Libraries. Minimal implicit Tree output may collapse a managed tool's dependency Libraries into one counted branch that names -v:n as the full-inventory gesture. Normal, Detailed, and explicit output formats list every Library.

Unselected Markdown, plain text, JSON, envelope, table, TSV, and JSONL output all consume that same Package children document. The tree title prints the subject identity followed by the owner-issued properties of the displayed children — source, selected target, and asset root, as in System.Text.Json 10.0.12 (NuGet; net10.0; lib) — and nothing else. JSON carries subject, completion, total and selected Counts, and typed child rows. Row formats expose the exact asset ID, asset path, target, and child role; they carry no replay command, because host navigation is not package content (see Section shapes). Package children output does not run the unrelated all-binary Signals scan or inspect selected Libraries. --count counts the owner-issued child population without producing rows; --rows windows the same ordered identities, and --fields or --columns projects child-row columns. Windows retain the complete population Count and original child ordinals; a window selecting no rows from a non-empty Package does not claim that the Package has no Libraries.

Select Package Info explicitly for Package facts. A bare Package Tree is distinct from the dependency graph: select Dependency Hierarchy together with --tree for rooted transitive dependencies.

package ID[@VERSION] --workspace PACKET inspects the matching direct Package in the packet's selected context, independently of its focused tab, and reuses the exact Package Root and target admitted during Workspace restoration. Appending --share preserves ordinary stdout and writes a derived Package packet or URL as the final stderr line. An exact selector can inspect a currently resolved floating Package member, but Share refuses rather than silently pinning that preserved definition.

For a direct NuGet.org Package query with one Dependency Hierarchy section, append --share url to keep the hierarchy on stdout and print its Inspect Web URL on stderr. The URL preserves the resolved exact Package version and target framework; the Browser reacquires that Package and runs the rooted dependency traversal. --share packet emits the packet instead. Local archives, other source selections, and hierarchy row or depth selections cannot currently be reproduced in the Browser and fail visibly.

For one package with exactly Files selected, -n, --tail, and --rows A..B select complete path/size rows after archive extraction, file enumeration, optional exact directory-segment --tfm filtering, and optional --path filtering. Count, table, TSV, JSONL, JSON, --value, and --paths observe the same selected rows; --roots instead emits their ordered distinct top-level package roots. Add --lines only to clip rendered text.

The package command renders a lone explicitly selected section in its declared shape's native format when no format is named, per Section shapes: a Table streams its TSV rows, a Hierarchy renders its tree, and a Text prints its payload. Files and Dependency Hierarchy are Hierarchies, the nuspec and README sections are Text, and every other section is a Table. The Files tree titles the subject with its issued properties (source, and the target when --tfm filters), groups files under their directories, and collapses single-entry directory chains into one node; directory nodes are context, so -n, --rows, and --count observe files only, and --tree is an accepted explicit format for it. Selecting several sections composes Markdown as before, with a Text section contributing its Path/Size fact row and its body only when it is the whole selection. An explicit format, an environment default, --print, --raw, --tree, --count, a projection, a shape flag, discovery, or a lens keeps its existing behavior.

The package file family — the nuspec, README, license, and skill sections — shares one Path/Size row schema, so -S @Files --table, --tsv, or --jsonl streams one listing with each member's rows in family order. Scalar sections (Package Info, Summary, Statistics, Signature, the SourceLink availability and integrity sections, and the nuspec and README Text sections) have no rows: selecting one of them alone with --count or --rows fails before acquisition and names an inventory section as the alternative. A bare -n on such a section is the rendered-line window it is for Library Info, not a row terminal. Count maps over several sections, and multi-package counts, keep their existing per-section meaning.

dotnet-inspect package System.Text.Json -S "Target Frameworks"
dotnet-inspect package System.Text.Json -S README
dotnet-inspect package System.Text.Json -S Files -n 5
dotnet-inspect package System.Text.Json -S @Files --tsv

For an exact online package version, -S README and one literal root README.md or skills/**/SKILL.md path with --content acquire directly through the PackageHouse semantic Files route rather than the legacy extraction route. The README section uses one host-neutral selection: README.md when present, otherwise PACKAGE.md. PackageHouse selects cache, size-first HTTP Range access, or complete fallback, while the operation publishes only the selected entry. That entry is detached through the shared package document-content inspection, then the CLI applies its existing separator, --raw, JSONL, or --out projection. Skill documents retain their containment and link-normalization behavior. Detached content projections accept documents up to 16 MiB; an exact README written to --out remains a bounded byte stream and is not subject to that detached-content limit. Local packages, floating or range version selection, target-framework filters, path globs and roles, scoped documents, .NET tool-wrapper redirection, and other package files retain their existing behavior.

The --files flag selects exactly the same section as -S Files. File predicates compose before row windows and Count:

dotnet-inspect package System.Text.Json@10.0.12 --files \
  --where "Root=lib" --where "Target=net8.0"
dotnet-inspect package System.Text.Json@10.0.12 -S Files \
  --lib --tfm net8.0
dotnet-inspect package System.Text.Json@10.0.12 --files \
  --where "Name=*.xml" --paths

Files admits Path (complete package-relative path), Name (filename), Directory (exact parent directory), Root (top-level folder), and Target (a complete directory segment). Text fields support case-insensitive = and != with * and ? wildcards; Target matches an exact segment case-insensitively. Repeated predicates combine with AND. --lib and --tools wrap Root equality and require exactly Files for one package; --tfm wraps Target equality for Files. All formats preserve package-relative paths. A filter with no matching files succeeds with zero rows. The old --layout spelling is removed.

Package flags and section equivalents

A package flag may select a section, filter its rows, select an inspection subject, or project a result. Only the first two have section/predicate equivalents. The following map distinguishes those contracts:

Flag Meaning Section or predicate equivalent
--files Select the Files section -S Files; it can compose with other package sections
--lib Filter Files to the lib/ root --where "Root=lib", with exactly Files selected
--tools Filter Files to the tools/ root --where "Root=tools", with exactly Files selected
--tfm TFM with Files Match a complete directory segment on file rows --where "Target=TFM"; --tfm all adds no predicate
--path SELECTOR Select Files and apply package path/role selection One literal file can use --where "Path=FILE"; repeated selectors, directory expansion, glob rules, @readme, and @agents retain their selector semantics
--library [DLL] Inspect selected compile libraries, optionally one exact DLL Changes the inspection subject; it is not a Files filter or section shortcut
--namesake-library Select the Library whose assembly name matches the package ID Selects a Library subject; it is not Root=lib or a filename filter
--tfm TFM with library inspection Select the package target before Library scope Uses package asset selection; it is not Files Target=TFM
--roots Project distinct top-level folders from selected Files A result projection, not a predicate or another section
--tfms Select the Target Frameworks section -S "Target Frameworks"; native output, formats, row selection, and Count are identical
--versions, --versions-with-feed Enumerate available package versions, optionally with feed provenance A separate version population; these do not select a section of one package version
--content Read documents selected by --path A content operation; selecting Files inventories entries without reading their contents

--lib and --tools have the same Files-only meaning throughout the package command. They require one package and exactly Files, are mutually exclusive, and do not select managed libraries. --tools does not request Library inspection. Package acquisition retains its existing .NET tool-wrapper redirection, so Files can inventory a wrapper's redirected payload package.

For example, System.Text.Json@10.0.12 --files --lib --tfm net8.0 inventories its DLL and XML entries under lib/net8.0. --library System.Text.Json.dll --tfm net8.0 instead inspects the selected managed Library. The latter applies package asset-role selection before inspecting metadata; a file path predicate cannot replace that subject selection. Files Target=net8.0 can also match entries under buildTransitive/net8.0 unless a Root predicate narrows them.

The separate version-listing and content modes reject explicit -S selection because they render their own populations. Giving one of these a section entrance would require preserving its row identity, ordering, acquisition, and output contract; it would not follow from replacing its flag with a Files predicate.

For one package with only --tfms or -S "Target Frameworks", -n, --tail, and --rows A..B select complete target-framework rows after framework folder enumeration, de-duplication, and TFM-priority ordering. --tfms can compose with other sections. Its former standalone JSON array is replaced by the section's established JSON contracts: plain --json preserves the typed package object; field or column projections follow Projected JSON. Bare output uses native TSV. Count, table, TSV, JSONL, and JSON observe the same selected rows; add --lines only to clip rendered text.

For one package with exactly SourceLink: Files selected, -n, --tail, and --rows A..B select complete library/type/URL rows after SourceLink collection and --type filtering. Count, table, TSV, JSONL, JSON, --urls, and --raw observe the same selected rows; add --lines only to clip rendered text.

Online range-version population is metadata-only: it enumerates versions without acquiring a package payload. --count projects the version Count as a scalar, including with --json; --count --envelope makes that same integer the Content of InspectionEnvelope<int>. Without Count, --envelope retains the complete directed version Document. --preview, --include-unlisted, configured source options, and --versions-with-feed remain semantic population inputs.

package query --explain returns installed query facets and CLI bindings as HAL JSON without contacting NuGet. --json is optional. This command-only terminal rejects package arguments, query/execution options, other output formats, and dotted projections. Process-wide controls such as --offline and --http-timeout remain available. Select needed embedded facets locally with jq, or use explain package-query/query/facets/depends .hal --json for a focused dependency-facet response. See Installed capability explanation for the worked workflow.

package query ID selects one exact package ID. A single terminal * selects a literal package-ID prefix. Explicit --take bounds candidate work before -n selects final package rows. Without explicit --take, a simple -n N also bounds direct package-row acquisition to N, up to the 1,000-candidate execution ceiling. Larger semantic heads remain valid and use that ceiling.

package query --ecosystem <id>, or --where "ecosystem=<id>", replaces the package argument with one Ecosystem's population: its core packages in authored order, each resolved exactly, then every package under each recorded prefix, admitting each package once under the shared candidate bound. The identity may be short (aspire) or canonical (ecosystem.aspire). It cannot be combined with a package ID or prefix argument, and ecosystem= is the only population term --where admits:

dotnet-inspect package query --ecosystem aspire -n 5
dotnet-inspect package query --where "ecosystem=ai" --where "license=MIT"

find PATTERN --package-prefix PREFIX remains API search across packages matching the prefix:

dotnet-inspect find Serialize --members --type System.Text.Json.JsonSerializer \
  --package-prefix System.Text

Use depends=<package-id> to require a direct dependency. Package Query considers all package manifest groups by default; add dependency-target=<TFM> to select one applicable dependency group instead. dependency-target=all spells the default explicitly and remains distinct from a manifest's real any group. Repeat depends to require every named dependency under the same scope. Use depends starts-with <literal-package-id-prefix> to require a direct dependency whose package ID begins with that prefix. The match is literal and case-insensitive; include a trailing . to express a dot-delimited family. Use depends-ecosystem=<canonical-ecosystem-id> to match a direct dependency against the ecosystem's core packages (matched exactly) and its package prefixes:

dotnet-inspect package query 'Microsoft.Extensions.*' \
  --where "depends=Microsoft.Extensions.DependencyInjection"
dotnet-inspect package query 'Polly.*' \
  --where "depends=System.Threading.Tasks.Extensions" \
  --where "dependency-target=netstandard2.0"
dotnet-inspect package query 'Microsoft.Extensions.*' \
  --where "depends=Microsoft.Extensions.DependencyInjection" \
  --where "depends=Microsoft.Extensions.Configuration" --count
dotnet-inspect package query Microsoft.Extensions.Http \
  --where "depends starts-with Microsoft.Extensions." \
  --where "dependency-target=net10.0"
dotnet-inspect package query Aspire.Hosting.PostgreSQL \
  --where "depends-ecosystem=ecosystem.aspire"

Add dependency-depth=2|3|4 to an exact depends=<package-id> term for source-authorized declared-range reachability. The match is inclusive: direct dependencies and transitive paths within the selected maximum depth qualify. It requires one exact dependency-target=<TFM>; the expensive query is limited to five package candidates:

dotnet-inspect package query Microsoft.Extensions.Http \
  --where "depends=Microsoft.Extensions.Primitives" \
  --where "dependency-target=net10.0" \
  --where "dependency-depth=2" --take 1

The result is not a NuGet restore claim. Evidence counts matching declaration edges and previews deterministic shortest paths built from declared ranges and resolved exact package coordinates. The shared 160-character display budget may shorten a preview, so it is not a complete path record or package coordinate. The legacy depends-transitive spelling remains available when a depth-2-or-greater-only match is required. Incomplete traversal remains a visible failure.

Use dependencies=cross-prefix to find packages with a direct dependency from a different first dot-delimited package-ID segment. It uses the same dependency-target scope and remains nuspec-only:

dotnet-inspect package query 'Azure.*' \
  --where "dependencies=cross-prefix"

Use references=<simple-assembly-name> to find packages whose managed ref/ or lib/ assemblies declare that AssemblyRef across any target-framework group:

dotnet-inspect package query 'Microsoft.Extensions.*' \
  --where "references=Microsoft.Extensions.DependencyInjection.Abstractions" \
  --take 20 -n 5

This package-content term matches simple names case-insensitively and reports the matching framework and archive path. It does not resolve or traverse the reference.

Use the same key at Library grain to query top-level *.dll files in one directory, or one installed or explicitly acquired platform reference pack:

dotnet-inspect library query ./artifacts/bin \
  --where "references=System.Text.Json"
dotnet-inspect library query --platform runtime \
  --where "references=System.Text.Json" --take 256 -n 10

Library Query tests each candidate Library's direct AssemblyRef table; repeated references terms are ANDed. --take bounds candidates scanned, while -n, --head, --tail, and --rows select matching Library rows afterward. Use library query -Q Libraries to discover the current vocabulary. Native images beside managed Libraries in the directory are skipped; a directory with no managed Library is a failed source. Missing or malformed Metadata remains visible rather than silently becoming a nonmatch: rows and --count print what was observed, with the failure warning and exit 1.

License selection also stays at the manifest boundary. license=any matches any nuspec license declaration. Closed semantic values match nuspec metadata without reading a license document: SPDX expressions match their exact expression, and license=OSMF recognizes a declared OSMFEULA.* file:

dotnet-inspect package query wix \
  --where "license=OSMF" --nuspec-only
dotnet-inspect package query Newtonsoft.Json \
  --where "license=MIT" --nuspec-only

Neither query opens the package archive. To inspect the license documents that the package actually ships, use the separate package-file section:

dotnet-inspect package wix@7.0.0 -S Licenses
dotnet-inspect package wix@7.0.0 -S Licenses --count
dotnet-inspect package wix@7.0.0 -S Licenses --print --raw

Package Query places the semantic result in Answer: MIT for the Newtonsoft.Json query, OSMF for the WiX query, and true for license=any. Supporting nuspec declaration kind and value remain separate evidence. --count already emits only the scalar count; --raw is useful with --print when only the selected document body is wanted without package or section framing.

The exact nuspec <license type="file"> target is always included. The same section also finds conventional text or Markdown license names and license directories; notices remain a separate legal-document concern. Reading that content is an explicit package projection and never informs license identity.

Add --where "key=value" to select product-owned Package Query terms, with one matched package per row and semantic answers. Structured evidence remains available in unprojected JSON and the inspection envelope. The initial CLI vocabulary covers package metadata, direct and bounded transitive dependencies, cross-prefix and ecosystem dependency classification, downloads, README presence, .NET tools and their CLI v1/v2 format, assembly references, skill packages, and nuspec license identity. Discover the admitted keys and values before constructing a query. Discovery also reports the product-owned execution class independently from the acquisition tier:

dotnet-inspect package query -Q Packages
dotnet-inspect package query Azure.Mcp \
  --where "tool=true"
dotnet-inspect package query 'Azure.Mcp*' \
  --where "tool-format=v2" --take 20 -n 5 --jsonl

Repeat --where to combine terms; the engine rejects incompatible selections. The broad tool=true term identifies the .NET tool package type from manifest evidence. Use tool-format=v1 or tool-format=v2 for settings-based format classification; the two specific formats are compatible filtering alternatives. Selecting a package-content term authorizes the required archive acquisition and defaults to at most 20 candidates. Use --nuspec-only to reject a query that would require package content. Without explicit --take, a simple -n N query pushes that semantic head into execution; explicit --take instead fixes the candidate population before row selection. Reached candidate limits and partial failures are reported explicitly. --count counts the selected matching package rows that the same query would render, with the same completion warnings and exit status. A reached candidate bound or partial failure therefore yields an observed count, not the scope's total. Incompleteness alone never withholds the count: only a search that fails before evaluating any candidate prints none, and an unsatisfied strict --rows window fails as it does for rows.

Package Query output adapts after execution. The default renders Packages when at least one package matched and Query Summary otherwise. The summary reports independent Candidates, Matches, and Evaluation Failures integer columns, so a missing package (Candidates=0) remains distinct from an existing package rejected by --where (Candidates=1, Matches=0). Select a stable shape explicitly with -S Packages or -S "Query Summary"; explicit Packages retains its empty table or array when no package matched. Bare -S is invalid without a selector. Select @Query to compose Packages and Query Summary in Markdown or JSON; table, TSV, and JSONL remain one-section formats.

Breaking change: package search and patternless find --package-prefix PREFIX have been removed. Use package query with an exact package ID or an explicit terminal-star prefix.

Exact Find handoff

An exact-version Package or explicit Platform Library search with --tfm uses one short-lived Workspace internally and preserves each declaration's exact coordinate and observation context without changing Find's established result presentation:

dotnet-inspect find System.Text.Json.JsonSerializer \
  --package System.Text.Json@10.0.0 \
  --platform System.Text.Json \
  --tfm net10.0

Find defaults to TSV, with one stable header and unified Type and Member rows: Coordinate, Kind, Source, Library, Pattern, Declaration, Signature, Match, and Ecosystem. Kind is type or member; Declaration describes the class, method, property, or other declaration category. Coordinates are display addresses, not substitutes for the internally retained declaration identity. Implicit Member matches are included in TSV. --columns selects columns and --no-header suppresses the header.

Settled Member and wildcard Type rows print progressively during source search. Ordinary Type patterns wait when implicit Member fallback could supersede a weak match. Ecosystem searches publish each settled layer before searching the next. Semantic row-selection requests (-n, --rows, --tail) retain the existing buffered selection behavior; Count emits its final scalar. Diagnostics stay on stderr, and already printed rows remain available if a later source fails.

Explicit --markdown, table, JSONL, and plain type-search JSON retain their existing shapes; plain JSON remains a root result array. When a selected Package row feeds Type or Member inspection internally, the handoff preserves the selected package-relative implementation asset and compatible TFM rather than reopening a same-named reference assembly. Platform implementation-pack observations decline exact internal reopening because public Platform syntax resolves the reference view.

--ecosystem selects a named Ecosystem and its ancestors, searching each layer's named platform and core-package populations nearest first. Canonical IDs (ecosystem.aspire) and short names (aspire) are case-insensitive; separate multiple selections with commas (for example, ai,blazor) or repeat the option. --ecosystem all selects every shipped ecosystem. An explicit Ecosystem cannot be combined with another Find source selector yet. --tfm still applies to core packages. Each result includes an Ecosystem column (or ecosystem JSON field) naming the layer that produced it; ordinary Find output is unchanged. A finite -n stops at a layer boundary and reports unsearched ancestors on stderr:

dotnet-inspect find '.Add*' --ecosystem aspire -n 20

This searches Aspire's core packages first and, when they fill the window, does not realize ASP.NET Core or Runtime. Only named populations are searched: registered package prefixes do not trigger package-prefix discovery. If the entire selection has no named populations, Find fails with a prefix hint. Explicit Markdown output retains Find's existing Members-before-Results sections; rows remain nearest-first within each kind. Unbounded default TSV instead publishes each layer's settled unified rows before the next layer. Selection-bearing requests keep the existing selection order until the separately owned row-selection work adopts the unified stream.

Package Query over selected implementation libraries

package query ... --where "library-literal=TEXT" --tfm TFM adds decoded string-literal qualification to the ordinary Package Query term plan. An exact package ID selects its latest eligible listed version. A terminal-star package-ID prefix evaluates at most five candidates; use --take 1..5 to choose the candidate bound. Ordinary terms AND-compose and prequalify before the query evaluates each survivor's selected implementation libraries for the exact target framework.

dotnet-inspect package query Newtonsoft.Json \
  --where "library-literal=Unexpected end when reading JSON" --tfm net6.0

dotnet-inspect package query 'Azure.Identity*' \
  --where "downloads=1m" \
  --where "library-literal=DefaultAzureCredential" \
  --tfm net8.0 --take 5

TEXT is a raw ordinal substring, not a type pattern: it is case-sensitive, matches no wildcards, and preserves 1 through 1,024 decoded UTF-16 code units, including leading/trailing whitespace and newlines. The Product planner records CLI --tfm as non-user-selectable library-target=<canonical-tfm> intent. The query covers selected primary implementation assemblies only, not every assembly in a package. One output row is one final matching package; typed selected-library context, the complete occurrence array, and bounded method-token/IL-offset previews remain evidence on that package Result. -n and --rows select final package rows, while --take bounds package candidates. Candidate failures remain visible and prevent an unqualified Count. Candidate packages are disposable: they are never added to the package cache.

Select -S "Literal Strings" to itemize every physical matching ldstr as a row with Package, Library, Method Token, IL Offset, and the complete decoded Literal. Prefix and interior substring matches remain whole strings. Repeated matches within one literal remain one physical row, while separate instructions retain separate coordinates. This evidence projection does not change package-grain row selection or Count.

Unprojected Package Query --json emits the complete owner-issued PackageQueryDocument. --envelope emits that same Content with Share and diagnostics using result kind package-query. Query controls such as --where, --take, and required semantic --tfm remain admitted; row selection, Count, projection, discovery, section selection, and competing formats are rejected. Typed incomplete or failed Content is still emitted before a nonzero exit.

Each evaluated candidate carries a Root reopening token. Hand that token back to reopen exactly the Root the result came from:

dotnet-inspect workspace --root-request TOKEN

The token is opaque, credential-free, and exact. workspace --root-request rejects a token this tool did not issue, and reports an unauthorized producer or unavailable content instead of opening a different Root that happens to share the package id and version.

Workspace inventory and structural navigation

Append --share packet or --share url to author the complete durable Workspace definition. Ordinary authoring performs no Package acquisition or live Workspace construction. The selected scalar is the workspace command's result on stdout, rather than the additive stderr side output used by noun commands:

dotnet-inspect workspace \
  --package System.Text.Json@10.0.0 \
  --tfm net10.0 \
  --register-package-prefix Microsoft.Extensions. \
  --share packet

Direct Package and registration inputs become one schema-version-3 definition and canonical format-3 packet. Registration-only authoring also remains resource-free. Normalized-equivalent Package coordinates are emitted once, while registration options retain their authored cross-kind order. A scanner-bearing Ecosystem fails visibly as non-projectable; the command never drops its scanner to manufacture a packet.

Declare an authentication-required package source to author a credential-free format-5 Inspect Web URL for a private-feed Workspace:

dotnet-inspect workspace \
  --package Private.Package@1.2.3 \
  --tfm net10.0 \
  --nuget-source-auth-required \
    https://nuget.pkg.github.com/example/index.json \
  --share url

Inspect Web prompts once per exact authentication-required endpoint for a username and personal access token. Credentials remain in page-session memory only: activation-local copies are cleared after settlement, while the active realization or incumbent-recovery binding may retain them until replacement or disposal. They are not placed in the packet or URL, retained definition, browser storage, logs, diagnostics, or telemetry. Reloading prompts again. Cancellation or failure before publication leaves the prior visible Workspace unchanged; if recovery after cutover also fails, Inspect Web enters a blocking retry state rather than exposing the failed tentative Workspace. Source declarations that do not require authentication activate without a prompt.

Add --make-package-dependencies-explicit to acquire the bounded manifest for every direct Package member, resolve its exact direct dependencies for the member's effective target, and append those dependencies to the same context before emitting the derived packet. PackageHouse uses a source-supplied manifest when available and otherwise acquires only the root nuspec from the package archive:

dotnet-inspect workspace \
  --package Microsoft.Extensions.Logging.Abstractions@10.0.0 \
  --tfm net10.0 \
  --make-package-dependencies-explicit \
  --share packet

The transformation also accepts a canonical Base64URL packet string through --packet. Existing members retain their order; new members use owner-issued dependency order and are deduplicated only within each context. The command emits no packet unless every selected Package manifest settles and the complete derived definition remains projectable. Unlike ordinary resource-free --share, this explicit transformation admits --preview and NuGet source policy because acquisition is part of the requested operation.

--packet accepts canonical Base64URL packet text. With --share, it validates the input and emits the canonical packet or selected URL without complete restoration. The --share selection governs this output scalar; inventory output formats apply only when --share is absent. Durable definition output cannot be combined with --kind, inventory row controls, --root-request, or Package Navigation selectors. Explicit NuGet source policy is accepted only for dependency enrichment or coordinate replacement; --preview is accepted only for dependency enrichment.

To edit one direct Package coordinate in an existing scenario, first list the packet's typed components and copy the canonical Package path:

dotnet-inspect workspace component list --packet "$w"
dotnet-inspect workspace package update \
  packages/avalonia@11.3.14/net8.0/~ \
  --packet "$w" --version 12.1.2
dotnet-inspect workspace package update \
  packages/avalonia@11.3.14/net8.0/~ \
  --packet "$w" --tfm net9.0 --share url
dotnet-inspect workspace package update \
  packages/avalonia@11.3.14/net8.0/~ \
  --packet "$w" --version 12.1.2 --json --envelope

Use --version, --tfm, or both, and select either scalar --share output or --json --envelope. The envelope includes the derived Share, actual Scope outcome, retention/fallback decision and diagnostics. Scalar output contains only the complete resulting packet/URL; fallback diagnostics go to stderr. No input packet is emitted as a successful failure fallback. Source options are allowed for this acquisition-backed route.

Replacement preserves unrelated contexts, registrations, row order, focus, and committed views. Format 4 can retain an active Library, Type or Member and its exact inspector. For example, changing Avalonia@11.3.14 to 12.1.2 on net8.0 follows Avalonia.Data.MultiBinding from Avalonia.Markup to its defining Avalonia.Base Library; its constructor can follow separately. An explicitly active Library stays paired with that Library instead. Both Versions must be exact pins. Changed TFMs require an unsubscribed single-member context; shared-context TFM changes, floating selected sources, ambiguous source positions and query-bearing scenarios are visibly refused. Do not combine Package update with dependency enrichment, direct construction, inventory controls, or --active-package/Library/Type/Member/inspector selectors: the packet owns that intent. Browser coordinate-control and capture adoption remain separate.

Use the same canonical paths for resource-free immutable Package edits:

dotnet-inspect workspace package add Markout@0.35.2 --packet "$w"
dotnet-inspect workspace package remove \
  packages/markout@0.35.2/net10.0/~ --packet "$w"

The default workspace output is the typed top-level inventory. Package occurrences appear in committed Scope order, followed by inert registrations in declaration order. Overlap is preserved because committed content and registration intent are different facts:

dotnet-inspect workspace \
  --package System.Text.Json@10.0.0 \
  --package Markout@0.35.2 \
  --tfm net10.0 \
  --register-library System.Text.Json@10.0.0/System.Text.Json@10.0.0.0 \
  --register-package-prefix Microsoft.Extensions. \
  --register-ecosystem aspire

Use repeatable --kind package|exact-library|package-prefix|ecosystem to select inventory kinds without changing Workspace construction. -n N, --tail, and --rows A..B select complete typed entries after that filter; --count observes the selected entries, while --lines explicitly selects rendered lines. JSON and JSONL retain the typed entry arms and their portable details. --verbose adds each Package producer, requested/selected/effective target, runtime identifier, and asset-selection status to human output.

Restore one current-format canonical Base64URL Workspace packet string for inventory instead of supplying direct construction options:

dotnet-inspect workspace --packet PACKET

Packet input is mutually exclusive with direct Package and registration construction. Workspace Definitions performs complete restoration, including group and non-Package context intent and retained Navigation state, before the CLI enters the inventory operation. CLI refinement of that restored Navigation state is intentionally deferred. Top-level workspace --packet combines only with inventory controls when --share is absent; nested component and Package commands own packet editing.

workspace never selects an occurrence implicitly, even when the Workspace contains exactly one Package.

Add --active-ecosystem ID to select one exact Ecosystem registration from the current top-level inventory receipt. Short IDs such as aspire normalize to the canonical ecosystem.aspire registration. The result activates the Ecosystem subject and its ecosystem.overview lens without acquiring Packages, Libraries, platform assets, or population:

dotnet-inspect workspace \
  --register-ecosystem aspire \
  --active-ecosystem aspire

This acquisition-absence claim is unverified by a dedicated composition gate; the Release tests verify the visible structural result.

Add --active-package N to evaluate one exact occurrence by its one-based Workspace order. The detailed result includes the active subject, complete Workspace-to-Member hierarchy slots, Library asset IDs, bounded Type and Member inventories, target-aware lens availability, and retained diagnostics. For this CLI consumer, the current active catalog entries are available once Navigation admits the exact subject because those entries execute on demand; query and result non-success remains inside the selected entry. This does not prevent another producer from supplying explicit unavailable or failed availability evidence to the Navigation evaluator:

dotnet-inspect workspace \
  --package System.Text.Json@10.0.0 \
  --tfm net10.0 \
  --active-package 1

Library asset IDs, Type full names, and Member stable selectors in that output can drive an exact stateless descendant plus lens request. Copy those selector fields verbatim: line separators, tabs, rendering hazards, and literal backslashes, plus characters reserved by Markdown tables, use a reversible backslash transport spelling that workspace decodes before exact selection:

dotnet-inspect workspace \
  --package System.Text.Json@10.0.0 \
  --tfm net10.0 \
  --active-package 1 \
  --library compile:lib/net10.0/System.Text.Json.dll \
  --type System.Text.Json.JsonSerializer \
  --lens .compare

Add --member <stable-selector> and use a member.* lens for a Type-to-Member destination. The contextual .<name> spelling above lowers through the View Facet Registry to the exact canonical ID for the destination kind; full IDs such as type.compare remain the durable spelling in output, packets, and cross-host handoffs. --all-libraries uses the aggregate Library as the source while --library still names the destination Type's exact defining Library. A source-only --all-libraries request omits --library; supplying both without a Type destination is rejected. Root-only and explicit-empty Packages have no All-libraries subject and return a typed non-success snapshot instead of throwing.

Selector misses retain the evaluated snapshot and diagnostics. The command claims that a Type or Member is not present only when its scoped inventory is complete; otherwise it reports incomplete evidence. Unavailable, failed, inapplicable, and unknown destination lenses leave both requested halves uninstalled and return nonzero with typed diagnostic data. JSON and JSONL Type and Member rows carry the defining Library asset ID, and Member rows carry both containing and declaring Type names. Process-local Workspace, occurrence, generation, action, and authority identities are omitted.

Projects and local assets

dotnet-inspect project ./src/DotnetInspect.Cli -S Skills
dotnet-inspect project ./src/DotnetInspect.Cli -S @Project
dotnet-inspect project ./src/DotnetInspect.Cli -S Skills -n 1 --tail
dotnet-inspect project ./src/DotnetInspect.Cli -S Skills --print --row 1
dotnet-inspect project ./src/DotnetInspect.Cli -S README
dotnet-inspect project ./src/DotnetInspect.Cli -S README --print --row 1
dotnet-inspect type Command --project ./src/DotnetInspect.Cli
dotnet-inspect member Command --project ./src/DotnetInspect.Cli -S "Member Index"
dotnet-inspect library ./artifacts/obj/ILInspector.Metadata/release/ILInspector.Metadata.dll -S Signals

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. The project command reads only valid package Skills and root README.md documents listed by the existing restore output. It does not interpret package AGENTS.md or PROJECT.md files. Select @Project to compose both document inventories, or select Skills for that focused view. With exactly one document section selected, -n, --tail, and --rows A..B select complete document rows before Count, structured output, projection, or print/bare lowering. Add --lines only to clip rendered text. Multi-section @Project output retains its independent section row sets and rendered-line -n fallback.

Types, members, and source

An exact type target with no competing operation or projection defaults to the compact public Type hierarchy; --tree explicitly selects the same Tree profile. A short name that platform find resolves to one exact Type, such as type JsonSerializer, renders the same Tree. The Tree lists one row per Member group under its category, and a category counts its Member groups. It shows no overload Counts; use member <Type> <Name> for a Member group's overloads.

static class System.Text.Json.JsonSerializer
├─ Properties (1)
│  └─ IsReflectionEnabledByDefault
└─ Methods (10)
   ├─ Deserialize
   └─ …

--all includes non-public and hidden Member groups. --mermaid selects a standalone graph TD over that same Type, category, and Member-group hierarchy. It requires one exact Type and cannot be combined with discovery, match, listing/glob/namespace-prefix targets, member filters, row or line windows, verbosity-driven output, another format, or a selected section. It fails with no stdout when compact inspection is unavailable (including managed netmodules or bounded inventory), even if an XML documentation sidecar is present. Tree retains the legacy Type rendering fallback when compact inspection is unavailable. Count, sections, Markdown, tables, JSON, filters, and windows keep their existing independent routes.

An explicit verbosity keeps the verbosity-driven Type rendering rather than the compact Tree. -v:m adds the base Type and Member signatures, with an overload Count in place of the signatures for each overloaded constructor, method, operator, explicit interface implementation, or extension group; properties (including indexers) and events list each signature, and fields list each name. -v:n and -v:d list every overload signature. That rendering rejects -v:q; add --markdown for compact sections.

dotnet-inspect type System.Math --platform System.Private.CoreLib --tree
dotnet-inspect type System.Math --platform System.Private.CoreLib --mermaid

The type and member commands render a lone explicitly selected section in its declared shape's native format when no format is named, per Section shapes: a Table streams its TSV rows (type System.String -S Methods, member System.String.Trim -S Methods, the Type Info record as field/value TSV, Signature as its one row) and a Text prints its undecorated payload (Source, Decompiled Source, IL, API Declarations, PDB Source, Source Diff, Annotated Source, the overlays, and Finding Census). The shape decides, not a list of section names. Annotated Source Document and Call Graph keep their composed rendering: the first is a document with no bare payload, the second a graph. An explicit format, an environment default, --print, --row, --tree, --count, a projection, a shape flag, discovery, an envelope, or an analysis query keeps its existing behavior, and selecting several sections composes Markdown as before. Scalar sections (Type Info, API Info, and every Text payload other than Source) have no rows: selecting one alone with --count or --rows fails before acquisition and names an inventory section as the alternative; a bare -n on it is the rendered-line window. Signature is a one-row inventory whose row is the resolved member, so --count answers 1. Count maps over several sections keep their per-section meaning.

Implementers and Derived Types are explicit, expensive Type sections in @Relations. They preserve the exact Type occurrence selected for ordinary Type output while scanning the selected source population. Platform Type relations scan the runtime, ASP.NET Core, and .NET Standard populations by default; an explicit --framework deliberately narrows the scan to that one family. An implementation-only Platform focus such as System.Private.CoreLib remains the selected Type occurrence while hierarchy binding uses its exact corresponding reference definition. Missing or ambiguous correspondence fails visibly. Count and Rows are independent producer terminals: Count-only requests no rows, and a finite head or closed-range --rows window reaches the producer as a finite prefix bound. An unbounded request uses a 10,000-row safety bound and reports continuation as incomplete output. Tail selection is rejected because the forward-only producer cannot satisfy it without privately materializing the complete population. Package relation rows include the package-relative asset in Source, so distinct ref, lib, or runtime occurrences remain distinguishable.

Every other type or member Text with a bare payload (API Declarations on the type command, Decompiled Source, Annotated Source, PDB Source, IL, and the overlays) has a fact row: --table, --tsv, and --jsonl emit its section, line count, and character count. Source Diff keeps its own row form, the comparison metadata and summary. --json on any of them except API Declarations emits the facts plus the complete payload as content; API Declarations keeps its inspection envelope, whose content carries the complete text. A fact row is not an inventory, so --count and --rows stay rejected. Composed Markdown still shows each Text's body, so -S "Decompiled Source,IL" reads side by side.

Source is the Text whose rows are its exact lines, per Source document cardinality: --count reports the line count, which includes the empty final line after a trailing line terminator; --rows selects lines, which native output, --markdown, and --plaintext print as text; and --table, --tsv, and --jsonl emit one row per line with its number, UTF-16 start offset, content, and terminator, which --columns and --fields can project. --jsonl carries each line's content exactly; --tsv and --table normalize a tab inside a line to a space, as every TSV in this CLI does. --json stays the complete Source document, so it rejects --rows. Default output is unchanged, and -n remains a rendered-line window.

dotnet-inspect type string --tree
dotnet-inspect member System.String.Trim:1 -S Source --count
dotnet-inspect member System.String.Trim:1 -S Source --rows 2..3
dotnet-inspect type --platform System.Text.Json -n 1 --tail --json
dotnet-inspect find JsonSerializer --platform System.Text.Json
dotnet-inspect member JsonSerializer --package System.Text.Json -m Serialize
dotnet-inspect member --explain
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize --explain
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 --explain
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize --explain .tips
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize -E
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 -S @Source
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 -S "Finding Census" --json
dotnet-inspect member JsonElement --package System.Text.Json DeepEquals:1 -S Facts --json
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 -S Calls
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 -S Calls -n 1 --tail --json
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 -S Callers
dotnet-inspect member System.ThrowHelper --platform System.Private.CoreLib --all \
  -m ThrowArgumentNullException:1 -S Callers -n 1 --tail --json
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 --source-parts --json
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 --print --part xml-docs
dotnet-inspect member JsonSerializer --package System.Text.Json Serialize:1 \
  --print --part body --markdown
dotnet-inspect type JsonSerializer --platform System.Text.Json -S "Source Files" --urls --json-array
dotnet-inspect library address 0x060002EA+0x0 \
  --package System.Text.Json --library System.Text.Json.dll

A bare ordinary method name selects its MemberGroup. Its default output is a native Tree rooted at one compact identity line and containing every public, non-hidden exact overload; explicit --tree renders the same population. This remains a MemberGroup when the selected version has one overload. Use --columns "Signature;Description" to request compiled documentation for each returned exact overload and render the bounded population as a table. Select an exact Member with an ordinal or digest when the intended subject is one declaration rather than its overload family. Its native default is one singular Signature view containing the display signature, digest, and canonical signature, followed by its independently settled compiled-documentation outcome, with no sibling Rows or Count. Missing or failed documentation remains visible without invalidating the resolved Member document. The one-based ordinal selects from the current MemberGroup's stable baseline order; after resolution, the owner-issued exact identity and population binding replace that ordinal as the durable subject.

--all is an API visibility option. API-level commands use their ordinary public-facing declaration population by default; add --all when the question includes non-public, hidden, or obsolete declarations. It is not a general "analyze every implementation" option.

Implementation-oriented sections define their own population. For example, Library Metrics summarizes the selected Library's admitted implementation bodies, including private and compiler-generated bodies when they are part of that population, without requiring --all. If an aggregate result identifies a non-public body and you follow it into an API-level command, that separate command may require --all to resolve the declaration.

Some body-oriented commands also begin with an API lookup. In those commands, --all can be necessary to resolve a non-public, hidden, or obsolete Type or Member root. Once resolved, the implementation operation uses its complete admitted body population by default; --all does not widen traversal, select more relationships, or request every analysis.

-k/--kind filters the logical C# declaration kind. Explicit interface properties and events compose their accessors into one property or event row, so select them with -k property or -k event. -k explicit-interface-implementation selects explicit method implementations that are not composed into a property or event declaration.

Exact library ... -S "Library Metrics" --json emits the complete Research LibraryStructuralReportDocument: the Analysis receipt and coverage, numeric distributions and maximum-body identities, async disposition, typed type summaries, cross-type relationships, Analysis diagnostics, and the methodology-v2 Type-leverage document. Type leverage preserves exact metadata type identities, the separately ordered sea-level and mountain-peak rankings, raw directional degrees, one nullable dominant pole per Type, role and evidence qualifications, Metadata signature-use and Analysis body-use receipts, and Graph work receipts. A Type that qualifies at both directional maxima receives the larger-degree pole; an exact degree tie receives no pole while remaining in both rankings. --envelope emits identical content plus Share and operation diagnostics:

dotnet-inspect library Markout.dll --package Markout@0.35.2 \
  --tfm net10.0 -S "Library Metrics" --json
dotnet-inspect library Markout.dll --package Markout@0.35.2 \
  --tfm net10.0 -S "Library Metrics" --envelope

This complete transport is separate from Markout lowering. Markdown, table, TSV, and JSONL retain their existing Library Metrics row contracts and add separately named Sea-Level Types and Mountain-Peak Types row groups. Those groups present the Research-issued order, named degree, role, exact type key, and qualification summary without blending the rankings into one score. Complete JSON requires one exact Library, one target framework, and the exact singleton section; it rejects row, field, column, Count, discovery, payload, and competing presentation projections rather than truncating Content. Type summaries carry exact metadata keys separately from display labels, and every relationship endpoint names a retained summary, so a Copilot App can render an SVG without recovering identity from display text. Library Metrics Share is currently nonProjectable.

Exact library ... -S "Dependency Structure" reports internal namespace dependencies derived from whole-library method evidence. Namespace edges are the section's QuerySpace rows. Nodes show Type count and topological level; cycle members are emphasized and carry their exact cycle index. Isolated namespaces remain visible in an unwindowed graph:

dotnet-inspect library FluentValidation.dll \
  --package FluentValidation@12.1.1 --tfm net8.0 \
  -S "Dependency Structure"
dotnet-inspect library FluentValidation.dll \
  --package FluentValidation@12.1.1 --tfm net8.0 \
  -S "Dependency Structure" --mermaid
dotnet-inspect library FluentValidation.dll \
  --package FluentValidation@12.1.1 --tfm net8.0 \
  -S "Dependency Structure" -n 10 --head

-n, --head, --tail, and --rows select namespace edges before graph rendering; a selected graph retains only edge endpoints. --count executes the namespace-edge QuerySpace Count terminal. The section is explicit-only and is not added by verbosity or category selection. Markdown and tabular formats lower the Markout graph as an edge table; --mermaid lowers the same graph as a diagram.

Exact -S "Dependency Structure" --json emits the complete Research document: Analysis and population receipts, Type and namespace nodes, internal and external edges, cycles, explanations, completeness, and diagnostics. --envelope emits the same Content plus a currently nonProjectable Share. Complete JSON requires one exact Library and one target framework, and rejects row, field, column, Count, discovery, print, shape, and competing presentation projections rather than truncating Content.

Exact library ... -S "Name Families" reports the most prevalent one- and two-word Type-name suffix families in one Library. The default all population covers every Type definition. --name-family-population selects ordinary, generated, mixed, or unknown when exactly bound source provenance is available:

dotnet-inspect library FluentValidation.dll \
  --package FluentValidation@12.1.1 --tfm net8.0 \
  -S "Name Families" -n 10 --head
dotnet-inspect library FluentValidation.dll \
  --package FluentValidation@12.1.1 --tfm net8.0 \
  -S "Name Families" --name-family-population ordinary --count

-n, --head, --tail, and --rows are semantic QuerySpace selection over family rows; --count executes the corresponding QuerySpace Count terminal. The section is explicit-only and is not added by verbosity or category selection.

Exact -S "Name Families" --json emits complete Content: every Type word and residual row, every population and family member address, methodology and oracle identity, provenance qualification, and partition receipts. --envelope emits the same Content plus a currently nonProjectable Share. These complete transports accept the population selector but reject row, field, column, Count, discovery, print, and shape projection. Markdown, table, TSV, and JSONL lower only the already selected family rows and show at most five labeled Type examples per family.

Exact -S "Architectural Families" composes those suffix families with the Library's exhaustive signature-only structural evidence. Each family row reports foundation, hub, orchestrator, unclassified-role, sea-level, and mountain-peak Type counts together with its population, source provenance, and structural-evidence disposition:

dotnet-inspect library FluentValidation.dll \
  --package FluentValidation@12.1.1 --tfm net8.0 \
  -S "Architectural Families" -n 10 --head
dotnet-inspect library FluentValidation.dll \
  --package FluentValidation@12.1.1 --tfm net8.0 \
  -S "Architectural Families" --name-family-population ordinary --count

Exact -S "Architectural Family Types" exposes the supporting Type rows from the same managed operation. Each row retains its artifact-scoped Type identity, one- and two-word families, source disposition, signature degrees, issued structural role and pole, and structural-evidence disposition:

dotnet-inspect library FluentValidation.dll \
  --package FluentValidation@12.1.1 --tfm net8.0 \
  -S "Architectural Family Types" -n 20 --head

Both sections are explicit-only. -n, --head, --tail, and --rows select the chosen family or Type rows before Markout lowering; --count counts that row set. --name-family-population applies to either exact section. The operation reuses the complete name-family population and one exhaustive signature-only structural acquisition; it does not request method bodies or Library Metrics implementation profiles.

Exact --json from either section emits the same complete architectural-family composition document rather than only the selected presentation rows. It contains every exact Type row, every population and family support address, both owners' methodology and work receipts, structural qualifications, and composition accounting. --envelope emits identical Content plus a currently nonProjectable Share. Complete transports require one exact Library and target framework and reject row, field, column, Count, discovery, print, shape, and competing presentation projections.

See API and implementation population scope for the distinction between API visibility, implementation completeness, and package-library selection.

For a Type catalog with an explicit package, library, platform, or project source, including positional or -t Type globs, -n, --tail, and --rows A..B select complete types after type, kind, and unsafe filtering. Markdown, table, TSV, JSONL, and JSON observe the same selected types; assembly-level companion evidence such as Type forwarders remains visible. Add --lines only to clip rendered text. Exact-type, selected-section, discovery, shape, match, and ambiguous commandless modes retain rendered-line fallback. Numeric -t is a literal Type filter, not a row-count spelling.

With exact member -S Calls, -n, --tail, and strict --rows A..B select complete direct call-site rows after analysis of the selected overload and its generated evidence methods. Repeated calls to the same target remain distinct. Markdown, table, TSV, JSONL, structured JSON, and Count observe the same selected call sites in their existing IL-offset order. Add --lines only to clip rendered text. Callers, Call Graph, @Calls, mixed sections, discovery, and Calls included only by verbosity retain their existing row contracts or rendered-line fallback.

With exact member -S Callers, -n, --tail, and strict --rows A..B select complete deduplicated caller-site rows after the selected target overload and all authorized caller scopes have been scanned. Markdown, table, TSV, JSONL, structured JSON, and Count observe the same selected call sites, including Source when the completed caller rows came from multiple assemblies. Add --lines only to clip rendered text. Calls, Call Graph, @Calls, mixed sections, discovery, and scope-implied Callers without the exact selector retain their existing row contracts or rendered-line fallback.

Exact member ... -S "Call Graph" --json emits the complete semantic InspectionGraphDocument: typed member subjects, directed call edges, physical call-site occurrences, characteristics, seeds, completeness limits, and failures. --envelope emits the identical document under content plus Share and diagnostics:

dotnet-inspect member System.Text.Json.JsonSerializer Serialize:1 \
  --platform System.Text.Json -S "Call Graph" --json
dotnet-inspect member System.Text.Json.JsonSerializer Serialize:1 \
  --platform System.Text.Json -S "Call Graph" --envelope

This complete transport is separate from Markout lowering. Markdown, Mermaid, tree, table, TSV, and JSONL keep their existing presentation and row contracts. Complete Call Graph JSON requires the exact singleton section and rejects row or line windows, fields, columns, Count, payload projections, and competing presentation formats rather than truncating the semantic document. Call Graph Share is currently nonProjectable; a Copilot App may render the typed content as SVG without recovering graph semantics from Mermaid or display labels.

Focused member -S "Source Locations" --json reports member, document, and pdb_span without fetching source text or adding generic section/row wrappers. PDB spans describe executable source, not the entire declaration. Opt in with --source-parts to acquire checksum-verified source and discover lexical ranges. --print --part member|xml-docs|attributes|signature|body prints the selected part; both gestures imply Source Locations when -S is omitted. The full member includes attached XML documentation and attributes; the body includes its delimiters. Missing parts fail visibly, and unqualified --print still prints the whole source document. These are lexical source parts, not parsed documentation or stronger physical-authorship evidence. Human-readable part output restores the original first-line indentation; structured JSON content remains the exact token-selected text.

Use a Workspace packet as reusable aggregate context when the Type may be defined by any Library in its selected context:

packet=$(dotnet-inspect workspace \
  --package System.Text.Json@10.0.0 \
  --tfm net10.0 \
  --share packet)

dotnet-inspect type System.Text.Json.JsonSerializer \
  --workspace "$packet"

# Given a schema-4 packet from a Type-capable producer:
dotnet-inspect type System.Text.Json.JsonSerializer \
  --workspace "$schema4_packet" \
  --share packet

type --workspace requires one exact Type and one canonical Base64URL Workspace packet string; URL input is rejected. It uses the packet's selected context independently of its focused tab. The packet is the sole location source, while the receiving command still applies its own NuGet source, credential, cache, and offline policy. Optional --share keeps ordinary Type output on stdout and writes the derived schema-4 packet or URL as the final stderr line when the input is schema 4. A workspace --share producer without source declarations emits schema 3; one with source declarations emits schema 5. Schema 3 remains a valid inspection input but cannot encode the derived Type scenario; requesting Share from that input fails visibly without discarding the Type output.

Compatibility and change tracking

dotnet-inspect diff --package Markout@0.33.0..0.35.2
dotnet-inspect diff --platform System.Runtime@9.0.0..10.0.0 --breaking
dotnet-inspect type System.Text.Json.Schema.JsonSchemaExporter --package System.Text.Json@9.0.0..8.0.6 --match
dotnet-inspect member System.Text.Json.JsonSerializer Deserialize:1 --package System.Text.Json@9.0.0..10.0.0 --match
dotnet-inspect timeline --package Markout@0.33.0..0.35.2 --type Markout.MarkoutWriterOptions --members --at all -S Transitions -n 10 --tail
dotnet-inspect timeline --package System.Text.Json@8.0.0..9.0.0 --type System.Text.Json.JsonSerializer --members --at all -S Evaluations --rows 2..

type/member --match follows one source API coordinate across exactly two literal package versions, preserving the written direction. Member matching resolves its selector only at the source; the destination selector comes from API correspondence, so a moved overload ordinal is not independently replayed. Matching is declaration-only: an ordinal selecting a singleton Property/Event accessor is refused; omit the accessor ordinal to match that declaration. Ordinals selecting among overloaded indexer declarations remain supported. Use --tfm to select one API surface and optional --library to narrow the source Library. --all widens source selection to the existing IncludeAll API scope; destination declaration matching remains strict and does not apply a second accessibility filter. Plain text and Markdown render the typed result; --json emits complete Content, and --envelope adds Share and diagnostics. This is separate from root match, which compares implementation structure.

Ordinary API diffs with one Library at each endpoint consume the shared Library API Diff contract intended for website Compare. This includes single-Library packages, platform libraries, and local DLL pairs. --type narrows the complete comparison; --all widens its API scope. The endpoints must be versions of the same logical Library (assembly name, culture, and public-key token).

On this route, unprojected --json serializes the complete LibraryApiDiffOutcome, replacing the former {changes: ...} presentation view. Use --envelope for that same Content plus Share and diagnostics; --compact controls whitespace for either complete JSON boundary, not projected or other Diff operations. For example:

dotnet-inspect diff --package System.Text.Json@9.0.0..10.0.0 --tfm net8.0 --envelope --compact

Envelope output accepts --all, but rejects Type/classification filters, section selection, explicit verbosity, row/line windows, and non-API modes. Explicitly projected JSON, such as -S Changes --json, retains its existing presentation schema. Share is explicitly non-projectable for comparison endpoints; it is not a replay URL.

The exact local-Library Implementation Diff route also exposes complete typed Content. Exact section selection chooses the operation rather than projecting its result; --type and --member remain semantic request inputs recorded in the Content:

before=old/Foo.dll
after=new/Foo.dll
dotnet-inspect diff \
  --library "$before..$after" \
  -S "Implementation Diff" --type Foo.Widget --envelope

Unprojected --json emits the same ImplementationDiffDocument found at --envelope.content; --compact controls whitespace. The document retains Before/After assembly identity, MVID and provenance, structured C# and IL evidence, complexity changes, and per-mechanism coverage. Share is currently non-projectable for the ordered endpoint pair. Package/platform ranges, PDB Source enrichment, row or field projection, alternate formats, and additional sections remain on the existing rendered paths or are rejected for complete transport.

Changes without a compatibility classification remain visible under Other API Changes, or as unclassified rows in detailed output. They are not classified as breaking or additive. An incomplete or rejected comparison returns nonzero and says not compared, rather than claiming no changes. Multi-Library packages, member-filtered diffs, Analysis Diff, Implementation Diff, analysis-set views, and mixed-section requests retain their existing routes; this adoption does not add the website Compare UI.

Use -S @Diff to compose the Changes, Analysis Diff, and Implementation Diff views. Annotated Source Diff, Complexity Context, Structural Context, Summary, and Transitions remain exact-name sections because their focused semantics do not compose with those comparison views.

--analysis selects which keyed Finding comparisons a pairwise diff runs. It takes one or more analysis identities, comma-separated or repeated, and -S then selects views of their result. diff -D, --help, and explain analyses list the identities: api, api-attribute, allocation, call-site, unsafety, csharp, il, and string-literals. The request's surface comes from its filters: any --member is Member, otherwise --type is Type, otherwise Library. The body analyses (allocation, call-site, unsafety, csharp, il) take exactly one --member; api-attribute takes --type; string-literals takes the Library surface and exactly one --where predicate.

dotnet-inspect diff --package System.Text.Json@9.0.0..10.0.0 \
  --type System.Text.Json.JsonSerializer --member "Serialize:1" \
  --analysis api,call-site,allocation

dotnet-inspect diff --package Microsoft.Azure.SignalR@1.20.0..1.33.1 \
  --analysis string-literals \
  --where "Literal contains https://"

dotnet-inspect diff --library old/Foo.dll..new/Foo.dll \
  --analysis string-literals --where "Literal starts-with https://" --json

String-literal predicates use exact ordinal UTF-16 matching. The key is case-sensitive Literal; the supported operators are contains and starts-with. Each Transition row retains the complete decoded literal. Two matching positions within one literal still produce one row, while separate physical ldstr instructions remain separate occurrences. Package diffs with several Library assemblies compare corresponding assemblies by file name and name each assembly in the Transition target. An assembly present at only one endpoint contributes added or removed literals. The single-Library target remains the package name.

Omitting --analysis selects the default set, api, so diff A B output is unchanged. One selected analysis defaults to Changes for api and to Transitions otherwise; several default to one Summary row per analysis with its outcome (Compared, Unavailable, or Failed) and its Added, Removed, Changed, and Present counts, each counted over the Transition rows its analysis emits (string-literals emits no Present rows, so its Present count is 0). -S Transitions lists each selected analysis's per-Finding transitions in selection order; at the Type surface api shows its api.type rows and then its api.member rows. Changes requires api. Transitions requires a selected analysis that declares it at the request surface: Type and Member analyses do so at their surfaces, while string-literals declares Library Transitions. --breaking, --additive, --changed, and --name-only refine Changes only. Unknown, duplicate, empty, surface-unsupported, and wrong-cardinality entries are all reported before acquisition.

Pairwise --finding and -S "Finding Transitions" are retired: they fail with guidance naming the --analysis identity and -S Transitions. --history keeps --finding and does not accept --analysis yet. --analysis does not combine with Analysis Diff, Implementation Diff, Annotated Source Diff, Complexity Context, or Structural Context. --json emits the shared DiffAnalysisDocument; --envelope emits that same Content plus Share and diagnostics. Both retain the exact string-literal predicate in the comparison context.

Select Annotated Source Diff with exactly one package Type and Member to emit the complete portable AnnotatedSourceDiffDocument. C# comparison is included by default; --il includes the corresponding IL instruction comparison. The document retains exact physical endpoints, type-forwarder hops, per-medium line maps into its contained source documents, and product-issued text comparisons. A Member present on only one endpoint has a typed absent side and no manufactured two-sided comparison. This route requires --json; --compact controls whitespace.

dotnet-inspect diff \
  --package System.Text.Json@11.0.0-preview.6.26359.118..11.0.0-preview.7.26381.103 \
  --tfm net10.0 \
  --type System.Text.Json.JsonSerializerOptions \
  --member .ctor:1 \
  -S "Annotated Source Diff" --json --il

Select Implementation Diff directly to inspect body-level C#, IL, and normal-flow complexity evidence. Select Complexity Context directly for a focused view with nullable Old, New, Delta, Population Size, and Percentile Rank fields. The rank is the inclusive percentage of delta-bearing methods in this diff whose absolute complexity delta is no greater than the row's. It is positional context, not an unusualness or quality judgment; an all-equal population gives every row 100. Use column projection with JSON Lines to emit dedicated cells instead of parsing Evidence:

--implementation is the conventional shortcut for exact -S "Implementation Diff" selection. It contributes that canonical section before ordinary section resolution, so explicit peer sections compose normally and all validation, output formats, and complete transport behavior remain identical.

dotnet-inspect diff --package Markout@0.33.0..0.35.2 \
  --type Markout.MarkoutWriter \
  -S "Complexity Context" \
  --columns Member,State,Delta,PopulationSize,PercentileRank,Kind \
  --jsonl

Select Structural Context directly to inspect signed instruction, complexity, loop, exception-region, direct-call, allocation, and async deltas with their direction signature and exact local cohort frequency. It includes complete, unambiguous pairs, including all-Unchanged pairs; added, removed, incomplete, and ambiguous pairs do not appear. Cohort Size is a local frequency, not an outlier or quality judgment. Use the stable Kind value research.complexity.structural-cohort and dedicated fields for structured automation:

dotnet-inspect diff --package Markout@0.33.0..0.35.2 \
  --type Markout.MarkoutWriter \
  -S "Structural Context" \
  --columns Member,InstructionDelta,ComplexityDelta,InstructionDirection,CohortSize,PopulationSize,Kind \
  --jsonl

Structural matching

Use the Clone Candidates section for a globally ranked search from an exact Library, Type, or logical Member seed. Breadth and candidate admission are independent; the default is Everything plus SimilarNames.

dotnet-inspect type Cases.Widget --library ./app.dll -S "Clone Candidates"
dotnet-inspect member Cases.Widget --library ./app.dll -m Value \
  -S "Clone Candidates" \
  --where "Breadth=Self" \
  --where "Discovery=All"
dotnet-inspect type Cases.Widget --library ./app.dll \
  -S "Clone Candidates" -n 2
dotnet-inspect package ./app.nupkg --library app.dll \
  -S "Clone Candidates" -n 2
dotnet-inspect type Cases.Widget --library ./app.dll \
  -S "Clone Candidates" -n 1 --tail --count
dotnet-inspect type -Q "Clone Candidates"

Breadth accepts Self, SelfAndRegisteredEcosystems, or Everything; Discovery accepts SimilarNames or All. The current CLI supplies the selected exact library as its finite Workspace participant snapshot and discloses that scope in tabular diagnostics and structured coverage. It does not infer registered-ecosystem membership or silently narrow the requested breadth. -n, --tail, and strict --rows windows select complete ranked candidate pairs consistently across Markdown, tables, TSV, JSONL, projected JSON, complete JSON, and --count. Coverage and the work receipt remain complete evidence, so structured receipt.returned_pairs can exceed the selected rows length.

Rows are retrieval candidates, not checked clone relations. They retain rank, both exact method endpoints, the 0-10,000 total and component scores, and the optional type/member name-similarity evidence. Plain --json also retains the portable seed, participant identity and provenance, coverage, failures, limits, and work receipt. --rows, --columns, --fields, --count, --table, --tsv, and --jsonl operate at the declared candidate-row output seam.

Pairwise match remains the checked comparison path:

dotnet-inspect match Left.Compute Right.Compute --library ./app.dll
dotnet-inspect match Left.Compute Right.Compute --library ./app.dll --body
dotnet-inspect match Sample.Encode --similar --library ./app.dll
dotnet-inspect match Sample.Encode --similar --library ./app.dll --assembly-wide --top 10

--body adds decompiled C# and IL body differences alongside the independent structural-match result. Both methods must resolve to the same physical assembly. A bodyless or unavailable endpoint stays visible rather than implying equal bodies. Use Markdown (the default) or --json; body evidence is not supported with --table, --tsv, --jsonl, or --similar. --body --json returns a match/body envelope: the body document retains per-producer native verdicts, physical endpoint addresses and availability, structured C#/IL differences, diagnostics, and cleanup outcomes. Plain match --json keeps its existing flat structural document. --body returns nonzero on query cancellation or failed body comparison while preserving the available output; a valid bodyless endpoint is reported as NoApplicableInput, not a body match. The publication and CLI gates cover these distinctions.

--similar ranks structural candidates for one seed method. It is a discovery step, not a verdict: a rank establishes no relation, no semantic equivalence, and no authorship or copying claim. Within one image, confirm a candidate by re-running the pairwise form on the selected pair.

The default candidate population is the seed's declaring type. --assembly-wide opts into whole-assembly retrieval, which costs materially more. -n, --tail, strict --rows windows, and --top select complete ranked candidate rows after retrieval; --top uses the structural-similarity ranking already issued by Analysis. Markdown, table, TSV, JSONL, JSON, and --count consume the same selected candidate sequence. JSON retains the complete per-method outcomes, blockers, and query receipt, with row_selection counts that distinguish returned candidates from selected rows. --max-results and --max-methods move the product retrieval limits themselves. In --table, --tsv, and --jsonl, the ranked candidates are the only row shape; the seed, scope, disposition, receipt, blockers, and disclosure are written to stderr so stdout stays single-shaped and parseable.

Every ranked row prints a Token column holding the candidate's metadata token, which the pairwise form accepts directly as the second operand. That keeps every row addressable even when a name is ambiguous across overloads or property accessors:

dotnet-inspect match 'Sample.Encode' 0x06000CF8 --library ./app.dll

A metadata token is a table row index, not a portable identity, so it addresses a member only in the assembly that defines it. match resolves a token against the image named by --library and fails when that image does not define the row, rather than binding it to an unrelated member.

That distinction is visible when --library names a facade. If the seed's type is forwarded, the ranked rows come from the assembly that actually defines them, so the run names that assembly and the exact --library value to pass when confirming a candidate:

dotnet-inspect match System.String.IsNullOrEmpty --similar --library ./System.Runtime.dll

Comparing candidates drawn from two different assemblies is not supported; inspect each side on its own.

Relationships and graphs

dotnet-inspect package Microsoft.Extensions.Logging@10.0.0 \
  -S Dependencies
dotnet-inspect package Microsoft.Extensions.Http@10.0.0 \
  -S "Package Info"
dotnet-inspect package Microsoft.Extensions.Http@10.0.0 \
  -S "Ecosystem Dependencies" \
  --columns "Ecosystem,Kind,Dependency,Declared By"
dotnet-inspect package Microsoft.Extensions.Logging@10.0.0 \
  -S "Dependency Hierarchy" --depth 2 --tree
dotnet-inspect depends Stream --markdown --mermaid
dotnet-inspect depends Int128 --table --rows 1..10
dotnet-inspect depends Int128 \
  --where "Kind=Interface" \
  --order-by "Target desc" \
  --top 5 --table
dotnet-inspect depends NpgsqlOptionsExtension \
  --package Npgsql.EntityFrameworkCore.PostgreSQL@8.0.4 \
  --tfm net8.0 \
  --envelope
dotnet-inspect depends NpgsqlOptionsExtension \
  --package Npgsql.EntityFrameworkCore.PostgreSQL@8.0.4 \
  --tfm net8.0 \
  --json
dotnet-inspect depends \
  --project ./src/App/App.csproj \
  --depth 2 \
  -S "Dependency Hierarchy,Dependencies"
dotnet-inspect depends \
  --package Microsoft.Extensions.Hosting@10.0.0 \
  --nuspec ./artifacts/local.nuspec \
  -v:n
dotnet-inspect depends \
  --package-prefix Microsoft.Extensions \
  --max-packages 100 \
  -S @Dependencies
dotnet-inspect depends --nuspec ./artifacts/local.nuspec -D --effective
dotnet-inspect depends --package Newtonsoft.Json --tfm net8.0 \
  -S Dependencies
dotnet-inspect depends --package System.Text.Json@9.0.0 --tfm net11.0 \
  -S Pruning
dotnet-inspect depends --package Microsoft.AspNetCore.Authentication.JwtBearer@10.0.0 \
  --tfm net11.0 --platform-family aspnetcore -S Pruning
dotnet-inspect depends \
  --project ./src/DotnetInspect.Cli \
  --nuspec ./artifacts/package.nuspec \
  -S "Dependencies,Failures" \
  -v:n
dotnet-inspect type IEquatable --project ./src/DotnetInspect.Cli \
  -S Implementers -v:q
dotnet-inspect extensions string --project ./src/DotnetInspect.Cli -v:q
dotnet-inspect graph integrations \
  --package Microsoft.Extensions.DependencyInjection.Abstractions@10.0.0 \
  --package Microsoft.Extensions.Logging.Abstractions@10.0.0 \
  --package Microsoft.Extensions.Logging@10.0.0 \
  --package Microsoft.Extensions.Http@10.0.0 \
  --tfm net10.0 \
  --relationship integration.observed \
  -n 10 --tail --table
dotnet-inspect graph calls \
  Microsoft.Extensions.DependencyInjection.ProviderBuilderServiceCollectionExtensions \
  AddOpenTelemetrySharedProviderBuilderServices~4d95928639 \
  --root-package OpenTelemetry@1.18.0 \
  --root-tfm net10.0 \
  --tfm net10.0 \
  --all
dotnet-inspect graph libraries \
  --library ./Consumer.dll \
  --library ./Provider.dll
dotnet-inspect graph packages \
  --package Microsoft.Extensions.Http.Polly@11.0.0-rc.1.26425.128 \
  --package Polly.Extensions.Http@3.0.0 \
  --tfm netstandard2.0
dotnet-inspect graph packages \
  --package Microsoft.Extensions.Http.Polly@11.0.0-rc.1.26425.128 \
  --package Polly.Extensions.Http@3.0.0 \
  --tfm netstandard2.0 \
  -S "Library Pairs,Call Sites" \
  --json
dotnet-inspect graph cluster 1 \
  --package Microsoft.Extensions.Http.Polly@11.0.0-rc.1.26425.128 \
  --package Polly.Extensions.Http@3.0.0 \
  --tfm netstandard2.0 \
  --table
dotnet-inspect graph cluster 3 \
  --library ./Consumer.dll \
  --library ./Provider.dll
dotnet-inspect graph libraries \
  --library ./Consumer.dll \
  --library ./Provider.dll \
  -S
dotnet-inspect graph libraries \
  --library ./Consumer.dll \
  --library ./Provider.dll \
  -S "Provider API Types" \
  --table

For asset roots, Dependency Hierarchy is the rooted explanatory result: shared targets reached through different parents remain separate occurrences, and tables, JSON, JSONL, row windows, and Count use that same occurrence currency. On package, selecting this section invokes the same host-neutral Depends operation; --tree only chooses its projection. Dependencies remains the direct declaration evidence section and does not acquire transitive packages. The removed package --dependencies spelling reports replacement guidance rather than acting as a second hierarchy selector. Positional depends <type> retains its existing Dependency Graph section until Type relationships move to the general Graph operation. That route now projects its existing Source, Target, and Kind predicates plus field and Traversal ordering through -Q "Dependency Graph". --top requires a Source, Target, or Kind field order; Traversal is a sequence order. Asset-mode Dependency Hierarchy and Package Dependency Hierarchy inherit the same --depth capability from the Dependency operation.

For recursive package traversal, --tfm selects the root package dependency group and configures the stable traversal target. When --tfm is omitted, the root keeps its package-local selection while newly reached packages use the product traversal default, currently net11.0; a compatible destination selection does not replace that target on later edges.

For graph integrations and graph calls, one semantic row is one logical graph edge in the completed typed document. Head/Tail and strict Window select those edges before Markdown, table, TSV, JSONL, JSON, Mermaid, plaintext graph, or Count lowering; selection does not reduce package acquisition or hide retained graph failures. Add --lines only to clip rendered text explicitly. graph libraries, graph packages, and graph cluster retain independent section row sets; their adopted Direct Use Clusters and Call Sites cohorts are described below.

graph packages requires exactly two Package coordinates and one explicit --tfm. It acquires only those Package subjects, enumerates the complete cross-Package implementation-Library matrix, and evaluates both call directions for each Library pair. The explicit --tfm is one shared acquisition request; each Package may independently select a different compatible implementation asset framework. The default Direct Use Clusters rows use a canonical Package-pair-wide cluster ordinal. Library Pairs exposes every admitted matrix cell, including complete empty pairs, while Call Sites exposes the physical calls supporting each cluster. --columns and --fields both project the selected section's row vocabulary. Reversing the two --package values does not change canonical row order or cluster assignment. The operation does not traverse Package dependencies; use graph calls for the dependency-aware member workflow. graph cluster N accepts the same Package pair and defaults to the selected cluster's Call Sites. Package-backed Public Root Paths is not yet available; that exact section continues to require the local-Library route.

graph calls is the integration-style complement to the general member -S "Call Graph" view. It starts from one exact member in --root-package, automatically follows the root's authorized dependency graph, and shows only calls crossing the selected supply-chain baseline plus the shortest baseline paths needed to reach them. Root asset selection stays exact; dependency traversal independently uses --tfm or the product default. In the OpenTelemetry example, --all is needed only because AddOpenTelemetrySharedProviderBuilderServices is a non-public starting declaration. It widens that API lookup; it does not mean all calls, remove the graph bounds, or widen the body population, relationship set, dependency traversal, or selected baseline. Each edge is typed as connector, boundary, or unclassified-boundary, and row-oriented output retains the physical MVID, MethodDef token, IL offset, operand token, call kind, dispatch kind, and loop state. A dependency member with unique ownership also retains its exact package id, version, and selected framework. Inspect Web loads that coordinate through its ordinary package path only when the user selects the graph node, then opens the exact member; ambiguous ownership publishes no package coordinate.

For an unresolved ordinary AssemblyRef from a Package participant, the CLI evaluates reachable Package suppliers first and eligible exact Platform targets second. A selected supplier is admitted into a fresh immutable Workspace generation, and the call graph is rebuilt against that successor. Continuation uses finite command-owned work limits and the Workspace deadline; exhausted or incomplete work remains visible instead of becoming a final missing binding.

The default --baseline self+registered-ecosystems excludes the exact root, explicit --first-party-prefix values, and the product platform registrations (.NET Runtime, ASP.NET Core, and Microsoft.Extensions) from highlighting. --baseline self retains only the exact root and explicit first-party prefixes as connectors. --baseline nothing highlights every known dependency Package and rejects first-party prefixes because that baseline excludes nothing. Traversal and acquisition remain unchanged by all three values. Platform- delegated dependency routes do not become Package boundaries, while genuinely unknown ownership remains an unclassified-boundary.

The OpenTelemetry example retains the explanatory connector paths but highlights OpenTelemetry.Api rather than registered Microsoft.Extensions Packages. Unavailable dependency participants remain visible through typed routes and diagnostics rather than being silently dropped. Use --table, --jsonl, or --json for exact receipts; -n, --tail, and --rows select complete logical edges after graph construction.

For positional type dependencies, --json writes the complete TypeDependencySectionResult Content, and --envelope writes the identical camelCase value under content with schema_version: 1, result_kind: "type-dependencies", share, and diagnostics. The motivating example resolves the full matched type Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal.NpgsqlOptionsExtension. The Content retains the complete dependency relationships and the separately selected rowSelection.relationships; internal dependency enums remain numeric.

Envelope framing and diagnostic member names use lower snake case. Share keeps the owner values available and nonProjectable; diagnostic severity remains Information, Warning, or Error, and absent correspondence is retained as null. Baseline envelopes have no evidence member.

With --envelope, --depth remains a traversal input and --rows, -n/--head/--tail remain semantic relationship selection. --compact is accepted. Competing formats, --json, Discover/schema/effective modes, -S, explicit -v, Count, fields/columns, presentation projections or decoration, and rendered-line clipping are rejected before acquisition. --verbose and -E .tips remain on stderr. --share retains its existing policy and emits its optional URL or packet as the final stderr line. There is no --evidence-envelope support yet.

Asset-mode output, Discover, Count JSON, and ordinary non-JSON output are unchanged. A service-issued empty or non-success Content value is still serialized with its existing exit behavior; an acquisition failure that produces no result emits no substitute envelope.

Pruning is explicit-only and evaluates direct declarations of the named roots; it does not prune dependency-graph edges or run transitive traversal. The default comparison family is runtime; use --platform-family aspnetcore to select the ASP.NET Core inventory. In its output, Candidate is the package version resolved from the declaration and Platform Provides is separate platform-supply evidence. If those columns show 4.3.2 and 4.3.1, respectively, the disposition is PackageRetained: the command does not select or downgrade to 4.3.1.

graph libraries evaluates both directions in the pair; every row still names its directed source and target. Omitting -S shows Direct Use Clusters. In that default view, and with exact -S "Direct Use Clusters", -n, bare -N, --tail, and strict --rows select complete deterministic cluster rows before Markdown, plaintext, table, TSV, JSONL, JSON, or Count lowering. Use --lines for explicit rendered-line clipping. Select -S "Consumer Use Sites;Provider API Types" for the local methods containing direct calls and the provider declaring types selected by those calls. These are direct-use surfaces, not semantic feature clusters, public-entrypoint reachability, or a list of configured ecosystem Integrations. Select @Libraries to compose Call Sites, Consumer Use Sites, Direct Use Clusters, and Provider API Types in alphabetical section order. Public Root Paths remains an exact-name section because its required focused cluster does not compose with the pair-wide category. Summary, path, wildcard, category, and multi-section views retain rendered-line -n because their independent row schemas do not form one semantic sequence.

The default Direct Use Clusters section partitions the exact directed calls into connected components of source and target methods. Each explicit row retains its call-site references and separately counts source members, provider types, target members, extension methods, and physical sites. A one-extension-method row exposes a small direct-use footprint; it is not yet proof that the package is removable or that copying source is safe.

Use the pair-wide cluster ordinal to reopen one component as exact calls:

dotnet-inspect graph libraries \
  --library ./Consumer.dll \
  --library ./Provider.dll

dotnet-inspect graph cluster 3 \
  --library ./Consumer.dll \
  --library ./Provider.dll

dotnet-inspect graph cluster 3 \
  --library ./Consumer.dll \
  --library ./Provider.dll \
  -S "Public Root Paths"

graph cluster N requires the same two Libraries and defaults to exact Call Sites. Its heading and description identify the focused cluster and summarize its source-member, provider-type, target-member, extension-method, and physical call-site footprint. The rows name every source member, source token, target member, target token, call kind, evidence method, evidence token, and IL offset in that cluster. Use source and target identities for ordinary member inspection. Use the evidence token with the IL offset for library address, because a compiler-generated physical body can differ from the attributed source member. The cluster remains structural evidence rather than a source-inlining verdict.

Public Root Paths traces the selected cluster's exact consumer methods back to exhaustive public MethodDef roots in the consumer library. Each row reports one deterministic shortest local static path, its public root and destination tokens, and physical IL receipts for every logical step. The section must be named explicitly under graph cluster N; it is excluded from defaults and wildcard section selection. Pair-wide graph libraries rejects the section with focused-route guidance. A complete empty section means no public root has a local static path to the selected use sites. If pair, public-root, or path analysis is incomplete, retained positive paths are still rendered and the command exits nonzero instead of asserting absence.

dotnet-inspect member "<SourceType>" \
  --library ./Consumer.dll \
  -m "<SourceMember>" \
  -S @Source

dotnet-inspect member "<TargetType>" \
  --library ./Provider.dll \
  -m "<TargetMember>" \
  -S @Source

dotnet-inspect library address "<EvidenceToken>+<ILOffset>" \
  --library ./Consumer.dll

Workspace sharing and built-in guidance

dotnet-inspect workspace packet decode "$w"
dotnet-inspect workspace packet decode "$w" | jq
dotnet-inspect workspace packet encode --file workspace-state.json
dotnet-inspect workspace packet encode --file workspace-state.json --url
dotnet-inspect member JsonConvert \
  --package Newtonsoft.Json@13.0.4 \
  SerializeObject:1 \
  --tfm net6.0 \
  --share
dotnet-inspect depends \
  --package Newtonsoft.Json \
  --tfm net6.0 \
  --share
dotnet-inspect skill list
dotnet-inspect demo list
dotnet-inspect demo list -n 3 --json

workspace packet encode --url emits https://dotnet-inspect.net/?w=<packet> for the existing share-packet JSON shape. Packet-only output remains the default. This is not an encoder for workspace --json inventory output. The packet's existing limits and the browser's supported restoration shapes still apply.

Bare --share emits a complete Inspect Web URL; --share url spells that default explicitly, while --share packet emits only the canonical packet.

member --share[=url|packet] projects one explicitly selected public member overload from an exact NuGet.org package version and target framework. The URL opens that member's API Overview in the published browser. Select an overload with Name:N, Name~digest, or --index N. Local, project, platform, private-feed, non-public, multi-library, and other rendering or analysis modes fail visibly rather than producing a link the browser cannot restore.

depends --package <id>[@<version>] --tfm <tfm> --share[=url|packet] projects the package Dependencies view without acquiring the package or traversing the graph in the CLI. An omitted version or latest is resolved from NuGet.org and pinned before emission; the published browser then acquires that exact coordinate and lazily computes the dependency graph for the selected target framework. Local archives, effective source policies that do not authorize exactly one NuGet.org source, wildcard, range, or build-metadata versions, omitted frameworks, the Browser-reserved Microsoft.NETCore.App Platform id, row windows, counts, and other rendering formats fail visibly rather than producing a non-reproducible link.

depends <type> --package <id>@<version> --tfm <tfm> --share[=url|packet] keeps the type dependency result on stdout and appends its canonical Dependencies URL or packet to stderr. Type sharing is limited to one exact NuGet.org package coordinate, a valid target framework, and the requested type; local, floating, ranged, private-feed, multi-source, platform, and non-projectable requests fail visibly.

The service constructs Share for positional type JSON regardless of whether stderr projection was requested. --json emits Content only; --envelope exposes Share alongside that Content. A nonProjectable Share does not change otherwise successful Content or its exit status. Mixed dependency sources and any explicit --depth are non-projectable because the published Browser cannot preserve those requests.

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, then use Repository workflow for contributor rules. Use overview.md when a change crosses subsystem ownership boundaries, and taste/skill-guidance.md when maintaining the embedded skill.

License

MIT

Exact explanation JSON

explain <resource> --json returns compact resource facts and HAL navigation. The declared fact names are local to the resource type; ordered values remain arrays. Non-available facts appear in fact_states, and relationship states and truncation remain explicit. Integers and decimals are lossless decimal strings; octets are base64 strings.

dotnet-inspect explain vocabularies/csharp.body-kinds --json
dotnet-inspect explain package-query/query/facets/library-literal --json
dotnet-inspect explain vocabularies/csharp.style-choices --depth 1 --json
dotnet-inspect explain vocabularies/csharp.body-kinds .contract --json

.contract explicitly selects the complete self-contained explanation Document with its schema declarations. It requires an exact resource and --json. HAL links use inspect-resource:/<resource-path> addresses; pass a returned href unchanged to explain to follow it. These addresses resolve locally, without HTTP access. Human explanation and capability search are unchanged.

For vocabulary, query-space, and query-facet roots, .data --json selects a self-contained reading dataset rather than a graph depth. Vocabulary data includes referenced vocabularies, direct value properties, complete positive boolean sets, and optional-text membership groups. Facet data includes required context and exposing bindings; exposed_facets is the binding's intersection with the selected facets, not its entire term population.

dotnet-inspect explain vocabularies/csharp.style-choices .data --json
dotnet-inspect explain package-query/query .data --json
dotnet-inspect explain package-query/query/facets/library-literal .hal --json

.hal embeds the reading resources under _embedded. Vocabulary reading uses _embedded.vocabularies and each vocabulary's _embedded.values; direct .data uses keyed vocabularies/values tables plus owner-order arrays. Both preserve native identities, map meanings and sparse property indices. scope reports the reading profile and complete selected population. Vocabulary catalog_values counts are bounded JSON numbers; integer map values retain their lossless decimal text representation.

For an exact vocabulary root, add -Q / --query-help to either reading projection to select native value identities before serialization:

dotnet-inspect explain vocabularies/csharp.body-kinds .hal --json \
  -Q ObjectCreationExpression
dotnet-inspect explain vocabularies/csharp.style-choices .data --json \
  -Q slot-local-names
dotnet-inspect explain vocabularies/api.accessibility .hal --json \
  -Q 'public;private'

Lists accept commas or semicolons, trim whitespace, deduplicate, and preserve owner order. A bare -Q after the projection selects all values; a supplied empty list fails. Matching is exact and case-sensitive: ObjectCreationExpression is a native body-kind identity, while objectcreationexpression is its path segment. No wildcard, display-label or path-segment matching is inferred. Shared selection includes only the exact referenced term values, so one style choice includes its tier meaning without the unrelated tier population. Optional groups and defaults contain selected members only; they do not enumerate all catalog alternatives.

-Q narrows data while .data/.hal selects its representation. It requires the reading projection and JSON; it is rejected for ordinary compact output, .contract, vocabulary collections, value-resource roots, other resource kinds, search text, --depth, and -n. Capability-search -n still caps search results; --depth still controls ordinary graph expansion. Root explain -Q does not replace command-local Package Query --explain -Q facet selection.

Full reading HAL has one implemented self link. A value-selected HAL response has one full-vocabulary collection link. Links advertise application/hal+json and use ?projection=hal; pass an emitted href unchanged to explain --json. You can add -Q to narrow that HAL address while retaining its projection. Reading profiles omit automatic contract/member navigation; request .contract --json explicitly when declaration inspection is necessary. Ordinary compact resource navigation can still expose other JSON detail links.

The reading projections require JSON and reject --depth and search operands. Closure is bounded to 256 resources and 4,096 observed targets; excess or incomplete selected observations fail visibly instead of producing sparse tables with ambiguous negatives. Absence from a Boolean set establishes false only for a selected member with complete available property coverage. Unselected values remain unknown. Neither projection supplies validation rules or host flag mappings that the catalog has not registered. The worked vocabulary reads include reusable jq exploration and a concrete agent workflow.