Quickstart

Record your first run in 60 seconds

Install the SDK, wrap your agent, and verify the result yourself. No account is required to use the open-source software. Python and TypeScript are byte-for-byte compatible.

New to the terminal? If you vibe-coded your way here and have never run a command line, start with Provenrail from zero instead. It spells out every keystroke, from opening the terminal to your first verified proof. This page is the faster reference once you are comfortable.
Install Python TypeScript Verify CLI Self-host the sink Team & SSO Licensing Source

Install

The CLI (pr quickstart, verifier, and sink). Recommended: install with uv, which brings its own pinned Python, so a later brew upgrade or system Python change cannot orphan it:

uv tool install provenrail

No uv yet? One line installs it: curl -LsSf https://astral.sh/uv/install.sh | sh.

Prefer pip? It works, but install it inside a virtualenv, not a system or Homebrew Python. A global pip install breaks the day Homebrew upgrades Python (the package lands in the old interpreter's site-packages). If that happens, recover with pipx reinstall provenrail or switch to the uv command above:

python3 -m venv .venv && source .venv/bin/activate
pip install provenrail

Using the SDK from your own project? Add it to that project's environment, again not system Python:

uv add provenrail   # or: pip install provenrail (venv active)

TypeScript / Node 20+ (recording SDK):

npm install provenrail

Python quickstart

One command sets up a local sink and writes .provenrail.json, so your code carries no URLs or tokens:

pr quickstart   # starts a local sink + writes config

Then two lines in your code:

import provenrail as fr

with fr.record("my-agent"):
    ...   # your agent runs; model and tool calls are captured

fr.record(...) provisions a stream, opens a signed session, and seals and drains it off-box when the block exits. A decorator form exists too: @fr.recorded("nightly-job"). Stop the local sink with pr quickstart --stop; point at your own sink with pr quickstart --url <URL>.

Drop-in capture (one line per SDK)

from provenrail.integrations import instrument_openai, instrument_anthropic, instrument_mcp

instrument_openai(openai_client, fr)      # every model call captured
instrument_anthropic(anthropic_client, fr)
instrument_mcp(mcp_session, fr)           # every MCP call_tool captured

TypeScript quickstart

import { record } from "provenrail";

await record("my-agent", async (pr) => {
  await pr.recordModelCall("openai", "gpt-5", { prompt }, out, { usage });
});

A run recorded in TypeScript is byte-for-byte compatible with one recorded in Python: the same sink accepts it and the same two verifiers prove it. Node 20+ is required (WebCrypto Ed25519).

Verify a run

Verification trusts neither the agent nor the sink. Anyone can run it, with no account:

pr verify bundle.json --pin pin.json

To verify your own recorded run after pr quickstart, export it from the local sink first (this uses the read token quickstart saves), then verify the bundle:

pr export my-run.json     # pulls your sealed run out of the sink
pr verify my-run.json     # recompute everything; trust nobody

Or verify in your browser, with the bundle never leaving your device: provenrail.com/verify. Try the live verified demo or watch it catch a tampered run.

CLI reference

pr quickstart        # local sink + config, zero tokens
pr demo              # records a session, anchors it, writes bundle.json + pin.json
pr export my-run.json  # export your own recorded run from the local sink
pr verify bundle.json --pin pin.json     # verify, trusting nobody
pr report --regime eu-ai-act bundle.json --md   # regulatory attestation
pr pack bundle.json    # self-contained evidence pack (zip) for auditors
pr diff run-a.json run-b.json            # diff two runs with provable fidelity
pr ots-verify proof.ots --data-sha256 H  # verify a Bitcoin (OpenTimestamps) proof
pr serve --anchor rfc3161               # run the sink yourself (real trusted time)
pr sidecar --upstream https://api.openai.com   # out-of-process capture proxy
pr witness --log <origin>=<pubkey>        # independent witness on separate infra

Self-host the sink

The sink is the append-only server that receives records. You run it; your records never reach us. For real third-party trusted time, anchor with RFC 3161:

pr serve --anchor rfc3161 --tsa https://freetsa.org/tsr

Or with Docker:

docker compose up
Harder to skip. Run pr sidecar as an outbound proxy and lock model egress to it, so capture is mandatory rather than a default. Add --fail-closed to refuse any call that cannot be recorded.

Team and SSO

On the Team plan you can invite up to 10 teammates with role-based access and connect your identity provider, so staff sign in with the IdP you already use. Everything is account-authenticated against your own sink; the integrity guarantee is unchanged on every plan.

Members and roles

Invite a teammate and they get their own key (shown once). Four least-privilege roles: owner (billing and everything), admin (manage streams, members, webhooks), member (run agents, export their own streams), and viewer (read only). An actor can only grant roles at or below its own.

curl -X POST $URL/v1/members -H "Authorization: Bearer $ACCOUNT_KEY" \
  -d '{"role":"admin","email":"dana@acme.com"}'
{
  "member_id": "mbr_9cf5...",
  "role": "admin",
  "api_key": "pr_mk_rPk8...",          # shown once, store it now
  "note": "store this key now; it is shown only once"
}

Single sign-on (OIDC)

SSO is API-first: you configure your IdP once, then your staff present an ID token from that IdP to receive a session key. Provenrail makes no network call (the JWKS is pinned out of band), and validation is strict, only RS256 and EdDSA are accepted, with issuer, audience and expiry all checked. New users are provisioned just-in-time at the default role.

# 1. Owner configures the org IdP once (issuer, audience, pinned JWKS, default role)
curl -X PUT $URL/v1/sso/config -H "Authorization: Bearer $ACCOUNT_KEY" \
  -d '{"issuer":"https://acme.okta.com","audience":"provenrail",
       "jwks":{ ... },"default_role":"member","email_domain":"acme.com"}'

# 2. A teammate authenticates with your IdP, then exchanges the ID token for a member key
curl -X POST $URL/v1/sso/login -d '{"id_token":"eyJhbGciOiJSUzI1Ni..."}'
{
  "member_id": "mbr_9ca5...",
  "role": "member",                    # JIT-provisioned at the default role
  "api_key": "pr_mk_lAFz..."
}
Strict by design. The IdP signing key is selected from your pinned JWKS by kid; alg: none and HMAC algorithms are rejected, so there is no algorithm-confusion bypass. An optional email_domain restricts which addresses may provision. Every login is written to the tamper-evident audit log.

Licensing

Provenrail is open-core and dual-licensed:

Get a commercial license key from your account, then activate it on your server:

pr activate prl_live_...        # verifies offline, stores the key
pr serve                       # now runs at your licensed tier

Verification is fully offline: the package ships the Ed25519 public key and checks the signed key locally, so nothing phones home and a licensed build works air-gapped. The license is a commercial control, not DRM; the open-source integrity guarantee is identical on every tier.

Source and spec

The wire format and verification steps are a frozen, public specification, so a third party can write an independent verifier and check the same bundles. The in-browser verifier at /verify is a second, independent implementation of that spec, kept in lockstep with the Python one. Source code is open under the licenses above.