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.
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
Point your existing OpenAI client at it
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
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…"
}
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)"
}
}
}
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
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.
When you’d want it
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.
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.
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
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
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.
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.
Event bus: embedded (files), Kafka / Redpanda, NATS JetStream. State: in-memory or Redis. Vector store: Qdrant or none. Pick what your org already runs.
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.
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