Inspector is a .NET CLI and runtime infrastructure for inspecting and manipulating Avalonia UI trees. It is designed for both human use and coding-agent automation with deterministic, machine-readable output.
- Enumerates visual and logical trees
- Reads node property metadata and values
- Applies node/property mutations (set property, insert/remove/move/reparent)
- Exposes capabilities and stable schema metadata for automation
- Supports:
- Host mode (instrumented runtime in app)
- Process mode (CLI-side no-host attach via
--pidor--name)
| Package | Version | Downloads | Install |
|---|---|---|---|
Inspector.Contracts |
dotnet add package Inspector.Contracts |
||
Inspector.Transport |
dotnet add package Inspector.Transport |
||
Inspector.Host |
dotnet add package Inspector.Host |
||
Inspector.AvaloniaAdapter |
dotnet add package Inspector.AvaloniaAdapter |
||
Inspector.Cli.Tool |
dotnet tool install --global Inspector.Cli.Tool |
Install the package you need:
dotnet add package Inspector.Contracts
dotnet add package Inspector.Transport
dotnet add package Inspector.Host
dotnet add package Inspector.AvaloniaAdapterGlobal tool:
dotnet tool install --global Inspector.Cli.Tool
inspector --helpLocal tool manifest:
dotnet new tool-manifest
dotnet tool install --local Inspector.Cli.Tool
dotnet tool run inspector --helpUpdate/uninstall:
dotnet tool update --global Inspector.Cli.Tool
dotnet tool uninstall --global Inspector.Cli.Toolsrc/
Inspector.Contracts Shared DTOs/enums/schema contracts
Inspector.Transport Local transport/session/authorization model
Inspector.Host In-process host runtime abstractions
Inspector.AvaloniaAdapter Tree/property/mutation adapter implementations
Inspector.Cli Command-line interface and agent-friendly output
tests/
Inspector.Tests xUnit test suite
samples/
Inspector.SampleApp Minimal host runtime integration sample
- .NET SDK compatible with
net10.0
scripts/ci-build.sh: restore, build, test, and pack all publishable packages.scripts/ci-release.sh: runsci-build.shand pushes.nupkg/.snupkgto NuGet..github/workflows/ci.yml: PR/push validation + package artifact upload..github/workflows/release.yml: tag/manual release publishing to NuGet (NUGET_API_KEYsecret required).
Run locally:
bash scripts/ci-build.shRelease locally:
NUGET_API_KEY=<your-key> VERSION=0.1.0 bash scripts/ci-release.shInspector.Cli command surface
Usage:
inspector capabilities
inspector connect [--mode <stub|host|process>] [--address <uri>] [--pid <int>] [--name <process-name>] [--client-id <id>] [--client-version <version>] [--secret <secret>] [--scope <scope>]...
inspector tree get --session-id <id> [--kind visual|logical]
inspector node get-properties --session-id <id> --node-id <id>
inspector node set-property --session-id <id> --node-id <id> --property <name> --value <json-or-text> [--operation-id <id>]
inspector tree mutate --session-id <id> --target-node-id <id> --operation <set-property|insert|remove|move|reparent> [--payload <json>] [--dry-run] [--operation-id <id>]
inspector tree batch-mutate --session-id <id> --operations <json-array|json-object> [--dry-run] [--operation-id <id>]
Global options:
--json Emit deterministic JSON output
--output <text|json> Select output mode
--help, -h Show help
Exit codes: 0=success, 2=validation error, 3=execution error, 10=unexpected error
# Capabilities
inspector capabilities --json
# Connect (host mode)
inspector connect --mode host --address local://inspector --client-id my-tool --json
# Connect (process mode by pid)
inspector connect --mode process --pid 12345 --json
# Connect (process mode by name)
inspector connect --mode process --name Inspector.SampleApp --json
# Visual tree
inspector tree get --session-id sess-123 --kind visual --json
# Node properties
inspector node get-properties --session-id sess-123 --node-id visual-button --json
# Set property
inspector node set-property --session-id sess-123 --node-id visual-button --property Width --value 320 --json
# Mutate tree (dry-run)
inspector tree mutate --session-id sess-123 --target-node-id visual-button --operation move --payload '{"index":0}' --dry-run --json
# Batch mutate (single call, multiple operations)
inspector tree batch-mutate --session-id sess-123 --operations '[{"targetNodeId":"visual-label","operation":"set-property","payload":{"property":"Text","value":"Welcome back"}},{"targetNodeId":"visual-root","operation":"insert","payload":{"typeName":"TextBox","name":"EmailInput","properties":{"Watermark":"Email"}}}]' --jsonIf you are developing from source, you can run the same commands with:
dotnet run --project src/Inspector.Cli -- <command> [args]When connected with --mode host, tree mutate supports structural and property mutations with JSON payloads:
set-property:{"property":"<name>","value":<json>}insert:{"typeName":"<type>","nodeId":"<optional-id>","name":"<optional-name>","classes":["..."],"properties":{"...":...},"index":0}move:{"index":1}reparent:{"parentNodeId":"<node-id>","index":0}remove: payload optional
The same operation payloads are also used by tree batch-mutate entries.
Examples:
# Create a new control node under visual-root (nodeId can be omitted for auto-generation)
inspector tree mutate --session-id <session-id> --target-node-id visual-root --operation insert --payload '{"typeName":"Avalonia.Controls.TextBox","name":"EmailInput","properties":{"Text":"","Watermark":"Email"}}' --json
# Set any property via tree mutate payload
inspector tree mutate --session-id <session-id> --target-node-id visual-label --operation set-property --payload '{"property":"Text","value":"Ready to login"}' --json
# Reparent and remove
inspector tree mutate --session-id <session-id> --target-node-id child-node --operation reparent --payload '{"parentNodeId":"new-parent","index":0}' --json
inspector tree mutate --session-id <session-id> --target-node-id old-node --operation remove --json
# Batch mutate using either raw array or { "operations": [...] }
inspector tree batch-mutate --session-id <session-id> --operations '{"operations":[{"targetNodeId":"visual-label","operation":"set-property","payload":{"property":"Text","value":"Ready to login"}},{"targetNodeId":"visual-root","operation":"insert","payload":{"typeName":"Avalonia.Controls.TextBox","name":"EmailInput","properties":{"Watermark":"Email"}}}]}' --jsonUse this mode to target an already-running process by PID or process name.
- Connect and capture session id:
inspector connect --mode process --pid <pid> --json
# or
inspector connect --mode process --name <process-name> --jsonCheck data.processSnapshotAvailable in connect output:
true: live UI snapshot is availablefalse: CLI will use fallback process metadata
- Reuse returned
sessionIdin follow-up commands:
inspector tree get --session-id <session-id> --kind visual --json
inspector node get-properties --session-id <session-id> --node-id <node-id> --json
inspector node set-property --session-id <session-id> --node-id <node-id> --property <name> --value <json-or-text> --jsonFor apps that include the sample snapshot publisher integration:
node set-propertyqueues live property mutation commands for the running process.tree mutatein process mode also queues live structural mutation commands (insert,remove,move,reparent,set-property) so runtime controls can be added/rearranged without restarting the app.tree batch-mutateapplies multiple mutations in one CLI call and queues each live process mutation command in order for faster bulk updates.
- Common process-mode errors:
cli.process.not_found: PID/name not foundcli.process.ambiguous: multiple processes match--name(retry with--pid)cli.process.exited: process ended before command execution
When the target app publishes live inspector snapshots (the included Inspector.SampleApp does), process mode returns live visual/logical nodes and node properties instead of fallback process metadata.
If no live snapshot is published by the target process, process mode falls back to process metadata nodes.
connectcreates a session and returnssessionId.- Session state is persisted across CLI invocations in a local temporary session store.
tree get,node get-properties,node set-property,tree mutate, andtree batch-mutaterequire a valid--session-id.
- Defaults to JSON when input/output is redirected (non-interactive)
- Supports explicit output selection via
--output text|json --jsonforces deterministic JSON output- Errors are returned with explicit non-zero exit codes
Repository includes a single Codex skill definition:
SKILL/inspector-avalonia-cli/SKILL.md
Install it locally:
mkdir -p ~/.codex/skills/inspector-avalonia-cli
cp SKILL/inspector-avalonia-cli/SKILL.md ~/.codex/skills/inspector-avalonia-cli/SKILL.mdsamples/Inspector.SampleApp is an Avalonia desktop app (dotnet Avalonia template) with inspector host wiring via InspectorHostRuntime and DelegateInspectorRequestHandler.
Run it with:
dotnet run --project samples/Inspector.SampleAppThen connect from CLI in host mode:
inspector connect --mode host --address local://inspector --jsonThis repository includes a functioning foundation (contracts, transport model, host runtime, adapter services, CLI, tests, sample app), including process-mode connection via --pid/--name and session-aware CLI workflows.