Treeship 0.18: onboard once, present anywhere
What shipped
Four releases in two days completed the identity stack. An agent now goes from nothing to verifiable with treeship onboard, carries its own certificate chain to its ship, hands a counterparty a presentation that verifies fully offline, and answers a live challenge to prove it holds the key right now. Its closed sessions become signed work-history records, and its track record is pinned to a Merkle checkpoint so a mismatch is a provable lie.
From 0.16.0:
treeship session closemints asession.v1receipt with headline, outcome, duration,tools_exercised, counts, areceipt_digest, and an attestation class ofself,runtime, orcountersigned.treeship keys exportprints a key's public half ased25519:<base64url>together with the exacttreeship trust addcommands a counterparty runs.- Capability matching now handles mid-pattern globs like
Bash(git:*)captured from a Claude Codesettings.json.
From 0.17.0:
agent register --own-keyalso mints a typedagent_cert.v1receipt, signed by the ship key, bindingagent://<name>to its per-agent public key.treeship presentandverify-presentationcarry the card, the cert chain, known revocations, and a Merkle staple, with--max-staple-ageturning freshness into aSTALEverdict.present --challenge <nonce>andverify-presentation --challengeprove the bearer controls the key now.treeship onboardcomposes register,attest card, and--publishin one idempotent pass.
From 0.17.1 and 0.18.0:
merkle publishandmerkle proofbuild the tree truncated to the checkpoint'stree_size, andmerkle proofrefuses an artifact newer than the checkpoint.resolve,audit,verify-capability, andverify-presentationexit nonzero on a hostile verdict and emit one JSON verdict object under--format json.treeship profileandverify-profilecompute a checkpoint-pinned track record, with--attestsigning it as aprofile.v1claim.treeship history <agent>projects the log to signedsession.v1records, filterable with--class self|runtime|countersigned,--since, and--limit.
Why it matters
Before 0.17.0 a counterparty had to pin every agent's leaf key by hand, and verification needed a registry in the loop. Now a counterparty pins one ship key and verifies every agent under it, the same shape as a TLS chain. A static presentation proves the record, and the challenge proves the bearer.
Two bugs found by dogfooding made the fixes urgent. Registering a second agent in the same workspace silently overwrote the first agent's card, because the agent's name was not part of derive_agent_id. And every Merkle proof emitted after a checkpoint reconstructed the wrong root, so legitimate artifacts read inclusion INVALID to every auditor. Both are fixed and regression-tested.
How it works
treeship onboard <agent> --publish
treeship keys export
treeship present <agent>
treeship verify-presentation <path> --max-staple-age 15m
treeship present <agent> --challenge <nonce>
treeship verify-presentation <path> --challenge <nonce>
treeship profile <agent> --attest
treeship verify-profile <path>
treeship history <agent> --class countersignedonboard runs agent register --own-key, attest card from --from-harness, --tools-json, --from-a2a, or --tools, and with --publish the full publish, merkle checkpoint, and merkle publish anchor. It ends by printing the trust bundle: the trust add commands for agent_cert and hub_checkpoint, plus the resolve and audit commands that verify the agent.
verify-presentation walks the agent_cert.v1 chain to a pinned ship root, with the pubkey always taken from your trust store and never from the wire. It enforces the validity window fail-closed, honors authorized revocations, re-checks the staple's checkpoint signature and inclusion proof, and reports the staple age as an explicit bound. In challenge mode the response is checked only against the subject key the card verification itself established. A replayed response, a response signed by a non-card key, or a tampered timestamp each reject with a specific reason.
verify-profile rebuilds the log's first tree_size leaves at the pinned checkpoint, cross-checks the root against the pin, recomputes every field through the same aggregation path as profile, and compares. A match grades the profile checked. A mismatch names the differing field and exits nonzero. history re-verifies every session.v1 envelope on your machine and re-proves each anchored entry's inclusion offline.
What it does not do
- A static presentation is replayable. It proves the record, not the bearer. Only challenge mode proves live key control.
- The
session.v1record is best-effort. A record failure warns and never wedgessession close, and the sealed package stays the source of truth. anchoredis not an attestation class the record carries. It is a later, derivable state.- History proves what was recorded, never everything that happened.
- Keystore entries rewrapped under the hardware machine key in 0.16.0 are not decryptable by older binaries. Keep one CLI version per machine.
keys exportin this range emits--kind ship. The kind was split three ways in 0.19.0.
Where to go next
- The agent handshake
- Agent identity
- CLI: present / verify-presentation
- CLI: onboard
- CLI: profile / verify-profile
- Treeship 0.19: the security-hardening release
This entry was written on 11 September 2026 from the 0.16.0, 0.17.0, 0.17.1, and 0.18.0 changelog and the code as released, and is filed under the release date.