Treeship
Get started

Handoffs

A handoff is a signed transfer of work between actors or across Treeships.

A handoff records the chain of custody when work moves between agents, between humans and agents, or between organizations.

Handoff scenarios

Agent to Agent

One agent hands off research results to another agent for execution, with a signed transfer record.

Agent to Human

An agent produces output that a human needs to review. The handoff proves what was delivered and when.

Cross-Treeship

Work moves between organizations. Each side has its own keys. The handoff bridges trust domains.

Same-Treeship handoff

treeship attest handoff \
  --from agent://researcher \
  --to agent://executor \
  --artifacts art_research_001,art_validate_002
✓ handoff attested
  id:        art_handoff_xyz
  from:      agent://researcher
  to:        agent://executor
  artifacts: art_research_001, art_validate_002

The receiver can verify the handoff before acting:

treeship verify art_handoff_xyz
✓ verified
  target:     art_handoff_xyz
  actor:      agent://researcher -> agent://executor
  actor proof: asserted (ship key)
  artifacts:  2 named, all present in this store

verify checks the handoff envelope, then reports whether the artifacts it names are in this store. The handoff verifies on its own: a receiver holding only the handoff sees the envelope pass and the named work reported as absent, with a warning that nothing above vouches for the work itself.

Cross-Treeship handoff (cross-org)

When work moves between organizations, each side has its own Treeship and keys.

# Company A -- attest a handoff
treeship attest handoff \
  --from agent://company-a/researcher \
  --to agent://company-b/legal-review \
  --artifacts art_output_123

treeship hub push art_handoff_xyz
# -> https://treeship.dev/verify/art_handoff_xyz
# Share this URL with Company B
# Company B -- verify before acting
treeship hub pull art_handoff_xyz
# Pin Company A's key once, then verify against your own trust store.
# There is no --trusted-key flag: trust roots are pinned, not passed per call.
# The first argument is the KEY ID Company A's `treeship keys export` printed
# (key_<16 hex>), not a label: pins are matched against the signature's key id.
treeship trust add key_<company-a key id> ed25519:<company-a-pubkey> --kind cert_issuer --label company-a --yes
treeship verify art_handoff_xyz
✓ verified
  target:     art_handoff_xyz
  actor:      agent://company-a/researcher -> agent://company-b/legal-review
  actor proof: asserted (ship key)
  artifacts:  1 named, 1 NOT in this store: art_output_123
⚠ the handoff names work this store does not hold

The handoff verifies; the work it names is not here. hub pull the named artifacts too, or ask Company A for a bundle that includes them (treeship bundle export), then import it and verify again.

No shared infrastructure required. The signature is the trust. Company B does not need to trust the Hub or any third party -- only the public key of Company A.

The key-id matching above is specific to this actor-proof flow (treeship verify <artifact-id>, which walks a signed agent_cert.v1 against cert_issuer pins by key id). treeship package verify -- the check a .treeship package runs on its own signers, including receipt_binding -- matches every pin (cert_issuer, agent_cert, session_host alike) by the key's own bytes instead, never by id. Two different checks, two different matching rules; neither is a stand-in for the other.

Handoff flags

FlagRequiredDescription
--from <uri>YesActor URI of the sender
--to <uri>YesActor URI of the receiver
--artifacts <ids>YesComma-separated artifact IDs being transferred
--approvals <ids>NoApproval IDs the receiver inherits
--obligations <text>NoObligations the receiver must satisfy