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.json

The 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:

v0.12.7 additions — dashboard UI coverage Phase 1:

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-04

Mandatory 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: --topology implies --tv5. Passing --topology automatically activates the TV-5 3D topology REST + WebSocket endpoints without needing a separate --tv5 flag.

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-only

Additional 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 8080

Additional 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:

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.