Architecture¶
The repository is organized as three sibling Python packages sharing one runtime:
netbox_sdk— standalone API/SDK layer (no CLI or TUI dependencies)netbox_cli— Typer CLI layer (requires[cli]extra)netbox_tui— Textual TUI layer (requires[tui]extra)
Dependency Direction¶
flowchart LR
CLI["netbox_cli\nTyper CLI"]
TUI["netbox_tui\nTextual TUI"]
SDK["netbox_sdk\nCore SDK"]
CLI --> SDK
TUI --> SDK
CLI -. "lazy import\n(TUI launch commands only)" .-> TUI
netbox_sdk is the stable core. It must remain importable without Typer or Textual installed.
SDK Internal Components¶
flowchart TB
config["config.py\nConfig model, profile persistence\nenv vars, auth header assembly"]
cache["http_cache.py\nFilesystem JSON cache\nTTL · ETag · stale-if-error"]
client["client.py\nNetBoxApiClient\nasync aiohttp · auth · SSRF protection"]
schema["schema.py\nSchemaIndex\nOpenAPI parsing · resource resolution"]
services["services.py\nresolve_dynamic_request()\nrun_dynamic_command()"]
facade["facade.py\nApi → App → Endpoint\n→ Record / RecordSet"]
typed["typed_api.py\ntyped_api()\nVersion-specific typed clients"]
models["models/\nGenerated Pydantic models\nv4_3 · v4_4 · v4_5 · v4_6"]
config --> client
cache --> client
schema --> services
client --> services
client --> facade
schema --> facade
facade --> typed
models --> typed
| Module | Role |
|---|---|
config.py |
Pydantic Config model, multi-profile persistence, token sanitization, environment variable loading |
client.py |
NetBoxApiClient — async aiohttp HTTP client, auth injection, HTTP cache integration, SSRF protection |
http_cache.py |
HttpCacheStore — filesystem JSON cache with TTL, ETag/If-Modified-Since, stale-if-error |
schema.py |
SchemaIndex — parses bundled OpenAPI JSON into groups, resources, operations, and filter params |
services.py |
resolve_dynamic_request() / run_dynamic_command() — maps CLI actions to HTTP calls |
facade.py |
api() — PyNetBox-style async facade: Api → App → Endpoint → Record/RecordSet |
typed_api.py |
typed_api() — version-specific typed clients with Pydantic request/response models |
models/ |
Generated Pydantic models for NetBox 4.3, 4.4, 4.5, and 4.6 |
Package Layout¶
Full package tree
netbox_sdk/
__init__.py
client.py
config.py
http_cache.py
schema.py
services.py
plugin_discovery.py
formatting.py
logging_runtime.py
output_safety.py
trace_ascii.py
demo_auth.py
facade.py
typed_api.py
typed_runtime.py
versioning.py
exceptions.py
models/
v4_3.py · v4_4.py · v4_5.py · v4_6.py
typed_versions/
v4_3.py · v4_4.py · v4_5.py · v4_6.py
django_models/
reference/openapi/
netbox-openapi.json (default)
netbox-openapi-4.3.json
netbox-openapi-4.4.json
netbox-openapi-4.5.json
netbox-openapi-4.6.json
netbox_cli/
__init__.py
runtime.py
dynamic.py
support.py
demo.py
dev.py
django_model.py
markdown_output.py
docgen_capture.py
docgen_specs.py
docgen/
netbox_tui/
__init__.py
app.py
cli_tui.py
dev_app.py
logs_app.py
graphql_app.py
django_model_app.py
chrome.py
navigation.py
nav_blueprint.py
panels.py
widgets.py
state.py
dev_state.py
django_model_state.py
graphql_state.py
filter_overlay.py
theme_registry.py
*.tcss
themes/*.json
Data Flow¶
flowchart LR
CMD["nbx dcim devices list"]
INIT["netbox_cli.__init__\nroot Typer app"]
DYN["netbox_cli.dynamic\n_register_openapi_subcommands()"]
SVC["netbox_sdk.services\nresolve_dynamic_request()"]
CLIENT["netbox_sdk.client\nNetBoxApiClient.request()"]
OUT["netbox_cli.support\nmarkdown_output"]
CMD --> INIT --> DYN --> SVC --> CLIENT --> OUT
nbxdispatches to the root Typer app innetbox_cli/__init__.pynetbox_cli.dynamicregisters allnbx <group> <resource> <action>commands at startup from the OpenAPI schemanetbox_sdk.services.resolve_dynamic_request()maps the action to(method, path, query, payload)NetBoxApiClient.request()executes the HTTP call with auth, caching, and SSRF protectionsupport/markdown_outputrender the response as Rich tables or Markdown
flowchart LR
CMD2["nbx tui"]
LAZY["netbox_cli\nlazy-imports netbox_tui"]
APP["netbox_tui.app\nNetBoxTuiApp"]
SDK2["netbox_sdk\nclient · schema · formatting"]
TUI2["Textual\nwidgets · TCSS · theme registry"]
CMD2 --> LAZY --> APP --> SDK2 --> TUI2
nbx tuiinnetbox_cli/__init__.pylazy-importsnetbox_tui(soimport netbox_cliworks without Textual)NetBoxTuiApptakes the activeNetBoxApiClientandSchemaIndexfrom the CLI runtime- All data queries go through
netbox_sdk.clientandnetbox_sdk.schema - Formatting (badges, labels, colors) comes from
netbox_sdk.formatting - UI layout is pure Textual: TCSS stylesheets + theme registry
Responsibilities¶
netbox_sdk¶
Owns:
- API client behavior (HTTP, auth, caching, token refresh, file upload)
- Profile and config loading from disk and environment variables
- HTTP response caching (filesystem-backed, ETag/If-Modified-Since)
- OpenAPI schema indexing and resource resolution
- Dynamic request resolution from
(group, resource, action)tuples - Plugin discovery helpers
- Shared formatting and output safety utilities
- Demo auth helpers and Django model parsing/cache helpers
- All three public API layers:
NetBoxApiClient,api(),typed_api()
netbox_cli¶
Owns:
nbxentrypoint and root command registration- Runtime config/index/client factories (
netbox_cli/runtime.py) - Dynamic command wiring from OpenAPI schema (
netbox_cli/dynamic.py) - CLI output rendering (
support.py,markdown_output.py) - Demo/dev/docgen command trees
CLI commands that launch a TUI must lazy-import netbox_tui and surface an install hint for pip install 'netbox-sdk[tui]' when needed.
netbox_tui¶
Owns:
- All six Textual applications:
NetBoxTuiApp,NbxCliTuiApp,NetBoxDevTuiApp,NetBoxGraphqlTuiApp,NetBoxLogsTuiApp,DjangoModelTuiApp - Shared Textual widgets, chrome, panels, and state management
- TCSS stylesheets and theme registry
Shared data transformations (semantic_cell, humanize_value, row parsing) live in netbox_sdk.formatting, not in the TUI package.
Packaging¶
| Install command | What you get |
|---|---|
pip install netbox-sdk |
netbox_sdk only — SDK, no CLI or TUI |
pip install 'netbox-sdk[cli]' |
netbox_sdk + netbox_cli |
pip install 'netbox-sdk[tui]' |
netbox_sdk + netbox_tui |
pip install 'netbox-sdk[all]' |
Everything including demo tooling |
Verification¶
For architecture-affecting changes, run: