Mental model
What spt-core is, the five or six nouns everything else builds on, and how the pieces fit. Read this once and the rest of the docs are mostly reference.
The shape of the system
spt-core is per-machine infrastructure for agents. One binary (spt)
installs on each machine. It carries everything: the CLI, the messaging
substrate, the always-available daemon, and the networking layer. Agent
harnesses — Claude Code, Codex, Pi (the pi coding agent), anything — plug in
through a declarative adapter manifest and a small command surface
(spt api …). spt-core never contains harness-specific logic; adapters
declare what varies, spt-core does the work.
machine A machine B
┌──────────────────────────────┐ ┌──────────────────────────────┐
│ spt daemon (one per machine)│ QUIC │ spt daemon │
│ ┌────────┐ ┌───────────┐ │◄──────►│ (paired: same subnet) │
│ │ broker │ │ brain │ │ P2P │ │
│ │ PTYs · │ │ routing · │ │ │ ┌───────┐ ┌─────────┐ │
│ │ sockets│ │ registry ·│ │ │ │ alice │ │ doorbell│ │
│ └────────┘ │ lifecycle │ │ │ │(agent)│ │ (shell) │ │
│ └───────────┘ │ │ └───────┘ └─────────┘ │
│ ┌─────┐ ┌─────┐ │ └──────────────────────────────┘
│ │ bob │ │ ling│ ← endpoints (perches live on disk; sessions come
│ └─────┘ └─────┘ and go, identity persists)
└──────────────────────────────┘
Endpoints and perches
An endpoint is anything addressable: an agent (bob), a worker, a
shell (a driven non-agent surface — a notifier, a robot, a sensor). Every
endpoint has a perch: its durable on-disk seat — identity, address,
message spool, state. Sessions are ephemeral; perches persist. That split is
why a message sent to an offline agent is queued, not lost, and why an agent
can be revived days later as the same agent.
Endpoint IDs are adapter-agnostic: bob is bob whether his sessions run
under one harness today and another tomorrow.
Messaging
The primitive everything else uses. spt send <id> delivers live when the
target is listening, spools when it isn’t; spt ring <id> is the blocking
ask (send + wait for the reply); __REPLY_TO__ routing makes answers cheap.
Payloads carry typed operations and file blobs, not just text. Try it: the
messaging quickstart.
The daemon: broker and brain
One spt daemon per machine owns all shared state: hosted session PTYs,
the network identity and endpoint, the registry, every spool, all lifecycle
loops. You never manage it — any spt invocation auto-starts it.
Internally it splits in two, and the split is what makes self-update seamless:
- the broker holds only what must never die: PTY masters, spawned child processes, listening sockets. It almost never updates.
- the brain holds all logic and restarts freely. An update swaps the brain while the broker keeps every session’s process and byte stream intact — running agents don’t notice.
Live agents and the mind
A live agent is an agent endpoint with a persistent working memory. Its context survives session resets and even machine moves through three file-drop mechanisms (no special APIs inside the agent’s session):
- commune — the agent drops a context delta; spt-core ingests it into the endpoint’s tracked mind (two tiers: a live tier that follows the agent everywhere, and a project tier scoped to one project).
- signoff — a graceful goodbye: final commune, then teardown.
- echo-commune — when a session ends without a signoff, spt-core runs a bounded summarizer over the session’s history so the context delta is captured anyway.
The mind syncs between paired machines, so reviving bob elsewhere brings
his memory with him.
Instances, dormancy, and rest
One endpoint can have instances on several nodes. Instances rest when
unused — dormant (warm, zero idle cost, instantly wakeable) or
suspended (cold) — and remain addressable while resting: messages for
them are held and delivered on wake. spt wake bob re-activates the seat in
place; nothing is respawned.
Subnets, pairing, and the network
Machines pair into subnets — private, named groups sharing a registry of endpoints. Pairing is a one-time ceremony seeded by a TOTP code (the same six digits an authenticator app shows); after that, connectivity is zero-config peer-to-peer QUIC with relay fallback, no central server. Every endpoint’s visibility and sync scope is controlled per subnet; nothing is shared by default with anyone you haven’t paired with.
The harness contract
The seam third parties build against — two halves:
- the manifest: a TOML file declaring
what varies per harness (how to spawn a session, which hooks fire, how to
read history). Command templates are opaque strings; spt-core fills
{key}placeholders and runs them. SPT is not a harness: models, flags, and tools are always the adapter’s business. - the
spt apisurface: the inbound commands a harness’s hooks fire to keep spt-core’s state in sync (session started, went idle, session ended, …).
A working adapter is a manifest plus whatever the harness already has. Build one in the adapter quickstart.
Self-update
Releases are signed (Ed25519, two-key trust anchor baked into every binary) and propagate peer-to-peer: one machine fetches a release, its peers verify and stage it from each other. Updates apply with the broker/brain split, so no endpoint process terminates or suspends during a self-update — the system’s standing invariant.
Where to go next
| You want to… | Go to |
|---|---|
| see two agents talk | Messaging quickstart |
| integrate a harness | Adapter quickstart → Manifest reference |
| build a notifier/robot/sensor | Shells |
| pair two machines | Networking & pairing |
| every command and flag | CLI reference |