For newcomers · 2 of 2
Proof of what ran
You sent some code to a sandbox and got an answer back. A month later somebody asks: what exactly did you run, where did it run, and what came back? "I'm fairly sure it said 4" is not an answer anyone in an audit enjoys hearing. This page is about the written record plimsoll keeps instead, using the five runs from what a sandbox is (INTERNAL · plimsoll site →).
A slip, not a recording
A store receipt does not contain the groceries. It lists what you bought, what it came to and when, printed by the till at the moment of sale, so that later you can check the bag, or the bank statement, against it. It is small, it is specific, and it is written by the shop.
plimsoll writes the same kind of slip for every run it answers, and the slip names things by a short code computed from their bytes. That code is a digest: a SHA-256 hash of some content, used as its name. The same bytes always give the same digest, and changing a single byte gives a completely different one, with nothing in common with the first. Think of a barcode printed for one exact set of bytes, where a one-letter change prints an unrelated barcode.
The slip is called a run record: the statement plimsolld (the plimsoll server) attaches to every answered run, holding the digests of the request and of the result, the isolation evidence, and the start and end times.
Here is the slip for the first run, the polite stranger who printed
Hello from a stranger. 2 + 2 = 4. It is the real record, read from the signed
recording beside this page.
| Line | What it says |
|---|---|
request_sha256 | The digest of everything you sent that decides what runs: the code, the time limit, the weakest room you would accept, the version of the protocol your client speaks. |
result_sha256 | The digest of the answer as sent: the output, the exit code, whether it timed out, whether any output was cut short. |
provider, isolation | Which backend ran it and which room it says that was. The provider is the backend that actually runs the code; the isolation tier is how strong the wall around the run is, weakest first process, container, kernel, vm. |
environment | Which build of the JavaScript engine ran it, named by its digest. |
started, ended | When plimsolld received the request and when it finished the answer, by plimsolld's clock. The slip shows them in UTC, where the evening of 2026-11-05 had already become the 6th. |
record_sha256 | The digest of every line above: the slip's own name. Change any line and it no longer fits. |
| the rest, empty here | A run in a session (one sandbox kept open for many calls) also names its place in the chain of calls; other rooms also name their sandbox policy, the software image they selected, the software rule the caller asked for, or the instance that ran it. None applies to these runs. |
Notice what is not on the slip: the code and the output. Only their digests. You already hold both; the record names exactly which bytes they were in 64 characters each, so it is small enough to keep beside every result. A few things are left out on purpose, such as how long the run took, which differs every time and would make two identical runs look different (every field, and what is left out (EXTERNAL · official docs ↗)).
Check it yourself
A slip is only useful if you can hold it against the bag. Pick a run. Your browser takes what was sent and what came back, works out both digests from scratch, and compares them with the record. Then it works out the record's own digest from its lines. Nothing is fetched; everything is in this page.
What was sent
What came back (edit it)
The recipe your browser just followed
Every value is written as its length (an 8-byte number) followed by its bytes. A digest is SHA-256 over a domain string that names what is being hashed, then each field's name and content in a fixed order. There is no JSON and no binary message format in it, so any language with a hash function gets the same answer, and the page computes SHA-256 in its own script so it works even opened from a file.
- What was sent, domain
plimsoll.run-request.v2:protocol,minimum_isolation,timeout_ms,software_mode,software_identities(a count, then each one),kind,code,grant_profile. - What came back, domain
plimsoll.run-result.v1:kind,exit_code,timed_out,stdout,stderr,stdout_truncated,stderr_truncated. - The record, domain
plimsoll.run-record.v4: every line of the slip in the order of the specification (EXTERNAL · official docs ↗), empty ones included.
Numbers are decimal text, true and false are the words. That is the whole recipe.
Why the client checks both
At the door of a shop you can ask two different questions of a receipt. Did they ring up what I put on the belt? And is what is in my bag what the receipt says?
The two digests are those two questions. If the request digest does not match what you sent, the record describes a different request, or the client and server encoded it differently. A proxy (a program between you and the server) could have rewritten it, a bug could have cut it short, or someone could have meddled. A result digest mismatch likewise means the recorded answer and your copy disagree, possibly because of a changed answer or an encoding bug. Neither mismatch establishes what actually ran.
The official clients for Go, Python and TypeScript do what your browser just did, on every
answer, before handing it over. In Go a mismatch is the error DataLoss wrapping
record.ErrMismatch, and an answer with no record at all is refused the same way. A
mismatch still hands back the result along with the error, because the code may well have run, and
pretending otherwise would be worse. That much needs no key at all: it is arithmetic.
Who holds the pen
A record on its own is plimsolld's say-so, and anyone with a text editor can type one. Signing adds a name to it: a mark that only the holder of one particular key can make and that anyone can check. The key that makes it is a signing key: a private key that signs statements so that anyone holding the matching public key can check them.
The obvious place for that key would be plimsolld. It is deliberately not there: plimsolld holds no key. It runs strangers' code, and in the cheapest room it runs it inside its own program. A key inside plimsolld would be one escape, a bug that lets code inside a sandbox act outside it, away from forging every record it ever wrote.
So the shop's till prints the slip, but the stamp lives with your accountant at the door, who stamps a slip only after checking it against the bag. A thief who gets behind the till can print slips all day. He cannot stamp them.
The accountant is the harness: a program outside plimsolld that drives runs and
checks their results. Here it is plimsoll-attest. It sends your request, recomputes
both digests from its own copy of the request and the answer, refuses a record that does not
match, and signs the ones that do. A run record signed this way is what plimsoll's documentation
calls a receipt: a signed claim about an operation or file, whose signature and subject
can be checked without independently repeating the work.
The harness keeps every signed record in one file, a bundle, one line per run. Each line holds
the request and the answer in full beside the signed record, and is itself signed with a link that
names the line before it, and the file ends with a checkpoint that says how many lines came before.
Remove, move, add or change a line and the file fails the check, with one exception shown below. Because a bundle holds the code and
its output in full, plimsoll-attest creates it readable by its owner only; this one is
published on purpose.
This recording's key was made for it, and its private half was deleted when the recording ended, so nobody, the author included, can sign another line with it. The public half is harness.pub, beside this page; the signature check above uses it.
The exact format, for the curious
Each signature is Ed25519. The signed form is a DSSE envelope (Dead Simple Signing Envelope, a small standard format that wraps a payload together with its signatures) around an in-toto statement (a standard format for signed statements about software) whose subject is the record's own digest and whose predicate is the record's fields. The key's ID is the SHA-256 of the public key's standard encoding. Signing, verifying and replaying (EXTERNAL · official docs ↗).
What the checks said
Here is what plimsoll-attest printed when its checks were run on the files beside
this page on 2026-11-05. The output is as recorded, with file paths shortened to the names the files
have here.
The recording, checked whole
$ plimsoll-attest verify -pub harness.pub bundle.jsonl verified 10 entries signed by key 352859fe4899c645de1aac6dd1e201cc5d7dea1c12b43eb19e1a722d5eafed78, whole to its last checkpoint: 5 single runs
Ten entries for five runs: plimsoll-attest run adds one run each time it is called
and closes each with a checkpoint, so every run is followed by one.
Someone changed the arithmetic
tampered.jsonl is the same file with one byte changed: the first run's
stored output now says 2 + 2 = 5. Everything else, the signed record included, is
untouched.
$ plimsoll-attest verify -pub harness.pub tampered.jsonl plimsoll-attest: entry 1: attest: broken bundle chain: the line's link signs other content $ plimsoll-attest verify-record -pub harness.pub -line 1 tampered.jsonl plimsoll-attest: attest: the stored request or response does not match the signed record: record: the run record does not match the request and result it came with: result digest 5729016f7460d2a08282c51e8b8a2b320a4d20622a11eba110f1411497cb2f9a, the result received digests to 0f11e9b9948cfd6d3b5aad752ccb4dceaf58a19b0289d8896541d5826e03689b
The whole-file check stops at the first thing wrong, the link. Checking that line alone shows the
real damage: the answer no longer has the digest the signed record names. Press "Change one character"
on the first run above and your browser arrives at the same 0f11e9b9….
Run it again
For code that gives the same answer every time, there is a check that does not rest on the old record's word: send the same request again, to the same room or another, and compare the new answer's digest with the old one. The bundle keeps each request in full, so it can be sent again exactly.
$ plimsoll-attest replay -daemon http://127.0.0.1:48731 -pub harness.pub bundle.jsonl entry 1: same result (5729016f7460d2a0) entry 3: same result (010e91949552438e) entry 5: same result (b03a54b03ee3fbba) entry 7: same result (09235dcadd4744c7) entry 9: same result (4687e6f2f3cf04e2)
All five came back byte for byte the same, the memory hog's 31 piles and the endless loop's timeout included. Code that reads the clock or draws random numbers will differ by design.
Some receipts went missing
shortened.jsonl is the recording cut back to its first two lines: the first run and its checkpoint.
$ plimsoll-attest verify -pub harness.pub shortened.jsonl verified 2 entries signed by key 352859fe4899c645de1aac6dd1e201cc5d7dea1c12b43eb19e1a722d5eafed78, whole to its last checkpoint: 1 single runs $ plimsoll-attest verify -pub harness.pub -expect requests-sent.txt shortened.jsonl plimsoll-attest: attest: the bundle's calls are not the caller's: requests missing [9b793a5a50a1423c adfd9ea06434fba4 e5dcc730cae6e03f e6d3942c2b5b344f], not expected []
The cut file passes on its own, and that is not a bug in the check: a file that ends at a checkpoint looks exactly like a file that was always that short. What catches it is a list kept outside the file. requests-sent.txt is the caller's own note of the five request digests it sent, and against that list four calls are missing.
What a receipt cannot prove
- That the room was what it says. The
isolationline is plimsolld's statement, built from its settings and its startup checks. It is never attestation, cryptographic proof, usually rooted in the hardware, of what software a machine is running. A compromised server can state anything, and the signature then faithfully vouches for a lie it was handed (the sign on the door (INTERNAL · plimsoll site →)). - That the answer is right. It proves what came back, not that it is true. In
plimsoll-attest's own words, when it checks one line: "It authenticates the recorded request and response, not that what the guest (INTERNAL · glossary →) printed is true." - That you have all of them. A whole file says nothing about runs the harness was never
handed, and a file cut back to an earlier checkpoint still checks as whole. Keep your own list of
request digests and hold the file to it with
-expect, as above. - When, by anyone's clock but plimsolld's. The start and end times are plimsolld's. An outside timestamp needs an outside clock.
- That anyone looked. A signature says which key signed, not that a person checked anything, or that the statement is true.
- That your secrets are safe in it. A digest hides its content only when the content is hard to guess. The digest of a short answer can be found by trying likely answers until one fits, and the bundle beside it holds the code and the output in full.
How this recording was made
On 2026-11-05, on one laptop, from a checkout of this repository. The token value is left out;
the private key no longer exists. The keygen command creates the signing key and
its public checking key. The loopback address 127.0.0.1 reaches only the same machine.
go build -o plimsolld ./cmd/plimsolld go build -o plimsoll-attest ./cmd/plimsoll-attest SANDBOX_PROVIDER=wasm PLIMSOLL_ADDR=127.0.0.1:48731 PLIMSOLL_TOKEN=... ./plimsolld & ./plimsoll-attest keygen -out harness # harness.key (owner-only) and harness.pub export PLIMSOLL_CALLER_TOKEN=... for r in polite network files memory forever floor; do ./plimsoll-attest run -daemon http://127.0.0.1:48731 -key harness.key -bundle bundle.jsonl requests/$r.json done # floor is refused: nothing ran, nothing added ./plimsoll-attest verify -pub harness.pub bundle.jsonl ./plimsoll-attest replay -daemon http://127.0.0.1:48731 -pub harness.pub bundle.jsonl rm harness.key
The requests are in requests/ (polite, network, files, memory,
forever and floor). tampered.jsonl was made by a short program that
read line 1, changed the 4 in its stored output to a 5, and wrote the line back the way the harness
writes it; shortened.jsonl is the first two lines of
bundle.jsonl. A test in docs/trainers checks every claim on
this page about those files, and rebuilds the evidence block the page reads from the bundle.
Keep reading
- What a sandbox is (INTERNAL · plimsoll site →): the five runs, and the rooms they ran in.
- Run it from your agent: the receipt you check yourself (INTERNAL · trainer site →): a signed line checked in your browser, flipped bit included.
- One sandbox, five calls (INTERNAL · plimsoll site →): records chained across a session, refused with one call dropped.
- Run records (EXTERNAL · official docs ↗): every field, the encoding, signing, verifying and replaying.