Getting Started with NovaFabric

NovaFabric turns any command — a training script, an AI agent, a notebook cell runner — into a Run Capsule: a structured, secret-scanned, self-contained directory containing the execution evidence capture observes. Capsules can be validated, replayed, diffed against each other, exported as signed Evidence Bundles, and fed into a queryable lineage graph — all without modifying the code you are running.

NovaFabric is local-first: everything in this guide runs entirely on your own machine. No accounts, no hosted backend, no telemetry, no network required for the core workflow (capture, validate, replay, diff, lineage). What you produce is not a trace row in someone else's database — it is a portable, replayable capsule you own.

What you will learn

By the end of this guide you will have, on your own machine:

  1. Installed NovaFabric and confirmed the nova CLI works.
  2. Captured a command into a Run Capsule with zero code changes.
  3. Validated the capsule against its JSON schemas.
  4. Captured a real LLM call recorded in OpenTelemetry GenAI semantic conventions.
  5. Inspected the secret-scan redaction proof.
  6. Replayed a capsule in read-only forensic mode.
  7. Detected a regression between two runs with structural diff — the same check you can wire into CI.
  8. Queried the lineage graph for blast radius and provenance.
  9. Exported a signed Evidence Bundle an auditor can verify offline.

Allow about 10–15 minutes.

Diagram source (Mermaid)
flowchart TB
    subgraph A["Capture"]
        direction LR
        S1["1 · Install"] --> S2["2 · Capture a run"] --> S3["3 · Validate it"]
    end
    subgraph B["Look inside"]
        direction LR
        S4["4 · Capture an LLM call"] --> S5["5 · Inspect the secret scan"] --> S6["6 · Replay, read-only"]
    end
    subgraph C["Compare and prove"]
        direction LR
        S7["7 · Diff two runs"] --> S8["8 · Query lineage"] --> S9["9 · Export signed evidence"]
    end
    A --> B --> C

These nine steps exercise all five NovaFabric primitives — Asset Registry, Run Capsule, Replay, Lineage, and Evidence Bundle — end to end. For the concepts behind each, see docs/concepts.md.


What you need

No API keys are required for Steps 1–3 and 6–9. Step 4 (a real LLM call) needs an Anthropic API key, but you can skip it and the rest of the guide still works.


Step 1: Install

pip install novafabric

Or, if you prefer uv:

uv add novafabric

Or as an isolated CLI tool — the right shape when you use nova as a command rather than as a library, because nothing leaks into (or breaks from) any project venv:

uv tool install novafabric   # same via: pipx install novafabric

Confirm the install:

nova --version
# novafabric 0.108.0

Both nova and novafabric are the same binary. The examples throughout this guide use nova.

Optional extras. The base install covers everything in this guide. Narrow extras exist for optional integrations (e.g. pip install "novafabric[serve]" for the experimental dashboard, or "novafabric[all]" for everything) — see docs/operator-guide.md.

Not sure which you have or need? nova doctor --check-extras lists every extra as complete or incomplete and prints the exact install command for the ones you are missing. Commands that need an extra also name it when it is absent.

Changed in v0.99.0 — the default install is much smaller (412 MB → 113 MB). duckdb, pyarrow, python-louvain and clickhouse-connect are no longer installed by default; they moved to the extras that actually use them (ADR-0222). Everything in this guide still works unchanged. If you relied on importing any of them after a plain pip install novafabric, use pip install 'novafabric[all]' or the narrower extra you need — see docs/operator-guide.md.

Optional one-time setup. nova init pre-creates the data directories (capsules/, keys/, replays/) under ~/.novafabric and generates a local Ed25519 keypair for signing Evidence Bundles (Step 9). It is optional — nova capture creates what it needs on first use — but handy if you want the directory tree in place up front. Re-running it is safe; nova init --force regenerates the keypair and archives the old one under keys/archive/.

nova init does not seal your captures. Sealing is opt-in: nova init prints nova seal init as an optional next step (see Seal your captures below).

Maturity. NovaFabric is in beta (v0.108.0 at the time of writing). Most surfaces work today but carry experimental maturity: interfaces may change before the v1.0 schema freeze. On-disk formats are not frozen until v1.0. See ROADMAP.md for the sequencing.


Step 2: Capture your first run

Wrap any command with nova capture. The simplest possible example:

nova capture python -c "print('hello from nova')"

You should see:

✓ Capsule written: ~/.novafabric/capsules/01HXAY7M5JZ8R7K4P9DPBYK2WX  (run_id=01HXAY7M5JZ8R7K4P9DPBYK2WX)

The ID in the path is a ULID — a time-sortable identifier unique to your run. Every capture produces a fresh one, so capsule directories sort chronologically.

NovaFabric captures by injecting hooks into the subprocess through Python's import system (a sitecustomize.py placed on PYTHONPATH). No changes to your code are required. The hooks are removed automatically when the command finishes.

What was written

~/.novafabric/capsules/01HXAY7M5JZ8R7K4P9DPBYK2WX/
  capsule.yaml          ← run manifest: id, status, command, timing
  trace.jsonl           ← execution spans (OpenTelemetry-compatible)
  model-calls.jsonl     ← LLM API calls, one record each (OTel GenAI semconv)
  tool-calls.jsonl      ← tool invocations (MCP or plugin hooks)
  assets.jsonl          ← asset references declared by the run
  env.lock              ← frozen environment: Python, packages, OS, CPU
  redaction-proof.json  ← proof that the secret scan ran (required to validate)
  replay.yaml           ← replay constraints and policy
  lineage.jsonl         ← lineage edges emitted by this run
  inputs/
  outputs/
    stdout.txt
    stderr.txt

The capsule captures both success and failure. If your command exits non-zero, the capsule is still written with status: failure, exit_code: N, and an error block. NovaFabric's own exit code mirrors the wrapped command's exit code, so it is safe to drop nova capture in front of any command in an existing pipeline.

Take a look at a few of these files. nova capture printed a run_id= — use it, or let the shell pick the most recent capsule:

# Either paste the run id nova printed …
RUN=~/.novafabric/capsules/01HXAY7M5JZ8R7K4P9DPBYK2WX

# … or take the newest one
RUN=~/.novafabric/capsules/$(ls -t ~/.novafabric/capsules/ | head -1)

# The manifest — run id, status, timing, command
cat $RUN/capsule.yaml

# What was printed
cat $RUN/outputs/stdout.txt

# Environment snapshot — Python version, installed packages, OS, hardware
cat $RUN/env.lock

Capsules are written under ~/.novafabric/capsules/ by default. Set NOVAFABRIC_CAPSULE_DIR to put them somewhere else — if you do, use that path here instead.

env.lock records the Python version, up to 200 installed packages, safe environment variables (secrets excluded), and OS / arch / CPU / memory (GPU detection is not implemented — the gpu fields are always empty) — enough to reason about whether a run is reproducible on another machine.


Step 3: Validate the capsule

nova validate checks the capsule directory against its JSON schemas and confirms all required files are present:

nova validate $RUN
# ✓ Valid capsule: 01HXAY7M5JZ8R7K4P9DPBYK2WX  status=success

Validation covers capsule.yaml, env.lock, redaction-proof.json, and lineage.jsonl. A capsule without redaction-proof.json is invalid — the secret scan must have run for the capsule to be trusted, and (as you will see in Step 9) an unredacted capsule cannot be exported as evidence.

Running many captures on one machine? An optional, opt-in warm capture daemon removes the per-run startup cost (nova daemon start, then novacap <cmd>). It is experimental and Linux-only; see the warm capture daemon guide.


Step 4: Capture a real LLM call

The print example produced an empty model-calls.jsonl because there were no LLM API calls. Let's capture a real one. (Skip this step if you don't have an API key — the rest of the guide does not depend on it.)

The examples/minimal-agent-run/ directory in the repository contains a ready-made example. If you have an Anthropic API key:

export ANTHROPIC_API_KEY=sk-ant-...
pip install anthropic

python examples/minimal-agent-run/agent.py

This example uses the in-process @agent decorator (novafabric.sdk.agent), which writes its own capsule to examples/minimal-agent-run/capsule/<run_id>/ (one per call; the script prints the path) — no nova capture wrapper needed (see the User guide: SDK decorator). If you do wrap it in nova capture, the model calls are filed into the decorator's capsule, and the wrapper capsule's model-calls.jsonl stays empty.

After the run, look at the model-calls record:

cat examples/minimal-agent-run/capsule/<run_id>/model-calls.jsonl | python -m json.tool | head -40

You will see one JSON record per LLM call, following the OpenTelemetry GenAI semantic conventions:

{
  "schema_version": "0.1.0",
  "gen_ai.system": "anthropic",
  "gen_ai.request.model": "claude-haiku-4-5-20251001",
  "gen_ai.request.temperature": 1.0,
  "gen_ai.request.max_tokens": 64,
  "gen_ai.request.messages": [...],
  "gen_ai.response.choices": [...],
  "gen_ai.response.finish_reasons": ["end_turn"],
  "gen_ai.usage.input_tokens": 22,
  "gen_ai.usage.output_tokens": 41,
  "status": "success",
  ...
}

This record is what nova replay uses to mock the call (Step 6), and what nova diff aligns when comparing two runs (Step 7). Sampling parameters such as temperature, top_p, and seed are captured because they are what an exact, deterministic replay would need to reproduce.

What NovaFabric captures automatically

NovaFabric installs capture hooks for the transports below. You do not configure anything — if the library is installed, the hook fires:

Transport What gets captured
openai SDK chat.completions.create calls
anthropic SDK messages.create calls
httpx (sync and async) Requests to known LLM API URLs
requests Same URL classification as httpx
aiohttp Async requests to known LLM API URLs
urllib3 Low-level requests; covers boto3 / Bedrock
mcp SDK Every call_tool invocation

URL classification uses a vendored registry of known LLM provider hostnames (OpenAI, Anthropic, Cohere, Together, Mistral, Replicate, AWS Bedrock, and Ollama on localhost:11434). Extend it with ~/.novafabric/url_registry.yaml to cover private endpoints. Third-party plugins can also register hooks via the novafabric.hooks entry-point group.

If none of these libraries are installed, the capsule is still written — you get environment, stdout/stderr, and timing.


Step 5: Inspect the secret scan

Every capsule includes a record of its secret scan: which files were scanned, with which rules, and what was redacted:

nova scan-secrets $RUN

A clean run prints:

✓ 01HXAY7M5JZ8R7K4P9DPBYK2WX: no findings

If findings were detected, nova scan-secrets lists each one (with a severity badge); add --fail-on <severity> to exit non-zero above a threshold, or --json to print the full redaction-proof.json for scripting. The redaction-proof.json file itself records that the scan ran, which files were checked, and how many findings were found. If a secret is detected, it is redacted in place as [REDACTED:rule-id] before the capsule is finalized. Every file in the capsule is scanned, including outputs/stdout.txt, env.lock and the manifest, and a final pass rescans the finished capsule before it is digested and sealed. The proof is generated on every capture. It records what the scanner did, not a guarantee: the scan is rule-based, so a secret in a format no rule knows is not found.


Step 6: Replay the capsule (read-only inspection)

Replay re-executes or inspects a capsule with external calls controlled. There are four honest, falsifiable modes for reproducing or judging a run — forensic, mocked, semantic, exact — plus a fifth, experimental intervention mode for counterfactual root-cause analysis (see the table below). We'll start with the safest — forensic — which reads the capsule without re-executing anything:

nova replay $RUN --mode forensic

Forensic mode reads and returns the manifest, traces, and model calls directly from the capsule directory. No subprocess is launched and no network calls are made — this is the safe way to inspect a run handed to you by a colleague or pulled from a CI artifact store.

Results are written to $NOVAFABRIC_HOME/replays/<replay-ulid>/replay_result.yaml (default ~/.novafabric/replays/; pass --output-dir to choose). Up to v0.106.0 they went under the current directory instead. A replay result is not a capsule (only the experimental intervention mode also writes a counterfactual capsule) — to diff behaviour, capture the run again and nova diff the two capsules.

The other modes each answer a different question:

Mode Re-executes? Network? Use it for
forensic No No Audit / post-incident inspection
mocked Yes OpenAI/Anthropic model replies (sync or async, streamed or not) and MCP tool results served from the capsule; other tools run live; fails closed on divergence CI / regression
semantic No No Text-similarity score (0.0–1.0) over the capsule's recorded responses
exact No No Eligibility check for a byte-exact re-run (deterministic env, seeds)
intervention (experimental) Yes, mocked semantics No Counterfactual root-cause: substitute one captured event per an InterventionSpec and see whether the outcome flips

NovaFabric deliberately does not claim byte-exact replay of remote LLM calls — that is why semantic mode exists. intervention mode is what nova diagnose --intervene / --search-root-cause use under the hood to test a failure hypothesis rather than just rank it — see User guide: replay for the details of each mode.


Step 7: Detect regressions with diff

Capture two runs of the same command with a controlled difference, then let NovaFabric show you what changed structurally — no reading log files:

# Capture a baseline
AGENT_MODE=baseline nova capture \
  --output-dir examples/replay-and-diff/runs \
  python examples/replay-and-diff/agent.py

# Capture a regressed variant
AGENT_MODE=regressed nova capture \
  --output-dir examples/replay-and-diff/runs \
  python examples/replay-and-diff/agent.py

# Compare them
RUNS=(examples/replay-and-diff/runs/*/)
nova diff "${RUNS[0]}" "${RUNS[1]}"

Output:

Diff: 01HX... → 01HY...
  changed=1  added=0  removed=0
Outputs:
  ~ outputs/stdout.txt

nova diff aligns model calls, tool calls, and outputs between the two capsules, so a score: 0.85 → score: 0.62 regression in stdout is detected structurally.

To use this as a CI gate:

nova diff "${RUNS[0]}" "${RUNS[1]}" --assert-no-regressions
# exits 1 if any regression is detected

This is the single most common production use of NovaFabric: wire nova diff --assert-no-regressions into CI so a "worked yesterday, fails today" agent fails the build with a portable capsule attached as evidence.


Step 8: Query the lineage graph

Every captured run writes lineage.jsonl into the capsule directory, recording which assets the run consumed and what it produced. NovaFabric also indexes these edges into a local SQLite graph as it captures.

The examples/lineage-chain/ example captures three runs that all depend on the same upstream dataset:

RUNS=examples/lineage-chain/runs

nova capture --output-dir $RUNS python examples/lineage-chain/step.py train-v1
nova capture --output-dir $RUNS python examples/lineage-chain/step.py eval-v1
nova capture --output-dir $RUNS python examples/lineage-chain/step.py promote-v1

Now query the graph.

Blast radius — "If this dataset changes, which runs must I re-evaluate?"

nova lineage blast-radius local:datasets/training-set@1.0.0
Blast radius of local:datasets/training-set@1.0.0
├── run:01K…  (train-v1)
├── run:01K…  (eval-v1)
└── run:01K…  (promote-v1)

Provenance — "What did this specific run depend on?"

nova lineage provenance <run-id>

If you ever lose the local SQLite index, rebuild it from the capsule contents:

nova lineage import examples/lineage-chain/runs/

The lineage graph is fully derivable from the lineage.jsonl files — the database is a rebuildable cache, never the source of truth. NovaFabric can also emit these as OpenLineage 2.0.2 events (START / COMPLETE / FAIL) to Marquez, Atlan, or OpenMetadata; see User guide: lineage.


Step 9: Export a signed Evidence Bundle

When you need portable, tamper-evident proof of what a run did — for a colleague, an archive, or an auditor — export the capsule as a signed Evidence Bundle:

nova export-evidence $RUN --output bundle.zip --key ~/.novafabric/keys/signing_key.pem

--key is required (the CLI errors with a clear message if it's omitted) — it points at the Ed25519 private key nova init already generated for you in Step 1. If you skipped nova init, run it now (it writes ~/.novafabric/keys/signing_key.pem), or generate an Ed25519 PEM with any tool, e.g. openssl genpkey -algorithm ed25519 -out key.pem.

An Evidence Bundle is a signed, self-contained ZIP: a copy of the capsule, its lineage edges, the JSON schemas, Ed25519-signed in-toto DSSE attestations, and a manifest.json with a SHA-256 for every file plus the verification recipe (full list). Its defining property is that it is verifiable with only sha256sum plus an ed25519 verifier — no NovaFabric runtime required, so an auditor can check it offline, air-gapped, years later.

A capsule can only be exported if its secret scan ran and produced a redaction-proof.json (Step 5) — you cannot ship evidence that was never checked for leaked secrets.

See User guide: export-evidence for the full bundle layout and the offline verification procedure.

Experimental — cryptographic sealing (NovaSeal). Beyond ed25519 Evidence Bundles, NovaFabric ships an experimental, opt-in in-process sealing core (v0.10+): DSSE ECDSA P-256 signatures, opt-in RFC 3161 trusted timestamps, and an append-only Merkle log, verified with nova verify (signature_ok / timestamp_ok / log_integrity_ok / identity_trust), driven by an optional ~/.novafabric/novaseal.yaml. Its interfaces may change before the v1.0 schema freeze; the dedicated, hardened NovaSeal signing service (network service, qualified timestamps, Sigstore-keyless by default — ADR-0041) remains planned. For portable proof with the most stable surface today, use the Evidence Bundle above. Sealing is fully opt-in: without a novaseal.yaml, capture and export behave exactly as in Steps 2–8.

Optional: seal your captures with a local identity

Run Capsules can be sealed and verified. To turn that on for this machine, run one command (experimental, ADR-0301; since v0.105.0 — on earlier versions you write novaseal.yaml by hand as described in NovaSeal configuration):

nova seal init

It creates a dedicated signing key, a local seal CA and a certificate under ~/.novafabric/keys/novaseal/ (private keys mode 600), and writes ~/.novafabric/novaseal.yaml. It works offline: no timestamp authority is configured and nothing is contacted. From then on nova capture seals new capsules:

nova capture python my_agent.py
nova verify ~/.novafabric/capsules/<run-id>/
#   Signer identity: SELF-ASSERTED local key (identity_trust=self-asserted)
#   signature_ok=True, timestamp_ok=None, log_integrity_ok=True, ...

What this does and does not prove:

Rotate the key with nova seal init --force (the old key is archived, the same CA issues the new certificate). If sealing fails during a capture, the capture still completes and prints a warning; the capsule is simply not sealed.


Where to go next

You now have a captured run, a validated capsule, a real LLM call recorded in GenAI semconv, a forensic replay, a CI-gateable diff, a lineage query, and a signed Evidence Bundle. The user guide covers every shipped nova command in detail.

A few directions to explore:

You want to... Where to go
Capture without wrapping in a subprocess (decorator pattern) User guide: SDK decorator
Capture an MCP-using agent (Claude Desktop, Cursor) User guide: mcp-proxy
Capture non-Python LLM clients (Node.js, Go, Claude Code) User guide: api-proxy
Run inside a Docker container, Kubernetes, or Slurm User guide: runners
Build a signed Evidence Bundle User guide: export-evidence
Register and lifecycle-manage AI assets (eval-gated promotion) User guide: asset registry
Gate promotion with OPA/Rego policy and maker-checker approval CLI reference: nova promote
Browse capsules in a local web dashboard User guide: nova serve
Hands-on tour of every capability (proxies, providers, KG, compliance) tutorials/feature-tour.md
Prove supply-chain provenance & eval integrity (dataset cards, contamination checks, SLSA-for-ML, OTel export) feature tour §17
Group runs into multi-turn sessions and replay them in order (experimental) CLI reference: nova session
Version prompts as immutable registry assets + deployment labels (experimental) CLI reference: nova prompt
Query cost / tokens / scores offline over your capsules (experimental) CLI reference: nova query
Attribute a failed run to its most likely cause, then replay-prove the hypothesis (experimental) nova diagnose <run-id> --search-root-cause
Export EU AI Act / ISO 42001 / NIST / GPAI compliance evidence (experimental) nova export-compliance --help, docs/concepts.md
Everything that shipped experimental in v0.59, in one list User guide: v0.59 summary
Why NovaFabric — plain-English value guide tutorials/why-novafabric.md
How capture works under the hood tutorials/how-capture-works.md
Capturing multi-agent systems tutorials/multi-agent-capture.md
NovaFabric vs Langfuse (complementary, not competing) tutorials/novafabric-vs-langfuse.md
The five primitives and the capsule format docs/concepts.md
What's shipped vs planned ROADMAP.md