Treeship
Get started

How it works

Signing, chaining, actors, verification, Hub, and Merkle proofs explained.

This page explains the mechanics behind Treeship. If you have not run the quickstart yet, start there. Come back here when you want to understand what is happening under the hood.

Signing

Every artifact Treeship produces is an Ed25519 signature over a structured payload.

When you run treeship init, a new Ed25519 keypair is generated and encrypted at rest on your machine. This key never leaves your device unless you explicitly export it. Every artifact your Treeship produces is signed with this key, which means anyone with access to your public key can verify any artifact you have ever created.

The signature format follows DSSE (Dead Simple Signing Envelope):

DSSE envelope
├── payloadType: application/vnd.treeship.action.v1+json
├── payload (base64-encoded JSON):
│   {
│     type:          "treeship/action/v1",
│     timestamp:     "2026-03-26T21:00:00Z",
│     actor:         "agent://researcher",
│     action:        "document.analyze",
│     parentId:      "art_previousstep",
│     approvalNonce: "nce_7f8e9d0a",
│     meta:          { ... }
│   }
└── signatures:
    [{ keyid: "key_9f8e7d6c", sig: "base64url(ed25519_sig)" }]

The signature is computed over PAE(payloadType, payload) (Pre-Authentication Encoding), which prevents type confusion attacks where a valid signature for one payload type could be reused for another.

Chaining

Artifacts form an ordered chain through parentId references.

When you create a new artifact, Treeship automatically sets its parentId to the ID of the most recent artifact in your local store. The artifact ID itself is derived from sha256(PAE_bytes)[..16], which means the ID is a content hash. If anyone tampers with the payload, the ID no longer matches and verification fails.

This gives you two properties:

  1. Ordering. You can walk the chain from any artifact back to the first one.
  2. Tamper evidence. Modifying, inserting, or removing any artifact breaks the chain for every artifact that follows it.

Actors

An actor is any entity that performs work inside your Treeship. Actors are identified by URI:

PrefixMeaningExample
human://A human identityhuman://alice
agent://An AI agent or automationagent://deployer
system://An external system (used in receipts)system://stripe-webhook

URIs are freeform after the prefix. Use whatever naming convention fits your organization.

All actors sign under the same Treeship key. The actor URI identifies who performed the action; the Treeship key proves which trust domain the action belongs to. This separation matters because a single Treeship often has multiple actors (a developer, a CI bot, and several AI agents) all contributing to the same chain of work.

Actors do not have their own keys. The Treeship key is the root of trust, and the actor URI is metadata within the signed payload. This keeps the key management surface small: one key to protect, one key to rotate, one key to verify against.

Actors appear in different roles depending on the attestation type:

AttestationFlagRole
Action--actorWho performed the action
Approval--approverWho authorized the action
Handoff--from / --toSender and receiver of work
Receipt--systemExternal system producing the receipt

Being referenced as an actor does not grant permission to act. To take a sensitive action, an agent still needs an approval from an authorized approver.

Verification

Verification is fully offline and deterministic. No network call, no server, no account.

treeship verify art_f7e6d5c4

The verifier performs the following checks:

Recompute the artifact ID

Derive the expected ID from sha256(PAE_bytes)[..16] and compare it to the stored ID. If they do not match, the payload has been tampered with.

Check the Ed25519 signature

Verify the signature in the DSSE envelope against the Treeship's public key. A bad signature means the artifact was not produced by the claimed Treeship.

Validate the statement schema

Confirm the payload conforms to the expected Treeship statement schema for its declared type.

Walk the parent chain

Follow parentId links recursively, verifying each ancestor artifact the same way. A broken link at any point fails the entire chain.

Check approval binding, scope, and replay (if present)

If the artifact references an approvalNonce, confirm a matching signed approval exists; if the approval has a scope, confirm the action's actor / action / subject fall inside the signed allow-lists; observe whether the same nonce was consumed earlier inside this verified package. Verify reports each property as a separate line and is explicit that cross-package replay enforcement is on the v0.10 / v0.11 roadmap, not yet shipped.

Return the result

Exit 0 means the full chain is intact. Exit 1 means something failed, with reasons printed.

The verifier is open source and MIT licensed. You can audit it, embed it in CI, or run it in a browser. Trust the math, not the infrastructure.

Hub

Hub is the optional sharing layer. It adds discoverability and public verify URLs, but it never adds trust. The signatures are the trust.

Hub connections

A hub connection is a named link between your local Treeship and a workspace on Hub. Hub connections work like tmux sessions: you can attach, detach, and kill them independently. Your Treeship stays the same regardless of how many hub connections exist.

tmuxTreeshipWhat it does
tmux new -s worktreeship hub attach --name workCreate a new named connection
tmux attach -t worktreeship hub use workSwitch to an existing connection
tmux detachtreeship hub detachDisconnect without destroying (keys preserved)
tmux kill-session -t worktreeship hub kill workRemove the connection permanently
tmux lstreeship hub lsList all connections

Hub connections are about audiences, not environments. The Treeship key stays the same across all hub connections. Artifacts never change. Hub connections only control where artifacts appear on Hub.

Treeship (one keypair, one artifact store)
 |-- hub: default  -> hub.treeship.dev/alice/personal
 |-- hub: acme     -> hub.treeship.dev/acme-corp/projects
 +-- hub: client-x -> hub.treeship.dev/clientx/deliverables

Most developers need exactly one hub connection.

When you attach to Hub, your Treeship's public key is registered. If the same public key appears in multiple hub connections, Hub knows they belong to the same Treeship. This is how Hub links workspaces to identities without requiring accounts or emails.

Attach and detach

Hub uses a device-authorization flow. When you run treeship hub attach, the CLI prints a URL and a short code. You visit the URL in a browser, enter the code, and approve the connection. From that point on, the CLI can push artifacts to your Hub workspace.

Detach disconnects the active hub connection but preserves all keys locally. You can re-attach later without re-authenticating.

Kill removes the hub connection from local config permanently. Artifacts already pushed to Hub remain there: they are content-addressed and independently verifiable.

DPoP authentication

Hub connections use DPoP (Demonstration of Proof-of-Possession) tokens. Each API request includes a proof that the caller holds the private key associated with the connection. This prevents token theft: a stolen access token is useless without the corresponding private key.

Hub connection commands

CommandDescription
treeship hub attachConnect to Hub (creates new or reconnects)
treeship hub attach --name <name>Create or reconnect a named hub connection
treeship hub detachDisconnect active hub connection (keeps keys)
treeship hub lsList all known hub connections
treeship hub statusShow active hub connection details
treeship hub use <name>Switch active hub connection
treeship hub push <id>Push artifact to active hub connection
treeship hub push <id> --hub <name>Push to a specific hub connection
treeship hub push <id> --allPush to all hub connections
treeship hub pull <id>Pull artifact from Hub
treeship hub openOpen workspace in browser
treeship hub kill <name>Remove a hub connection

Hub connection config

Hub connections are stored in ~/.treeship/config.json:

{
  "hub_connections": {
    "default": {
      "hub_id": "hub_661e5463912d",
      "key_id": "key_9f8e7d6c",
      "endpoint": "api.treeship.dev"
    },
    "work": {
      "hub_id": "hub_a2b3c4d5e6f7",
      "key_id": "key_9f8e7d6c",
      "endpoint": "api.treeship.dev"
    }
  },
  "active_hub": "default"
}

Each hub connection has its own DPoP keypair for authenticating with Hub. Adding or removing a hub connection never changes your Treeship key.

Configs from earlier versions (flat hub object or docks format) are automatically migrated to the hub_connections format on first run. No manual action required.

Workspace URLs

When you push an artifact to Hub, it gets a public URL:

https://treeship.dev/verify/art_f7e6d5c4

Anyone who opens that URL can verify the full artifact chain in their browser. No account, no install, no CLI required. The browser-based verifier runs the same checks as the CLI verifier described above.

Merkle proofs

Hub periodically creates Merkle tree checkpoints over all artifacts in a workspace. These checkpoints enable two additional guarantees:

Inclusion proofs

Given an artifact and a checkpoint, anyone can verify that the artifact was included in the checkpoint's Merkle tree. This proves the artifact existed at the time the checkpoint was created, even if Hub later tries to deny it.

Anti-backdating

Because checkpoints are published at known intervals, you can prove that an artifact existed before a certain time. If your artifact appears in checkpoint N, and checkpoint N was published at time T, then the artifact must have been pushed before T. This prevents anyone (including Hub) from inserting artifacts after the fact and claiming they were always there.

How it works in practice

You do not need to interact with Merkle proofs directly. Hub creates checkpoints automatically, and the browser verifier checks inclusion proofs when they are available. The guarantees are there whether or not you think about them.

If you want to verify a proof manually:

treeship hub verify-inclusion art_f7e6d5c4
✓ inclusion verified
  checkpoint: cp_20260326_2100
  root:       sha256:a1b2c3...
  proof:      3 intermediate hashes

This confirms the artifact was included in the specified checkpoint and that the Merkle path is valid from the artifact's leaf node to the checkpoint root.