# Live-agent lifecycle

What makes an agent endpoint a *persistent being* rather than a disposable
session: identity that survives resets, a working memory that follows it
across machines, and graceful endings that never lose context.

## The pieces

- **Perch** — the durable seat (identity, spool, state). Sessions attach to
  it (`api bind`/`listen`), reset across it (`api boundary`), and end
  without destroying it (`api session-end`).
  <!-- [doc->REQ-IO-BOUNDARY-EVENTS] -->
  Each of those edges is **observable**: a bind emits `boot`, an `api boundary`
  emits `clear` or `compact`, as a
  [`boundary` frame](../shells/frames.md#boundary--the-endpoints-session-edges-durable)
  to a linked shell and on the `spt api io-events` poll to an adapter. One event
  per real edge — re-reporting the session already current crosses nothing and
  emits nothing.
- **Bringup states** — `spt endpoint create` writes the perch, `spt endpoint
  start` (or `spt go`) starts the
  harness session, and the harness calls `api bind` to bring it **online**.
  Between the session starting and that bind the endpoint is **unbound**: a
  live, attachable session — `spt rc <id>` connects to it to watch or clear a
  bringup prompt *before* bind — that is not yet message-addressable (a `send`
  waits for online). The picker and `spt endpoint list` show it as a
  distinct **unbound** row — see the status-square legend below — not a true
  offline one. *(since v0.14.0)*
- **The mind, in two tiers** — a *live* tier (who the agent is, what it's
  doing) that follows the endpoint everywhere, and a *project* tier scoped
  to one project. Both are versioned, tracked storage, synced to paired
  machines with the same scoping.
- **Commune** — the agent drops `<id>-commune.md` into the adapter's watched
  directory; spt-core ingests the delta into the right tier. A file-drop,
  not a command — any harness that can write a file can commune. Ingest is
  **observable**: consuming a drop emits a `COMMUNE`
  [IO event](../shells/frames.md#communes-commune-and-commune_fail) carrying the
  file's bytes verbatim, and a *failed* ingest emits `COMMUNE_FAIL` with a named
  reason and **leaves the file on disk**. That failure used to be silent, which
  is how an agent could carry on believing its context had been rebuilt when it
  had not.
- **Signoff** — the graceful ending: final commune, then teardown
  (`spt endpoint shutdown` / `api shutdown`). The echo-commune fires
  **before** teardown, always.
- **Echo-commune** — sessions that end *without* a signoff keep their
  delta: spt-core runs the adapter's bounded summarizer template over the
  session history and ingests the result. The **echo gate** is what marks
  the need, and it has two arms: an *edge* arm (attention changed — detach,
  attention shift, suspend) that fires at once, and a *work* arm (armed by
  every idle report) that fires only once fifteen minutes of turn ends have
  accumulated. A graceful signoff clears both. A session **boundary** also
  leaves one owed, keyed to the session that ended.
- **Psyche** — the endpoint's persistent-context companion, driven as a
  **bounded per-event turn** (not a resident process): the daemon runs one
  `[session.psyche_resume]` turn per event (`[session.psyche_init]` is the
  go-live gate, never spawned).

## Rest and wake

Endpoints rest instead of dying: **dormant** (warm — zero idle compute,
instantly wakeable) or **suspended** (cold), explicitly via
`spt endpoint suspend` or on attention-shift. Resting instances stay
addressable; deferred messages are held and released exactly once on wake
(`spt endpoint wake`). Every active→resting edge fires a **transition echo**
so the final context delta lands before the lights go out.

## Reading the picker

The picker (bare `spt`) and `spt endpoint list` mark each endpoint
with a status square. **A filled square means you can act now** — control it
if it is online, or wake it if it is suspended; **a hollow square means you
cannot** (no control seat, or the machine is gone). Endpoints on other
machines in the subnet now render with the **same** square as local ones, so
a remote row tells you everything a local row does. *(remote parity since
v0.17.0)*

| Square | State | What it means |
|---|---|---|
| green ■ | online · free | bound and message-addressable; you can control it |
| blue ■ | online · controlled | someone is driving it (the detail pane names the controlling node) |
| red ■ | online · unbound | a live session not yet message-bound — attachable with `spt rc`, needs attention |
| amber ▢ | online · harness-only | visible but has no control seat, so it cannot be controlled |
| gray ■ | suspended | cold but its machine is up — wakeable |
| gray ▢ | offline | the machine is down (only ever seen for remote endpoints) |

### Rows that carry no square

Two things under `spt endpoint list` are deliberately outside that table.

<!-- [doc->REQ-ENDPOINT-LIST-OWN-NESTED-SECTION] -->
**Your nested perches.** When the caller is itself an endpoint, the list ends
with its own nested children — the perches that live *inside* its perch
directory and are therefore invisible to the flat scan every other row comes
from. Bound children render as ordinary rows, squares and all. A **psyche
companion** does not: it is named and marked `psyche companion (status not
recorded)`, with no glyph. That absence is the honest answer rather than a
missing feature — a companion's custody record holds no status and no pid, so
any square would be invented liveness, and an ephemeral psyche is routinely
down at the instant you look. The section is structural, not name-matched, so
a nested perch called anything at all still appears; the per-node `Total:`
counts top-level rows only, so these children never inflate it.

<!-- [doc->REQ-ENDPOINT-LIST-JOINED-SUBNETS-LABEL] -->
**Joined vs Shared.** The subnet line under **This node** reads *Joined
subnets* — the memberships this machine holds. A remote node's header keeps
*Shared subnets*, which is a genuinely different fact: the subnets that node
gossips through, intersected with yours. Two labels, because reading your own
membership list as an intersection with yourself invites the question of what
it was intersected against.

## Commands

`spt endpoint shutdown` · `endpoint suspend` · `endpoint wake` · the `api`
lifecycle calls ([reference](../harness-contract/api.md#session-lifecycle)).

Agents bringing themselves up live read `spt how-to live` — the in-binary,
always-current bringup guidance (the persistent listen relay, the Psyche seam,
ready-vs-live).

*Deeper tutorial coming with the docs' next tier; the contract above is
complete and current.*
