Lineage and execution-graph commands
Part of the NovaFabric CLI reference. Both nova and novafabric run the same binary.
Lineage commands (v0.4)
nova lineage provenance
nova lineage provenance <ref> [--depth N] [--kind run|asset|artifact] [--edge-type TYPES] [--with-facets] [--output text|json]Show what the given node depends on (forward traversal).
Options:
--edge-type TYPES— comma-separated edge types to include. Valid values:contains,spawned,delegated_to,replayed_from. Omit for all edge types.--with-facets— print column-level lineage facets carried by traversed edges (experimental, ADR-0090): table, column names (never values), read/write access, extraction confidence. Also available onblast-radius.
nova lineage provenance my-agent --edge-type spawned,delegated_to
nova lineage provenance 01HX... --with-facetsnova lineage blast-radius
nova lineage blast-radius <ref> [--depth N] [--kind run|asset|artifact] [--edge-type TYPES] [--output text|json]Show what depends on the given node (backward traversal).
Options:
--edge-type TYPES— comma-separated edge types to include. Same valid values asprovenance. Invalid types exit 1.
nova lineage blast-radius my-model --edge-type contains,replayed_fromnova lineage replay-chain
nova lineage replay-chain <run-id> [--output text|json]Show the replay chain back to the original captured run.
nova lineage time-travel
nova lineage time-travel <ref> --asof <iso8601> [--kind run|asset|artifact] [--output text|json]Show the lineage state of a node as of a given timestamp.
nova lineage import
nova lineage import <path>(Re-)index lineage from a capsule directory or a parent runs/ directory.
nova lineage metrics
Experimental (ADR-0212).
nova lineage metrics [--top N] [--output text|json]Rank structurally critical nodes over the whole local lineage graph: degree, PageRank (bounded power iteration), betweenness (seeded sampling above 2 000 nodes — the output says when it sampled), and articulation points ("single points of failure"). Scores are descriptive rankings for attention, not calibrated importance. Oversize graphs fail loudly at the whole-graph read bound instead of silently truncating.
nova lineage root-cause
Experimental (ADR-0213).
nova lineage root-cause <run-id> [--depth N] [--capsule-dir DIR] [--output text|json]Walk the failed run's upstream provenance and rank suspect nodes with bounded additive
signals: error evidence (cues shared with ADR-0084), recency decay, an edge-confidence
multiplier, and failure correlation across sibling failed runs. With --capsule-dir,
the responsible run is additionally step-attributed via the nova diagnose engine. No
error signal upstream → responsible: null; the command never fabricates a culprit.
nova lineage export-graph
Experimental (ADR-0214).
nova lineage export-graph [--format graphml|gexf|cypher] [-o FILE] [--ref R [--kind K] [--depth N]]Byte-stable export of the lineage graph (whole graph, or one node's provenance +
blast-radius neighbourhood via --ref) for enterprise graph tooling: GraphML/GEXF for
Gephi/yEd, idempotent Cypher MERGE statements for Neo4j. Topology and attributes
only — seal/signature material never travels with this export; nested edge facets are
carried as a facets_json string attribute.
nova insights
Experimental (ADR-0215).
nova insights [--top N] [--output table|json|markdown] [-o FILE] [--cost-db PATH]One synthesized report over the captured lineage graph: top hubs and articulation
points (ADR-0212), seeded Louvain communities, orphan nodes, health ratios
(largest-component fraction, orphan ratio), and best-effort cost hotspots (lineage
node payloads, or a --cost-db evidence-fabric DuckDB aggregate). Unavailable data
sources are reported as unavailable, never fabricated. --output markdown -o FILE
produces a shareable weekly artifact.
nova lineage emit-openlineage
nova lineage emit-openlineage <path> [--output TARGET] [--with-facets] [--otel-correlation]Emit capsule runs as OpenLineage 2.0.2 events.
<path>— a single capsule directory or a parentruns/directory (all capsules inside are emitted)--output, -o TARGET— destination:-for stdout, anhttp://...URL, or a file path--with-facets— (NF-036, ADR-0096) attach NovaFabric custom run facets to the COMPLETE event:novafabric_capsule(capsule id/run id/hash),novafabric_eval(verdictpassed/failed/n/a+ suite + metrics),novafabric_policy(promotion gate + decision), and the standardexecutionParametersfacet (reproducibility run params). Additive — a consumer that ignores custom facets sees unchanged core OL events. Every facet is schema-validated before emission.--otel-correlation— also attach thenovafabric_otel_correlationfacet (trace_id/span_id) when the capsule records them, so a lineage node links to its OTel GenAI spans (NF-037). Implies--with-facets.
If --output is omitted, the target is resolved from OPENLINEAGE_URL → OPENLINEAGE_FILE → stdout.
# Stdout
nova lineage emit-openlineage .novafabric/runs/01HX.../ --output -
# HTTP endpoint (Marquez, Atlan, etc.)
nova lineage emit-openlineage .novafabric/runs/ --output http://marquez:5000
# With NovaFabric custom facets + OTel correlation
nova lineage emit-openlineage .novafabric/runs/01HX.../ --with-facets --otel-correlation
# Environment variable
OPENLINEAGE_URL=http://marquez:5000 nova lineage emit-openlineage .novafabric/runs/Dashboard equivalent: Lineage tab → Export OpenLineage Events panel (returns JSON preview + copy button).
nova lineage consume (experimental, cluster-scale)
nova lineage consume [--nats-url URL] [--kuzu-path DIR] [--subject SUBJECT]
[--batch-size N] [--fetch-timeout S]
[--flush-batch-size N] [--flush-interval-s S]Runs the LineageConsumer NATS JetStream pull consumer (cap-006) in the
foreground: pulls capsule events, derives lineage edges, and bulk-COPYs them
into KuzuDB on a size-or-time flush trigger. Runs until interrupted (Ctrl-C).
This is the cluster-scale deployment path — local-mode capture never requires
this command; lineage is written directly by the local SqliteLineageStore.
Requires the scale extra (nats-py) and the scale-kg extra (kuzu):
pip install 'novafabric[scale,scale-kg]'.
--nats-url— defaults to$NOVA_NATS_URL--kuzu-path— defaults to$NOVA_KUZU_PATHor.nova/kg/lineage.kuzu--subject— NATS subject pattern (defaultnovafabric.lineage.>)--batch-size— max messages pulled per NATS fetch (default 500)--fetch-timeout— seconds per NATS fetch (default 1.0)--flush-batch-size— edges accumulated before a KuzuDB COPY flush (default 2,000 — seebench/lineage/MEASURED_CEILING.md: the 10K-edges/second write-throughput gate passes at this batch size and above, and falls short below it)--flush-interval-s— max seconds between flushes even below--flush-batch-size(default 15.0)
nova lineage consume
nova lineage consume --nats-url nats://hub.example.com:4222 \
--kuzu-path /var/lib/novafabric/lineage.kuzu
nova lineage consume --flush-batch-size 5000 --flush-interval-s 30Not exactly-once: a NATS message is acked immediately once its edges are extracted, before the size-or-time flush actually persists them to KuzuDB. If a flush fails, the buffered edges for that flush are dropped and logged, not redelivered — lineage is derived, non-authoritative data, not the evidence chain, so this tradeoff favors simplicity over exact-once delivery guarantees.
Producer taxonomy gap — resolved 2026-07-30 (ADR-0220):
the real event producer is capture/orchestrator.py (forwarded verbatim by
the Go novafabric-spool-forwarder, which never inspects event_type
itself — the earlier framing of this as a Go-vs-Python taxonomy problem was
itself found to be wrong during the fix). It now emits the canonical
RunStarted/RunCompleted/RunFailed event types with parent_run_id
populated, so this command correctly derives SPAWNED_BY edges from real
captured runs — verified end-to-end by
tests/scale_architecture/test_lineage_consumer.py::TestRealProducerEndToEnd.
Remaining gap: ArtifactProduced/ArtifactConsumed edges still require
a producer that emits those event types, which none currently does — only
run-boundary lineage is available from the NATS path today.
Agent execution graph (experimental, ADR-0124)
nova graph agent (experimental, ADR-0124)
nova graph agent <capsule-dir> [--format json|dot|mermaid] [-o FILE] [--digest] [--stats]Reconstruct one run's execution DAG — which model call invoked which tools,
how calls nested under OTel spans, and the observed sibling order — from records
the capsule already holds (model-calls.jsonl + tool-calls.jsonl +
trace.jsonl). A projection, not a capture: read-only, offline, works on any
capsule ever captured (including v0.2), adds no capsule field. Distinct from
nova lineage (cross-run causation) and nova kg (fleet security graph); spec:
agent-execution-graph-v0 (schemas/agent-execution-graph.schema.json).
The output is content-addressed: nodes and edges are canonically sorted and
hashed into a graph_digest, so the same capsule always yields byte-identical
JSON — comparing two digests is a cheap "did the control-flow shape change"
check. Three deterministic edge types only (span_parent,
agent_invokes_tool, follows); nothing is inferred beyond what the spans
encode. Calls with no recoverable parentage attach to a synthetic root node
with an explicit reconstruction_note (missing_parent, orphan_tool_call,
unlinked_span) — never a silent heuristic repair.
# Canonical JSON graph to stdout
nova graph agent .novafabric/capsules/<run_id>
# Only the content hash — for verify/diff pipelines
nova graph agent <capsule> --digest
# Shape summary: node/edge counts, max depth, max fan-out
nova graph agent <capsule> --stats
# Text exports for rendering elsewhere
nova graph agent <capsule> --format mermaid -o run-graph.mmd
nova graph agent <capsule> --format dot | dot -Tsvg > run-graph.svg--format json|dot|mermaid—jsonis canonical;dot/mermaidare deterministic text exports of the same nodes and edges (no new dependency).--digest— print only thegraph_digestline.--stats— print only{node_count, edge_count, max_depth, max_fan_out}.-o / --output FILE— write to a file instead of stdout.
Exit codes: 0 success, 1 not a readable capsule directory, 2 bad flags.
A partially malformed capsule still yields a best-effort graph plus notes.
Lineage store operations (Phase 6, E-3..E-5)
Commands for migrating lineage edges between backends and generating deployment profiles for cluster-scale lineage infrastructure.
Reference: src/novafabric/cli/lineage_migrate.py, design/adr/0053-lineage-at-scale.md (private).
nova lineage-store migrate
Migrate lineage edges from a Parquet file or an ObjectCapsuleStore to a SQLite
store. Runs dry-run by default; pass --commit to actually persist.
nova lineage-store migrate [PARQUET] [--db PATH] [--commit|--dry-run]
[--no-validate] [--from-ocs] [--ocs-tenant TEXT] [--ocs-run-ids TEXT]
[--ocs-data-dir PATH]| Flag | Default | Description |
|---|---|---|
PARQUET |
(optional) | Source Parquet file (deprecated; use --from-ocs for the ADR-0022 canonical path) |
--db |
lineage.db |
Target SQLite database path |
--commit / --dry-run |
dry-run | Commit to target store (default is dry run) |
--no-validate |
off | Skip post-load divergence check |
--from-ocs |
off | Migrate from ObjectCapsuleStore (ADR-0022 canonical path) |
--ocs-tenant |
"" |
OCS tenant identifier (required with --from-ocs) |
--ocs-run-ids |
"" |
Comma-separated run IDs to migrate (required with --from-ocs) |
--ocs-data-dir |
. |
Local OCS data directory for the fallback adapter |
# Parquet migration (deprecated)
nova lineage-store migrate edges.parquet --db lineage.db --commit
# OCS-backed migration (ADR-0022 canonical)
nova lineage-store migrate --from-ocs \
--ocs-tenant acme \
--ocs-run-ids run-001,run-002 \
--db lineage.db --commitExit codes: 0 = success, 1 = argument error, 2 = divergence detected.
nova lineage-store profile
Print a docker-compose YAML deployment profile for the chosen lineage backend.
nova lineage-store profile [--target kuzudb-vertical|janusgraph-minimal]
[--node-size TAG] [--rf N] [--image-tag TAG]| Flag | Default | Description |
|---|---|---|
--target |
kuzudb-vertical |
Profile target: kuzudb-vertical or janusgraph-minimal |
--node-size |
16g-ram-500g-nvme |
Node size tag for kuzudb-vertical profiles |
--rf |
3 |
Cassandra replication factor (for janusgraph-minimal) |
--image-tag |
(unset) | Deprecated. For kuzudb-vertical, sets the single nova-lineage image tag (falls back to latest if unset). For janusgraph-minimal, overrides all three images (janusgraph/cassandra/novafabric) to the same tag — prefer leaving it unset so each image uses its own independently-pinned default (JanusGraph 1.1.0, others latest) |
# KuzuDB vertical profile (single-node, NVMe-optimised)
nova lineage-store profile --target kuzudb-vertical --node-size 32g-ram-1t-nvme
# JanusGraph minimal cluster profile (Cassandra RF=3)
nova lineage-store profile --target janusgraph-minimal --rf 3Prints a complete docker-compose.yml to stdout. Pipe to a file or kubectl apply.
Metadata DB recovery (BQ-013)
nova rebuild-metadata-db
Rebuild the metadata database from the manifest chain log using checkpoint-based replay. Disaster-recovery path when the metadata DB is lost; completes in minutes regardless of chain length (AC-1, BQ-013).
nova rebuild-metadata-db [--prefix TEXT] [--target-db PATH]
[--backend local|s3|minio|ceph_rgw|azure_blob] [--data-dir PATH]| Flag | Default | Env var | Description |
|---|---|---|---|
--prefix |
"" (all tenants) |
— | Tenant or tenant/run_id prefix to scan |
--target-db |
nova-metadata-rebuild.db |
— | Path to the output SQLite database |
--backend |
local |
NOVA_OCS_BACKEND |
Storage backend: local, s3, minio, ceph_rgw, azure_blob |
--data-dir |
(optional) | — | Local backend: path to the object store root directory |
# Rebuild from local storage (all tenants)
nova rebuild-metadata-db --target-db recovered.db
# Rebuild a single tenant from an S3 backend
NOVA_OCS_BACKEND=s3 nova rebuild-metadata-db \
--prefix acme \
--target-db acme-recovered.dbPrints per-step progress, total capsules found, elapsed time, and any integrity warnings. The output SQLite file is ready for use as a replacement metadata DB.
Reference: src/novafabric/cli/rebuild.py, src/novafabric/object_capsule_store/rebuild.py.