treeship-core 0.24.0

Portable trust receipts for agent workflows - core library
Documentation
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://treeship.dev/schemas/session.v1.json",
  "title": "session.v1",
  "description": "A completed work session as a typed, signed record: the atom of an agent's work history. Minted by `treeship session close` from the session's own sealed evidence (never hand-written), and carried as the payload of a Treeship receipt artifact with kind=session.v1. See docs/specs/work-history.md.",
  "type": "object",
  "required": [
    "session_id",
    "actor",
    "outcome",
    "started_at",
    "closed_at",
    "attestation_class",
    "receipt_digest"
  ],
  "properties": {
    "session_id": {
      "description": "The session this record summarizes.",
      "type": "string"
    },
    "actor": {
      "description": "Actor URI the session ran as, e.g. agent://hermes.",
      "type": "string"
    },
    "headline": {
      "description": "One-line human narrative of the session, from the sealed receipt.",
      "type": ["string", "null"]
    },
    "outcome": {
      "description": "How the session ended: completed | abandoned | failed.",
      "type": "string",
      "enum": ["completed", "abandoned", "failed"]
    },
    "started_at": {
      "description": "RFC 3339 session start.",
      "type": "string"
    },
    "closed_at": {
      "description": "RFC 3339 session close.",
      "type": "string"
    },
    "duration_ms": {
      "description": "Session wall-clock duration in milliseconds.",
      "type": "number"
    },
    "harness": {
      "description": "Capture surface(s) the session ran under: distinct tool runtime ids from the sealed receipt (e.g. 'claude-code'), or 'cli' when no tool runtime was involved.",
      "type": "string"
    },
    "custody": {
      "description": "Who held the signing key, when that is not the actor. ABSENT means self-custody -- the actor signed for itself, the default and the strong case. Present means a service signed on the actor's behalf: a materially weaker claim, so it is recorded rather than inferred. Deliberately a separate axis from attestation_class, which grades how EVIDENCE was captured; this grades who held the KEY. They vary independently -- a service-mediated room can have excellent runtime-captured evidence and still be custodially signed. Under self-custody, forging a participant's action needs that participant's key; under delegated custody, a compromised service can mint any history for every actor it signs for. Same receipt shape, different threat model.",
      "type": "object",
      "required": ["mode", "signer", "on_behalf_of"],
      "additionalProperties": false,
      "properties": {
        "mode": {
          "description": "Only 'delegated' is ever serialized. Self-custody is the absence of this whole object, so existing receipts stay byte-identical and 'no custody block' cannot be misread as 'custody unknown'.",
          "type": "string",
          "enum": ["delegated"]
        },
        "signer": {
          "description": "The identity whose key actually produced the signature, e.g. svc://gateway-rooms. This is who a verifier is really trusting.",
          "type": "string"
        },
        "on_behalf_of": {
          "description": "The actor the signature is claimed to be FOR, e.g. agent://fizz. A verifier can confirm the signer signed; it cannot confirm this actor agreed, and must not present it as though it could.",
          "type": "string"
        },
        "reason": {
          "description": "Why the actor did not sign for itself, e.g. 'browser-mediated room; participants hold no local key'.",
          "type": "string"
        }
      }
    },
    "attestation_class": {
      "description": "How the record's evidence was captured, per the work-history ladder: self (the agent's own receipts, no external signal), runtime (events emitted by a harness hook or bridge the agent cannot forge or omit), countersigned (a second party signed evidence in the package, e.g. consumed human approvals). Labeled, never laundered; 'anchored' is a later, derivable state (publish + witness), not set at close.",
      "type": "string",
      "enum": ["self", "runtime", "countersigned"]
    },
    "action_count": {
      "description": "Signed artifacts in the session chain.",
      "type": "number"
    },
    "approval_count": {
      "description": "Approval uses consumed during the session (each backed by a signed grant embedded in the package).",
      "type": "number"
    },
    "handoff_count": {
      "description": "Agent-to-agent handoffs during the session.",
      "type": "number"
    },
    "event_count": {
      "description": "Events in the sealed session event log.",
      "type": "number"
    },
    "tools_exercised": {
      "description": "Tool names actually invoked during the session, computed from captured events (never hand-written). Feeds capability cards' `exercised` grade.",
      "type": "array"
    },
    "receipt_digest": {
      "description": "Digest of the sealed session receipt (receipt.json) this record summarizes; binds the record to its evidence.",
      "type": "string"
    },
    "receipt_merkle_root": {
      "description": "Merkle root of the sealed .treeship package, when composed.",
      "type": ["string", "null"]
    },
    "report_url": {
      "description": "Published session report URL, when one exists.",
      "type": ["string", "null"]
    },
    "room": {
      "description": "Room this session hosted, when it was created with `treeship room create`. Mirrored here from session.json so `invitation_authority` -- which decides who may mint invitations -- is bound into the DSSE-signed payload rather than living only in unsigned local state. Absent (null) for ordinary, non-room sessions.",
      "type": ["object", "null"],
      "properties": {
        "room_id": {
          "description": "Stable room identifier, distinct from session_id.",
          "type": "string"
        },
        "host_pubkey": {
          "description": "Base64url-no-pad Ed25519 public key the room's invitations are issued under.",
          "type": "string"
        },
        "invitation_authority": {
          "description": "Who may mint invitations for this room.",
          "type": "object",
          "properties": {
            "kind": {
              "type": "string",
              "enum": ["host_only", "delegated_to", "open"]
            },
            "delegates": {
              "description": "Present only when kind is delegated_to.",
              "type": "array",
              "items": { "type": "string" }
            }
          },
          "required": ["kind"]
        },
        "workflow_ref": {
          "type": ["string", "null"]
        },
        "checkpoint_every_actions": {
          "type": ["number", "null"]
        },
        "participants": {
          "description": "Finalized (both-signed) participant artifact ids, in join order.",
          "type": "array",
          "items": { "type": "string" }
        }
      },
      "required": ["room_id", "host_pubkey", "invitation_authority"]
    }
  }
}