Dashboard commands
Part of the NovaFabric CLI reference. Both nova and novafabric run the same binary.
nova dashboard
Status: experimental (ADR-0235). Widgets and dashboards are portable, versioned JSON files
under $NOVAFABRIC_HOME/dashboards. Files are the storage, not an export format — there is no
database table of user dashboards, so deleting that directory removes them with nothing left to
migrate. They live outside any capsule directory: capsules are signed evidence and stay read-only.
nova dashboard list # what is on disk
nova dashboard validate ./untrusted.widget.json # check without installing
nova dashboard apply ./widgets/ # install a file or a directory (idempotent)
nova dashboard show run-throughput # print one as JSON
nova dashboard export run-throughput -o ./out.widget.jsonThe web dashboard's Dashboards view offers the same two steps for one document at a time
(experimental): Validate is a dry run through the same loaders, and Save stores exactly the
previewed bytes atomically, needs operate scope, and is audited. It refuses builtin
documents, symlinked targets and bodies over 256 KiB. Directory installs stay with apply.
A minimal widget:
{
"$novafabricWidget": true,
"version": 1,
"id": "run-throughput",
"title": "Runs per day",
"query": {"select": ["count()"], "group_by": ["status"], "since": "7d"},
"presentation": {"chart": "bar"}
}A dashboard references widgets by id and never inlines them, so one widget is reusable:
{
"$novafabricDashboard": true,
"version": 1,
"id": "ops",
"title": "Ops",
"widgets": [{"widget": "run-throughput", "position": {"x": 0, "y": 0, "w": 6, "h": 4}}]
}⚠ A widget is untrusted input. These files are designed to be shared, so treat one that
arrives from outside as you would any other foreign input. nova dashboard validate checks the
JSON Schema first and then hands the embedded query to the same validator nova query uses, so
a widget cannot express a query the CLI itself forbids. The id field is the only one that
reaches a path and is constrained by the schema; there is no user-supplied code, no raw SQL, and
no templating.
ⓘ Fields this build does not recognise are preserved on export, so a file authored by a newer NovaFabric round-trips without losing its settings. A newer format version is refused rather than parsed — a wrong chart is worse than no chart.
Local dashboard (experimental, v0.7)
nova serve --experimental
Start the experimental local dashboard. Read-only browsing of capsules, registry, and lineage; Layer-B compute-only mutations (register, eval, promote, forensic replay, redact, export evidence). Per ADR-0027.
v0.11 additions — the following dashboard capabilities are now available in nova serve:
| Endpoint | What it does |
|---|---|
POST /api/evidence/{bundle_id}/verify |
Full cryptographic verification: Ed25519 DSSE + RFC 3161 TSR + NovaSeal Merkle log inclusion. Returns {signature_ok, timestamp_ok, log_integrity_ok, seal_available, valid, errors[]}. |
POST /api/runs/{run_id}/validate |
Capsule schema + required-file check. Returns {valid, errors[], run_id}. |
GET /api/runs/{run_id}/redaction-proof |
Returns the full redaction-proof.json for a capsule (404 if not yet scanned). |
GET /api/assets/{name}/diff |
Field-by-field diff of two asset spec versions (?from_version=&to_version=). Returns {added, removed, changed, identical}. |
GET /api/holds |
List all active legal holds across all registries. Returns {total_active, registries[{name, holds[]}]}. |
POST /api/holds |
Place a new hold. Body: {registry, reason, duration_days?}. Path-traversal guard on registry name. |
POST /api/holds/{hold_id}/release |
Release a hold by ID. Returns {released, hold_id, registry}. 404 if unknown or already released. |
POST /api/runs/{run_id}/replay/semantic |
Semantic similarity analysis: computes pairwise difflib similarity across model call responses. Returns {similarity_score, matched_run_id, …}. Read-only. |
POST /api/runs/{run_id}/replay/exact |
Exact replay eligibility check: validates env.lock.lock_mode=deterministic and seed on all model calls. Returns {exact_eligible, exact_reasons[], exact_hash_count, …}. Read-only. |
POST /api/runs/{run_id}/verify |
Full NovaSeal check on a capsule: DSSE signature + RFC 3161 timestamp + Merkle log inclusion (mirrors nova verify). Returns {sealed, configured, signature_ok, timestamp_ok, log_integrity_ok, valid, errors[]}. Returns sealed=false if capsule was not sealed; configured=false if NovaSeal profile missing. |
GET /api/lineage/{run_id}/emit-openlineage |
Emit OpenLineage events for a capsule run to the configured transport (mirrors nova lineage emit-openlineage). Returns {ok, run_id, event_count, events[]}. |
POST /api/assets/register-from-yaml |
Register an asset directly from a YAML spec string (mirrors nova register). Body: {spec_yaml: "<yaml string>"}. Returns {ok, name?, error?}. |
GET /api/reports/run-history |
Run history report; query params: from, to (ISO dates), status (all|ok|error|failed), agent (name filter), format (json|csv). Returns {rows[], columns[], generated_at, report_type}. |
GET /api/reports/eval-regression |
Eval regression report; params: from, to, suite. |
GET /api/reports/capsule-compare |
Side-by-side capsule diff report; params: run_a, run_b. |
GET /api/reports/cost-burn |
Cost burn over time; params: from, to, model. |
GET /api/reports/throughput |
Agent throughput; params: from, to, resolution (1h|1d|1w). |
GET /api/reports/evidence-inventory |
Evidence bundle inventory; params: from, to. |
GET /api/reports/policy-audit |
Policy decision audit log; params: from, to, policy_id, result (pass|fail|warn). |
GET /api/reports/seal-verification |
NovaSeal verification status for all capsules; params: from, to. |
GET /api/reports/executive-summary |
Management summary across key metrics; params: from, to. |
GET /api/reports/release-comparison |
Side-by-side release diff; params: version_a, version_b. |
GET /api/kg/entity-queue |
List all pending ReviewItem records from the Tier-3 human review queue. Returns {ok, count, items[]}. |
GET /api/kg/entity-queue/stats |
Return pending/approved/rejected counts for the review queue. Returns {ok, pending, approved, rejected}. |
POST /api/kg/entity-queue/{item_id}/approve |
Approve a review item. Body: {canonical, resolved_by}. Returns {ok, item_id, canonical}. |
POST /api/kg/entity-queue/{item_id}/reject |
Reject a review item. Body: {resolved_by?}. Returns {ok, item_id, status}. |
GET /api/compliance/audit/map |
Return compliance coverage matrix for all audit profiles (nist-ai-rmf, eu-ai-act-high-risk, gdpr, soc2-type2, iso42001, scientific-reproducibility). Mirrors nova audit map --profile. |
GET /api/compliance/erasure/status |
List persisted GDPR erasure requests from $NOVAFABRIC_HOME/erasure.db (ADR-0210, experimental). Params: ?subject_id= (exact filter), ?limit=. Returns {cap003_enabled, requests[{request_id, subject_sha256, state, reason, requested_at, executed_at, capsule_ids[], receipt, receipt_sha256, error_class}]}, newest first. |
GET /api/runs/{run_id}/children |
Return parent capsule metadata and list of child capsule summaries for a distributed/parent-child run. Returns {ok, run_id, parent_status, child_count, children[{run_id, status, edge_type, exit_code}]}. |
v0.34.0 additions — regulatory compliance export endpoints:
| Endpoint | What it does |
|---|---|
GET /api/compliance/euaiact/status |
EU AI Act Art.12 configuration — high_risk, provider_mode, retention_months, deadline. Mirrors nova euaiact status. Dashboard: GovernanceTab → EU AI Act Art.12 Status. |
POST /api/compliance/euaiact/export |
Art.12 structured log export. Body: {from_date?, to_date?} (ISO 8601 UTC). Returns {ok, records[], count, retention_months, mode}. Mirrors nova euaiact export. Dashboard: GovernanceTab → EU AI Act Export. |
POST /api/compliance/export/rocrate |
RO-Crate v1.1 ZIP export for a run ID. Body: {run_id}. Returns {ok, filename, zip_base64, size_bytes, note}. Mirrors nova export-rocrate. Dashboard: ComplianceTab → RO-Crate Export (one-click browser download). |
POST /api/lineage/export-prov |
W3C PROV-JSON lineage document for a run ID. Body: {run_id}. Returns {ok, run_id, document, note}. Mirrors nova lineage export-prov. Dashboard: LineageTab → PROV-JSON Export. |
POST /api/compliance/export/c2pa |
C2PA v2.3 manifest for a run ID. Body: {run_id, include_training_mining?}. Returns {ok, run_id, manifest, note}. Mirrors nova export-c2pa. Dashboard: ComplianceTab → C2PA Export. |
POST /api/compliance/export/ropa |
GDPR Art.30 RoPA entry for a run ID. Body: {run_id, controller_name?, controller_contact?}. Returns {ok, run_id, document, completeness, missing_fields, note}. Mirrors nova export-ropa. Dashboard: ComplianceTab → GDPR Art.30 RoPA Export. |
POST /api/compliance/export/aibom |
CycloneDX 1.7 AI-SBOM for a run ID. Body: {run_id}. Returns {ok, run_id, bom_format, serial_number, component_count, components, generated_at, note}. Mirrors nova export-aibom. Dashboard: ComplianceTab → AI-SBOM Export. |
POST /api/compliance/export/nist-rmf |
NIST AI RMF 1.0 quantitative risk report for a run ID. Body: {run_id}. Returns {ok, run_id, overall_score, risk_level, metrics, missing_evidence, generated_at, note}. Mirrors nova export-nist-rmf. Dashboard: ComplianceTab → NIST AI RMF Report. |
GET /api/aibom/status |
CRA SBOM compliance coverage across all capsules. Returns {ok, regulation, cra_deadline, spec_version, capsule_directory, total_capsules, capsules_with_aibom, capsules_missing_aibom, coverage_status}. Mirrors nova aibom status. Dashboard: ComplianceTab → AI-SBOM Coverage Status. |
v0.12.8 fixes — eval results panel:
- Null score →
—— when an eval suite stores{"score": null}(binary pass/fail, no numeric score), the panel now shows a muted—instead of0.00. Prevents false-zero interpretation. - Empty suite name →
(unknown suite)— ifsuite_nameis blank in the database, the row label falls back to italic(unknown suite).
v0.12.7 additions — dashboard UI coverage Phase 1:
- Infra tab — 10 Phase 0–6 cluster-scale component status cards (NovaSeal, Collector, Object Store, Metadata DB, Lineage at Scale, Parent/Child, Server Mode, Eval Suites, Policy Gates, Run Capsule) with
shipped / partial / placeholder / plannedbadges. - Commands tab (35 builders) — expanded from 13 to 35 command builders across 4 journey tracks (Debug & Replay, Govern & Approve, Audit & Lineage, Infrastructure & Scaling). Live preview + copy for every builder.
- Lineage QueryPanel — interactive provenance / blast-radius / replay-chain query panel in the Lineage tab. Live CLI equivalent preview.
- Context-aware autocomplete — every database-reference input (Lineage ref, Diff run A/B, Holds registry, Policy resource ref) shows live-filtered suggestions from loaded data. Extended in v0.30.3 to full 100% coverage:
deploymentId/incidentId(localStorage MRU viauseLocalMru);subjectIdpanels;runIdin AssurancePanel and StorageOpsCard (live-fetched). Makefilebundletarget —make bundlerebuilds the web dashboard and rsyncs tosrc/novafabric/serve/static/.make serve-localrebuilds and starts the server.Makefileserve-topology-onlytarget —make serve-topology-onlystartsnova serve --experimental --topologywithout rebuilding the SPA; useful on remote servers without npm/Node installed. Usemake serve-topologyon dev machines that need to rebuild the SPA first.
pip install 'novafabric[serve]' # one-time, opt-in (FastAPI + uvicorn)
nova serve --experimental
nova serve --experimental --port 8080 --no-browser
nova serve --experimental --capsule-dir ~/runs/2026-04Mandatory flag: --experimental. Without it the command prints the gate banner and exits cleanly.
| Flag | Default | Purpose |
|---|---|---|
--experimental |
(required) | Acknowledges the experimental gate. |
--port |
4321 |
TCP port. |
--host |
127.0.0.1 |
Bind address. Refuses non-localhost without --insecure. |
--capsule-dir |
$NOVAFABRIC_HOME/capsules/ |
Where to look for capsules. |
--db-path |
~/.novafabric/registry.db |
Registry/lineage SQLite path. |
--no-browser |
off | Don't auto-open a browser tab. |
Authentication. The server binds 127.0.0.1, validates the Host header, and requires a
session token on every /api/* request (the probes GET /api/health, /livez, and
/readyz are open). The browser is launched with the token already in the URL; for scripts,
pass it either way — since v0.97.0 an Authorization: Bearer header is accepted everywhere
?token= is, and when the header carries a Bearer credential it is the authoritative one:
curl -H "Authorization: Bearer $(cat ~/.novafabric/.serve-token)" \
http://127.0.0.1:4321/api/stats # preferred — keeps the secret out of shell
# history, proxy logs, and Referer headers
curl "http://127.0.0.1:4321/api/stats?token=<token>" # still supported (SPA, printed links)Pin a stable token with NOVAFABRIC_SERVE_TOKEN for Docker/CI; otherwise it persists in
$NOVAFABRIC_HOME/.serve-token across restarts.
The CLI is the canonical interface. Every dashboard action surfaces the equivalent nova command and writes to ~/.novafabric/dashboard-audit.jsonl.
nova serve --topology
Start the experimental live topology dashboard alongside nova serve. Requires novafabric[serve]. Adds three topology endpoints to the running server and serves the packages/nova-dashboard/ SPA from /topology/.
Note:
--topologyimplies--tv5. Passing--topologyautomatically activates the TV-5 3D topology REST + WebSocket endpoints without needing a separate--tv5flag.
nova serve --experimental --topology
nova serve --experimental --topology --port 8080
# On a remote server where the SPA is already built (no npm/Node required):
make serve-topology-onlyAdditional flag:
| Flag | Default | Purpose |
|---|---|---|
--topology |
off | Enable topology endpoints + SPA. Automatically implies --tv5. Requires --experimental. |
--tls-cert PATH / --tls-key PATH |
off | Serve HTTPS natively (ADR-0241, experimental). Both required together; the key must be chmod 600 — unusable material refuses to start. Env: NOVA_TLS_CERT_PATH / NOVA_TLS_KEY_PATH. |
Topology endpoints added when --topology is set:
| Endpoint | Protocol | Description |
|---|---|---|
GET /topology/clusters |
HTTP + Apache Arrow IPC | Returns the full cluster layer (ads.v1.cluster_layer). Auth required. |
WS /topology/stream |
WebSocket — TDP v1 | Live graph delta stream. Requires Sec-WebSocket-Protocol: nova-tdp-v1 header; rejects with code 4400 otherwise. Supports subgraph_expand, subgraph_collapse, and resume_from client messages. |
GET /metrics/stream |
SSE | Real-time metric frames (ads.v1.metric_frame). Supports Last-Event-ID for reconnect gap recovery. |
Dependencies (added automatically via novafabric[serve] if --topology is used): duckdb, pyarrow, networkx, python-louvain.
nova serve --tv5
Enable the experimental TV-5 3D Topology View. Mounts /api/tv5/ REST + WebSocket endpoints and adds a 3D View (TV-5) tab in the nova-dashboard SPA.
nova serve --experimental --tv5
nova serve --experimental --topology --tv5
nova serve --experimental --tv5 --port 8080Additional flag:
| Flag | Default | Purpose |
|---|---|---|
--tv5 |
off | Enable TV-5 3D topology REST + WebSocket API. Requires --experimental. |
TV-5 endpoints added when --tv5 is set:
| Endpoint | Protocol | Description |
|---|---|---|
GET /api/tv5/live |
HTTP JSON | Current topology state: windowId, nodeCount, edgeCount, layoutAgeMs. |
GET /api/tv5/windows |
HTTP JSON | List available snapshot windows. Accepts from and to Unix timestamp query params. |
GET /api/tv5/snapshot/{windowId} |
HTTP JSON or msgpack | Return topology snapshot (positions, node types, edge count). Window IDs validated to ^[a-z0-9_-]+$; path traversal blocked. Returns msgpack if the optional msgpack package is installed, else JSON. |
WS /api/tv5/ws |
WebSocket | Pushes {type: "snapshot", windowId} on every new layout. Client sends {type: "subscribe", topologyId} to confirm. |
Environment variables:
| Variable | Default | Purpose |
|---|---|---|
TV5_SNAPSHOT_DIR |
.nova/tv5_snapshots |
Directory for fine and coarse snapshot tiers. |
TV5_MAX_FINE_SNAPSHOTS |
288 |
Maximum number of fine-tier snapshots to retain. |
TV5_MAX_COARSE_SNAPSHOTS |
168 |
Maximum number of coarse-tier snapshots to retain. |
Notes:
- TV-5 is experimental (ADR-0068). Server-side layout uses
networkx.spring_layoutas an FA2 approximation (OQ-030: Python fa2 is blocked at 100K nodes). msgpackis an optional runtime dependency; the server falls back to JSON automatically.- TV-5 does NOT require
--topology, but--topologyautomatically implies--tv5. Both flags may be passed together without conflict.
Environment variable: NOVA_DASHBOARD_DUCKDB_PATH (default ~/.novafabric/dashboard.duckdb) — path to the DuckDB database holding the cluster-layer topology.
The SPA at http://localhost:4321/topology/ auto-fetches the cluster layer on mount, opens the TDP WebSocket stream, and renders the agent graph using Sigma.js 3 + Graphology 0.26 with FA2 incremental layout in a Web Worker.
For the full capability matrix and limitations vs CLI, see dashboard.md.