# 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.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`.
