Terminal UI and CLI for NetBox — fast search, IPAM lookups, and device context.
Ask the questions you actually ask at the terminal — what is this IP, where is this device, what owns this prefix? — from the shell, a k9s-style TUI, or an MCP server for AI agents.
Status: pre-1.0, read-only. Safe, diff-confirmed PATCH writes come later
(ROADMAP.md).
First run? Just launch the TUI — with no config it opens a first-run wizard that captures a profile (url + token), test-connects, and drops you into the app:
nbox # first run: guided onboarding, then the TUIPrefer the shell? Configure a profile by hand:
nbox profile add work https://netbox.example.com --token-env NETBOX_TOKEN
nbox profile use work
export NETBOX_TOKEN=... # or store the token: nbox config token set
# Look things up from the shell
nbox search edge01
nbox device edge01
nbox ip 10.44.208.55
nbox prefix 10.44.208.0/24See Installation below for setup instructions.
- Fast shell lookups —
device,ip,prefix,vlan,site,rack,circuit,provider,aggregate,asn,ip-range,tenant,contact,vm,cluster,vrf,route-target, andinterface, each as a one-liner. - Normalized search — one
searchquery runs in parallel across devices, sites, racks, IPs, prefixes, VLANs, circuits, providers, aggregates, ASNs, IP ranges, tenants, contacts, VMs, clusters, VRFs, and route targets, returning ranked, deduped hits. Scope it with--site/--region/--site-group/--location(one at a time, exact scope), or narrow by--status/--tenant/--role/--tag/--vrf. - IPAM-aware — IP → most-specific parent prefix → VLAN → scope resolution, prefix utilization and children, a navigable prefix tree, and
next-ip/next-prefixfor free addresses and blocks (computed locally withipnet). - A k9s-style TUI — a three-pane home (navigation rail → results → live preview), an overview dashboard, a hierarchical prefix tree, cross-object navigation between related objects, fuzzy filters, recents, and an in-app profile + settings editor. Twelve themes;
NO_COLORhonored. - Agent-ready —
nbox serveis a read-only MCP server: the same lookups exposed as nine tools (plus every object as annbox://{kind}/{ref}resource), returning the exact JSON view models the CLI does, so AI agents (Claude Code, Claude Desktop, …) query NetBox safely. Stdio for a local subprocess, or a loopback HTTP transport with OIDC resource-server auth for a network-reachable, read-only deployment. See docs/MCP.md. - Scriptable —
-o plain|json|csv,--fields,--raw, versioned--envelope, and stable exit codes; stdout stays clean for piping, logs go to stderr. See docs/SCRIPTING.md. - Fast on repeat — a small in-memory read cache (per profile, ~30s) keeps TUI back-navigation and chatty agents from re-hitting NetBox; the detail footer shows "cached Ns ago" and
nbox_cache_clearbusts it. - Multi-instance — profiles for several NetBox instances (switch live in the TUI), journals folded into detail lookups, open-in-browser and copy, and tag listing.
See docs/FEATURES.md for the full command reference, docs/COMPARISON.md for how nbox compares to the NetBox web UI and raw API calls, and docs/ARCHITECTURE.md for the internals.
nbox doesn't replace NetBox — it's a fast read path into it. When to reach for which:
| Task | nbox | NetBox web UI | curl / pynetbox |
|---|---|---|---|
| "What is this IP?" (address → prefix → VLAN → scope) | one command / one keystroke | several clicks across pages | several requests + manual joins |
| Search across object types at once | one ranked, deduped query | per-type search pages | one request per endpoint |
| Use it over SSH on a jump host | yes — one static binary, no runtime | no (needs a browser) | only if Python/curl are present |
| Machine output (JSON/CSV, stable exit codes) | built in | no | you build it |
| Feed an AI agent | built in (nbox serve, MCP) |
no | you build it |
| Reserve / allocate / edit (writes) | not yet — read-only | yes | yes |
Full matrix and a "when to use each" guide: docs/COMPARISON.md.
nbox ip 10.44.208.55Resolves the address, its most-specific parent prefix (VRF-scoped), the prefix's
VLAN, and its scope (site, location, region, …). Add --vrf <name> when the same
address exists in several VRFs.
nbox device edge01Device plus its interfaces, IP addresses, cables, VLANs, and services in one
lookup. In the TUI, the device screen splits these onto i/p/c/v/s tabs.
nbox next-ip 10.44.208.0/24 --count 4 # next available addresses
nbox next-prefix 10.0.0.0/8 --length 26 # first free /26Read-only — nothing is reserved. Both take --vrf to scope the prefix.
nbox device edge01 --json | jq '.primary_ip4.address'
nbox search edge01 -o csv --cols name,site,status > devices.csv
nbox prefix 10.44.208.0/24 --json --envelope --raw # versioned, single-lineclaude mcp add nbox -e NBOX_TOKEN=nbt_xxx.yyy -- nbox servenbox serve is a read-only MCP server; an MCP host launches it as a subprocess
and gets the same JSON view models the CLI returns. See docs/MCP.md.
Requires Rust 1.88+:
# Install Rust (if not already installed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env
# Install nbox
cargo install nboxbrew install lance0/tap/nboxMulti-arch image (amd64/arm64):
docker run --rm ghcr.io/lance0/nbox:latest --helpMount a config or pass -e NBOX_TOKEN=... plus a profile (or --config) to run
real lookups against your NetBox.
Download from GitHub Releases:
| Platform | Target |
|---|---|
| Linux x86_64 | nbox-x86_64-unknown-linux-musl.tar.gz |
| Linux ARM64 | nbox-aarch64-unknown-linux-musl.tar.gz |
| macOS Apple Silicon | nbox-aarch64-apple-darwin.tar.gz |
| macOS Intel | nbox-x86_64-apple-darwin.tar.gz |
| Windows x86_64 | nbox-x86_64-pc-windows-msvc.zip |
# Download, verify, and install (Linux x86_64 example)
curl -LO https://github.com/lance0/nbox/releases/latest/download/nbox-x86_64-unknown-linux-musl.tar.gz
curl -LO https://github.com/lance0/nbox/releases/latest/download/SHA256SUMS
sha256sum -c SHA256SUMS --ignore-missing # macOS: shasum -a 256 -c
tar xzf nbox-*.tar.gz && sudo mv nbox /usr/local/bin/Note: Piping a script from the internet to sh is convenient but bypasses your chance to read it first. Use one of the methods above, or review the script before running. It downloads the latest release binary for your OS/arch and falls back to
cargo installif there's no asset for your platform.
curl -fsSL https://raw.githubusercontent.com/lance0/nbox/master/scripts/install.sh | shgit clone https://github.com/lance0/nbox
cd nbox && cargo install --path .cargo install nbox builds the canonical single binary — clipboard, the MCP
server (stdio + HTTP transport), OS-keyring token storage, and update checks are
all on by default. There are no feature-variant builds to choose between.
| Feature | Default | Description |
|---|---|---|
clipboard |
Yes | Copy values with y in the TUI (via arboard) |
http |
Yes | nbox serve --http loopback MCP transport (+ OIDC) |
keyring |
Yes | OS-keyring token storage (nbox config token) |
updates |
Yes | GitHub update notifications |
keyring-secret-service |
No | Linux D-Bus (Secret Service) keyring backend — for desktop packagers |
# Lean stdio-only build (drops all of the above):
cargo install nbox --no-default-features# Bash
nbox completions bash > ~/.local/share/bash-completion/completions/nbox
# Zsh (add ~/.zfunc to fpath in .zshrc first)
nbox completions zsh > ~/.zfunc/_nbox
# Fish
nbox completions fish > ~/.config/fish/completions/nbox.fish
# PowerShell (add to $PROFILE)
nbox completions powershell >> $PROFILE
# Elvish
nbox completions elvish > ~/.elvish/lib/nbox.elvMan pages are available too. nbox man > nbox.1 writes the top-level page; pass
a directory — nbox man man/ — to write the full set instead (nbox.1 plus one
nbox-<subcommand>.1 per subcommand, so man nbox-device works once installed).
nbox # launch the TUI
nbox status # connection + backend capabilities + NetBox/Django/Python versions
nbox search <query> [--limit N] [--status/--site/--region/--site-group/--location/--tenant/--role/--tag <v>] [--vrf <id|rd|name>] [--cols a,b,c] [--partial]
# one scope flag at a time, exact match; --vrf filters IP/prefix results.
# Full scope/filter semantics: docs/FEATURES.md
nbox device <name-or-id> [--journal] [--journal-limit N]
nbox ip <address> [--vrf <name>] [--journal] # --vrf disambiguates duplicates across VRFs
nbox prefix <cidr> [--vrf <name>] [--journal] # includes utilization + children when present
nbox next-ip <cidr> [--count N] [--vrf <name>] # next available address(es)
nbox next-prefix <cidr> [--length L] [--vrf <name>] # available free block(s)
nbox vlan <vid-or-name> [--site <s>] [--group <g>] [--journal]
nbox site <name-or-slug> [--journal]
nbox rack <name-or-id> [--journal]
nbox circuit <cid-or-id> [--journal]
nbox provider <slug-or-name-or-id>
nbox aggregate <cidr-or-id> [--journal]
nbox asn <number> [--journal]
nbox ip-range <start-or-id> [--journal]
nbox tenant <slug-or-name-or-id>
nbox contact <name-or-id>
nbox vm <name-or-id>
nbox cluster <name-or-id>
nbox interface <device> <interface>
nbox tags # list tags (slug, name, count)
nbox journal <kind> <ref> # recent journal entries for an object
# --journal folds recent entries into a detail lookup (cap 5)
# --journal-limit N overrides the cap (implies --journal)
nbox open <kind>/<ref> # device, ip, prefix, vlan, site, rack, circuit, provider,
# aggregate, asn, ip-range, tenant, contact, vm, cluster, vrf, route-target,
# and interface/<device>/<name> (the name may contain slashes,
# e.g. xe-0/0/1)
nbox raw GET <api-path> # raw read-only API request (escape hatch)
nbox serve [--http <addr>] # read-only MCP server for AI agents (stdio, or loopback/OIDC HTTP)
nbox config <init|path|show|token> # token: keyring set/clear/status (never echoed)
nbox profile <add|use|list|show>
nbox completions <bash|zsh|fish|powershell|elvish>
nbox man [DIR] # man pages: `nbox man > nbox.1` (top-level),
# or `nbox man man/` for the full per-subcommand setThese apply to every command:
| Flag | Effect |
|---|---|
-o, --output <fmt> |
plain (default), json, or csv (tabular/list results only) |
--json |
Shortcut for -o json |
--fields a,b,c |
JSON: keep only these top-level fields |
--raw |
JSON: compact (single line) instead of pretty |
--envelope |
JSON: wrap as { schema_version, data } |
-p, --profile <name> |
Use a specific profile for this invocation |
--config <path> |
Use an alternate config file |
--log-level <spec> |
tracing filter (info, debug, nbox=debug, …) |
--log-file <path> |
Write logs to this file (and stderr); stdout stays clean |
--no-tui |
Refuse to launch the interactive TUI (a bare nbox or nbox tui exits 2 instead) |
-o csv is for tabular/list results (e.g. search); a single object is rejected
(use --json or plain). Custom fields appear as cf.<name> rows in plain output
and a custom_fields object in JSON.
Logs go to stderr by default (so stdout stays clean for piping and --json).
Point --log-file <path> (or log_file in config) at a file to also capture
them there. The level resolves --log-level → config log_level → NBOX_LOG →
RUST_LOG → warn. nbox never writes logs to stdout.
Exit codes are stable: 0 success, 1 generic error, 2 usage error, 3
auth/permission (401/403), 4 not found, 5 ambiguous reference. See
AGENTS.md for the full machine-readable surface.
| Key | Action |
|---|---|
/ |
search |
: |
command palette |
f / F |
filter results / clear filters |
Tab / Shift+Tab |
switch pane focus (or cycle detail tabs) |
j / k |
move selection / scroll detail (on the nav rail, live-browse the kind) |
g / G |
top / bottom |
PgUp / PgDn |
page up / down |
Enter |
open selected object |
o |
open in browser |
y |
copy current item label |
R |
related objects (jump between connected objects) |
D |
overview dashboard |
T |
prefix tree (Space / ← / → collapse/expand) |
t |
cycle theme |
r |
refresh |
P / Ctrl+P |
switch profile (cycle forward / backward) |
S |
open the Config modal (profiles + settings) |
b / Esc |
back / clear search |
i p c v s |
device tabs (interfaces / IPs / cables / VLANs / services) |
e |
rack elevation |
u |
dismiss update notice |
? / F1 |
help |
q / Ctrl+c |
quit |
The command palette (:) accepts device/ip/prefix/vlan/site/vrf <ref>,
find <q> (or bare text), filter <key>=<value>, open, copy, theme <name>,
profile <name>, config, and refresh. The home screen lists recently opened objects (deduped,
most-recent-first) when there are no search results — press Enter to reopen one.
Set [ui].refresh_secs to auto-refresh the current search on an interval (off by
default).
P / Ctrl+P (or profile <name> in the palette) switches between the profiles
in your config without restarting: it rebuilds the client for that instance and
re-probes /api/status/, so the header flips to the new profile and its NetBox
version. With a single profile the hotkey is a no-op. The cycle is session-only —
it does not rewrite active_profile in your config (use nbox profile use <name>
for that).
S (or config in the palette) opens the Config modal to manage profiles
in-app: list them (active marked), and add / edit / select / delete without
hand-editing config.toml. The add/edit form covers name, url, token_env,
auth_scheme, and verify_tls, plus an optional masked token field. When a
keyring is available, a typed token is stored there (never in config.toml);
otherwise nbox saves the profile metadata and tells you to use token_env or
NBOX_TOKEN. Ctrl+T test-connects before you commit; Enter saves, Ctrl+G
saves and switches to it. Unlike the quick P cycle, selecting or adding-and-using
a profile here persists active_profile to your config. Deleting the active
or last profile is blocked.
Tab switches the Config modal to its Settings section, a two-pane editor —
categories on the left, the selected category's fields on the right:
- Appearance —
theme(cycle with←/→/Space, applied live). - Behavior —
refresh_secs(auto-refresh interval; empty/0= off) andopen_browser_command(a custom browser-open command; empty = OS default). - Logging —
log_level(a tracing filter likenbox=debug) andlog_file(a path); both persist and apply on the next launch.
↑/↓ pick a category, → enters its fields (↑/↓ move between them, Esc
steps back), and Enter or Ctrl+S saves every changed field back to
config.toml (format-preserving — comments and unrelated keys are kept), re-arms
the auto-refresh without a restart, and applies the new browser command to the next
open. Settings live in ~/.config/nbox/, so they survive upgrades.
[ui].open_browser_command, when set, is what nbox open and the TUI o action
run to open a URL (the URL is appended as a literal final argument, never
shell-interpolated); leave it empty to use the OS default opener.
Twelve built-in themes. Set with [ui].theme in the config or press t to cycle:
default, kawaii, cyber, dracula, monochrome, matrix, nord,
gruvbox, catppuccin, tokyo_night, solarized, light.
light is the only light-background theme. NO_COLOR is honored — when set, the
TUI renders without color and marks the selection with a > cursor.
First-time setup needs no hand-edited TOML: launch nbox with no config and the
TUI runs a first-run wizard that captures a profile (url, token or token_env,
auth_scheme, verify_tls), test-connects, writes it, and continues into the
app. The same wizard appears when a config exists but has no resolvable active
profile. You can still configure by hand — the file lives at:
| OS | Path |
|---|---|
| Linux / macOS | ~/.config/nbox/config.toml |
| Windows | %APPDATA%\nbox\config.toml |
config_version = 1
active_profile = "work"
[ui]
theme = "default"
confirm_writes = true
# refresh_secs = 30 # TUI auto-refresh interval in seconds (omit/0 = off)
# open_browser_command = "" # custom browser-open command (empty = OS default)
# Local read cache (optional; on by default). A short in-memory de-dupe window so
# repeated reads (TUI back-nav, a chatty agent) don't re-hit NetBox. Never serves
# stale data across a write you made; cleared on profile switch.
[cache]
enabled = true # master switch
ttl_secs = 30 # reuse window in seconds (clamped to 5–300)
[profiles.work]
url = "https://netbox.example.com"
token_env = "NETBOX_TOKEN"
auth_scheme = "auto" # auto | bearer | token
verify_tls = true
timeout_secs = 15
page_size = 100
exclude_config_context = true
# Per-surface backend (optional; omit for all-REST). REST is canonical; GraphQL
# is an opt-in accelerator for the VRF and route-target views. Search is always REST.
[profiles.work.api]
vrf = "graphql" # rest | graphql
route_target = "graphql" # rest | graphqlTokens are never written to config. nbox resolves them in order: the profile's
token_env variable (if set & present), then NBOX_TOKEN, then the OS keyring
entry for the profile (nbox config token set — input hidden, never echoed). Env
always overrides the keyring. nbox config token status shows the active source
(never the token). See docs/CONFIG.md for the full reference.
nbox serve runs a read-only MCP server, stdio by default. An MCP host (Claude
Desktop, Claude Code, …) launches nbox serve as a subprocess and speaks JSON-RPC
over stdin/stdout; it reuses the same query + view layer as the CLI, so the tools
return the same JSON view models. The NetBox URL and token come from the active
profile / env, and it takes the same -p/--config flags. JSON-RPC goes to
stdout; all logging stays on stderr.
The tools are all annotated read-only:
| Tool | What |
|---|---|
nbox_status |
Connection + backend capabilities + NetBox/Django/Python versions. |
nbox_search |
Search devices/sites/racks/IPs/prefixes/VLANs/circuits/providers/aggregates/ASNs/IP-ranges/tenants/contacts/VMs/clusters/VRFs/route-targets; query (required), limit, status, site, region, site_group, location, tenant, role, tag, vrf (id|rd|name; filters IP/prefix results only). |
nbox_get |
Fetch one object by kind (device, ip, prefix, vlan, site, rack, circuit, aggregate, asn, ip_range, tenant, contact, provider, vm, cluster, vrf, route_target) + ref; vrf/site/group disambiguate. |
nbox_get_interface |
One interface on a device, with its cable-path trace. |
nbox_next_ip |
Next available address(es) in a prefix (nothing is reserved). |
nbox_next_prefix |
Available free child prefix(es) of a given length, or all free blocks. |
nbox_journal |
Recent journal entries for an object. |
nbox_list_tags |
List tags (name, slug, color, usage count). |
nbox_cache_clear |
Drop nbox's local read cache so the next lookups fetch fresh (read-only w.r.t. NetBox). |
The same objects are also exposed as MCP resources via one template,
nbox://{kind}/{ref} (e.g. nbox://device/edge01), for hosts that browse or
attach resources instead of calling tools — reading one returns the same JSON
view nbox_get does.
Stdio is the default. For local clients that prefer HTTP framing, serve the same
tools at /mcp (Streamable HTTP) on a loopback address — the transport is in the
default build (behind the http cargo feature, on by default; --no-default-features
gives a lean stdio-only build). It binds loopback only, validates Origin/Host,
and takes an optional static bearer:
nbox serve --http 127.0.0.1:8080 [--http-token "$(openssl rand -hex 16)"]For a network-reachable, read-only deployment, run nbox as an OAuth 2.1 resource
server: it validates inbound IdP JWTs on /mcp and advertises Protected Resource
Metadata (RFC 9728). Provider-agnostic; configuring OIDC is what lifts the loopback
restriction (terminate TLS in front):
nbox serve --http 0.0.0.0:8080 \
--oidc-issuer https://idp.example.com --audience https://nbox.example.comThis is accountability, not per-user RBAC — the last hop to NetBox still uses the
single profile token, so scope that token read-only. An audit log
(nbox::audit) and an optional per-caller rate limit (--rate-limit) round it
out. Full setup, security model, and IdP notes: docs/MCP.md.
Per-user NetBox identity bridging (so NetBox sees the real caller), writes, and a raw escape-hatch tool come later.
- Requires NetBox 4.2+ (the polymorphic
scopemodel for prefixes/VLANs). nbox checks the instance version via/api/status/on connect. Full 4.2 / 4.3 / 4.5+ matrix: docs/COMPATIBILITY.md. - Targets the NetBox REST API (
/api/) as the canonical integration path. nbox status --jsonand MCPnbox_statusinclude a per-surfaceapiblock (configured vs effective backend) and a typedcapabilitiesobject with version compatibility, REST behavior, and per-surface GraphQL support.- Auto-detects v2 API tokens (NetBox 4.5+,
Authorization: Bearer nbt_…) and legacy v1 tokens (Authorization: Token …); force one withauth_scheme. - Optional, read-only GraphQL (
/graphql/) as a per-surface accelerator for the VRF and route-target views ([profiles.<name>.api]vrf/route_target = "graphql"). nbox probes the schema so NetBox 4.2, 4.3, and 4.5+ filter/pagination differences are handled without hard-coding a version, and falls back to REST (with the reason instatus) when a surface isn't supported. Search is always REST — NetBox's GraphQL API has no equivalent to REST's full-textq, so GraphQL never backs the search surface. REST stays canonical and powers search, identity resolution, detail lookups, raw, journals, and available-IP/prefix operations.
| Symptom | Fix |
|---|---|
no config at … — run nbox config init |
First run: just launch nbox for the guided wizard, or nbox profile add …. |
error: authentication failed (exit 3) |
The token is missing/invalid. Check nbox config token status for the resolved source; export NBOX_TOKEN or point token_env at a set variable. |
403 / permission denied (exit 3) |
The token is valid but lacks object permissions, or your NetBox needs LOGIN_REQUIRED-aware tokens. Use a token with read access. |
| TLS / certificate error | For a lab with a self-signed cert, set verify_tls = false on that profile (never in production). |
operation timed out on one search endpoint |
Transient; nbox already disables stale keep-alive reuse. Retry, or raise timeout_secs. |
ambiguous (exit 5) |
The reference matched several objects — disambiguate (--vrf for an IP/prefix, --site/--group for a VLAN). |
keyring not available (Linux) |
The default static binary has no D-Bus backend. Use token_env/NBOX_TOKEN, or install a build with keyring-secret-service. |
| NetBox version error | nbox requires NetBox 4.2+. Check nbox status. |
Full list with copy-paste fixes: docs/TROUBLESHOOTING.md.
- Features — full command reference
- Configuration — config, profiles, token resolution, cache
- Compatibility — NetBox 4.2 / 4.3 / 4.5+ matrix and how nbox adapts
- Comparison — nbox vs the NetBox web UI / raw API, and when to use each
- Scripting & automation — JSON/CSV/envelope schemas, exit codes, jq recipes, CI
- MCP server — agent setup, tools, HTTP/OIDC
- Architecture — internal design and module structure
- Agents — machine-readable surface, output formats, exit codes
- Troubleshooting — symptoms and fixes
- Known Issues — current limitations
- Changelog — release history
- Roadmap — planned features
- Contributing — development setup and guidelines
- Security — vulnerability reporting and security posture
Licensed under either of MIT or Apache-2.0 at your option.
