# session
Source: https://docs.treeship.dev/cli/session

> Manage attestation sessions. Start, close, report, and share Session Receipts.

A session groups related work into a single unit. When you close a session, Treeship composes a Session Receipt v1 and writes a portable `.treeship` package that can be inspected and verified offline, or uploaded to a hub for sharing at a permanent public URL.

See the [Session Receipts concept page](/docs/concepts/session-receipts) for the full format and determinism rules.

## treeship session start

Start a new session.

```bash
treeship session start
treeship session start --name "fix auth bug"
treeship session start --actor agent://coder
treeship session start --allow-dangerous-root
```

### Options

| Option                   | Description                                            |
| ------------------------ | ------------------------------------------------------ |
| `--name <text>`          | Human-readable session name                            |
| `--actor <uri>`          | Default actor URI for attestations in this session     |
| `--allow-dangerous-root` | Permit a session whose git root is your home directory |

Starting a session writes `.treeship/session.json`, initializes an append-only event log at `.treeship/sessions/<session_id>/events.jsonl`, and emits a `session.started` event. All subsequent attestations and wrap calls are linked to the session.

<Callout type="warn">
  Treeship refuses to start a session when the git toplevel is your home directory. Start from a project checkout instead. Use `--allow-dangerous-root` only when you intentionally want a home-scoped session.
</Callout>

## treeship session status

Show the current session state.

```bash
treeship session status
```

Outputs session id, name, actor, started-at timestamp, artifact count verified against the chain, and the number of events in the session's event log.

If no session is active, exits cleanly with a hint to run `session start`.

## treeship session invite

Mint a single-use, expiring invitation that lets a second agent join an existing session. This is the host side of the [multi-agent session](/docs/concepts/multi-agent-sessions) lifecycle.

```bash
treeship session invite ssn_abc --invitee-cert "ed25519:ISSUER:org-x" --expires 1h
treeship session invite ssn_abc --invitee-pubkey deadbeefdeadbeef --capabilities tool.call
treeship session invite ssn_abc --open --expires 30m
```

### Arguments

| Argument       | Description                                                         |
| -------------- | ------------------------------------------------------------------- |
| `[session_id]` | Session to mint the invitation for. Defaults to the active session. |

### Options

| Option                             | Description                                                                               |
| ---------------------------------- | ----------------------------------------------------------------------------------------- |
| `--invitee-cert <issuer:subjects>` | Cert-restricted invitation. Format is `<issuer_pubkey>:<subject1,subject2,...>`.          |
| `--invitee-pubkey <fp-or-pubkey>`  | Pubkey-restricted invitation. A 16-hex fingerprint or a full canonical pubkey.            |
| `--open`                           | Open invitation that anyone holding the blob can redeem. Opt-in only.                     |
| `--capabilities <types>`           | Comma-separated action types to grant. Defaults to `tool.call`.                           |
| `--expires <duration>`             | Lifetime such as `30s`, `5m`, `1h`, `7d`. Defaults to 1 hour. The protocol max is 7 days. |
| `--format <text\|json>`            | Output format. JSON returns `{ invitation_id, bootstrap_blob, session_ref, expires_at }`. |
| `--no-armor`                       | Emit raw JSON instead of the armored blob.                                                |

Exactly one of `--invitee-cert`, `--invitee-pubkey`, or `--open` is required. The command signs the invitation with the keystore's default key (the session host), persists it under the artifact store, and prints an armored `-----BEGIN TREESHIP INVITATION-----` bootstrap blob on stdout.

<Callout type="info">
  A joining agent only honors the invitation if the host's issuer key is pinned locally as a `session_host` trust root. Pin it with `treeship trust add <key_id> ed25519:<pubkey> --kind session_host --yes`. See [Multi-Agent Sessions](/docs/concepts/multi-agent-sessions#the-sessionhost-trust-root).
</Callout>

## treeship session join

Redeem an invitation and emit a pending participant event. This is the joiner side of the lifecycle.

```bash
treeship session join --invite-file ./invite.blob --actor agent://researcher
cat ./invite.blob | treeship session join --invite - --actor agent://qa
```

### Options

| Option                  | Description                                                         |
| ----------------------- | ------------------------------------------------------------------- |
| `--invite <blob>`       | Paste the bootstrap blob inline. Use `-` to read from stdin.        |
| `--invite-file <path>`  | Read the bootstrap blob from a file.                                |
| `--actor <uri>`         | Joining agent's actor URI, such as `agent://researcher` (required). |
| `--format <text\|json>` | Output format.                                                      |

The command pins the issuer against the local `SessionHost` trust roots, verifies the invitation signature, checks expiry and restriction, records the nonce in the Approval Use Journal with `max_uses=1`, and emits a single-signature participant envelope that is pending the host countersign. It prints the participant artifact id to pass to `session countersign`. A second join against the same invitation fails through the journal's single-use path.

## treeship session countersign

Host countersigns a pending participant event. After this runs, the participant envelope carries two signatures (joining agent plus host) and verifies as a finalized join.

```bash
treeship session countersign art_part_abc123
```

### Arguments

| Argument         | Description                                         |
| ---------------- | --------------------------------------------------- |
| `participant_id` | Participant artifact id produced by `session join`. |

The command confirms the running default key matches the invitation's issuer, attaches the host countersign over the same canonical bytes, self-verifies, and overwrites the storage record with the finalized two-signature envelope. A participant envelope is invalid until both signatures are present.

## treeship session close

Close the active session, compose the Session Receipt, and write a `.treeship` package.

```bash
treeship session close
treeship session close --summary "fixed JWT expiry bug"
```

### Options

| Option             | Description                                         |
| ------------------ | --------------------------------------------------- |
| `--summary <text>` | Plain-text summary of what the session accomplished |

On close, Treeship:

1. Appends a `session.closed` event to the event log.
2. Walks the artifact chain from `.last` back to the session's root artifact.
3. Composes a canonical [Session Receipt v1](/docs/concepts/session-receipts) from the events, the artifact chain, and the agent graph.
4. Builds a [`.treeship` package](/docs/concepts/session-receipts#package-format) under `.treeship/sessions/<session_id>.treeship/` with `receipt.json`, `merkle.json`, `render.json`, per-artifact inclusion proofs, and a static `preview.html`.
5. Signs a `session.close` chain artifact as before.
6. Prints the package path, the canonical receipt digest, and the Merkle root.

Close is guarded by a lock so only one close or abandon operation can mutate session state at a time. Git reconciliation is also bounded: if the untracked-file scan exceeds the cap, Treeship skips per-file untracked events, records the truncation in the receipt proofs section, and `treeship package verify` reports a `reconcile_completeness` warning.

Example output:

```
✓ session receipt composed
  package:   .treeship/sessions/ssn_42e740bd9eb238f6.treeship
  digest:    sha256:942e6b2bfcbe860223fbae57ee7d9b73400a278ccfb0f1d5ca865aec9ce9aba6
  merkle:    mroot_effc020c67548f53
  files:     8

✓ session closed
  id:       ssn_42e740bd9eb238f6
  duration: 6m
  receipts: 2
  events:   2
```

After close, run [`treeship package verify`](/docs/cli/package) against the package path to confirm the receipt is locally verifiable.

## treeship session abandon

Quarantine a wedged active or closing session without deleting evidence.

```bash
treeship session abandon
```

The command moves `.treeship/session.json` or `.treeship/session.closing` plus the session event directory into `.treeship/quarantine-*`. Use it when a close was interrupted or a session is poisoned and you need the next `session start` to begin cleanly. The quarantined files remain available for debugging.

## treeship session report

Upload a closed session's receipt to the configured hub and print the permanent public URL.

```bash
treeship session report
treeship session report ssn_42e740bd9eb238f6
```

### Options

| Argument       | Description                                                                                               |
| -------------- | --------------------------------------------------------------------------------------------------------- |
| `[session_id]` | Session ID to upload. Defaults to the most recently closed session's package under `.treeship/sessions/`. |

The command:

1. Locates the `.treeship` package for the requested session (or the most recently modified one).
2. Reads `receipt.json` verbatim so the digest signed by `session close` is preserved bit-for-bit.
3. DPoP-signs a `PUT {hub_endpoint}/v1/receipt/{session_id}` request using the active hub connection's private key.
4. Prints the permanent receipt URL.

If a package directory exists but `receipt.json` was never written, `session report` reports the package as incomplete instead of treating it as a missing closed session.

Example output:

```
✓ session receipt uploaded
  hub:      local
  session:  ssn_42e740bd9eb238f6
  agents:   1
  events:   2

  receipt:  https://treeship.dev/receipt/ssn_42e740bd9eb238f6

  → share this URL freely -- it never expires and needs no auth
```

<Callout type="info">
  The receipt URL is permanent and public. No token, no expiry, no auth required to fetch it. A2A clients, dashboards, and offline verifiers can all `curl` it programmatically. See [`GET /v1/receipt/{session_id}`](/docs/api/receipt-get) for the API reference.
</Callout>

## What gets sealed in a receipt

A Session Receipt v1 includes:

* **Session metadata**: id, name, mode, started-at, ended-at, duration, status
* **Participants summary**: total agents, spawned sub-agents, handoffs, max delegation depth, hosts, tool runtimes
* **Agent graph**: every agent instance with its role, host, depth, and edges (parent-child spawn, handoff, collaboration, return)
* **Timeline**: all events in deterministic order (timestamp, sequence\_no, event\_id)
* **Side effects**: files read, files written, ports opened, network connections, processes, tool invocations
* **Artifacts**: chain entries with content-addressed ids
* **Merkle root + inclusion proofs** over the artifact ids
* **Render hints** for Explorer and the preview HTML

Events the session can capture include tool calls, file reads (via the [daemon's sensitive-file watcher](/docs/cli/daemon)), file writes, network connections, process execution, agent spawning, handoffs, collaborations, and returns.

<Callout type="info">
  A session is auto-sealed: the chain of signed artifacts inside the session is what the receipt commits to via the Merkle root. The receipt itself is a human-readable summary on top of that cryptographic backbone.
</Callout>