AI agents you can hand to an auditor.

ProofVisor is a small server you drop in front of your agent’s LLM and tool calls. Every request is recorded. Every limit you set is enforced before the call goes out. Every session can end with a signed receipt (the shipped configs sign by default). Anyone who holds your deployment’s public key can verify that receipt offline, without asking you or us for anything else.

See the full flow ▶︎ Watch the film (30 s) Open the console Verify a receipt

v0.1.0‑rc.5 (pre‑release) · Apache‑2.0 · Rust · Runs on your machine, your VM, or your cluster

Point your existing OpenAI client at it

One line of code. Zero SDK.

ProofVisor speaks OpenAI’s chat/completions and MCP over plain HTTP. Change the base URL your client points at. Nothing else in your app moves. (Long histories are compacted by default before forwarding. Auditable, and one config line to disable.)

Works the same way for Ollama, LM Studio, Azure OpenAI, vLLM, LiteLLM, and anything else that speaks the OpenAI chat/completions wire format. Requests are forwarded unchanged; the provider setting (openai, anthropic, or gemini) only selects how the upstream response frames are parsed. The Anthropic and Gemini presets point at those vendors’ OpenAI-compatible endpoints.

python
  from openai import OpenAI

  client = OpenAI(
      api_key=os.environ["OPENAI_API_KEY"],
+     base_url="http://127.0.0.1:8484/v1",
  )

  client.chat.completions.create(
      model="gpt-4o-mini",
      messages=[{"role": "user", "content": "hello"}],
  )

What you get

Three things you didn’t have before.

A signed record of every session

When the agent’s session finishes, whether that’s a single chat completion or a 40-step tool-using conversation, ProofVisor hands back a receipt like the one on the right. It commits to the full event chain, the cost, and how many tool calls were allowed vs blocked.

Verification is one pvctl receipt-verify call with your public key. Or about 30 lines of your language’s Ed25519 library. You don’t need to trust ProofVisor to trust the receipt; you only need the public key, obtained from the operator out of band.

The browser verifier at /verify/ checks the signature and the receipt’s internal consistency, but it only knows the sample and demo keys. For a real deployment it reports “internally consistent, trust anchor not verified” until you compare the key fingerprint with the deployment page in the console.

receipt.json
{
  "receipt_version": 2,
  "receipt_id": "01a00219-b3d0-7c31…",
  "session_id": "sess-2026-08-14-42",
  "issued_at": 1786741634000,
  "issued_at_iso": "2026-08-14T21:07:14.000Z",
  "ai_agent": {
    "version": "0.1.0",
    "charter": { "name": "triage‑bot", "type_id": 1 },
    "instance_uid": "9c04e2d1…"
  },
  "subject": {
    "kind": "event_chain",
    "chain_head": "b2b7c9d8…",
    "event_count": 47
  },
  "tool_calls": {
    "total": 8, "allowed": 7, "blocked": 1
  },
  "cost": {
    "prompt_tokens": 12408,
    "completion_tokens": 3819,
    "cached_tokens": 0,
    "cost_usd_micros": 84340
  },
  "stop_reason_id": 92,
  "stop_reason": "Budget Exceeded",
  "key_id": "c8f2…",
  "public_key_b64": "fStglR1c…",
  "signature_b64": "wg7A0Kx3…"
}

Hard limits, refused at the door

That blocked: 1 in the receipt was a tool call that would have blown past the session’s payout cap (max_payout_usd_micros). Your agent received a plain HTTP 403 and moved on. The provider was never contacted; the money was never spent.

Set caps on total tool calls, per-tool calls, spend in micro-USD, and prompt tokens. Turn on the semantic loop breaker if your agent tends to retry the same failing thing until you go broke.

POST /v1/mcp
HTTP/1.1 403 Forbidden
Content-Type: application/json

{
  "error": {
    "code": -32001,
    "message": "tool call blocked by ProofVisor policy",
    "data": {
      "reason": "max_payout_usd_micros (cap 50000000)"
    }
  }
}

Evidence you can send anywhere

Every event is written as OCSF-shaped JSON. The same schema your SIEM already speaks. A session on the signed workflow (the default in every shipped config) ends in a receipt; a session on the unsigned workflow ends in an ATIF trajectory file compatible with the Harbor validator, and can be promoted to a receipt later. Every artifact is just a file on disk.

Ship the files to S3, feed them into Vector, hand them to a customer’s evidence locker, or archive them for the seven years your industry demands. The daemon does not phone home; uploading evidence to the hosted console is a separate, opt-in pvctl console-sync step.

$ ls -R spool/ data/
spool/atif/
├─ 84a3f01c….json        # ATIF v1.7 trajectory (hashed session id)
├─ receipts/
│   └─ 84a3f01c….json    # signed session receipt
└─ outbox/
    └─ 84a3f01c….receipt.json # pending broker publish
data/bridge/
└─ topics/
    └─ agent.tool_call/
        └─ p0.jsonl           # OCSF event stream

See what’s happening

A dashboard for the agent you already deployed.

Every ProofVisor instance ships a small operator dashboard at /dashboard. Open it in a browser and you can see the sessions your agent is running right now: which prompts, how many tokens, how much money, which tools were called, which calls were blocked, and where the ones that failed got stuck.

It reads the same in‑memory state that produces receipts and /metrics. No extra service, no separate database, nothing to log into. Off by a config flag if you don’t want it.

Want the bigger picture? The hosted console demo shows the multi‑deployment view with demo data, and the pitch page walks the whole flow on film in 30 seconds.

  • Live session table with cost, tokens, tool calls, stop reason
  • Click a session to see its receipt as raw JSON, live
  • Filter by open, closed, or capture‑failed. And by workflow
  • No JavaScript framework, no phone‑home. Served straight from the binary

When you’d want it

Three moments this pays for itself.

The 3 AM cost spike

Your agent gets stuck in a retry loop and burns $2,400 on a Sunday. ProofVisor’s loop breaker plus the payout cap would have cut it off at $10, logged what happened, and let your on-call sleep.

The compliance email

An auditor asks which customers’ data your agent touched last quarter. Instead of running a scavenger hunt through LangSmith and provider dashboards, you hand over a directory of receipts and a public key.

The customer question

A customer wants to know whether the agent you built for them called any model or tool other than the ones you promised. You give them a session receipt and about 30 lines of verification code.

Get started

60 seconds, one prompt at a time.

One command installs both binaries. The installer downloads prebuilt releases for Linux and macOS, checks their SHA‑256 checksums, and falls back to cargo install --git (which needs Rust) on any other platform. Then run pvctl: the wizard asks one thing at a time and writes the config file for you. When it finishes, ProofVisor is running on http://127.0.0.1:8484.

Point your OpenAI client at that URL as if it were the provider. No code changes beyond the one line above.

$ curl -fsSL https://proofvisor.com/install.sh | sh
$ pvctl

  Welcome to ProofVisor! A couple of quick questions and you're done.

  Where do your AI models come from?
  1) OpenAI (GPT models)
  2) Anthropic (Claude)
  3) Google (Gemini)
  4) Azure OpenAI
  …
  11) Ollama on this computer (free, no key needed)
  12) LM Studio on this computer (free, no key needed)
  13) Somewhere else (I have a URL)
  Type a number and press Enter [1]: 1

  Paste your OpenAI API key: ••••••••••••••

  All set!
  API key:  ~/.proofvisor/keys/openai.key (private to your user account)

  Start ProofVisor now? [Y/n]: y

  ✓ ProofVisor is running at http://127.0.0.1:8484
  Use it from any OpenAI-compatible app:
    Base URL: http://127.0.0.1:8484/v1
    API key:  anything (your real key stays on this machine)
  Press Ctrl-C to stop.

Under the hood

Boring, on purpose.

ProofVisor is a Rust workspace of thirteen crates. The daemon never phones home and needs no hosted service: it writes files, and you keep the signing key. The hosted console is opt-in; your daemon only talks to it if you run pvctl console-sync.

Runs anywhere Rust runs

Single static binary, or Docker Compose with the full stack (broker, state store, vector DB, cold storage). Also ships a hardened Kubernetes manifest and a systemd unit with sensible defaults.

Pluggable backends

Event bus: embedded (files), Kafka / Redpanda, NATS JetStream. State: in-memory or Redis. Vector store: Qdrant or none. Pick what your org already runs.

Interoperable formats

Events are OCSF 1.10; trajectories are ATIF v1.7; receipts are Ed25519 over RFC 8785 canonical JSON. If you already have a SIEM or an evidence tool, it probably already reads these.

Actually audited

Every fix is regression-tested. The full suite runs on every code push; supply-chain policy is enforced by cargo‑deny. Read the security model before you deploy it. It’s honest about what it does and does not defend against.

Read more

Everything else.