# Changelog

All notable **user-facing** changes to `spt` — what a person running the CLI
notices or does differently. The `## [<version>]` section of each release
becomes that release's GitHub Release notes verbatim (see
`docs/RELEASE-RUNBOOK.md`). This project follows
[Keep a Changelog](https://keepachangelog.com) and semantic versioning
(pre-1.0: breaking changes bump the minor).

## [Unreleased]

## [0.30.0] - 2026-07-08

Adds a statically-linked Linux build for hosts with an older system C library.

### Added

- A statically-linked musl Linux artifact (`spt-x86_64-linux-musl`) that runs on
  Linux hosts whose system C library is too old for the default build (pre-glibc
  2.39), where that build will not start. On such a host `spt update fetch` now
  selects and verifies this artifact automatically. The default (glibc) Linux
  build is unchanged and remains the standard Linux artifact.

## [0.29.1] - 2026-07-08

A reliability patch for message delivery into a live session.

### Fixed

- A long multi-line message delivered into a live session could arrive with its
  opening lines cut off when the session had been cleared or checkpointed earlier
  in its run — the message was typed before the freshly-cleared terminal was ready
  to receive it. Such a message now arrives intact. (The earlier fix in 0.29.0
  covered only the moment a session first starts; this extends it to every clear
  during a session's life.)

## [0.29.0] - 2026-07-07

A lifecycle-reliability release: previously-online sessions are re-launched automatically after a daemon restart, an attached terminal no longer freezes behind a slow or suspended session, a long multi-line message typed into a live session arrives intact, and an in-place update finishes in a single command.

### Added

- **`spt update apply --finish` completes an update in one command.** It swaps in the new binary and restarts the daemon onto it; previously-online sessions are then re-launched automatically. `spt update apply` now also works while the daemon is stopped — it swaps in place, and the next `spt daemon start` runs the new version.
- **The daemon now keeps a log on disk.** Its diagnostics are written to a rotating, size-capped file under the daemon's home directory, so a failure that happens in the background leaves a trace you can read after the fact.

### Changed

- **`spt daemon stop` now protects live sessions.** When hosted sessions are running it lists them and refuses to stop unless you pass `--force` (the sessions come back on the next start), so an accidental stop no longer tears down running agents.
- **`spt rc` no longer starts a daemon by itself.** It attaches only to an already-running daemon; if the daemon is down it says so and exits instead of silently launching one — the cause of the old "I had to stop it several times" behavior. While reconnecting it now shows a live countdown.

### Fixed

- **Hosted sessions are re-launched after a daemon restart.** Previously-online sessions come back automatically once the daemon restarts (including as part of an update) instead of being left offline. The restart still interrupts them — this restores the session, it does not preserve its in-flight work.
- **An attached terminal no longer freezes behind a stalled session.** If a session's underlying process hangs or is suspended, `spt rc` keeps updating and a stuck connection is dropped automatically so you never lose control; reattaching and taking control (`--take`) keep working. `spt daemon status` reports when such a drop happened.
- **A long, multi-line message typed into a live agent's terminal arrives complete.** When a message is delivered by typing it into a live session, it is no longer truncated at the front. (Messages drained through the polling channel were never affected.)
- **`spt endpoint digest --json` no longer repeats rows.** Activity replayed across a session checkpoint is collapsed to a single entry.
- **Waking an agent starts exactly one session.** Two wake requests arriving at once no longer launch it twice.
- **A dead owner no longer leaves an agent showing as online.** When the process that owns a listener exits, the listener stops promptly, so the agent shows offline and can be re-bound.
- **Live agents save their context reliably.** Fixed a case where an agent's automatic context save could fail — silently writing to the wrong place, or repeatedly erroring — when its save directory was left to resolve from the daemon's own working directory; a mis-configured directory now produces a clear one-time warning instead.

## [0.28.0] - 2026-07-06

A join-truth release: joining a subnet now tolerates a skewed or stepped system clock so it finds members it used to silently miss, no longer raises the elevated-permission prompt before a member is actually found, and can show the exact ceremony clock it is using — plus a loud warning when no time server can be reached.

### Added

- **`spt subnet join --verbose` now shows the ceremony clock.** The verbose output prints the joiner's pairing time-step, its clock offset, and whether that clock is NTP-corrected or running uncorrected on the raw system clock — so a skew-related join problem is visible at a glance.
- **A loud warning when no time server answers.** If every NTP server is unreachable during a join, `spt` prints `NTP_TOTP_UNCORRECTED: all NTP servers unreachable — ceremony clock = raw system clock`, instead of silently proceeding on a possibly-wrong clock.

### Changed

- **Joining no longer raises the elevated-permission prompt before a member is found.** `spt subnet join` now asks for OS elevation only once it has actually located a subnet member, rather than up front — so a join that can't find anyone no longer pops an elevation prompt for nothing. The `--code` path is unchanged.

### Fixed

- **Join now finds members it used to miss when the clock is off.** The pairing ceremony clock is corrected against NTP (and re-steps when the system clock jumps), so a joiner whose machine clock is skewed no longer silently fails to meet a subnet member.
- **A failed join now reports the joiner's own clock in the failure detail.** The `spt subnet join --verbose` failure block now also carries the joiner's daemon-side ceremony clock (time-step, offset, and corrected/uncorrected state), so a met-then-refused join shows the clock state on both sides instead of leaving the joiner's half unexplained.

## [0.27.0] - 2026-07-06

A worker-truth release: the background "worker" endpoints an agent spawns now carry stable minted ids, stay out of your endpoint list and the run picker, get cleaned up when they leak, and inherit their parent's account; and harness adapters are validated more strictly when you add or update them. **Breaking for adapter authors: the worker control verbs changed shape — see Changed.**

### Added

- **Leaked or orphaned worker endpoints are now cleaned up automatically.** A finished worker whose results have been collected is removed immediately; an orphaned worker (parent gone) or one that leaked without a stop signal — even under a live parent — is reaped after a configurable time-to-live (`worker_reap_ttl_secs`, default 24h) instead of lingering as a dead offline row.

### Changed

- **Breaking (adapter authors): worker endpoints now use core-minted ids and token-free, session-symmetric control verbs.** A spawned worker is assigned a stable `<parent>-w<N>` id by the core, and the verbs that drive a worker now key on its session id with no separate token. Adapters that spawn or control workers must migrate to the new verb shape; the old form no longer works.
- **`spt endpoint list` hides worker endpoints by default.** Worker endpoints no longer clutter the default listing; pass `--workers` to include them.
- **The run picker no longer offers worker or companion (psyche) endpoints.** These aren't independently startable, so the picker lists only endpoints you can actually launch.

### Fixed

- **A spawned companion (psyche) now runs under its parent's account.** A psyche launched for a live agent inherits the parent agent's captured account/home root, so it runs in the right environment instead of a default one.
- **Adapters that reference an unfillable or misspelled template key are now refused when you add or update them.** Adding or updating a harness adapter validates its spawn/role templates at registration time — an unknown or misspelled `{placeholder}`, an unterminated `{`, or a contradictory environment directive (removing and reading the same variable) is rejected with a clear message, instead of failing later when a session is spawned.

## [0.26.0] - 2026-07-06

A remote-truth release: acting on an endpoint that lives on another node — waking it, suspending it, attaching to its screen — now works by bare id across your subnets and reports honestly when it can't; the picker gains back-navigation, a purge shortcut, and remote wake; and adapter handling, session resume, sender identity, and error messages all tell the truth about what happened.

### Added

- **Wake or suspend an endpoint on another node by its bare id.** `spt endpoint wake <id>` and `spt endpoint suspend <id>` (and the other remote verbs) now find the right endpoint across the subnets your node belongs to without an explicit `--subnet`, and report a clear host error when the target can't be woken instead of failing quietly.
- **The picker can wake a suspended remote endpoint.** A suspended row that lives on another node now offers Wake-now directly from the pick list.
- **`x` purges an endpoint from the pick list.** Highlight a row and press `x` to remove that endpoint, with an in-list confirm before it happens.
- **Backspace steps back one screen in the picker.** Backspace now backs out one picker screen, matching Esc.
- **`spt endpoint run --id <id>` reuses that endpoint's own adapter.** Running an existing endpoint by id reuses the harness adapter it was created with instead of dropping you into the choose-a-new-adapter picker.

### Changed

- **Adapters must meet their declared minimum core version to be added or updated.** Both adding and updating a harness adapter now enforce the adapter's minimum-`spt` requirement; one that needs a newer `spt` is refused with a clear message instead of being installed and failing later.
- **Resuming a session keeps that session's adapter.** Resume-from-history now follows the adapter recorded for each session, so a resumed endpoint runs the adapter it was created with rather than a default.

### Fixed

- **Attaching to a remote endpoint's screen now recovers from a dropped connection.** If the link to a live remote view is severed, the attach auto-reconnects within a bounded window and, failing that, gives up with a plain-language message instead of hanging; and other attach failures now name what happened and what to try instead of showing an internal transport error.
- **An internal fault mid-attach no longer permanently wedges all later attaches.** Previously one internal fault during attach churn could make every subsequent attach time out until the daemon was restarted; the affected state now self-heals (worst case, one screen's scrollback resets and repaints) instead.
- **A cold attach now repaints the program's window title.** Attaching to a running session restores the child program's terminal window/tab title instead of leaving it blank.
- **Ending one session no longer stops messages to another endpoint that is still listening.** A soft session-end keeps a still-live listener's delivery address, so its messages keep arriving.
- **A message sent from inside an spt-hosted session is attributed to that endpoint.** A send from within a hosted session is now stamped as coming from that endpoint rather than the bare command-line identity.
- **An endpoint that exists but has never run now reads as suspended.** Its status is derived consistently instead of showing an in-between state.
- **A stale "controlled" marker left by a gone controller now clears itself.** When the process that held an endpoint is gone, the controlled/viewer marking heals on its own.
- **The picker shows a project's readable name everywhere, and tells same-named projects apart.** The remaining raw-slug spots now show the friendly name, and two projects that share a name are disambiguated by their folder.
- **`spt daemon stop` no longer hangs when the daemon is busy.** Shutdown is now bounded and drains in-flight connections, so stop returns promptly instead of parking under load.
- **`spt endpoint list` (and `spt whoami`) now flag an endpoint whose input translation has failed.** The endpoint's line shows `input-translation: FAILED (<reason>)` and what it means for you — typed input may not reach the session — instead of the fault being invisible.
- **A remote wake or screen-open no longer spuriously fails with "op already applied — retry with a fresh op_id".** Internal operation ids raised from different sources could collide; they are now kept distinct, and a stale collision retries once on its own.
- **Acting on an endpoint that lives on another node now says so in plain language.** A remote operation against an endpoint hosted elsewhere reports `this endpoint is not hosted on this node` and points you at `spt endpoint list` to find where it lives, instead of an internal-sounding failure.

## [0.25.0] - 2026-07-04

A psyche-ephemeral release: a live agent's Psyche is no longer a resident background process — each event runs one bounded turn — and its conversation now survives the parent agent's context reset, stays out of the way when it fails, and cleans up cleanly on upgrade.

### Changed

- **A live agent's Psyche no longer runs as a resident background process.** Instead of one long-lived Psyche process per live agent, each pulse or event now runs a single bounded Psyche turn. Liveness is measured by turns succeeding, not by a process staying resident — nothing lingers between events.
- **A Psyche now keeps its own conversation across a parent context reset.** The Psyche's session is owned independently of the parent agent, so its thread continues uninterrupted when the parent's context is reset — the companion no longer loses its place.
- **Nested agent ids resolve without `--subnet` on multi-subnet nodes.** Referring to a `parent/nested` agent on a node that belongs to more than one subnet no longer requires an explicit `--subnet`; resolution finds the agent locally. This also clears the Psyche-poll refusal that a prior version surfaced loudly.
- **Harness-contract manifest keys added.** Adapter manifests can now use `{parent_session_id}` (the hosting agent's session), `{subnet}`, and `{psyche_context_file}` — the last replaces the inline `{psyche_context}` key, passing the Psyche's mind as a file path rather than inline on the command line, so large contexts no longer risk overrunning the operating system's argument-length limit.

### Fixed

- **A failing Psyche no longer takes your endpoint offline.** When a Psyche turn fails, the live endpoint stays ready and keeps delivering messages. A gone-session condition triggers a loud reseed with a fresh start; any other failure counts against a small strike budget and is recorded as an endpoint error status — the parent agent is never taken offline, and the older machinery that could disrupt delivery is gone.
- **Upgrading now cleans up stranded Psyche processes and leftover binary copies automatically.** Upgrading from an older version sweeps away a Psyche process left resident by the previous daemon and removes leftover own-copy binary files at daemon start, instead of leaving them for manual cleanup.

## [0.24.0] - 2026-07-03

A picker-polish release: the endpoint picker's labels, keys, and flows now tell the truth about what each action does and where it acts — and message delivery no longer breaks after a context reset, with a dropped adapter profile fixed along the way.

### Added

- **The choose-project panel now marks your current directory.** A history entry whose folder is your current working directory is tagged `(CURRENT DIR)`; if your current directory isn't already in the history, a `CURRENT DIR --> <folder>` row is offered so you can start there directly.
- **The interactive endpoint picker now titles its terminal window.** The window or tab is set to `SPT Endpoint Picker` when the picker opens interactively.

### Changed

- **Two picker action labels now name their target.** "Fork endpoint here --> <current dir>" states the directory the fork will run in, and "Set shortcut here --> <current dir>/<file>" names the exact shortcut file that will be written, so the label cannot drift from what actually happens.
- **The translation-binary protocol now requires an explicit commit terminator.** Every `{"type":"event"}` a translation binary receives must be answered with a trailing `{"commit":true}` — including an event with nothing to inject, which must still answer with a bare commit. The harness-contract docs also correct the missed-commit consequence: a missed commit no longer permanently kills the binary — it is tolerated and the envelope is re-spooled once.

### Fixed

- **The picker's confirm panel now shows the readable project name.** The one remaining place that still displayed a raw project slug now shows the friendly name, matching the rest of the picker and `spt endpoint list`.
- **The picker's `h` and `s` keys now work only where they can launch, and the footer only hints them there.** Headless-start (`h`) and shortcut (`s`) previously fired from rows that could not launch anything, and the footer advertised them where they were dead; both are now live only on a highlighted row that can actually start the endpoint, and the footer hint matches.
- **"Change harness adapter" now only changes the adapter.** Choosing it no longer re-prompts for an id and home directory and then starts a session — it picks a new adapter, applies it to the endpoint, and returns to the confirm panel.
- **An endpoint's adapter profile is no longer dropped on reconnect.** An endpoint created with an adapter profile (e.g. `claude-spt:ccs`) keeps that profile; re-binding no longer strips it back to the bare adapter.
- **A missed commit no longer stops idle message delivery.** Previously an event that armed nothing (such as a context reset) could make the translation binary miss its commit and permanently stop delivering that session's idle messages until it was restarted. A single miss is now tolerated — the healthy binary is kept and the next message delivers through it; only repeated misses or a genuine crash fault it, triggering a bounded automatic respawn and recording a fault status on the endpoint instead of failing silently.
- **Message delivery and scheduled wake-ups now survive a context reset.** After a context reset, an idle agent could stop receiving messages and scheduled wake-ups until its session was restarted; the session boundary now re-stamps its readiness in the correct order across the reset, so messages and wakes right after a reset are delivered instead of dropped.
- **A `--force-native` send that cannot be delivered now says why.** The failure message distinguishes its cause — empty message, no daemon running, endpoint active mid-turn, no working translation binary, or not a controllable endpoint — instead of a single identical message for every case.

## [0.23.0] - 2026-07-03

A run-truth release: starting, resuming, and shutting down agent sessions now behave honestly — no duplicate sessions, no stale "controlled" markers, no orphaned processes — alongside picker and listing display polish and a fix for adapter updates that could get permanently stuck on a machine running an agent.

### Changed

- **Projects now display a recognizable name.** Across the agent picker (history, the choose-project panel, resume titles) and the `spt endpoint list` project column, a project shows a readable name (e.g. `spt-core`) instead of a raw slug; two projects with the same name are told apart by their folder.
- **`spt endpoint list` output refreshed.** The shared-subnet and total lines are dimmed, the status glyph now sits beside the endpoint name, and the status word is colored.
- **The agent picker no longer offers "View" for an offline endpoint.** An offline endpoint has no live session to view, so only Start is offered.
- **`spt daemon status` now warns about a stale at-logon task registration.** If the auto-start task was registered by an older installer in an unsafe form, `spt daemon status` flags it with guidance to re-register via the current installer; the daemon self-protects either way.
- **Piping `spt daemon run` to another command now discards its output by design.** A piped launch is treated as a detached one and its console output is dropped; to capture the daemon's output, redirect it to a file (e.g. `spt daemon run 2>daemon.log`) instead.

### Fixed

- **Colored CLI output on Windows consoles no longer garbles.** On a raw Windows console, `spt endpoint list` and `--help` no longer print raw escape sequences; when the console cannot render color, the output is cleanly stripped instead.
- **Resume-from-history now labels each session with its own project.** Past sessions no longer all read as the newest project, and internal or host sessions no longer appear as unresumable rows.
- **The Start-now project chooser no longer lists the same project twice.**
- **A dead or offline endpoint no longer reads as "controlled."** The controlled/viewer marking is cleared once the session is gone — including across a daemon restart — instead of lingering.
- **`spt endpoint run` over an already-live endpoint no longer duplicates the session.** It attaches to the running session (or, when headless, reports that the endpoint is already live) instead of silently starting a second session with a crossed view.
- **Resuming a session no longer hangs at "No sessions match."** Resume — including after a daemon restart — now restores the real recorded session, or starts fresh with a clear notice when there is nothing to resume.
- **`spt endpoint shutdown` now fully tears down a wedged or crash-looping Psyche.** Its child processes are killed too, instead of being left orphaned for a manual cleanup.
- **A crash-looping Psyche is now detected and stopped.** Instead of silently respawning several times a second, the loop is halted, backed off, and surfaced as an error.
- **Adapter updates no longer get permanently stuck on a machine running an agent.** Leftover files from a prior update no longer make every later `spt adapter update` fail and roll back; update errors now name the file and operation involved.
- **One agent can no longer corrupt another agent's session identity.** An agent's endpoint identity and presence are no longer overwritten by another agent's Psyche, and a dead endpoint can no longer be silently re-bound to a different agent's session.

## [0.22.0] - 2026-07-03

A picker-and-presence truth release: the endpoint picker and listing show real project, type, and control state — including for endpoints on other machines — and a few rough edges around piping and cross-node display are fixed.

### Added

- **`spt api endpoint-info`.** A new command that emits, as JSON, which node an endpoint is attached to — for harnesses that need to resolve the node from which a controller is attached.

### Changed

- **`spt endpoint list` now shows a project column.** Each row reads id / project / type / status, so you can see at a glance which project an endpoint belongs to.
- **The endpoint picker got two UX fixes.** Starting an endpoint now opens a choose-project panel, and the resume view keeps the top endpoint details panel visible.

### Fixed

- **Endpoints on other machines now show truthful details.** A remote machine's rows previously displayed faked adapter, history, and control information; the gossiped rows now carry the real adapter, project history, and whether the endpoint is being controlled.
- **A controlled endpoint now reads as CONTROLLED accurately — and stops reading CONTROLLED once control ends.** An endpoint being driven shows as controlled both in its own machine's picker and from other nodes; when the controller detaches or exits, the stale controlled/viewer marking is now cleared instead of lingering.
- **`spt send` from inside an agent's hosted session no longer mis-stamps the sender.** The sender could be stamped as `cli@<node>`, causing replies to bounce; sender identity now falls back to process ancestry when the session's environment variables are absent.
- **Piping `spt` output to a command that closes early no longer errors.** Sending output to something like `| head` that closes the pipe now exits cleanly (0) instead of failing with a broken-pipe error.

## [0.21.0] - 2026-07-02

A visibility + update-honesty release: the endpoint list is reorganized around machines, and `spt update apply` / `spt daemon status` are clearer about which version is actually running.

### Added

- **`spt endpoint list --show-all`.** Suspended (resting) endpoints are now hidden by default to cut clutter; `--show-all` reveals them. Each machine's total discloses how many were hidden (nothing silently vanishes), and a corrupt record always shows regardless.
- **`spt daemon status` now reports the running daemon's version.** It shows the version the running daemon was built from beside the installed version and flags a mismatch — so you can tell when an update is on disk but the daemon still needs a restart to fully load it. The `--json` output gains matching `broker_image` / `broker_stale` fields.

### Changed

- **`spt endpoint list` (and `spt whoami`) is now grouped by machine, not by subnet.** Your own node comes first, then each remote machine alphabetically — every endpoint appears once per machine (no more duplicate rows for a machine reachable through several subnets), with a per-machine total and the subnets it shares with you. The old `ENDPOINTS:` summary line (which counted a machine once per subnet) is removed.
- **`spt update apply` now tells you when a daemon restart is needed.** On a successful update it notes that daemon-coordinated features keep running the previous version until you restart the daemon, and points you at `spt daemon status` to confirm which version is live.
- **`spt endpoint list --json` gains a per-endpoint `endpoint_type` field.** Additive — the existing JSON shape is otherwise unchanged.

### Fixed

- **`spt update apply` when already up to date no longer errors.** Re-running apply on a version that is already installed used to fail with an "access denied" error; it now recognizes the up-to-date state and exits cleanly with a clear message.
- **Concurrent first-time store initialization no longer fails.** Two spt processes initializing the same fresh data store at once (for example the daemon and a command racing on first use) could fail with a "could not lock config file" error; initialization is now race-tolerant.

## [0.20.0] - 2026-07-02

A cross-node delivery release: messages to a remote, idle spt-hosted endpoint now arrive immediately, alongside adapter-update, sender-labeling, and auth-recovery fixes.

### Added

- **New `{node}` manifest substitution key.** Adapter manifests can reference the advertised node label as a single-token `{node}` in command templates.

### Changed

- **`spt send` with no explicit sender now stamps `cli@<node>`.** A delivered message never shows a blank sender — a message sent without a from-identity is attributed to the originating node instead of arriving empty.
- **Clearer delivery diagnostics.** Spool and idle-drain failures now emit loud, one-shot log lines, and operator notes on message-delivery timing are documented.

### Fixed

- **Messages to an idle remote endpoint now deliver immediately.** A message sent across the network to an spt-hosted endpoint that was idle used to wait for the receiving adapter's next poll; the daemon now injects it on arrival, and any messages spooled while the endpoint was active drain the moment it goes idle. Cross-node delivery no longer stalls.
- **`spt adapter update` on a profile endpoint now actually updates and reports honestly.** Updating a specific profile (`--adapter <name>:<profile>`) previously could report success without swapping anything; it now performs the swap and only reports success once the adapter has really been replaced.
- **A perch stranded on a dead session now recovers itself.** When the session a perch was pinned to is gone, the next activity re-pins it automatically instead of staying wedged; a pin to a still-live different session is still refused.

## [0.19.1] - 2026-07-01

A follow-up field-hardening release. Three bugs surfaced by running `spt` across real remote nodes — and by a machine losing power mid-write — are fixed.

### Fixed

- **`spt rc <endpoint>` no longer refuses to attach to a node you reach through more than one subnet.** When the same machine was advertised into several subnets, `rc` wrongly reported that the endpoint `exists in several subnets` and asked you to disambiguate — but a subnet is not a way to tell nodes apart, so there was nothing to pick. `rc` now recognizes the entries as one node and attaches.
- **A machine that lost power no longer shows up as online forever.** If a perch's on-disk record was destroyed by a hard reset (a power loss can leave the file present but zero-filled), the endpoint used to keep advertising as online. Perch records are now written durably, and a record that is present but unreadable is treated as not-alive — shown as suspended, distinct from one that is simply gone.
- **A corrupt local perch now reads as offline everywhere, not just under the Subnet tab.** Such a perch was invisible in `spt endpoint list` and in the `spt endpoint run` picker's Local and Project views while still showing online under Subnet; all views now agree and show it offline.

## [0.19.0] - 2026-07-01

A field-hardening release. Twelve bugs surfaced by running `spt` across real remote nodes are fixed: cross-node attach and messaging now work and tell the truth, remote presence and counts read correctly, attaching to a running terminal session repaints cleanly instead of corrupting scrollback, `spt rc` works on Windows 10 / raw PowerShell, and adapter update and digest handle relocated installs.

### Added

- **`spt rc` can now attach to an endpoint running on another node.** Previously `spt rc <endpoint>` only resolved endpoints with a live session on the local machine — a cross-node `Active` endpoint (visible in `spt endpoint list`) failed with `no live session for endpoint`. `rc` now resolves the owning node from the registry and attaches over the network, so you can drive a remote endpoint the same way you drive a local one.

### Changed

- **`spt endpoint list` now labels the local machine by name.** The `LOCAL (this node)` header is now `This node: <node-id>`, so a listing captured from one machine is unambiguous about which node produced it.
- **`spt endpoint list` uses the same status codes and colored markers as the `spt endpoint run` picker.** The non-interactive listing previously printed raw, text-only status; it now renders the picker's colored square glyphs and status vocabulary, so both surfaces read identically.
- **`spt endpoint run` groups endpoints by machine instead of by subnet.** A machine that shares two subnets with you used to appear twice (once per subnet) with duplicate endpoints; it now shows as a single group with the shared subnets listed beneath the machine name.
- **A lone detached endpoint no longer reads as `Dormant`.** `Dormant` is the multi-instance routing state; a single detached instance now displays as online instead of borrowing that label.
- **The top-right endpoint ID badge is off.** The one-shot corner badge scrolled off screen and left artifacts as the hosted TUI animated or resized; it is disabled pending a proper sticky overlay.

### Fixed

- **Attaching to a running terminal session no longer corrupts the scrollback.** Cold-attaching to a full-screen TUI (e.g. Claude Code) used to replay the raw output ring into a fresh terminal — flipping the alternate screen on and off mid-stream and spilling TUI frames into history. The broker now keeps an authoritative screen model and synthesizes a clean repaint of the current screen on a cold attach, so you get the live frame, not a corrupt transcript. (A resume from a known point still re-fetches raw output as before.)
- **`spt rc` to an already-running endpoint no longer prints garbled escape codes on Windows 10 / raw PowerShell.** The garbling was the same raw-ring replay problem as above (not a client terminal-mode issue — `spt endpoint run --attach` rendered fine in the same terminal); the clean-repaint-on-attach fix resolves it. VT output is also enabled defensively on legacy Windows consoles.
- **`spt rc` to a live local endpoint no longer times out with `brain IPC read deadline elapsed` after a self-update.** A single panic while the broker's effect journal was locked could poison it and brick every subsequent attach; the journal now recovers from a poisoned lock, and the loopback attach path fails fast with a real error instead of an opaque 10-second deadline.
- **`spt send` across nodes no longer reports `SENT(WAN)` when nothing was delivered.** A cross-node send was a fire-and-forget local buffer write — a refused or no-perch delivery was silently dropped while the sender printed success. The receiver now writes the delivery outcome back and the sender waits for it, so a real failure prints an honest line; the dial also tries the last-known direct address first (mirroring the gossip path) instead of forcing a cold discovery on every send.
- **The remote endpoint count no longer drifts as endpoints are added and purged.** A remote viewer's `--nodes` count counted non-routable ghost rows in the denominator and never evicted purged endpoints, producing wrong ratios like `0/2` or `1/3`. The count now uses a routable-only denominator, and rows left offline past a grace window are evicted from the gossiped snapshot instead of leaking forever.
- **A locally-controlled endpoint no longer shows as "ready to control" on other machines.** Remote viewers only learned about a *remote* controller; a locally-driven endpoint gossiped as uncontrolled. The broker now advertises whether *anyone* (local or remote) is driving an endpoint, so remote viewers see it as controlled.
- **`spt adapter add` no longer swallows install errors.** Errors from the install-as-first-update step were discarded; the failing step's output is now surfaced, and the composite post-install step runs at install time.
- **`spt adapter update` no longer fails to re-register after fetching.** The update derived the install directory from the `[update]` repo name rather than the adapter's registered source directory — so after a repo rename it wrote to a fresh empty directory and then failed re-register with `os error 2`. Update now targets the registered source directory and tolerates a changed update repo.
- **`spt endpoint digest` now works for endpoints whose transcript lives under a relocated profile.** A profile that relocates the harness transcript tree (via a runtime env like `CLAUDE_CONFIG_DIR`) produced `NO_DIGEST` because the on-demand extractor ran without that environment. The digest path now carries the profile's transcript-location environment to the extractor, which locates and reads the transcript itself.

## [0.18.0] - 2026-06-30

A small release that smooths `spt update`: clearer messaging when the latest version is already downloaded, and a one-step `spt update fetch --apply`.

### Added

- **`spt update fetch --apply`.** Fetch and install in a single step — it applies the staged update even when the latest was already downloaded (so a no-op fetch still installs). The one-shot "get me to the latest", replacing the brittle `spt update fetch && spt update apply` chain (which skipped the install whenever fetch found nothing new to download). A genuine fetch problem (bad signature, no build for your platform, a real downgrade) still stops without installing.

### Fixed

- **`spt update fetch` no longer reports an already-downloaded update as an error.** When the latest version was already fetched and only needed installing, `spt update fetch` printed a raw internal rejection (`UPDATE_FETCH_REJECTED:Rollback { … }`) and exited non-zero, which read as a failure. It now says **"Update (counter N) is already downloaded. Run `spt update apply` to install it."** (or "Already up to date") and exits cleanly; genuine refusals print a plain, readable reason instead of a debug dump.

## [0.17.0] - 2026-06-28

A minor release that hardens joining a subnet across the wider internet and makes endpoint presence tell the truth across machines: a join now survives a half-broken IPv6 connection, the join flow asks for the code only after it finds a member and tells you what is happening (and what went wrong), dead endpoints no longer appear online on other machines, and the endpoint picker shows the same detail for remote endpoints as for local ones.

### Added

- **`spt subnet join` now shows progress while it searches.** Instead of a single silent "Searching…", the command prints the elapsed time and the deadline every few seconds, so a slow join reads as "still working", not "hung".
- **`spt subnet join --verbose`.** On a failed join, `--verbose` prints a diagnostic dump — which IP families were usable, the time window it searched, how many attempts it made against the deadline, and the last concrete error — so you can tell a dead subnet from a wrong code from a network problem.
- **Force an IP family off — `SPT_DISABLE_IPV6` / `SPT_DISABLE_IPV4`.** Set either environment variable to make the daemon skip that IP family at startup regardless of what it probes (a deterministic escape hatch, mirroring `SPT_NTP_SERVER`). Setting both is an error.
- **The endpoint picker shows remote endpoints in full detail.** Endpoints on other machines in the subnet now render with the same state as local ones — bound vs. unbound, who is controlling an endpoint (the controlling node is named in the detail pane), and harness-only endpoints — instead of being flattened to a plain online/offline dot.

### Changed

- **Joining a subnet now survives a half-broken IPv6 connection.** If a machine can resolve IPv6 addresses but cannot actually reach them, `spt` used to silently spend its whole join window on the dead path and fail with no error. It now checks each IP family once at startup and uses only the ones that actually work (both, IPv4-only, or IPv6-only), so a join over a broken-IPv6 network succeeds.
- **`spt subnet join` asks for the pairing code after it finds a member, not before.** The join is now two-phase: it first finds a member of the subnet, then prompts for the code and pairs immediately. Because the code is used the moment you enter it, a slow search no longer causes a freshly-read code to be rejected as "wrong", and re-entering a code after a typo retries the pairing only — it no longer restarts the whole search. (The non-interactive `--code` form is unchanged.)

### Fixed

- **Other machines no longer show your closed endpoints as online.** An endpoint whose session had ended was advertised to other nodes in a way they painted as online (green), even though its own machine correctly showed it closed. A closed-but-machine-up endpoint is now advertised as suspended, so every machine agrees: it reads as suspended (a distinct gray, wakeable), never falsely online.
- **A failed subnet join now tells you why.** A join that could not find a member used to end with no message at all. The failure is now reported before any code prompt, with the last concrete error (and the full diagnostic dump under `--verbose`).

## [0.16.0] - 2026-06-25

A minor release adding a one-lever adapter-update arc (a delegated post-step), a global `--json` for status queries, an incremental digest cursor, a persistent `spt rc` identity marker, and manifest substitution primitives — plus the removal of `spt send --reply-to`.

### Added

- **Composite adapter update — `[update.post]`.** A manifest can declare a delegated post-step that `spt adapter update` runs *after* the primary update avenue resolves, so one command both pulls the adapter's `.spt` (e.g. from a GitHub release) **and** runs an in-harness sync. The post-step runs unconditionally (even on an up-to-date no-op), reads a published JSON line on stdin describing the update, and its stdout decides the post-update notice. A post-step failure warns and falls back — it never rolls back the committed pull.
- **Global `--json` for status queries.** `endpoint list`/`whoami`, `daemon status`, `subnet status`/`show-code`, `endpoint description`/`role`, `adapter list`/`version`, `notif list`, `grant list`, `access list`, `shell list`, and `how-to` now accept a global `--json` flag emitting stable, explicit fields for scripted consumption. (Action commands ignore it.)
- **`spt endpoint digest` incremental cursor.** `--json` output gains `--last <N>` (the last N turns; `--last 1` is the latest turn), a stable per-entry `seq` that survives live re-projection and window slides, `--after <seq>` (only what is newer, with a full-refresh signal if the cursor fell out of the window), a `partial` flag on the in-progress turn, and a per-entry `ts` — so a consumer can process turn-ends incrementally instead of re-reading the whole window.
- **`spt rc` identity marker.** An attached controller now shows a persistent top status row — right-aligned `SUBNET : ENDPOINT_ID @ NODE` in cyan — so you always know which endpoint you are driving. It re-asserts across alt-screen, resize, and scroll-region resets.
- **Manifest substitution primitives.** Two adapter-static substitution keys — `{adapter_dir}` (the adapter's install dir, which survives updates) and `{adapter_name}` — are available wherever command/string substitution runs, and `[strings]` values are now substituted at `get-string` read time. This lets an adapter resolve a path to its own packed binary without spt-core ever executing it.
- **`[message-idle-translation-binary]` takes a `command`.** The idle-delivery translation binary can be declared with a `command` (program token plus args, with adapter-static substitution) instead of the bare `path`, so it can be invoked as a subcommand of a consolidated adapter binary. The spawn and stdin/stdout protocol are unchanged.
- **Empty-scope creation flow.** Running `spt endpoint run` (or bare `spt`) on a node with no endpoints at all now opens directly on the adapter-creation screen instead of an empty picker.

### Changed

- **`[message-idle-translation-binary].path` is deprecated** in favor of `command`. It still parses (and warns at registration); exactly one of `path`/`command` may be set.

### Removed

- **`spt send --reply-to` is removed.** The send target is now a required positional argument; reply correlation rides the structural `from` on the message envelope. (The flag was a target-fallback nicety with no wire effect.)

## [0.15.0] - 2026-06-24

A minor release adding per-message delivery controls to `spt send`, an opaque metadata payload, a resume-context pull command, and a Windows console-flash fix.

### Added

- **`spt send` delivery-window controls.** `--idle-only` delivers a message only while the target is idle (the idle/wake window), holding until then; `--active-only` delivers only through the target's own poll, without ever waking an idle target. (`--active-only` replaces the old `--deferred`, which still works as a hidden back-compat alias.)
- **`spt send` channel controls.** `--prefer-native` delivers through the target's translation binary when one is running and falls back to the normal channel otherwise; `--force-native` delivers only through the translation binary, with no fallback or spooling (reported undelivered if none is running).
- **`spt send --ephemeral`** drops a message that can't be delivered to a translation-binary target within its window, or that expires (TTL), instead of spooling it. (A harness-relay target with no live listener still spools — that evaporation case lands in a later release.)
- **`spt send --json-payload <JSON>`** attaches an opaque JSON metadata blob alongside the message body, carried verbatim for the receiving adapter to parse (it does not replace the body).
- **`spt api psyche-download <id>`** pulls an agent's resume context for an adapter to restore at session start, appending any not-yet-synthesized commune/signoff updates.

### Fixed

- **Inbound messages are no longer silently lost if the delivery worker faults mid-handoff** — they re-spool and surface on the next poll (closes the transient gap left after the v0.14.3 raw-inject removal).
- **The spt-hosted translation binary no longer flashes a console window on Windows.**

## [0.14.3] - 2026-06-23

A patch release hardening idle message delivery to spt-hosted endpoints.

### Fixed

- **Idle messages to an spt-hosted endpoint are no longer silently dropped when delivery can't complete.** If no working translation helper is available to submit an incoming message to an idle spt-hosted endpoint, the daemon now queues the message for poll-based delivery and honestly reports it as queued — instead of typing it into the endpoint's terminal without ever submitting it (which looked delivered but was not). Delivery via a working helper is unchanged.

## [0.14.2] - 2026-06-23

A patch release fixing idle message delivery to spt-hosted endpoints.

### Fixed

- **Messages delivered to an idle spt-hosted endpoint now submit instead of stalling half-typed.** The daemon now resolves an adapter's idle-delivery translation binary against the adapter's install directory, so it launches correctly; previously the helper failed to start and an incoming message was typed into the endpoint's terminal but never sent.

## [0.14.1] - 2026-06-23

A patch release: `spt adapter add` no longer clobbers an existing install and reports its outcome more clearly, and the interactive `spt endpoint run` picker now lets you choose a new endpoint's home subnet on multi-subnet nodes.

### Added

- **The interactive `spt endpoint run` picker offers a home subnet.** On a node that belongs to more than one subnet, choosing *Create new* now prompts for which subnet the new endpoint should home to, with your most-recently-used subnet first. (The non-interactive `--subnet` path from 0.14.0 is unchanged.)

### Changed

- **`spt adapter add` is non-destructive.** Re-adding an already-registered adapter is now refused, with guidance to use `spt adapter update` or `spt adapter remove` instead. A fresh install stages the new files and swaps them in only once it is complete, so a failed or repeated add can no longer clobber a working install or leave it half-written (previously this could surface as a cryptic "os error 2").
- **`spt adapter add` reports its outcome more clearly.** Its messages now distinguish an adapter that is installed and ready from one whose install is still pending.

## [0.14.0] - 2026-06-23

A release focused on how endpoints are created: each endpoint now picks its subnet once, when you create it, on nodes that belong to more than one subnet; and you can attach to an endpoint while it is still starting up, before it is ready to receive messages.

### Added

- **An endpoint chooses its subnet when you create it.** `spt endpoint run` homes a new endpoint to a single subnet for its lifetime. On a node that belongs to just one subnet this happens automatically. On a node in two or more subnets, `endpoint run` now settles the subnet up front: interactively it proposes your most-recently-used subnet and asks you to confirm; non-interactively it requires `--subnet <name>` and, if you omit it, refuses immediately with the list of available subnets instead of hanging. Previously a multi-subnet node could stall silently during endpoint bringup.
- **You can attach to an endpoint before it finishes starting.** Between the moment an endpoint is spawned and the moment it binds, it now accepts a connection: `spt rc <id>` (and `spt endpoint run --attach`) drops you into the live pre-bind session, so you can watch startup or clear a bringup prompt before the endpoint is ready. Such an endpoint is not message-addressable yet — it appears as a hollow `UNBOUND` row in the endpoint picker, `spt endpoint list`, and `spt whoami`, distinct from an offline endpoint.

## [0.13.2] - 2026-06-22

A release focused on adapter packaging and updates: one adapter package can cover several platforms, adapters update live without restarting your agents, installs can pull from private GitHub repositories, plus a few adapter-tooling conveniences.

### Added

- **One adapter package can cover multiple platforms.** A `.spt` adapter can now bundle binaries for several operating systems and CPU architectures alongside one shared manifest; installing extracts the shared files plus the binary for your platform. Existing single-platform packages keep working.
- **Adapters update without restarting your agents.** When an adapter updates, the daemon stops just that adapter's background binary, swaps it in place, reloads its manifest, and restarts it — running agents continue across the update.
- **Adapter installs and updates can use private GitHub repositories.** `spt adapter add --release` can fetch from a private repo through the GitHub CLI, with no access token to manage. New `--gh` / `--https` flags choose the transport (default: automatic).
- **Adapters can show a notice after they update.** An adapter may declare a short Markdown message shown once, only when an update is actually applied.
- **`spt adapter version <name>`** prints an installed adapter's version.
- **`spt adapter digest-proof` and `spt adapter translate-proof` can test an unpackaged adapter** via new `--dir` / `--manifest` options — proof a development or bare-file adapter before it's installed.

### Fixed

- **`spt --help` and the CLI reference no longer leak internal tracking codes.** Generated help and reference text are swept clean of internal identifiers.

## [0.13.1] - 2026-06-22

A patch release: an author-time proof tool for idle-delivery translation binaries, plus a correction to the translation-binary contract docs.

### Added

- **`spt adapter translate-proof <adapter> --event '<EVENT…>'`** — validate an adapter's `[message-idle-translation-binary]` without a live session. It spawns and feeds the declared binary exactly as the daemon does at idle delivery and prints the keystroke commands it emits (`{key}` / `{text}` / `{delay_ms}` / `{commit}`), failing a binary that emits nothing or never sends a terminating `{commit}`. The author-time mirror of `spt adapter digest-proof`.

### Fixed

- **The `[message-idle-translation-binary]` contract now documents `{commit}`.** The published contract had omitted the mandatory `{"commit":true}` sequence terminator (and its degenerate example would have faulted at the 5-second commit deadline); it now describes `{commit}`, the inject floor, and the commit-deadline behavior.

## [0.13.0] - 2026-06-21

A minor release: idle message delivery for spt-hosted endpoints now runs through an adapter translation binary, `spt rc` gains real paste, key, and mouse support on Windows and stays attached under heavy output, session resume actually resumes a prior session, and the daemon no longer flashes a console window.

### Added

- **Idle message delivery for spt-hosted endpoints now uses a translation binary.** An adapter can declare a `[message-idle-translation-binary]`; spt-core brings it up alongside the endpoint, where it polls the relay for incoming messages and optionally emits keypresses, delays, and text injection that spt-core applies to the endpoint's terminal. Idle delivery now flows through the relay poll for every endpoint, instead of spt-hosted endpoints falling back to direct PTY injection.
- **Windows paste in `spt rc`.** Ctrl+V and right-click now paste the local clipboard into the attached agent as a single bracketed paste.
- **Windows special keys in `spt rc`.** Arrow keys, Home/End, Delete, function keys and other special keys are translated to terminal sequences and reach the agent — previously only plain characters got through.
- **`spt rc` forwards mouse scroll** to the agent's terminal.

### Fixed

- **Pasting or typing into an spt-hosted endpoint no longer freezes the daemon.** A large paste or input burst could wedge the daemon's input path so every new attach died; input now runs on a dedicated per-session writer and never blocks the daemon (this also covers the effect-journal stall on interactive input).
- **Session resume actually resumes now.** Agent endpoints track session history and offer explicit session resume via `spt endpoint run` (`--resume <session>` or *Resume from history*); the adapter manifest can now declare a `[session.resume]` command so the relaunch reattaches the prior session instead of always starting a new one. The run picker now shows each row's working directory and local time.
- **`spt rc --view` viewers survive a high-output terminal.** A viewer no longer dies when the output backlog rolls over or it is briefly evicted — it snaps forward or skips to live instead of failing — and a slow controller can no longer starve a concurrent viewer.
- **`spt rc` no longer races a just-started agent.** Attach now waits for the endpoint to come online, instead of failing when you attach immediately after `spt endpoint run`.
- **The daemon no longer flashes or respawns a console window on Windows.**
- **Windows Backspace and Ctrl+Backspace now do the right thing in `spt rc`.** Backspace deletes a character and Ctrl+Backspace deletes the previous word (Windows-native), instead of both deleting only a character.

### Changed

- **The `spt endpoint run` picker is clearer.** It opens directly on an existing pick, auto-attaches, shows the controlling node name, and produces clean bring-up output.
- **Human-prose command output renders Markdown.** Prose output (how-to topics and similar) now shows styled headers and emphasis in a terminal and clean plain text when piped — matching the v0.12.1 `--help` fix.

## [0.12.1] - 2026-06-18

A patch release fixing the live-agent lifecycle in a real terminal: attaching to a running agent, keeping it alive when you close the terminal, and the daemon staying responsive now all work as intended. Also polishes `spt endpoint list`, the run picker, and `spt --help`.

### Fixed

- **Attaching to a running agent now shows its output.** `spt rc <id>` against an agent started with `spt endpoint run` now delivers the agent's terminal output immediately, instead of connecting to a blank screen.
- **Closing the terminal that started an agent no longer kills it.** When `spt endpoint run` launches the background daemon for you, closing that terminal tab or window now leaves the agent running and re-attachable with `spt rc <id>`.
- **A crashed agent with a disconnected viewer no longer freezes the daemon.** A dead agent process combined with an abruptly-closed `spt rc` could previously wedge the daemon so new agents wouldn't start; the daemon now stays responsive and marks the dead agent offline.

### Changed

- **`spt endpoint list` and `spt whoami` always include this machine's local agents** — your own just-started agent always shows up. **The `--local` flag has been removed**: local agents are now always merged into the listing.
- **The `spt endpoint run` picker offers the right action.** An already-running agent now offers **Attach** instead of a meaningless "Start now".
- **`spt --help` renders cleanly.** Help text no longer shows raw `**` and backtick characters — emphasis and command names display as styled text in a terminal, and as plain text when piped or redirected.

## [0.12.0] - 2026-06-18

A minor release fixing the live-agent lifecycle: running an agent, attaching to it, and stopping or restarting the daemon now behave correctly, and an agent's reported status reflects whether it is actually reachable.

### Added

- **`spt endpoint purge <id>`** — removes an offline endpoint's record and leftover files in one step (offline endpoints only).
- **Agents started with `spt ready` now appear in the `spt endpoint run` resume-from-history picker when offline.** Previously only live agents were offered there, so a message-listener agent couldn't be relaunched from history; now it can.

### Fixed

- **An agent's status now reflects whether it is actually reachable.** A daemon-hosted agent whose session has gone away is now marked offline on the next check instead of staying "online" indefinitely. Agents reached over a relay are unaffected.
- **Attaching to an agent no longer hangs on a dead or silent session.** `spt rc` now fails fast with a message instead of showing an endless blank screen, and stopping an endpoint marks it offline.
- **`spt daemon stop` now fully stops the daemon.** It finishes releasing its sockets before reporting success, and it cleans up the agent and Psyche processes it launched instead of leaving them running.
- **Stopping or signing off a single agent now also shuts down its Psyche.** Previously, stopping one agent (without stopping the whole daemon) left its Psyche process running until the next `spt daemon stop`; the Psyche is now reaped as soon as the agent is un-hosted.
- **Restarting the daemon no longer revives stale "online" agents** that are not actually running, and no longer leaves a duplicate Psyche behind.

## [0.11.0] - 2026-06-17

A minor release: messages now reach daemon-hosted agents, endpoint environment variables are populated, and several errors are clearer.

### Fixed

- **`spt send` now delivers to an agent whose terminal is hosted by the daemon.** When the target has no `spt api listen` relay (the daemon holds its terminal directly), `spt send` previously queued the message silently. It now injects the message into the agent's session and reports "Sent" only once delivery is confirmed — otherwise it queues it ("Queued") as before, and never reports a false "Sent".
- **`spt endpoint run` now fills in `[env]` values.** Placeholders such as `{id}` in an adapter's `[env]` entries (for example `SPT_ENDPOINT_ID`) were never substituted, so an agent launched without explicit flags came up with an empty endpoint id and never registered. The values are now substituted and set on the launched process.
- **A daemon-hosted terminal now reports a clear message when the daemon is stopped,** instead of failing with a raw "failed to fill whole buffer" that looked like a crash.
- **Clearer error when an adapter's manifest has not been extracted yet.** Using such an adapter now reports an actionable message (and logs it as skipped) instead of a raw "os error 2" and a silent drop.
- **A removed endpoint no longer lingers with a stale status** — it is now shown as offline.

## [0.10.0] - 2026-06-17

A minor release: richer, consistent agent status in the picker and `spt endpoint list`.

### Added

- **Four-state endpoint status in the picker.** Beyond offline and online, a live agent running only inside its harness (with no hosted terminal) now shows as "online — harness only", and an agent whose session is currently being driven by someone shows as "online + controlled" — so you can tell at a glance how an agent is reachable.

### Changed

- **Subnet entries now show a readable node label instead of a raw key prefix,** rendered the same way in both the picker and `spt endpoint list`.
- **`spt endpoint list` columns are now aligned** instead of ragged, and the subnet listing notes that it is the subnet view, so a local agent you just started isn't mistaken for missing.

### Fixed

- **The picker now loads each agent's project history** — it previously always showed empty.
- **A self-owned agent listed under both Local and Subnet no longer shows conflicting status.** The live local status is now authoritative for both listings.

## [0.9.1] - 2026-06-17

A patch hardening harness-adapter resolution and making a stale-daemon error actionable.

### Fixed

- **Going live or ready still resolves the adapter when the harness executable was renamed in place.** After an in-place update that leaves the running program renamed (e.g. `claude.exe.old.<timestamp>`), the daemon now matches it to its adapter by the name stem before the first dot, so bringup keeps working instead of failing to find the adapter.
- **A daemon left running from before 0.9.0 now reports an actionable error.** Seeding a session against an out-of-date daemon previously failed with a cryptic "failed to fill whole buffer". It now explains the cause and tells you to run `spt daemon stop` (the daemon restarts automatically on the next `spt api` command).

## [0.9.0] - 2026-06-17

A minor release: harness-hosted agents go live (or ready) without naming an adapter — the daemon resolves it from the running session.

### Added

- **`[adapter] host_binaries` manifest field** — declares which harness executables an adapter hosts; the daemon matches a live session to its adapter by the running binary.
- **`spt adapter use <adapter>[:profile]`** — sets the default adapter profile per harness binary. Durable (survives adapter updates); without it, the most-recently-registered matching adapter is used.

### Changed

- **Going live or ready under a harness no longer requires `--adapter`.** `spt api seed` records just the session (pid + id); `spt api listen` resolves the owning adapter automatically from the session's process — restoring the one-step legacy bringup. `--adapter` remains an optional override for adapter development.

## [0.8.4] - 2026-06-17

A patch fixing a Windows launch failure for harness/shell adapters whose start command is a script.

### Fixed

- **Windows: harness and shell sessions launched via a script command now start.** A start command that resolves to a Windows batch file (`.cmd`/`.bat`) or an extensionless CLI shim (e.g. the node `ccs` launcher) previously failed with "not a valid Win32 application" (os error 193) — the daemon tried to execute the non-PE file directly. spt-core now resolves the program through `PATHEXT` (preferring real executables) and runs script targets through their interpreter (`cmd.exe` / PowerShell). No change on macOS/Linux.

## [0.8.3] - 2026-06-16

A reliability patch: a dead or unresponsive subnet peer can no longer stall background sync.

### Fixed

- **A dead or unresponsive peer can no longer stall background sync.** The daemon now bounds every network operation it makes on a live agent's behalf, so a roster peer that has gone offline (or stopped responding mid-handshake) fails fast as an ordinary, recoverable error instead of hanging the daemon's peer-sync loop. Previously such a peer could freeze background synchronization for tens of minutes and force repeated internal restarts; now the peer is simply skipped and retried on the next cycle, and a healthy node's sync keeps flowing. Normal peers are unaffected (no added latency).

## [0.8.2] - 2026-06-16

A reliability patch for command-template argument handling and dead-on-launch Psyche reporting.

### Fixed

- Command-template substitution now fills each argument as a single element: a multi-word or quoted value (e.g. a Psyche prompt) is passed through intact instead of being split or injected across multiple arguments.
- A daemon-hosted Psyche that launches but exits immediately is now correctly reported as a failed host (the harness-reachable psyche-host-error signal added in v0.8.1), instead of leaving a phantom "online" entry backed by a dead process.

## [0.8.1] - 2026-06-16

A visibility fix: a daemon that can't host a live agent's Psyche now reports it, instead of leaving the agent looking online with no cause.

### Fixed

- **Harness-reachable psyche-host failure signal.** When the daemon cannot host a live agent's Psyche (for example, the adapter's psyche binary is missing from its install directory), the failure is now recorded on the agent's perch state and surfaced by `spt endpoint list` / `spt whoami` as a `psyche-host: FAILED (<reason>; <n> attempt(s); <ts>)` line. Previously this failure was silent — visible only on the daemon's internal stderr — leaving an agent reporting `online` with no Psyche and no visible cause. Liveness (`status`) is unaffected and remains authoritative; the new `psyche_host_error` field is additive and backward-compatible.

## [0.8.0] - 2026-06-16

Remote shells you can hand off and watch across the subnet, two new in-CLI how-to guides, plus adapter-distribution and install fixes.

### Added

- **Drive and watch a hosted shell across the subnet.** Building on the remote-terminal host from 0.7.0, a hosted session now has a single live driver and any number of read-only watchers, with explicit per-capability consent before a sensitive action runs. You can tunnel into a same-node session, and a gateway node can own the shell on behalf of a peer it fronts. (Cross-node tunnelling is not yet available.)
- **Two new `spt how-to` guides: `subnet` and `live`.** Pairing machines (create vs join, the 6-digit code, reaching remote agents) and running as a live agent (the persistent `spt api listen` relay, the Psyche seam) now have task-oriented in-binary topics instead of dead-ending.
- **Update an adapter from a GitHub release, optionally signature-checked.** An adapter's `[update]` feed can now be a GitHub release (`avenue = "gh_release"`); `spt adapter update` pulls the newer `.spt`. Declare a `signing_key` and verification is fail-closed — an unsigned or wrong-signature artifact is refused, not installed.
- **`spt api` resolves an adapter's manifest and install directory from `--adapter`.** Pass `--adapter <name[:profile]>` without `--manifest` and spt looks both up from the registry; `--manifest` becomes an override for an unregistered or local manifest.

### Fixed

- **A bundled adapter binary resolves from its install directory before `PATH`.** An adapter that ships its own helper binaries — a `[digest]` extractor, the Psyche-spawn command — now finds them in the adapter's install directory first, so a bare program name in a manifest works without you placing it on `PATH`.
- **The Windows at-logon task starts the daemon in the background.** It now launches detached (`spt daemon start`) instead of holding a foreground console window.

## [0.7.3] - 2026-06-15

Install an adapter straight from a GitHub release.

### Added

- **`spt adapter add --release <user/repo>` installs an adapter from a GitHub release.** Point it at a repo — optionally with `--tag <tag>` and `--asset <name>` — and spt downloads the published `.spt` archive, extracts it, and registers the adapter. This lets you ship an adapter that lives inside a larger repository, where cloning the whole tree with `--github` doesn't fit. It trusts HTTPS and GitHub for the download, and doesn't change how an already-installed adapter updates.

### Changed

- Clearer adapter-installation guidance: a spelled-out post-install activation step and the distribution-repo layout for `--github`.

## [0.7.2] - 2026-06-15

A digest-proof fix: `spt adapter digest-proof` now works with the documented `{session_id}` example templates.

### Fixed

- **`spt adapter digest-proof` now fills the same substitution keys the live extractor does.** A proof run previously supplied an empty key map, so any extractor template using `{session_id}` (the shape in the published examples) failed instead of producing a sample. It now populates `{id}` and `{session_id}` to match runtime, with an optional `--session` to pin a specific value.

## [0.7.1] - 2026-06-15

A consistency-and-clarity patch: messages now arrive in one envelope across every channel, and `spt update apply` confirms success in plain language.

### Changed

- **One message envelope across every channel.** Messages drained with `spt api poll` and `spt api worker-poll` now arrive in the same `<EVENT type="msg" from="…">…</EVENT>` envelope as the live `spt api listen` stream — one format to parse everywhere, and several queued messages are now self-delimiting. (Building an adapter? Parse the `<EVENT>` envelope on the poll channel; the older internal frame is gone.)

### Fixed

- **`spt update apply` now confirms the update applied, in plain language.** A successful apply prints `Updated spt-core to vX.Y.Z.` with a link to the changelog, instead of the earlier provisional "trial" wording that left a finished update looking unresolved. (The changelog link now points at the canonical `github.com` address.)

## [0.7.0] - 2026-06-14

Remote terminals land. You can now bring an agent up under spt's own terminal host and attach to it from your own machine or across the subnet — drive it, or just watch — with a real one-at-a-time controller and any number of read-only viewers.

### Added

- **`spt endpoint run` brings an agent up under spt and attaches you to it.** spt hosts the session's terminal itself; `spt endpoint run --adapter <a> --id <name>` starts it and drops you in. Detach (see `spt rc`) and it keeps running headless until you come back — from this machine or another node.
- **`spt rc <id>` — attach to a running session's terminal.** Scrollback replays, live output streams, your keystrokes drive it. Detach with **ctrl-b** then `d` (the session keeps running); `ctrl-b ctrl-b` sends a literal ctrl-b. Works the same whether the session is on this machine or across the subnet.
- **Controller / viewer model.** One person drives at a time (the *controller*); any number can **`spt rc <id> --view`** to watch read-only (no input, never resizes the session). The controller's window size drives the terminal.
- **`spt rc <id> --take` — take control.** If someone else is driving, `--take` kicks them (they get a loud "you were taken over by …" notice and are detached) and you become the controller. A plain `spt rc <id>` on a session someone else controls now **refuses with guidance** (it tells you to `--view` or `--take`) instead of silently stealing control.
- **`spt endpoint run` is now an interactive picker.** Run it bare (no `--adapter`/`--id`) and pick *Create new* (choose a harness adapter + profile, name the endpoint) or *Pick existing* (browse by project / local node / subnet with live status, type-to-filter, and a description pane), then attach / start / view / resume-from-history. The flagged form is unchanged for scripts. **Bare `spt`** (no subcommand) opens the same picker on an interactive terminal — a pipe, redirect, or CI run still prints help instead. A controlled endpoint in the picker shows **View** and **Kick and take control** (not a plain attach), pinned with `controlled by <node> (+N viewing)`. Press `s` to bake the current selection into a project-root `spt-<id>` launcher shortcut (an adapter can brand it, e.g. `cc-<id>`, via the new `[adapter] shortcut_basename` manifest field).
- **`spt subnet join` shows a QR code + setup code on success.** After joining, scan the QR (or read the `otpauth://` code) to re-provision an authenticator app for the subnet.
- **Privilege-gated commands self-elevate, cross-platform.** When a command needs elevation, spt re-launches itself the right way for your system — a Windows UAC prompt, a Linux desktop `pkexec`/terminal `sudo`, or inline `sudo` in a terminal — and prints the exact command to run by hand when it can't.
- `spt spt` — ???

### Changed

- **`spt whoami` now shows the full picture.** It is an alias for `spt endpoint list` — your own endpoint pinned first (with its description, if set), then the subnet roster — instead of just printing a bare id.

## [0.6.0] - 2026-06-13

The session digest grows up — its own adapter seam, it follows an agent across `/clear`, and it shows the context spt itself feeds the agent.

### Changed

- **The session digest gets its own adapter seam, follows an agent across `/clear`, and shows the context spt feeds it.** An adapter now declares a `[digest]` *extractor* that maps its native log to the digest's `{role, text, tool, ts}` contract — its **own** manifest section, separate from `[history]` (which stays full-fidelity for the echo-commune). The digest **spans** a `/clear` or `/compact`: it enumerates an endpoint's recent sessions and shows a `── /clear ──` divider instead of going blank at every reset. It also **interleaves spt's own injected context** (session-start Psyche download, echo mirror, incoming messages) with the agent's activity, in time order. New `spt adapter digest-proof <adapter> --sample <log>` runs your extractor against a real log and prints exactly what parsed, what rendered, and **every dropped line with the reason** — no more silent-empty digest.
  - **Breaking (adapter authors):** this **supersedes** the v0.5.0 guidance to emit the digest contract through your `[history]` normalizer. Declare a `[digest]` extractor (or push via `spt api digest-entry`) instead; one `[history]` normalizer can no longer serve both the opaque echo-commune and the contract-typed digest.

## [0.5.0] - 2026-06-13

Adapter customization and richer session surfaces — make an adapter your own without forking it, give an agent a durable role, mark who a message came from, and get an at-a-glance "what is this agent doing" view for any session.

### Added

- **Adapter profiles — customize an adapter without forking it.** `spt adapter create-profile <adapter> <name>` makes a named variant of an installed adapter (its own environment, prompts, and capabilities); launch it by addressing `adapter:name`. A profile you create locally **survives updating or re-adding** the underlying adapter, and `spt adapter list` shows each profile as its own spawnable option. `spt adapter delete-profile` removes one. (A profile may only *tighten* what the adapter allows — an attempt to loosen a capability is refused at registration.)
- **Adapter config values.** `spt adapter set-string <adapter> <key> <value>` and `spt adapter get-string <adapter> <key>` read and write an adapter's named settings — per-profile when you address a profile.
- **Keyword hints.** An adapter can teach its own commands in context: when a keyword it declares appears in one of your messages, a one-line tip surfaces — at most once per session, so it never nags.
- **`spt endpoint role` — a durable agent role.** Set a free-form statement of what an endpoint is for; it is shown to the agent **first**, at the start of every new session. `spt endpoint role` is the only thing that writes it — nothing automated ever overwrites your wording.
- **`spt api digest-entry`** lets a harness with no readable session log feed its activity directly, so even those sessions show a live digest.

### Changed

- **The live session digest now works for any session, not just terminal-hosted ones.** `spt endpoint digest <id>` builds its at-a-glance view from a session's normalized logs instead of scraping the raw terminal stream — so a session spt-core doesn't host in its own terminal (for example a Claude Code session) now shows a digest too. `--follow` still streams changes as they happen.
  - **Breaking (adapter authors):** the `[pty_digest]` manifest section is **removed**. The digest now rides your `[history]` source — emit your history records as `{"role": …, "text": …, "tool": …}` JSON (or push them with `spt api digest-entry`) and the digest builds itself. No digest-specific manifest section is needed.
- **Messages now carry who sent them — a person or an agent.** A message you send is delivered marked as user-sent, and the daemon re-stamps anything that falsely claims to be from a user. A human-backed **Gateway** endpoint is accepted as a first-class endpoint — addressable, able to own shells, and able to subscribe to digests — including from another machine on your subnet.

## [0.4.2] - 2026-06-11

### Fixed

- **(Linux) An update now takes effect immediately — no manual restart needed.** On Linux, applying an update replaced the program on disk but the background service kept running the *previous* version until you restarted it by hand, so a fix could sit installed-but-inactive without you realizing the update hadn't truly taken hold. The service now relaunches its worker onto the freshly applied version on its own — the seamless behavior Windows already had. As an added safeguard on every platform, an update that somehow comes up running the wrong version is now detected and rolled back automatically instead of being recorded as applied.

## [0.4.1] - 2026-06-11

### Fixed

- **An unreachable peer can no longer stall your node's background work.** If another machine on your subnet dropped off mid-exchange — a network drop, a sleep, a hard crash — the daemon's outbound loops (peer sync, notifications, update checks) could hang waiting on it, in the worst case for hours, until something restarted the service. Now a stalled exchange gives up on its own in under a minute and the background loops resume, so one dead peer never freezes the rest of your node.

## [0.4.0] - 2026-06-10

### Fixed

- **`spt update apply` now actually runs the new version — no manual restart needed.** Previously, applying an update replaced the program files on disk but the already-running background service kept executing the *old* code until you manually restarted it. A fix could sit installed-but-inactive, and you'd keep seeing the old behavior — sometimes for a long time without realizing the update hadn't truly taken effect. The background service now relaunches itself onto the freshly installed version automatically, so an update goes live the moment you apply it. The swap is seamless: terminal sessions and network connections the daemon is hosting stay alive across it — nothing you're running gets dropped.
- **A failed update now rolls back on its own.** If a newly applied version can't start cleanly, the service automatically returns to the last version that was working instead of leaving you with a daemon that won't come up. Your machine keeps running on a known-good build while you sort out the bad release.

### Changed

- **(Windows) The background service no longer flashes brief console windows** when it starts or restarts its internal worker process.

## [0.3.2] - 2026-06-09

### Fixed

- **`spt update fetch` can no longer end up installing another platform's binary.** In a mixed Windows/Linux fleet, fetching an update on one machine and letting another machine pull it peer-to-peer could hand that machine a build for the *wrong* operating system — leaving `spt` unable to start. `spt update fetch` now downloads the signed, multi-platform update set, so every machine installs (and re-shares to its peers) the build for its own platform. As an extra safeguard, `spt update apply` refuses any staged update whose target platform can't be confirmed to match this machine. If you have an update staged from 0.3.1, re-run `spt update fetch` on 0.3.2 to replace it with the platform-safe set.

### Changed

- **`spt update apply` prints a friendly confirmation** — for example `Updated spt-core to v0.3.2.` followed by a link to the changelog — instead of a terse internal status line.

## [0.3.1] - 2026-06-08

### Added

- **`spt update fetch`** — pull and stage the latest signed release straight from the project's GitHub releases, then `spt update apply` to install it. This bootstraps the first machine in a fleet (or any machine with no peer to update from), which previously could only receive an update from another machine that already had it. The download is verified against the same signed-release keys as peer-to-peer updates. Add `--tag vX.Y.Z` to fetch a specific version.

### Fixed

- **Messages sent from Windows no longer arrive garbled.** A message piped into `spt send` or `spt ring` from a Windows shell (whose text carries a carriage return) could corrupt how the message displayed on the receiving machine. The message codec now neutralizes carriage returns, and `send`/`ring` trim their input like `notify` already did.
- **A node is no longer stranded offline after a reboot.** If the daemon started before the machine's network was ready (common immediately after boot), it used to come up with no connection and stay that way until you manually restarted it — `spt daemon` would just report the peer pump as "STALLED". Now the daemon keeps retrying the network in the background and brings itself online once the network is up, with no restart needed. While it's waiting, `spt daemon` reports "no connection" honestly instead of a misleading stalled-pump message. (On Linux the installed service now also waits for the network at boot.)

## [0.3.0] - 2026-06-08

### Added

- **`spt subnet revoke <node>…`** — remove one or more machines from a subnet across the **whole fleet**, not just locally. It tells every member to drop the node within moments, then rotates the subnet's shared secret so the removed machine is locked out and must re-pair to come back. By default the rotation is batched at the end of a one-hour window — several revokes in that window share a single rotation, and any member that was briefly offline heals automatically across it. Pass `--force-rotate-seed` to rotate the secret immediately (the compromised-machine path; a member that's offline at that moment will have to re-pair rather than auto-heal). Name each target by hostname, key prefix, or full key. Requires running elevated. This is the fleet-wide counterpart to `spt subnet prune`, which only cleans a dead node off the local machine.
- **`spt daemon start`** — bring the daemon up in the background, idempotently. When `spt` is installed as a service (the Linux per-user service, or the Windows logon task), `start` and `stop` now drive *that* service instead of a stray hand-started daemon — so the two never fight each other for the connection. `spt daemon start` on an already-running daemon just says so and does nothing.

### Changed

- **Subnets are now a full mesh.** *(Breaking — see the upgrade note.)* Every machine in a subnet now connects directly to, and shows, **every other member** in `spt subnet status --nodes` — previously you mainly saw the machines you had paired with directly. Membership in the subnet is now what grants trust, replacing the separate per-peer trust list that earlier versions kept.
  - **Upgrading from 0.2.0:** there is no automatic migration of the old trust list, so after updating, **re-pair your machines into their subnets** (`spt subnet join`, or create + invite from a seed holder) to rebuild membership. Until a machine is re-paired, it won't be reachable in its subnets.
- **`spt daemon stop` is service-aware.** If a managed service owns the daemon, `stop` asks the service manager to stop it cleanly (so it doesn't immediately restart), instead of signalling the process directly. A hand-started daemon still stops the same way as before.
- **`spt daemon run` is now strictly foreground on every platform** — it stays attached to your terminal until you stop it (the form the installed service uses). For a background daemon, use `spt daemon start`. On Windows, running `daemon run` from an elevated shell now refuses with a hint rather than silently disappearing into the background.
- **`spt daemon status` shows what manages the daemon** — whether a service owns it (and is active) or it was started by hand.

### Performance

- **`spt subnet status --nodes` is much faster when several nodes are offline.** It now checks all the quiet nodes at once, so the view comes back in about the time of a single check instead of stacking the wait up node by node. (This matters more now that a subnet is a full mesh and you see every member.)

### Fixed

- **A peer's name no longer disappears when it goes offline.** Once you've seen another node's hostname in `spt subnet status --nodes`, it now stays shown even after that node goes offline — previously the name reverted to a bare key after the node went quiet for a while. The name is only forgotten when you explicitly `spt subnet prune` that node.

## [0.2.0] - 2026-06-08

### Added

- **`spt endpoint` command group.** A single home for everything you do to an endpoint: `spt endpoint fork`, `suspend`, `wake`, `shutdown`, `rename`, `stop`, and `digest` all live here now. (See **Changed** — this is where these moved from.)
- **`spt endpoint list`** — one combined view of every endpoint you can see, grouped by subnet, with your own endpoint pinned at the top.
  - `spt endpoint list --local` shows just this machine's endpoints.
  - `spt endpoint list --subnet <name>` filters to one subnet.
  - `spt endpoint list --detail` adds each endpoint's description blurb.
- **`spt endpoint description [set]`** — read or write an endpoint's description blurb (bare command shows it, `set` writes it).
- **`spt endpoint access`** — per-endpoint access control (`allow` / `revoke` / `open` / `list`), scoped to the individual endpoint.
- **`spt daemon` command group:**
  - `spt daemon status` (or bare `spt daemon`) — a node status view: whether the daemon is running, its background-sync health, your subnets, and your local endpoints.
  - `spt daemon stop` — cleanly stops the running daemon.
  - `spt daemon run` — runs the daemon in the foreground (previously a hidden command).
- **Pause and resume a subnet without stopping the daemon:**
  - `spt subnet detach <name>` — stop advertising and connecting for that subnet (peers see you go offline for it) while everything else keeps running.
  - `spt subnet attach <name>` — start serving it again.
  - Add `--save` to either to make that choice the default the next time the daemon starts.
  - `spt subnet status` now shows a per-subnet state for each subnet (serving / detached / no connection).
- **Leave a subnet:** `spt subnet leave <name>` removes the subnet and its trust completely from this node.
- **Clean up dead nodes:** `spt subnet prune <node>` removes a stale node's trust so this machine stops trying to reach it. You can name the node by its hostname label, a key prefix, or the full key; it refuses if the name is ambiguous or refers to yourself.
- **Node names in `spt subnet status --nodes`.** Each node now shows its hostname label and can be addressed as `@<hostname>` in commands. Nodes that aren't running any endpoints still show their hostname instead of a bare key.
- **Automatic re-pair cleanup.** If you reinstall or regenerate a node's identity and pair it again from the same machine under the same name, its old, now-dead identity is removed automatically during pairing — no manual prune needed.
- **Firewall setup on Windows.** The installer (when run elevated) now adds the inbound network rule `spt` needs so other nodes can reach you. If it wasn't added, `spt subnet status` and the "coming online" banner now tell you the rule is missing and print the exact command to add it.
- **Starts on boot.** The installer now registers `spt` to start automatically — at login on Windows, and as a per-user service on Linux — so your node is reachable after a reboot without running a command first.

### Changed

- **BREAKING — commands have been reorganized; old spellings no longer work (no aliases).** If a command isn't found, check its new home below. The agent-messaging commands you use most are unchanged: `spt send`, `spt ring`, `spt ready`, `spt whoami`, and `spt how-to` all stay where they are, as does top-level `spt notif`.
  - These endpoint commands moved **under `spt endpoint`**: `fork`, `suspend`, `wake`, `shutdown`, `rename`, `stop`, `digest`. For example, `spt fork …` is now `spt endpoint fork …`.
  - The old `resources` view is gone; its listing is now `spt endpoint list --detail` and its per-endpoint blurb is now `spt endpoint description`.
  - `spt notify …` moved to `spt subnet notify [message] [--target <subnet>]`. With no `--target`, it sends to your home subnet; if you have no home subnet and don't pass `--target`, it refuses rather than guessing.
  - Stopping/checking the daemon moved under `spt daemon` (`spt daemon stop`, `spt daemon status`).
- **`spt subnet status` tells the truth about a stopped daemon.** A node with no subnets now reads "this node is standalone" and no longer implies messaging works while the daemon is down. If the background sync has stalled, the status view says so instead of looking healthy.
- **Cleaner node listing.** In `spt subnet status --nodes`, a normally-named node now shows just its hostname (e.g. `KITSUBITO`) instead of `KITSUBITO (43a51d9a…)`; the extra key prefix only appears when two nodes share the same hostname and need telling apart.
- **`spt subnet` hints tidied.** The "hint:" lines now appear only on the bare `spt subnet` overview, not in `spt subnet status` (so the status view is clean to read).
- **Pairing works on machines with a wrong clock.** Pairing now checks network time and tolerates a node whose system clock is off by more than a minute (which previously made pairing fail silently). If network time can't be reached, it falls back to the local clock as before; it never changes your system clock.
- **Faster first sync after joining or restarting.** `spt` now remembers peers' last known addresses, so after a join — or after the daemon restarts — other nodes reappear in `spt subnet status --nodes` in seconds instead of taking up to a minute.
- **Endpoints going online/offline show up almost immediately.** When an endpoint starts or stops, peers now see the change in `spt subnet status --nodes` within seconds instead of waiting for the next sync cycle.

### Fixed

- **`spt subnet status --nodes` no longer hangs on a dead peer.** Checking a node that has gone away used to stall the command for ~30 seconds; it's now bounded to a couple of seconds, and the command prints "Checking remote nodes…" so the brief wait is expected.
- **Detached/unreachable peers now read as offline.** A peer you've detached from a subnet (or that has stopped serving it) is correctly shown offline in `spt subnet status --nodes`, instead of appearing online indefinitely just because its machine is up.
- **Messages from other agents now arrive properly formatted.** Incoming messages on the listener stream now include the full envelope with the sender's name, instead of showing as a raw, unwrapped line.
- **`sudo spt …` now works on Linux user installs.** When `spt` is installed to your user directory, elevation guidance that said to "run as administrator/root" used to dead-end with `sudo: spt: command not found`. The installer now also makes `spt` reachable under `sudo`, and on an interactive terminal `spt` re-runs itself with `sudo` automatically; otherwise it prints a command that actually works.
- **Elevated `spt` on Linux runs under your account, not root.** The first time you run an elevated `spt`, it asks once which account should own the daemon and its data, remembers that choice, and every later `sudo spt` runs the daemon and stores state under that account — never as root.
- **`spt daemon stop` on Windows now finds the daemon it started.** A daemon launched through Windows' elevation prompt could end up using the wrong home directory, so `spt daemon stop` reported "daemon not running" while a daemon kept running. It now keeps the right home directory across that elevation step.
- **Removed a confusing internal status line.** `spt` no longer prints the internal "DEELEVATED: running as uid …" notice during normal use.
- **Stale node rows clear out on their own.** Nodes that haven't been heard from in a while are now removed from the listing automatically, so old/dead entries stop cluttering `spt subnet status`.

## [0.1.1] - 2026-06-07

Maintenance fixes following the first public release. (This changelog was
introduced in 0.2.0; 0.1.1 and earlier are summarized here for completeness.)

## [0.1.0] - 2026-06-06

First public release of `spt`.
