# Reading .NET packages, APIs, and call graphs without loading the code

> dotnet-inspect is a C# tool with a matching browser app that reads NuGet packages, restored projects, and platform assemblies on the promise of metadata rather than execution. The CLI surface is narrow and easy to copy, the release line is moving fast at 0.26.0, and the README leaves exit codes, output formats, and the origin of its call graphs unexplained.

**richlander/dotnet-inspect** — Tool to inspect .NET assets, like docker inspect and kubectl describe.

- Repository: https://github.com/richlander/dotnet-inspect
- Stars: 151 · Forks: 12
- Language: C#
- License: not declared
- Published: 2026-08-27 · Updated: 2026-08-27 · Language: en
- Canonical page: https://hysenlabs.com/projects/richlander-dotnet-inspect

## Three ways to reach the same binary

The install section names two paths and stops there. The first is the .NET global tool:

```bash
dotnet tool install -g dotnet-inspect
dotnet-inspect package System.Text.Json
```

The second skips installation entirely and goes through `dnx`, the runner shipped with recent .NET SDKs:

```bash
dnx dotnet-inspect -y -- package System.Text.Json
```

The trade is a permanent entry on your PATH versus a one-off fetch of the tool package. A third path exists but is not written up. The top level of the tree carries `install.sh`, `install.ps1`, and `install-source.sh` beside a `.dotnet-install/` directory, and none of the three appear in the install section. The `dnx` form is the one every later example reuses, so a shell habit picked up from the first snippet will not carry over to the rest of the page.

## Every dnx example repeats the same -y -- pair

Past the first snippet the shape of a command stops changing. `dnx dotnet-inspect -y -- package System.Text.Json` is the shortest form, and the dependency, member, and demo examples all carry the same two tokens before the subcommand: a `-y` flag and a `--` separator. The separator has an obvious job, since everything after it belongs to dotnet-inspect rather than to `dnx`. The `-y` is the less documented half. The README never says what it confirms, whether it suppresses a prompt, or which prompt it would suppress, and the global tool example does not use it at all. If you wrap this tool in a script, that is the flag you will be guessing about, and the answer belongs to `docs/cli-reference.md` rather than to this page.

## depends means two different graphs depending on one token

The two dependency examples differ by a single argument, and that argument changes what comes back. The package level view pins the package and the framework:

```bash
dnx dotnet-inspect -y -- depends \
  --package System.Text.Json@10.0.0 --tfm net10.0
```

Swap the flag for a bare type name in the same position and you get the type level view:

```bash
dnx dotnet-inspect -y -- depends JsonSerializer \
  --package System.Text.Json@10.0.0 --tfm net10.0
```

Both keep the package pinned with an `@` suffix and both pin the target framework, so the same package can be read across framework monikers with no restore step of your own. The link beside each snippet is labeled separately, the package run as the same dependency view and the type run as the same type dependency view, which reads as a nested result rather than a renamed one. How the two outputs are formatted, whether one nests inside the other, and what happens to a package carrying no dependency metadata are not described in the README, which hands the reader off to `docs/cli-reference.md` for the full set of examples.

## member needs a package, a version, a framework, and an unexplained digit

Of the subcommands shown, the API lookup is the strictest about the parts it needs:

```bash
dnx dotnet-inspect -y -- member JsonSerializer \
  --package System.Text.Json@10.0.0 Serialize:1 --tfm net10.0
```

The type sits first as a bare argument, the package arrives as a flag with `@10.0.0` appended, then a second bare token `Serialize:1`, then the framework. The `:1` suffix is the piece the README does not explain, and the page offers no second example that would confirm what the digit selects, so treat that exact spelling as required rather than as a typo to correct. Drop the `@` suffix or the `--tfm` value and the lookup is underdetermined. The short `dotnet-inspect package System.Text.Json` line shows the looser case, where you ask about a package and accept whatever version resolves.

## Demo names encode the framework code path being traced

The three demos are named after specific framework methods rather than after verbs, and each one adds a Mermaid flag:

```bash
dnx dotnet-inspect -y -- demo options-add-callgraph --mermaid
dnx dotnet-inspect -y -- demo stj-getdecimal-callgraph --mermaid
dnx dotnet-inspect -y -- demo aspire-postgres-callgraph --mermaid
```

The names say what is being followed: an add call inside the .NET Options hub, the `GetDecimal` path in the JSON number parser, and the resource registration Aspire performs for PostgreSQL. The link beside each demo points at `dotnet-inspect.net` with the package, version, and framework encoded into the query string, and the Aspire link additionally carries a plain `package=Aspire.Hosting.PostgreSQL` parameter. That link resolves to Aspire.Hosting.PostgreSQL 13.5.3 for net8.0, while the tool asks for the .NET 10 SDK or later, so the framework you inspect is not pinned to the framework the tool runs on. The three link labels also name three different graphs: an inbound call graph for the Options demo, a runtime call graph for the JSON parser, and a resource registration graph for Aspire. Two other hosts sit above these: a working build at `dotnet-inspect.ca` and a nightly CoreCLR interpreter at `coreclr.dotnet-inspect.ca`.

## The no-loading promise sits next to the call graphs

The opening sentence sets the constraint: inspect libraries, NuGet packages, restored projects, and platform assemblies without loading the inspected code. The list that follows widens it to metadata, APIs, dependencies, source, implementation details, and version differences, reachable from the CLI or a browser. Reading source and implementation details without loading the assembly is the part of that claim that carries weight. The friction is with the demos, which follow execution paths inside Microsoft.Extensions.Options and System.Text.Json, and with the nightly build hosted on a CoreCLR interpreter. The README does not reconcile the two halves, so if your question is whether a graph comes from static metadata or from running code, this page will not settle it.

## Three tags inside three weeks on a version line under 1.0

Tags are landing quickly. v0.24.0 shipped September 3, 2026, v0.25.0 on September 7, and v0.26.0 on September 23, with the last push to the repository dated September 30, 2026. The repository is not archived, and the version number has not crossed 1.0, which is exactly the range where command shapes are still fair game to change between tags. That matters if you script against the tool: pin the package version the way the examples pin `@10.0.0`, and expect to re-read the CLI reference after each upgrade. The same activity shows in the tree, which carries `docs/`, `AGENTS.md`, `prompts/`, `skills/`, `.claude-plugin/`, `backlog.md`, a `dotnet-inspect.slnx` solution file, and central version files in `Directory.Build.props` and `Directory.Packages.props`. The README names `docs/cli-reference.md`, `docs/README.md`, and a `dotnet-inspect skill` command, and says nothing about the rest.

## Exit codes, output formats, and rollback are simply absent

Several operational questions have no answer in the documentation. There are no exit codes, no output formats beyond the Mermaid flag, and no description of what happens when a package version does not exist or when a target framework moniker is not recognized. There is no rollback procedure, and nothing states whether the hosted demos accept uploads, so read `dotnet-inspect.net` as a place to look rather than a place to publish your own builds. Licensing is a single closing line, MIT, and the tree carries a `THIRD-PARTY-NOTICES.TXT` file whose contents are not reproduced in any of the linked documents. The only hard requirement stated anywhere is the .NET 10 SDK or later.

## Conclusion

If you are reverse engineering a .NET package you cannot build, or tracing a framework call path, dotnet-inspect earns an afternoon of your time. If you need a stable command contract or documented exit codes today, it does not, because the version series is still under 1.0 and the tree is changing fast. Pin the package version the way the examples pin @10.0.0 and re-read the CLI reference after every upgrade.

## FAQ

### What is the command to inspect?

Installing the global tool gives you `dotnet-inspect package System.Text.Json`, and the install-free route is `dnx dotnet-inspect -y -- package System.Text.Json`. Every later example on the page uses the `dnx` form with a `-y` flag and a `--` separator before the subcommand.

### Does dotnet-inspect load the assembly it inspects?

The opening line says it inspects libraries, packages, restored projects, and platform assemblies without loading the inspected code, and the same line promises source, implementation details, and version differences. The page does not say how the call graph demos follow execution paths under that constraint.

### What .NET version does dotnet-inspect need on the machine running it?

The closing line requires the .NET 10 SDK or later. The Aspire demo link points at Aspire.Hosting.PostgreSQL 13.5.3 for net8.0, so the target framework you inspect can differ from the framework the tool itself runs on.

### What is the difference between the two depends examples?

`depends --package System.Text.Json@10.0.0 --tfm net10.0` gives the package graph, while `depends JsonSerializer` with the same package and framework flags gives the type graph. Both pin the version with an `@` suffix and both name the target framework explicitly.

### What license is dotnet-inspect released under and where is it stated?

MIT, stated in the last line of the README next to the .NET 10 SDK requirement. A `THIRD-PARTY-NOTICES.TXT` file sits at the top of the repository, and none of the linked documents reproduce its contents.

## Sources

- [Official README](https://github.com/richlander/dotnet-inspect#readme)
- [Project repository](https://github.com/richlander/dotnet-inspect)
- [Release notes](https://github.com/richlander/dotnet-inspect/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/richlander-dotnet-inspect
