Predicate registry
Typed, schema-validated receipt payloads. Registered predicate kinds are validated against a JSON Schema at attest time; unregistered kinds attest sign-on-submit, exactly as before.
Predicate registry
A Treeship receipt (treeship/receipt/v1) carries a free-form kind and an opaque JSON payload. The predicate registry makes specific kind values typed: each registered suffix is bound to a JSON Schema, and at attest time the payload is validated against that schema before the receipt is signed. A downstream verifier can then rely on the shape of a registered predicate, not just the signature.
This is additive and backward compatible:
- If
kindis registered, the payload must conform to its schema. A failure rejects the attest with a clear error, nothing is signed. - If
kindis not registered, the receipt attests sign-on-submit, exactly as before. Existing artifact types, signing logic, and chain structure are untouched.
# Registered: validated, then signed.
treeship attest receipt --system system://zmem --kind memory.write.v1 \
--payload '{"memory_id":"mem_1","content_hash":"sha256:ab","memory_type":"episodic","scope":"tenant://acme"}'
# Missing a required field: rejected before signing.
treeship attest receipt --system system://zmem --kind memory.write.v1 \
--payload '{"memory_id":"mem_1","memory_type":"episodic","scope":"tenant://acme"}'
# -> predicate validation failed: memory.write.v1: missing required field `content_hash`
# Unregistered kind: still works, sign-on-submit.
treeship attest receipt --system system://stripe --kind webhook.confirmation --payload '{"...":"..."}'Validation depth
Core runs a small, dependency-free structural check: every required field is present, and each present field whose schema declares a primitive type matches it (including unions like ["string","null"]). That is the complete contract for the flat memory predicates below.
boundary.v1 is a richer schema (const/enum/pattern/$ref). Core enforces its required-field and type structure; the full constraint set is delegated to the canonical published schema for external validators. The core validator is kept dependency-free on purpose so the security-critical signing path and the WASM verifier stay lean.
Registered predicates
memory.write.v1
A specific agent committed a specific memory at a specific time.
| Field | Type | Required |
|---|---|---|
memory_id | string | yes |
content_hash | string | yes |
memory_type | string | yes |
scope | string | yes |
activegraph_event_id | string | no |
activegraph_run_id | string | no |
supersedes | string or null | no |
memory.read.v1
Which memories an agent retrieved for an action, and the query that produced them.
| Field | Type | Required |
|---|---|---|
zmem_receipt_id | string | yes |
trace_sha256 | string | yes |
query_hash | string | yes |
retrieval_mode | string | yes |
memories_returned | integer | yes |
activegraph_event_id | string | no |
activegraph_run_id | string | no |
scope | string | no |
boundary.v1
A provider-neutral actor-checker evaluation boundary: what a checker was allowed to see, what policy denied, and the decision it reached. See Actor-Checker Boundaries for the model. The full schema is treeship.boundary.v1.
workflow.v1
A signed declaration of the path an agent workflow is allowed to take: its nodes, the edges between them, which node starts a run, which nodes may end one, and how many times a loop may repeat.
Declared before execution and signed, so the allowed path provably pre-exists the run it judges. Treeship then reconstructs the observed path from captured receipts and reports whether it conformed.
Treeship does not execute, schedule, or enforce the workflow. A declaration is evidence about a run, evaluated after the fact — the runtime (LangGraph, Temporal, Claude Code, an orchestrator of your own) still does the work. A clean report means every action in the evidence set fit the declaration and no declared step lacked evidence; it does not mean the evidence set is complete. See Workflow declarations for the model, including the three graphs (declared, observed, evidence) the verifier keeps separate.
| Field | Type | Required |
|---|---|---|
kind | const workflow.v1 | yes |
schema_version | const 1 | yes |
workflow_id | string | yes |
authority | string (actor URI that declared it) | yes |
entry_node | string (node id a run must start at) | yes |
terminal_nodes | array of node ids a run may end at | yes |
nodes | array (declared steps, with their allowed actors and tools) | yes |
edges | array (allowed transitions between nodes) | yes |
loops | array (bounded repeats, with an explicit iteration limit) | no |
agent_card.v1
A signed, verifiable agent capability card: a key attests an identity and a capability set. Carried as the payload of a receipt with kind=agent_card.v1. A card is key-bound only when its keyid is the envelope signer pinned under AgentCert; self-signed cards are reported self-asserted. Mint with treeship attest card; check against captured evidence with treeship verify-capability. See Capability Cards.
| Field | Type | Required |
|---|---|---|
schema | const agent_card.v1 | yes |
agent | string (actor URI) | yes |
keyid | string | yes |
version | string | yes |
capabilities | object (tools: exact or family.*) | yes |
owner | string | no |
supersedes | string or null | no |
constraints | object | no |
attestations | array | no |
evidence_anchor | object | no |
policy_ref | string | no |
agent_card_revocation.v1
Revokes a previously-minted agent_card.v1. Mint with treeship revoke-capability. verify-capability honors a revocation only when its signer is authorized — the card's own key (self-revocation) or a key pinned under the revoker trust kind (issuer revocation); any other signer is ignored (fail-closed).
The old single ship trust kind is deprecated and inert: no verifier accepts it, and treeship trust add --kind ship is rejected outright. It used to grant three unrelated powers at once — hub dedup, certificate issuance, and capability revocation — so pinning a hub silently let it kill capabilities. Pin revoker for this power, cert_issuer to issue certificates, hub_org for global single-use.
| Field | Type | Required |
|---|---|---|
schema | const agent_card_revocation.v1 | yes |
card | string (art_… of the revoked card) | yes |
revoked_at | string (RFC3339) | yes |
keyid | string | no |
reason | string | no |
supersedes | string or null | no |
agent_cert.v1
The ship-signed certificate binding a per-agent key to its agent:// URI. This
is what makes an actor proven (key-bound) rather than asserted. Minted by
treeship agent register --own-key and treeship onboard.
| Field | Type | Required |
|---|---|---|
agent | string (actor URI) | yes |
subject_key_id | string | yes |
subject_public_key | string | yes |
issuer | string | yes |
issued_at | string (RFC3339) | yes |
valid_until | string (RFC3339) | yes |
model | string or null | no |
description | string or null | no |
grant_revocation.v1
Withdraws a capability grant. Minted by treeship grant revoke. Only the grantor
may revoke — a revocation anyone could mint would be a denial of service against
every grant whose id they know, and grant ids appear in published receipts.
Actions signed before the revocation instant remain authorized.
| Field | Type | Required |
|---|---|---|
schema | const grant_revocation.v1 | yes |
grant_id | string | yes |
grantor | string | yes |
revoked_at | string (RFC3339) | yes |
reason | string | no |
session.v1
The actor-signed record of a completed session — the authenticated counterpart
to a .treeship package, which binds artifacts and the Merkle root but not the
narrative. treeship history and treeship profile read these.
19 fields; the seven required are session_id, actor, outcome,
started_at, closed_at, plus the schema's structural fields. Optional fields
cover headline, duration_ms, harness, and a custody object.
profile.v1
A derived, checkpoint-pinned track record over an agent's work history. Every
number recomputes from the log at the pinned checkpoint, which is what makes
treeship verify-profile able to call a mismatch a provable lie rather than a
disagreement.
15 fields, 6 required: agent, checkpoint_index, checkpoint_tree_size,
checkpoint_root, computed_at, sessions_total. The checkpoint triple is
what pins the claim to a point in the log.
blocked.v1
Records that an action was refused — the negative-space receipt. Two required
fields, reason_class and refused_kind; the rest (approver, actor,
irreversibility, quarantine_receipt, evidence_digest, reevaluate_when)
describe what was refused and under what authority.
verification.packet.v1
A prover's signed record of one discrete workload packet: which model, over
which input, produced which output, at which position in a stream. Signed by
the party that ran the workload (--system system://<prover>). It records the
packet so a recomputation can be checked against it later; it does not itself
claim the packet is reproducible or correct. sequence and prev_packet_id
let a verifier detect a dropped packet, not only a wrong one. See
Verification reporting.
| Field | Type | Required |
|---|---|---|
schema | const verification.packet.v1 | yes |
packet_id | string | yes |
stream_id | string | yes |
sequence | integer | yes |
model_digest | string (sha256:…) | yes |
input_digest | string | yes |
output_digest | string | yes |
produced_at | string (RFC3339) | yes |
prev_packet_id | string or null | no |
sampler_digest | string | no |
runtime_digest | string | no |
hardware_id | string | no |
token_count | integer | no |
reproducibility | enum bit_exact, bounded, none | no |
verification.recompute.v1
A verifier's signed result of recomputing one packet against its
verification.packet.v1 receipt. Signed by the party that ran the
recomputation (--system system://<verifier>), with --subject set to the
packet receipt's art_ id so the result chains onto the claim it checks. A
verdict outside match, mismatch, inconclusive is refused before
signing. method is free-form (bit_exact, difr, toploc, …) so a new
scheme needs no registry change.
| Field | Type | Required |
|---|---|---|
schema | const verification.recompute.v1 | yes |
packet | string (art_… of the packet receipt) | yes |
packet_id | string | yes |
method | string | yes |
verdict | enum match, mismatch, inconclusive | yes |
recomputed_at | string (RFC3339) | yes |
output_digest_recomputed | string | no |
distance | number | no |
threshold | number | no |
sample_seed | string | no |
recomputer_hardware | string | no |
notes | string | no |
evaluation.v1
An evaluator's signed result of running a named suite against a subject: a
model, an agent, a session or a sealed package. Signed by the evaluator's key
(--system system://<evaluator>), with --subject set to the artifact it
grades when the subject is a session or package, so the grade chains onto the
thing graded and verify walks from one to the other. It records what was
evaluated, with which suite (by digest, so two parties can agree they ran the
same thing), and what the evaluator concluded; it does not make the
evaluation sound. verdict and subject_kind are validated before signing.
The self-asserted rule. A grade is only as independent as its signer. A
receipt whose signing key is the same key that signs the subject's own
receipts is a self-assessment, whatever subject_actor says. A checker should
treat it as self-asserted and require the evaluator's key to be pinned under
its own trust root before reading a pass as a certification. This is the
receipt a capability-checkpoint scheme ("a model with capability X carries
certification Y") needs, and the rule is what keeps the graded agent from
grading itself.
| Field | Type | Required |
|---|---|---|
schema | const evaluation.v1 | yes |
subject_kind | enum model, agent, session, package | yes |
subject_digest | string (sha256:…, art_…, ssn_…) | yes |
suite_id | string | yes |
suite_digest | string | yes |
result_digest | string | yes |
verdict | enum pass, fail, inconclusive | yes |
evaluated_at | string (RFC3339) | yes |
subject_actor | string (actor URI) | no |
environment_digest | string | no |
score | number | no |
threshold | number | no |
capability | string | no |
coverage | string (art_… of a coverage.v1 receipt) | no |
notes | string | no |
coverage.v1
The denominator for "we monitored this". treeship session close mints one
per session, chained onto the close artifact and sealed in the package, so a
reader of the timeline knows what the harness was in a position to see. Two
halves, kept apart on purpose: declared copies each attached harness's
state file (status, potential coverage level, connection modes, the known
gaps frozen at install time), and observed counts what actually reached
the event log, by type. declared_level is the highest potential level among
the attached harnesses, or none when the workspace has no harness state. It
is a potential, never a claim that the harness captured anything; observed
is the claim, and gaps says in plain words what the record does not cover.
Signed by the ship's key: it is the session host's statement about its own
instrumentation, and a verifier who pinned the ship key as session_host
checks it with nothing more. An evaluator's
evaluation.v1 can point at it through its coverage
field. package verify reports it as the coverage row and warns when a
package carries none.
| Field | Type | Required |
|---|---|---|
schema | const coverage.v1 | yes |
session_id | string | yes |
actor | string (actor URI) | yes |
declared_level | enum high, medium, basic, backstop-only, none | yes |
harnesses | array of {harness_id, status, coverage, connection_modes[], known_gaps[], last_verified_at} | yes |
observed | object {events, event_types{type: count}, hosts[], agent_instances, first_event_at, last_event_at, event_log_skipped} | yes |
gaps | array of strings | no |
closed_at | string (RFC3339) | yes |
halt.v1
The kill switch, as a record. An operator's signed order that an actor (or
*, every actor in the workspace) must stop, or that a previous halt is
lifted. Minted by treeship halt <actor> and treeship halt --lift <actor>,
signed by the workspace's own key, chained onto the active session so the
sealed package shows when the switch was thrown, by whom, and when it was
lifted. While a halt stands, the harness gate refuses every tool call for
that actor and signs each refusal as blocked.v1 with
reason_class: operator_revocation. A marker without a matching signed
artifact from this workspace is reported as ignored by halt list and not
honoured by the gate.
What it reaches: every tool call the harness routes through hooks. What it does not: a process an agent started outside them. See the Claude Code gate.
| Field | Type | Required |
|---|---|---|
schema | const halt.v1 | yes |
action | enum halt, lift | yes |
actor | string (actor URI or *) | yes |
issued_at | string (RFC3339) | yes |
reason | string | no |
halt | string (art_… of the halt a lift ends) | no |
judgement.v1
A model's typed judgement, as the caller received it, and what the caller did
with it. Any judge: a decision model such as Jev, an LLM prompted to judge, a
classifier, or a deterministic rules engine. Signed by the party that asked
and acted, with --subject set to the action it gated so the judgement
chains onto the thing it decided. It carries the model and version, digests
of the state and the questions (committed to, not published), the one
question by key and type, the typed answer with its full probability
distribution and confidence, the threshold the caller held the answer to and
who set that threshold, and the outcome: acted, escalated, refused or
ignored. question.type, outcome and judge.kind are validated before
signing, and every probability is checked to lie in 0 to 1.
What it proves and what it does not. It is the caller's attestation of what
the judge returned and what was done about it, under which bar. A judge that
cannot be replayed (replayable: false, which is every sampled model)
cannot be re-run by a verifier, so the receipt does not prove the judge said
exactly this; it proves the caller committed to it before acting. It never
proves the judgement was right. A rules engine that is replayable is the one
kind of judge whose answer a verifier can reproduce from the same state.
package verify reports sealed judgements as the judgements row and flags
any that was acted on against its own bar (a yes answer allowed, a no answer refused, or no bar declared). treeship judge
mints these: the built-in rules judge, or any judge behind --judge-url.
| Field | Type | Required |
|---|---|---|
schema | const judgement.v1 | yes |
judge | object {model, provider, kind, replayable, request_id} with kind one of decision-model, llm, classifier, rules; request_id is the judge's own id for the answer when it gives one | yes (model) |
contract | object {id, version}: the versioned decision contract the judgement ran under | no |
state_digest | string (sha256:<hex>) | no |
questions_digest | string (sha256:<hex>) | no |
response_digest | string (sha256:<hex> of the raw response bytes the judge returned, as received by the caller) | no |
question | object {key, type, instructions, options[]} with type one of noul, choice, score | yes (key, type) |
answer | object {noul, choice, score, probabilities{}, confidence} | yes |
threshold | object {value, applies_to, set_by} with applies_to confidence or noul | no |
outcome | enum acted, escalated, refused, ignored | yes |
effect | string (allow, warn, deny, ask) | no |
latency_ms | integer | no |
usage | object {input_tokens, output_tokens} | no |
judged_at | string (RFC3339) | yes |
notes | string | no |
judgement.resolution.v1
A person's decision (or a stronger judge's) on a judgement that was escalated
or refused: the human label, as its own signed artifact. Minted by
treeship judge --resolve
under the decider's URI (human://alice), with the judgement as the receipt's
subject, and chained onto the session. decision is a closed vocabulary
(allow, deny, route); overrides names the judgement's effect this
decision replaces, when they differ. package verify pairs resolutions with
escalated judgements in the judgements row and reports an escalation with no
resolution in the package as open.
| Field | Type | Required |
|---|---|---|
schema | const judgement.resolution.v1 | yes |
judgement | string (art_… of the judgement) | yes |
by | string (decider URI) | yes |
decision | enum allow, deny, route | yes |
route | string (for route) | no |
overrides | string (the judgement's effect this replaces) | no |
reason | string | no |
resolved_at | string (RFC3339) | yes |
memory.quarantine-check.v1
Gates an approval on a memory-provider quarantine result. Required:
action_id, chain_root, decision_seq, clean. A grant with
--irreversibility one_way_consequential or higher requires one of these,
clean, signed by a key pinned under agent_cert.
reason.authorization.v1
An authorization decision from a reasoning provider. All seven fields are
required: schema, status, request_digest, mission, action,
reasoning, issues — the schema refuses a partial decision, so a receipt
cannot record a verdict without the reasoning behind it.
Actor URI schemes
A receipt or statement actor is an opaque string; Treeship does not enforce the scheme. These prefixes are the recognized conventions:
| Scheme | Meaning | Example |
|---|---|---|
human:// | A human principal | human://alice |
agent:// | An autonomous agent | agent://support-bot |
zerker:// | An agent behind the Zerker Gateway, addressed by its gateway agent ID | zerker://agt_12345 |
zerker://agt_<gateway_agent_id> works today with no special handling, it is a documented convention, not a validated type. (Actor strings written under the former farcaster://fid:<n> convention remain valid — actors are opaque.)
Schema versioning
schema_version field on receipts and certificates, legacy rules for missing field, forward compatibility guarantees.
Protocol specs index
Every design spec in docs/specs/, with its real implementation status — frontiers get a spec before code, and this index says which frontiers have been reached.