# Instances

One endpoint, several seats. `sergey` is a single identity; an **instance** of
sergey is his presence on one node. The registry tracks every instance's node
and state (active / dormant / suspended / offline), and the same mind syncs
to wherever he sits.

## The rules that keep it sane

- **Identity is adapter-agnostic and node-spanning** — instances on
  different nodes are rows under one endpoint id; renaming
  (`spt endpoint rename`) ripples everywhere, collision-checked.
- **Bare-id resolution never guesses** — `sergey` resolves locally first, then
  to the sole live instance; with several live nodes (or several subnets)
  it refuses and makes you qualify (`sergey@desktop`, `home:sergey`). Per-node
  recency is not comparable across nodes, so there's no silent
  "most recently active" pick.
- **The anchor subnet is immutable** — assigned at creation. Moving an endpoint
  into another subnet is `spt endpoint fork`: a **new identity** seeded with a
  one-time copy of the mind, diverging immediately. Copy-then-diverge, never
  re-anchor — history stays honest.
- **Visibility is per-(endpoint, subnet)** — hidden means neither advertised
  nor routable there, and hidden gates sync too.
- **Rest states are first-class** — dormant (warm) and suspended (cold)
  instances stay addressable; deferred messages are held and released
  exactly once on wake. Remote `spt endpoint suspend sergey@desktop` /
  `spt endpoint wake sergey@desktop` work across paired nodes.

## What a fork carries

<!-- [doc->REQ-FORK-MIND-COMPLETE] -->

A fork copies the source's **whole mind tier at its tip** — every tracked file
on that endpoint's branch, enumerated from the tree itself. Not a list of
filenames: a fork that copies named files drops every mind file nobody
remembered to add to the list, silently, one omission per file, discoverable
only by someone later noticing an absence. That had already happened in the
field — the endpoint's durable **role** file was tracked on the same branch and
simply was not copied, so every fork produced an endpoint whose role had
vanished. Copying the directory closes that gap and every future one in the same
move: context, role, [monics](../networking/monics.md), and whatever the mind
tier grows next all ride without anyone wiring them in.

There is **exactly one exclusion**, and it is a decision rather than an
oversight: surfaced-but-unresolved **conflict artifacts** stay with the mind
that surfaced them. A fork starts clean, and a fork inheriting the source's
unresolved pairs would make that quietly false. The source keeps all of it.

## Forking an endpoint another node holds

<!-- [doc->REQ-FORK-CONTROL-SURFACE] -->

The source does not have to sit on this machine. Name it `id@node` and the fork
is made **where the source is**, by the node that holds it:

```text
spt endpoint fork sergey@desktop sergey-lab --subnet labnet
```

What a fork *is* does not change across the boundary: a new identity, seeded
with a one-time copy of the source's whole mind tier, diverging immediately —
and **the source is left intact**. Both arms run the same primitive on the node
that holds the source, so a fork performed for a caller on another node is the
same act a local operator performs, refusal for refusal.

A fork that happened is reported as `FORKED:` and names the node that made it.
A request that goes unanswered is reported as `FORK_UNCONFIRMED:` — never as
forked:
a node too old to know the verb and a node that declined to admit you are
indistinguishable from the calling side, and calling either one done would be a
fork someone believes they have.

A node that *accepts* the request and then answers nothing is a third thing, and
it says so: `FORK_PEER_SILENT:`. The two silences are not the same fact. An
unanswered request came back from a stream the far side finished — an old or
refusing node, and the remedy is at that node's version or its admissions. A
silent one is still holding the stream open, which points at a node that is
wedged or overloaded, and there is nothing to upgrade. Neither is a fork.
<!-- [doc->REQ-WAN-REPLY-BOUND] -->

One stated limit: the new id is collision-checked against the same
**stale-tolerant** registry snapshot the local path reads, so a simultaneous
mint of the same name on another node can slip past it. It is a check, not a
distributed guarantee.

### The reach to fork and the reach to find are granted together

Forking across nodes is a [control surface](../networking/access-viewing.md) —
`FORK` — so the owner of the *source* decides, through the same rules every
other surface uses. It is its own surface rather than a rider on a neighbouring
one because a fork copies an endpoint's **entire mind**: folding it under
"you may suspend my agent" or "you may transfer files" would hand over
mind-cloning to anyone trusted with either.

**A `FORK` grant on its own cannot be exercised.** Listing an endpoint's
surfaces closes every surface not listed, so a `FORK`-only grant denies
`DISCOVER`; the holding node then never advertises that endpoint into the
registry the caller replicates, and the caller's **own resolution** — which runs
before anything is dialled — cannot find the name it has been given permission
to fork.

What comes back says the endpoint is not in view: *not on this node, and no node
in view holds it*. That is literally true, and it is **existence-shaped, not
permission-shaped** — word for word what a typo'd id or an endpoint that never
existed produces. Nothing tells the operator that a grant they hold is the
reason. So grant **both** `FORK` and `DISCOVER`; today the pairing is something
you have to know, and making the dead end announce itself is filed work rather
than shipped behavior.

### `--delete-source` is local only

`--delete-source` is the move-an-agent flag, and a fork whose source **resolves
to another node** never deletes. Asked for one anyway, the command **refuses the
whole invocation before anything is dialled** — nothing forked, nothing deleted
— naming the node that holds the source and what to do instead. It is refused
rather than quietly downgraded to a copy, because honouring half of what was
typed leaves an operator who meant to *move* an agent holding two live minds and
no word about the difference.

The trigger is where the source **resolves**, not how it was spelled: naming
your own machine explicitly (`sergey@thisnode`) is just a longer way of saying a
local source, and `--delete-source` works there exactly as it always has — the
delete running only after the fork is whole.

### Who a fork grant admits

<!-- [doc->REQ-FORK-ACCESS-GATED] -->

A fork request carries **no proven sender endpoint** today, so the only subject
that can govern it is the requester's **whole machine**. Node-tier rules decide,
and a rule naming a sender endpoint on `FORK` is
[refused when you type it](../networking/knocking.md#refusals-you-can-predict)
rather than stored to match nothing — the refusal names the machine form to use
instead.

That makes answering a knock for `FORK` a **widening** act, the shape described
in [Knocking](../networking/knocking.md#what-an-approval-may-and-may-not-write):
the grant admits every endpoint on that machine, whatever the knock named. An
endpoint's **own agent** must acknowledge that widening with `--admit-node` and
satisfy the node's policy; a user at the machine is node-sovereign and the
engine room's bring-up is its own authorization, so neither has to restate it.

You are told this **before** you answer, not after. The knock listing composes
each row's prescribed approval from the same predicate the approve path decides
on, so what it prescribes depends on who is reading it: to the endpoint's **own
agent** a row asking for `FORK` prescribes the `--admit-node` form and names
whose machine the grant would admit; a **person at the terminal** is
node-sovereign and sees the plain form; and where the node's policy forbids an
endpoint widening to a whole machine at all, the row offers **no invocation at
all** — it names the engine room as the only seat that can answer, so from the
agent's seat that request is a dead end rather than a harder path.

What the listing does **not** prescribe is the `FORK`-plus-`DISCOVER` pair. It
tells you what a grant would admit, not that `FORK` without `DISCOVER` cannot be
exercised at all — that remains something you have to know, and closing it is
filed work.

The gate reads the **handshake-proven** origin of the request, never anything
the request says about itself, and it is the *source* endpoint's rules that are
consulted — the endpoint whose mind is about to be copied is the one whose
owner's grant matters. A refusal creates nothing and, following the same posture
as the other surfaces, tells an unadmitted caller nothing about what exists.

## Startup defaults (`endpoint auto-start`)

<!-- [doc->REQ-ENDPOINT-AUTOSTART] -->
Infrastructure endpoints (a gateway the phone treats as always-there) should
not need hands-on bringup after a box reboot or daemon restart. `spt endpoint
auto-start <id>` records the endpoint — its id, adapter option, and working
directory — as a **startup default** in `daemon.json`; the daemon **replays**
every saved default when it starts, as a fresh session with the adapter
re-resolved at replay time. One entry per endpoint id (setting it again
replaces the prior one); `spt endpoint auto-start <id> --off` removes it.

Replay is best-effort and loud, and never blocks daemon start: a saved run
that comes up logs `ENDPOINT_AUTOSTART:<id>`; a saved adapter that no longer
resolves logs `ENDPOINT_AUTOSTART_SKIP:<id>` (set it again to refresh it); a
failed launch logs `ENDPOINT_AUTOSTART_FAIL:<id>` and the daemon carries on.
This is a **startup default**, not a session restore — it replays what you
recorded, never "whatever was up before the restart" — and it is symmetric with
`spt subnet attach --save` (the serve-state startup default).

## Commands

`spt endpoint list` · `endpoint rename` · `endpoint fork` ·
`endpoint create` · `endpoint start` · `endpoint resume` ·
`endpoint auto-start` · `endpoint suspend` · `endpoint wake` ·
`endpoint description` — [CLI reference](../cli/reference.md).

*Cold-launching an endpoint on a node that has no instance
("instantiate-anywhere") is deliberately deferred behind the consent
framework; the gate exists and refuses today.*
