A NetBox CLI built for humans at a terminal and agents in an automation loop.
NetBox already has a broad REST API. nbx exists to make that API easier to use safely from a shell, a script, or an AI agent without writing one-off curl commands for every workflow.
- Single static binary, no Python or runtime to install on the target machine.
- Typed commands generated from NetBox's OpenAPI schema, so common resources get discoverable flags and enum validation.
- Name and slug resolution for common foreign keys, so humans can pass
--site dc1instead of looking up numeric IDs first. - Versioned JSON output envelope (
nbxVersion,schemaVersion) so automation can depend on output shape. - Meaningful exit codes (0/1/2/3/4) for branching without parsing stderr.
- Agent-readable
SKILL.mdfiles describing each command's purpose, parameters, output, and errors.
Target NetBox release: v4.6.0.
Prebuilt binaries for Linux (x86_64, aarch64), macOS (Intel, Apple Silicon), and Windows (x86_64-msvc) are attached to each GitHub Release by .github/workflows/release.yml.
cargo install cargo-binstall # one-time bootstrap
cargo binstall nbxResolves the right prebuilt archive from the latest GitHub Release for your platform via [package.metadata.binstall] in Cargo.toml. No compilation. Sub-second install on a warm machine.
Grab the archive for your platform from the latest release, unpack it, and put nbx on your $PATH. Each release ships:
nbx-<version>-x86_64-unknown-linux-gnu.tar.gznbx-<version>-aarch64-unknown-linux-gnu.tar.gznbx-<version>-x86_64-apple-darwin.tar.gznbx-<version>-aarch64-apple-darwin.tar.gznbx-<version>-x86_64-pc-windows-msvc.zipSHA256SUMS— verify withshasum -a 256 -c SHA256SUMS
cargo install nbxCompiles the published source locally. Slower (minutes on a cold target dir) because typify-generated src/generated/types.rs is large and the dependency graph (reqwest, tokio, clap, …) gets built in release mode. Use this when no prebuilt suits your platform or you specifically want a from-source build.
cargo build --release
./target/release/nbx --help# One-shot auth, JSON output, suitable for scripts and agents.
NETBOX_URL=https://netbox.example NETBOX_TOKEN=... \
nbx dcim devices list --output json
# Persistent config for interactive terminal use.
nbx config init --url https://netbox.example --token <token>
nbx dcim devices list
# Fetch one resource by ID or default lookup value.
nbx devices get srv-db-07 --output json
# Create with typed flags and schema-derived enum validation.
nbx ipam vlans create --vid 100 --name mgmt --status active --output jsonResolution precedence (highest first):
--url/--tokenflagsNETBOX_URL/NETBOX_TOKENenv vars- Active context in
~/.config/nbx/config.toml - Top-level
url/tokenkeys in the same config file (single-context legacy form)
NetBox v4.5 v2 tokens of the form nbt_<key>.<token> are sent as Bearer. Legacy v1 tokens use NetBox's Token scheme. The config file is written with mode 0600; nbx warns when it reads a config with broader permissions.
For multiple NetBox instances (prod, staging, lab):
nbx config init --context prod --url https://netbox.corp.example --token ...
nbx config init --context staging --url https://netbox-staging.corp.example --token ...
nbx config use-context staging
nbx config current-context
nbx config get-contextsSelection precedence: --context <name> > NBX_CONTEXT env var > default_context in the config file.
Canonical form is nbx <app> <resource> <action>. Resource-level aliases (nbx devices list, nbx prefixes get …) are also accepted.
Preflight commands:
| Command | Purpose |
|---|---|
status |
Fetch /api/status/ through the same output envelope; only a URL is required. |
authentication-check |
Verify the configured token against /api/authentication-check/. |
Devices, interfaces, and prefixes have hand-written extensions on top of the generated typed flags — composite addressing, name-resolved foreign keys, allocation helpers, and trace commands:
| Resource | Actions |
|---|---|
dcim devices |
list, get, create, update, delete, bulk-update, bulk-delete |
dcim interfaces |
list, get, create, update, delete, trace, bulk-update, bulk-delete |
ipam prefixes |
list, get, create, update, delete, available-ips, available-prefixes, bulk-update, bulk-delete |
dcim devices list accepts --role repeatedly to OR multiple device-role slugs in one query (e.g. --role database-server --role application-server).
dcim inventory-items list has typed --device (slug, name, or numeric ID; non-numeric values are resolved to a device_id via /api/dcim/devices/), --role (repeatable, OR), --manufacturer, and --serial filters in addition to the generated --name / --tag.
The other resources are fully generated from the schema. They take typed flags for scalar fields and supported foreign keys in their Writable<X>Request schema:
| Resource | Default lookup |
|---|---|
dcim cables |
label |
dcim device-roles |
slug |
dcim device-types |
slug |
dcim locations |
slug |
dcim manufacturers |
slug |
dcim platforms |
slug |
dcim regions |
slug |
dcim site-groups |
slug |
dcim sites |
slug |
dcim racks |
name |
dcim inventory-items |
name |
extras tags |
slug |
ipam aggregates |
prefix |
ipam ip-addresses |
address |
ipam rirs |
slug |
ipam roles |
slug |
ipam vlan-groups |
slug |
ipam vlans |
name |
ipam vrfs |
name |
tenancy tenant-groups |
slug |
tenancy tenants |
slug |
get, update, and delete accept either a numeric ID or the default lookup value (override with --lookup-field). Interfaces additionally accept the gNMI-style composite address device:interface, e.g. srv01:Ethernet1.
--output json|table|ndjson—tableon a TTY,jsonwhen piped, unless overridden.--field a,b,c— comma-separated projection with dot notation for nested fields.-o name— shorthand for projecting justname.--query 'key=value&...'— passthrough to NetBox filter parameters.--limit <n>/--offset <n>— pagination overrides for a single page.--page-all— stream every page as NDJSON (overrides--output).--context <name>,--timeout <seconds>,--verbose,--dry-run.
Every JSON or NDJSON record carries the envelope documented in SCHEMA.md:
{
"nbxVersion": "4.6.0",
"schemaVersion": 1,
"data": { "id": 42, "name": "srv-db-07" }
}List responses include the NetBox pagination envelope alongside nbxVersion / schemaVersion:
{
"nbxVersion": "4.6.0",
"schemaVersion": 1,
"count": 137,
"next": "https://netbox.example/api/dcim/devices/?limit=50&offset=50",
"previous": null,
"results": [ { "id": 1, "name": "..." } ]
}schemaVersion is the agent contract version and is independent of the nbx crate version. It bumps only on a breaking output-contract change; additive changes (new fields, new error codes) do not. The contract is enforced by snapshot tests in src/output_snapshots.rs whose names embed the current schemaVersion — any breaking shape change forces a same-PR bump.
Errors are JSON objects with code, message, and detail:
{
"nbxVersion": "4.6.0",
"schemaVersion": 1,
"error": {
"code": "not_found",
"message": "NetBox resource not found",
"detail": { "status": 404, "response": { "detail": "Not found." } }
}
}| Exit | Code | HTTP triggers |
|---|---|---|
| 0 | success | 2xx |
| 1 | general / stream_error |
5xx, network, timeout, mid-stream NDJSON failure |
| 2 | not_found |
404 |
| 3 | auth_failed |
401, 403 |
| 4 | validation_error |
400, 422 |
429 responses are retried up to three times, honoring Retry-After (or 1s/2s/4s backoff if absent).
--page-all streams one NDJSON record per result. If a request fails mid-stream, nbx emits a final record with error.code: "stream_error" and exits non-zero — the stream is never silently truncated.
nbx is intentionally opinionated around the highest-value operational workflows first: DCIM devices/interfaces/cables/sites/racks/reference objects, IPAM prefixes/IP addresses/VLANs/VRFs/reference objects, Extras tags, and Tenancy tenants/groups. The schema-generated resource modules make this surface broad enough for day-to-day work while keeping the CLI predictable.
nbx is built against the OpenAPI schema from a single NetBox release (currently v4.6.0; see schema/README.md). On the first request of each session it probes /api/status/. If the running NetBox's major.minor doesn't match the pinned target, nbx prints a one-line warning to stderr and continues; behavior outside the pinned major.minor is best-effort.
Set NBX_SKIP_VERSION_CHECK=1 to suppress the probe (useful in CI against many NetBox versions, or when calling /api/status/ is restricted).
A weekly Schema drift GitHub Actions job (.github/workflows/schema-drift.yml) compares the pinned schema against the latest NetBox 4.6.x release and opens a tracking issue on diff. Bumping the pin is a deliberate PR documented in schema/README.md.
Use these escape hatches when the typed surface does not cover the exact request you need:
--query 'key=value&...'passes NetBox filter parameters through unchanged.--data <json>/--data-file <path>supplies complex mutation fields that do not fit the initial typed-flag model, such as cable terminations, custom fields, and tagobject_types. Typed flags take precedence when both set the same field.rawcalls any NetBox API path under/api/withGET,POST,PATCH, orDELETE. It uses the same authentication, retry, version-probe, envelope, projection, pagination, and dry-run behavior as typed commands.
nbx raw GET /api/plugins/example/widgets/ --query 'name=leaf-1' --output json
nbx raw POST /api/plugins/example/widgets/ --data '{"name":"leaf-1"}' --output jsonPrefer a typed command when one exists; use raw for plugin endpoints or NetBox endpoints that do not have a typed nbx command yet.
Skill files live under skills/<name>/SKILL.md, the layout the Vercel skills CLI expects. Each is a Claude-format SKILL.md with frontmatter (name, description) and ## Purpose / ## Parameters / ## Example / ## Errors sections — readable by any agent that can parse Markdown.
skills/
├── README.md
├── config/SKILL.md
├── generic-resource-actions/SKILL.md
├── dcim-devices-list/SKILL.md
├── dcim-devices-get/SKILL.md
├── dcim-devices-create/SKILL.md
├── dcim-interfaces-list/SKILL.md
├── dcim-interfaces-get/SKILL.md
├── dcim-interfaces-create/SKILL.md
├── dcim-interfaces-update/SKILL.md
├── dcim-interfaces-trace/SKILL.md
├── ipam-prefix-availability/SKILL.md
├── raw/SKILL.md
└── preflight/SKILL.md
# discover what's available
npx skills add Hebbian-Robotics/nbx --list
# install all nbx skills into Claude Code globally
npx skills add Hebbian-Robotics/nbx --all -g -a claude-code -y
# install specific skills
npx skills add Hebbian-Robotics/nbx \
--skill dcim-interfaces-list \
--skill dcim-interfaces-update \
-a claude-codeOther supported agents (-a <name>): amp, codex, cursor, gemini-cli, goose, opencode, windsurf, and more — see the skills CLI docs.
- Read the relevant
SKILL.mdfor command name, parameters, and expected output shape. - Run the command with
--output json(or--page-allfor NDJSON), passingNETBOX_URL/NETBOX_TOKENvia env. - Parse the response. Branch on the exit code; for non-zero, parse
error.codefor typed handling.
NETBOX_URL=https://netbox.example NETBOX_TOKEN=$TOKEN \
nbx dcim devices get srv-db-07 --output json
# exit 0 + envelope on success
# exit 2 + { "error": { "code": "not_found", ... } } if missingnbx completions zsh > ~/.zfunc/_nbx
nbx completions bash > /etc/bash_completion.d/nbx
nbx completions fish > ~/.config/fish/completions/nbx.fishcargo fmt
cargo clippy --all-targets --all-features -- -D warnings
cargo test --workspace --all-featuresThree artifacts are generated from schema/netbox-4.6.0.json:
src/generated/types.rs— every NetBox component schema, viatypify. Compile-checked.src/generated/endpoints.rs— endpoint metadata (path, method, parameters, request/response refs) for the initial target paths.src/generated/resources/<resource>.rs— per-resource typed CLI modules:<Resource>{Create,Update}Argsclap structs,ValueEnumtypes for status/role enums,<Resource>Actionsubcommand enum,run_<resource>_actiondispatcher, and create/update body builders. Generated for the initial agent-focused surface: DCIM sites/site-groups/regions/locations/manufacturers/device-types/device-roles/platforms/racks/inventory-items/cables, Extras tags, IPAM IP addresses/prefixes/VRFs/roles/VLAN groups/RIRs/aggregates/VLANs, and Tenancy tenant groups/tenants.
Devices, interfaces, and prefixes use the same generated typed flags (as <Resource>{Create,Update}Fields) but add hand-written extensions in src/commands/mod.rs: composite device:interface addressing, VLAN/LAG name resolution, the interfaces trace endpoint, and prefix availability allocation — none of which reduce cleanly to schema-shaped CRUD. The codegen marks them with extended: true and skips emitting the dispatcher and --data flags so the hand-written wrapper supplies them.
Most of src/ is generated, so exposing a new NetBox endpoint is small:
- Add the endpoint path (e.g.
/api/dcim/new-things/) toV0_1_TARGET_ENDPOINT_PATHSinxtask/codegen/src/lib.rs. - If the new resource references foreign keys reachable by name/slug, add an entry to
FK_RESOLVERSin the same file. - Regenerate (
cargo run -p nbx-codegen -- ...per the commands above). - Wire the generated module into
src/commands/mod.rsso it's reachable from the CLI dispatcher. - (Optional) Add a
SKILL.mdunderskills/so agents discover the new command. cargo test --workspace— drift checks inxtask/codegenconfirm the generated files match the pinned schema.
For endpoints not yet exposed as typed commands, agents can already call them through nbx raw <method> <path>, which inherits the same auth, output envelope, retry, projection, and dry-run behavior.
The runtime (HTTP client, auth, retries, output envelope, error model, projection) is hand-written by design — that's where the agent-facing opinions live.
Regenerate:
cargo run -p nbx-codegen -- schema/netbox-4.6.0.json src/generated/endpoints.rs
cargo run -p nbx-codegen -- schema/netbox-4.6.0.json src/generated/types.rs
cargo run -p nbx-codegen -- schema/netbox-4.6.0.json src/generated/resources/cargo test --workspace fails if any committed file under src/generated/ drifts from what the codegen would produce against the pinned schema. The drift checks live in xtask/codegen so a published cargo install nbx doesn't pull in the codegen toolchain. A NetBox version bump is a deliberate PR: update schema/, regenerate, review the diff, run tests and integration.
A netbox-docker integration job lives under tests/integration/ and runs in CI.
Apache-2.0. See LICENSE.