Chats and runs
The pin, the run record, and the invariant that keeps them honest.
The pin
A chat stores agent_version_id, not agent_id. It is written once at creation and never updated. Everything else in this product — reproducibility, honest diffs, audit trails, safe upgrades — is a consequence of that one column.
POST /v1/chats
{ "agent": "site-tester", "version": 3 }
→ { "chat_id": "c_4812", "agent_version_id": "av_9f2c…", "pinned": true }
// omit version → resolves stable ONCE, at creation, and writes the id.
// it never re-resolves later, no matter what publishes after.The run record
Each answer produces a run, split across three tables so the input and the output are independently addressable and independently hashable.
| Table | Holds |
|---|---|
| runs | version id, provider, requested and resolved model id, source mode, status, latency, tokens, cost |
| run_inputs | the input text, variables, attachments (by content hash) and the input hash |
| run_outputs | the answer, parsed JSON, schema validity, tool calls, citations and the output hash |
The invariant
run.agent_version_id always equals chat.agent_version_id. There are no exceptions and no special cases, because rerunning an input on a different version forks a new chat pinned to that version rather than switching the old one.
Attachments
Files attached to a question are hashed into the input hash alongside the text. "The same input" therefore means the same words and the same bytes — which is what makes a rerun an actual rerun rather than an approximation of one.
Source snapshots
Every source a run cites is stored with its URL, title, fetch timestamp and a content hash. That is what makes replay mode possible, and what lets you say the page said this on 14 August rather than hoping it still does.