Network halt
A last-resort switch stops the public network if it runs away: a quorum of
guardian keys, compiled into the binary, signs a halt, and every node that
accepts it relays the halt and stops. The design and its limits are in
ADR 0016. What it means for a node, wats resume and the restart policies are in
agent.md. What a stolen guardian key could do
(stop the public network, nothing more) is in the
threat model.
The power is minimal. A halt carries no code, deletes nothing, changes no
setting and upgrades nothing, and it only concerns the public network.
Each node can override it with wats resume. Opting out entirely is a
config file key, halt.accept = false, which the node warns about at every
start and in status.
The guardian set and the threshold change only through a release, announced in its notes: 1-of-1 (the founder) at first, then 2-of-3 and 3-of-5 with independent guardians. An empty set disables halts.
Current guardians
Section titled “Current guardians”Threshold: 1 of 1. Approval window: 24 hours. In force from the first release after 0.2.0.
| Guardian | Public key (Ed25519, hex) | Since |
|---|---|---|
| Vincent Carluer (founder) | 3f1675fefba2606f3b5187597e9e9087c708cf4c98c5709b3523186a114370bb |
2026-10-18 |
The source of truth is GUARDIANS and HALT_THRESHOLD in
crates/wats/src/halt.rs. A test checks that the keys are valid and the
threshold reachable.
Becoming a guardian
Section titled “Becoming a guardian”- The new guardian generates their own key on their own machine, and keeps it cold (below, “Guardian key”). Nobody else ever sees the secret.
- They send only the public key (64 hex), through a channel the maintainers can verify, e.g. signed or read aloud.
- A release adds the key to
GUARDIANSand sets the new threshold, and the approval window if it changes. Its release notes announce the set: every key, the threshold and the window. The set takes effect for each node when it upgrades to that release.
Removing or rotating a guardian
Section titled “Removing or rotating a guardian”A guardian whose key is lost or stolen, or who steps down, is removed by a release without that key. Rotating is the same release with a new key in place of the old one.
- Nodes on the new release ignore the removed key: its halts, approvals and unhalts no longer count for them, including events it signed earlier. The state is recomputed from the current set, so a halt that held only thanks to that key is lifted on those nodes at their next start.
- Nodes on older releases still count the old key until they upgrade.
With a stolen key, the thief can stop them until they upgrade, and
wats resumebrings them back meanwhile. A stolen key can do nothing else (ADR 0016 §6). - Below the threshold (keys lost faster than releases replace them), no
halt or unhalt is possible. Nodes keep running, and a halt already in
effect is cleared by
wats resumeor by a release with a new set.
Guardian key
Section titled “Guardian key”This section is for guardians. A guardian key is a dedicated Ed25519 key: never a node or author key, never in GitHub, and never on a machine that is online day to day.
-
Generate it on a trusted machine, ideally offline:
Terminal window wats guardian keygen --out guardian.key# seed written to guardian.key (mode 0600)# public key: <64 hex>The file holds the 32-byte seed in hex.
keygennever overwrites a file. -
Encrypt it at once with a passphrase, then delete the clear copy:
Terminal window age -p -o guardian.key.age guardian.keyrm guardian.key # or shred / rm -P where available -
Keep
guardian.key.agecold. Store one copy on a USB key and one in a private repository, and never keep it on the online machine. The passphrase lives in your password manager, not next to the file. -
Send the public key (64 hex). It goes into
GUARDIANSin a pull request, and ships with the next release.
Signing a halt, an approval or an unhalt
Section titled “Signing a halt, an approval or an unhalt”The secret never touches the disk in clear: every guardian command reads it
from standard input with --key -.
-
On an offline machine, sign with
--offline, which prints the signed event, then carry the file to any online machine and publish it there:Terminal window # offline, with the USB keyage -d guardian.key.age | wats guardian halt --key - --reason "…" --offline > halt.json# onlinewats guardian publish halt.json -
On an online machine, when speed matters more, decrypt from the USB key straight into the command. It publishes through the running node, or through a short-lived one:
Terminal window age -d /Volumes/KEY/guardian.key.age | wats guardian halt --key - --reason "…" -
Approvals (with more than one guardian) name the halt or the unhalt they approve, and must arrive within 24 hours of it:
Terminal window age -d guardian.key.age | wats guardian approve --key - <id> -
Lifting a halt takes an unhalt under the same quorum:
Terminal window age -d guardian.key.age | wats guardian unhalt --key - <halt id> --reason "…"
--key <file> also reads a clear file, for tests only.