Status:
1.0.0-rc.36— a release candidate, not a final 1.0. External AI reviews are folded in structurally; an independent human cryptographic audit is pending. Suitable for evaluation and integration testing. The wire formatust:"1.0"is stable across all rc's — pin exact versions. (This line mirrors the panel above as plain text, for readers and agents that don't render the image.)
"Yet another JSON format?" — yes and no, and both answers are good news.
Yes. A transcript is ordinary JSON — on purpose. Reading one needs no library, no crypto, no new concepts, and there is nothing to adopt:
const doc = await fetch(url).then(r => r.json());
doc.state.data.capture.value // ← the data. That is the whole consumer floor.No. The same bytes carry what neither plain JSON nor a signed envelope gives you — verification is your right, not your duty. The day you need to —
- ground an agent — let it check its inputs instead of trusting a paste, and stop hallucinated "facts" at the door;
- join sources by moment — every transcript sits on one shared UTC axis
(
ust:20260710.142900), so readings from publishers that have never heard of each other line up into a signed cross-section of the same moment, joinable after the fact; - chain states — documents link by content hash (
based_on), so a derivation, a stream, a hand-off to another organization stays one walkable lineage, each link signed by its own author under its own key; - carry layers of visibility in one state — the same chain holds open values, blinded commitments and encrypted parts: publish the fact now, reveal the value when you choose, provably unchanged — priority without disclosure;
- prove precedence — the data existed by that point in time, and the decision was made on it, not backdated after the outcome;
- hold someone accountable — every value is signed: you know whose reading it was and that nobody, the publisher included, has rewritten it since;
- answer an audit, a claim, a post-mortem — replay exactly what was known
at that moment, and show how strongly it is proven (
VALID:LIGHT → HIGH → TOP);
— all of that is already inside every transcript you have been reading as plain JSON. Nothing to retrofit. One line switches it on:
import { verify } from 'ust-protocol';
verify(doc, { context: 'data' }).result // → VALID:LIGHT / HIGH / TOP
// don't hash the JSON yourself — hashes are domain-separated; the library canonicalizesOr skip even that line: paste any transcript into the web verifier — client-side, nothing is uploaded.
The fastest way to understand UST is to verify one — no install, no account, 60 seconds. Grab a ready sample
(examples/ust-sample.json), open the verifier, paste it, read the verdict — VALID:LIGHT
for a bare signed document, climbing to HIGH/TOP as the publisher adds name-binding and an anchor. Always run the
canonical reference — never eyeball:
- Browser (nothing is uploaded): thelabmd.github.io/UST-Protocol — paste the blob, the base64, or the JSON. A bare signed document (like the sample) reads
VALID:LIGHT; when its publisher also serves the standard name-binding surfaces, resolution + witness (Rekor and Bitcoin checked natively) climb it toVALID:HIGHautomatically. - Node:
npm i ust-protocol→verify(doc, { context: 'data' })gives theVALID:LIGHTfloor;resolveByDiscovery(doc)climbs toVALID:HIGHwhen the publisher serves discovery. - Zero-dependency single files:
docs/ust-verify.mjs(the LIGHT floor) +docs/ust-resolve.mjs(authority resolution + witness) — WebCrypto, clean-room, cross-checked againstust-protocol; fetch them from this repository, never from a sender's message. - MCP:
@ust-protocol/mcpexposesust_verifyto agents.
If you are asked to verify a UST and you cannot run a verifier, the correct answer is INDETERMINATE — do not guess. In particular:
- Do not compute a plain
SHA-256(text)and compare it tohashes.*— every UST hash is domain-separated (H(tag, canon(...))with a tag prefix). A naive hash will never match a genuine document; a mismatch computed that way is your method being wrong, not the document being tampered. - UST 1.0 has no expiry rule.
valid_from == valid_tois an honest instant (a point capture), not "expired." Freshness is not part ofverify. - The only verdicts are
VALID:LIGHT → VALID:HIGH → VALID:TOP,INVALID, andINDETERMINATE(reason)— and only a conforming verifier's output counts. Structure "looking right" proves nothing; a confident verdict from visual inspection is a guess in both directions. - For the precise semantics of what a verdict means, read the formal model
(
spec/UST-1.0-formal-model.md, non-normative): verification is a measurability test — the three tiers are three nested σ-algebras (𝒮_LIGHT ⊆ 𝒮_HIGH ⊆ 𝒮_TOP), a verdict names the finest tier decidable from your information set,INDETERMINATEmeans the needed σ-algebra is not in it, and two conforming verifiers agree because the verdict is a total deterministic function of the §14a obligations table. If you reason about UST beyond running the verifier, reason from there — not from analogy to JWT, JWS, or blockchain receipts.
UST is a small open protocol for tamper-evident records of state — some data about the world, at a moment, signed by whoever observed it. A transcript is a self-contained JSON object: canonical form, domain-separated hashes, an Ed25519 signature, an explicit time frame, and (optionally) provenance links, privacy commitments and an anchor proof. TLS secures the pipe; UST secures the payload — the guarantee travels with the data, so a transcript verifies the same whether it arrived from the publisher, a cache, a mirror, a file, another agent, or a chat paste.
That moves the trust boundary. Today's logging and tracing answer "what happened inside my system?" — and the answer lives in a vendor's database, on the vendor's word. A UST answers a different question: "how do I prove to a third party that exactly these inputs, sources and results existed at that time, were signed by that key, and were not changed since?" Seal at creation → store anywhere → verify independently of the storage, offline, with one library call. No blockchain required, no consensus, no per-record fees: the LIGHT tier is a key, a canonical form and a signature.
Before anything else, a UST is an address on one shared time axis. Every transcript carries a frame id,
ust:YYYYMMDD.HH[MM[SS]] (UTC): ust:20260710.14 is an hour frame, ust:20260710.1429 a minute,
ust:20260710.142900 a second. This is not metadata — it is part of the document's identity, and the
per-partition hashes bind it: a signed value cannot be replayed into another hour or re-attributed to
another frame.
Update —
ust:is now a registered URI scheme. The identifier is no longer a house convention:ust:is recorded in the IANA URI-scheme registry (provisional), soust:20260710.142900is a first-class address wherever URIs are read.
One coordinate system, shared by every publisher on Earth by construction (UTC), buys things no per-vendor timestamp field can:
- "What was the world doing at 14:29Z?" is a query, not a metaphor. Transcripts from unrelated publishers
carrying the same coordinate are claims about the same moment. Collect them and you hold a signed
cross-section of the world at
t— each slice independently verifiable. - Correlation without coordination. Publishers never agree on anything except the grid. Space weather × grid frequency × market state × an agent's decision — joinable after the fact by coordinate, across organizations that have never heard of each other. Pattern mining over independent signed sources, no shared platform required.
- Containment is literal string prefixing. A second nests in its minute, the minute in its hour:
ust:20260710.14⊃ust:20260710.1429⊃ust:20260710.142900. Roll-ups and drill-downs are prefix scans; a parent frame can attest its children (attestation + Merkle root over their content hashes), so "the hour" becomes a signed aggregate of its seconds — provably complete over a closed range (verifyStream). - Sortable = streamable. Fixed-width UTC fields sort lexicographically in time order; a time range is a string range. Storage keys, feeds and archives inherit chronology for free.
Honesty holds on this axis too: at LIGHT the coordinate is the publisher's claimed frame; a TOP anchor
proves the document existed by a real point in time (and generated_at may not postdate its own anchor).
In an agent world nobody can hand you truth as a boolean. The closest thing to truth an agent can actually hold is earned confidence — made of two honest quantities: how much evidence the publisher staked (a signature; a name provably bound to the key; an anchor in real time), and how much of it the verifier could actually confirm, here and now. Not one flattering "yes" — a measured answer to "how strongly is this proven, to me, at this moment?"
| verdict | what is proven |
|---|---|
VALID:LIGHT |
the exact bytes · the signing key · the claimed time frame. Identity is the key itself (a self-certifying sha256: shard = key-form domain_shard); a name-form domain_shard (a real domain) is a domain claim the floor cannot confirm → INDETERMINATE, never a bare VALID:LIGHT. |
VALID:HIGH |
+ the publisher's name is provably bound to the key (genesis + key log). The reference verifiers collect this automatically from the standard surfaces (§20.1/§12.1a). Strength corroborated — the publisher's own witness shows no rival — or authoritative — independent non-membership (an anchored name-map inclusion, or a caller air-gap assertion); only authoritative names the definitive publisher and reaches TOP. |
VALID:TOP |
+ the document provably existed by a point in real time (anchor inclusion, e.g. Bitcoin/OTS). Stream completeness is a separate range verdict (verifyStream). |
INVALID |
a definite, deterministic failure (specific E-* codes) |
INDETERMINATE |
a dependency was unreachable, or an optional algorithm is unimplemented — cannot decide is never conflated with forged |
One signal the protocol never emits: "true." UST proves fixation, not truth — a publisher committed to these bytes at this time and cannot silently rewrite them. Whether the reading was correct is out of scope by construction; you learn whom to hold accountable and that nothing was tampered.
The part that makes UST more than "signed JSON": a single connected state does not have to be one document.
It can be a chain of independently signed layers, each a full transcript with its own key, time frame and
provenance — linked by content hashes (based_on + a recomputed seed), so the existence, order and lineage
of every layer are publicly provable while each layer's content is disclosed only to whom it is meant for:
- Blinded (
privacy: "blinded"): the value is replaced by a frame-bound commitment (H(domain_shard, ust_id, nonce, name, value)). Publish now, reveal later — and the revealed{nonce, value}provably reproduces the original commitment: it cannot be quietly swapped, moved to another hour, or re-attributed to another publisher. Embargoed results, private forecasts, positions, proof-of-priority. - Encrypted (
privacy: "encrypted"): ciphertext and commitment coexist; after decryption the verifier checks that the plaintext reproduces the same commitment (E-COMMITon mismatch) — "the ciphertext really contains what was publicly committed" is a checked obligation, not a promise. - Cross-party derivation: a partner who receives a layer can sign their own transcript on top
(
class: "derivation",based_on: [hash]) under their own key — an auditor later walks the whole chain, verifying each available layer independently. Trust composes, but is never inherited automatically: holding an outer layer does not vouch for the inner ones; each signature is checked on its own. - Deletable without breaking the proof: anchors commit to hashes, not contents — sensitive payloads can be destroyed later while "this existed, in this order, at this time" remains provable forever (and nothing can be forged back under the old hash).
Different consumers hold different depths of the same reality — the public sees L1, a client L1–L2, a partner L1–L3, an auditor the whole chain — and every one of them can verify exactly what they hold. That is the protocol's real subject: differentiated, provable access to a shared machine state.
UST is not a silver bullet, and it does not replace anything you run — not your telemetry, not your signing, not your lineage, not your logs. Each of those tools does its job well. What none of them defines is a portable object of state that travels between them and stays verifiable wherever it lands. That object is what UST standardizes. The only thing it replaces is the glue code you would otherwise write yourself.
| you already run | it keeps doing | a transcript adds |
|---|---|---|
| JWS / DSSE | signing any payload | a standard shape for the payload itself: id, time, partitions, provenance, tiers |
| Sigstore / Rekor | keyless signing, transparency log | a Rekor receipt slots in as anchor evidence — the same document, stronger time |
| in-toto / SLSA | build policy & provenance | an SLSA statement rides in a partition; based_on links it to its inputs |
| IETF SCITT | registries & receipts | a UST is a ready signed-statement payload; the receipt strengthens the same doc |
| C2PA | media provenance | the machine state around the shot — camera, sensors, model, decision — sealed next to it |
| W3C Verifiable Credentials | who the actor is, what they may do | what the actor observed, computed or did at t — VC certifies the actor, UST fixes the act |
| OpenLineage | dataset/job/run semantics | each run event becomes a signed, portable lineage node — verifiable without the backend |
| OpenTelemetry + SIEM | mass telemetry, search, alerting | the few checkpoints you must prove get sealed as transcripts; the rest stays telemetry |
| CloudTrail + Object Lock | managed audit & retention | seal at the source — the document stays provable outside the origin cloud |
| IPFS + OpenTimestamps | content addressing, proof-of-existence | one object that carries the address, the time, the signer and the verdict together |
The glue this replaces — what a comparable assembly looks like written by hand:
app schema + signing envelope + custom canonicalization + key-rotation DB
+ provenance graph + timestamping + WORM store + commitment conventions
+ custom verifier + custom trust semantics
With UST:
UST transcript + key custody of your choice
(+ optional discovery, + optional anchor, + optional storage of your choice)
If you need exactly one of those jobs, use that tool alone — you may not need UST at all. UST earns its place the moment state has to cross a boundary — between tools, between organizations, between clouds, or across time — and still prove itself on the other side.
Tools sign files, log events, timestamp hashes, record lineage. A UST carries the state between them — portable, layered, verifiable on arrival.
Produce and verify a LIGHT transcript — a signer, a frame, one verify call:
import { generateSigner, signObservation, nowFrame } from '@ust-protocol/web-signer';
import { verify } from 'ust-protocol';
const s = await generateSigner(); // Ed25519, non-extractable
const { ust_id, time } = nowFrame(); // instant capture frame
const doc = await signObservation(s, { ust_id, time, data: { capture: { kind: 'captured', value: { text: 'exact bytes' } } } });
console.log(verify(doc, { context: 'data' }).result); // → VALID:LIGHTWorking on the protocol itself? npm install && npm test runs the conformance suite (spec == package == vectors) —
see CONTRIBUTING.md.
npm i -g @ust-protocol/cli # installs the `ust` command
ust verify doc.json # exit 0 = VALID (tier in the verdict), 1 = not; auto-detects genesis/key context
# auto-resolves discovery + witness → VALID:HIGH out of the box (no-fork as EVIDENCE)
ust canon doc.json # canonical bytes + hash — diff any other-language implementation against this
ust genesis --domain example.org --profile silver --dns cf-api # the HIGH name-binding ceremony
ust witness rekor --domain example.org --deploy # log the genesis to Sigstore Rekor + serve the witnessOne entrypoint; the planned Go binary reproduces this exact surface. The ceremony self-verifies its outputs
(fail-closed) and upserts the _ust DNS TXT with a DNS-over-HTTPS readback. Witness anchors are cross-checked
against their substrate (Bitcoin via @ust-protocol/ots-verify, Rekor via @ust-protocol/rekor-verify —
opt-in plugins; the core verifier embeds no blockchain).
UST proves fixation, not truth: this publisher committed to this data, at this time, unchanged. It does not prove the data is correct — a publisher can sign a wrong reading. You learn whom to hold accountable and that nothing was tampered — a real, bounded guarantee, not an oracle of truth.
The precise semantics of every verdict — verification as a measurability test over three nested σ-algebras —
is the formal model: spec/UST-1.0-formal-model.md (non-normative).
Not every rung is equally settled. The STABILITY export is the machine-readable map:
| tier / rung | status |
|---|---|
LIGHT, HIGH |
stable — three independent adversarial audit rounds left them intact |
corroborated freshness |
experimental-usable |
attested freshness |
experimental extension — the STABLE verifier does not emit it |
attested (independent anti-equivocation over a checkpoint) is being re-based on a closed verification kernel
(mandatory append-only consistency proof, scope-bound pinning, one shared node/browser core). Until those ship
gates pass, deriveCheckpointFreshness caps a would-be attested result at corroborated and names the withheld
rung (attested_withheld: "experimental-gate"); the top rung is reachable only with an explicit
allowExperimentalAttested: true opt-in. This keeps the whole protocol from inheriting the youngest layer's risk.
| Path | What |
|---|---|
spec/UST-1.0.md |
the specification (normative) |
spec/UST-1.0-formal-model.md |
a measure-theoretic semantics (non-normative appendix) |
PORTING.md |
porting UST to another language — the narrowed value model, the vector arbiter, the crypto boundary |
vectors/ |
deterministic conformance vectors — any implementation should pass them (the cross-language canon arbiter) |
packages/ust-protocol/ |
the stateless reference verifier + producer (npm) |
packages/ust-mcp/ |
an MCP server exposing UST to agents (npm) |
packages/ust-web-signer/ |
WebCrypto browser signer (npm) |
packages/ust-cli/ |
the ust command — verify / canon / the HIGH genesis ceremony / witness (npm) |
packages/ust-ots-verify/ |
opt-in Bitcoin (OpenTimestamps) anchor-substrate plugin (npm) |
packages/ust-rekor-verify/ |
opt-in Sigstore Rekor anchor-substrate plugin (npm) |
extension/ |
"Make it UST" — a demo Chrome extension: sign by selection, verify by selection (LIGHT) |
docs/ |
the web verifier (client-side, GitHub Pages) + ust-verify.mjs, a zero-dependency verifier + llms.txt |
examples/ |
sample documents (valid + tampered) and verification recipes |
Code: Apache-2.0. Specification text: CC BY 4.0. Source code (packages/**, tooling) is licensed under
the Apache License 2.0 (LICENSE); the specification and documentation prose (spec/** and other .md docs)
under Creative Commons Attribution 4.0 International (LICENSE-SPEC). The names UST / Universal State
Transcript and the UST-compatible claim: see TRADEMARK.md. How changes are made:
GOVERNANCE.md.
© 2026 THE LAB