// the management console for Heartwood
Shape your signer.
Sapwood is the console for the Heartwood signer, in the browser and at the shell prompt: flash firmware, provision masters, derive identities, set policies, approve requests, take backups. The web app is a static page with no account, no server and no analytics, talking to the signer over USB, end-to-end encrypted relay commands, or the keyless bridge daemon on your own network; the CLI speaks the same frame protocol over the same cable from a terminal on Linux, macOS and Windows. Once provisioned, your keys stay on the device; the console only ever shapes what the device will agree to do.
$ sapwood device
✓ HEARTWOOD v0.13.7 · heltec-v4
identities 2 · connected apps 5
$ sapwood derive forge
✓ derived 'forge' under 'default'
npub1q3k…x7d0 · the same name always derives the same key
$ sapwood apps
IDENTITY SLOT APP METHODS KINDS AUTO PAIRED
default 0 gossip 6 all yes yes
$ sapwood firmware update heartwood-v4.bin
Waiting for approval. Hold the button on the device.
✓ Firmware verified. The device is rebooting into it.
EVERYTHING THE SIGNER NEEDS. NOTHING IT SHOULDN'T.
-
Provision
Bootstrap a device over USB from a 12/24-word mnemonic or an existing nsec, derived as a tree or used as-is. Secrets are zeroised in browser memory the moment they are transmitted.
-
Identities
Type a name; the signer derives the identity on-device from a master it already holds. No secret ever exists in the browser to steal.
-
Policies
Exact per-client allowlists of methods and event kinds, with presets for common apps. Anything outside the ceiling fails closed.
-
Approvals
A pending queue for requests that policy alone won't decide. Approve or deny from the console; the device remains the authority.
-
Firmware
Flash a new board in the browser, and update over USB or through the local bridge with the release signature and SHA‑256 verified before a byte is committed.
-
Backups
An imported key writes out as 24 BIP‑39 words that restore the identical npub, in Sapwood or Heartwood's offline CLI, never on a server.
-
Connectivity
Stage WiFi and relay changes, then activate them rollback-safe, with live red/amber/green health for every relay the signer uses.
-
Logs
The device's own log stream, live in the console. Watch a request arrive, meet policy, and leave signed.
-
Phone handoff
Move the operator credential to your phone through a protected QR flow that fails closed if anything looks wrong.
WHAT A COMPROMISED BROWSER GETS: NOTHING
- No keys to take
- Master secrets never leave the ESP32. Sapwood holds a management credential, not signing power. A hostile page with full control of the console still cannot extract a key or sign an event.
- Every change is challenged
- Remote mutations require the operator key, a device-issued one-time challenge, and the current client credential, so a captured command replays as garbage.
- The button outranks the browser
- Provisioning, seed and PIN changes, factory reset and the start of any firmware update need a physical press on the device. Software can ask; only your thumb can insist.
- Bounded operator
- The operator credential can shape policies and connectivity. It cannot read or replace seeds, change the PIN, or push firmware. By design, not by promise.
THREE PATHS, ALL YOURS
USB. Plug the board in and Sapwood speaks to it directly over Web Serial: flashing, provisioning, recovery, logs. The CLI drives the same cable from a terminal. Everything stays on your desk; nothing needs a network at all.
RELAYS. Day to day, management commands travel as end-to-end encrypted Nostr events to the signer's own outbound connection. No inbound port, no port forwarding, no cloud account, no management server. The relay carries ciphertext it cannot read.
BRIDGE. A signer tethered to a Pi or any Linux box is reachable through the keyless bridge daemon on your LAN: the same console, plus daemon health and restarts, with verified firmware pushed down the tether.
Honest requirements: Web Serial means a Chromium browser (Chrome, Edge or Opera) for the USB path. Firefox and Safari don't ship it. The CLI has no browser requirement at all.
THE SAME CONSOLE, AT A SHELL PROMPT
The sapwood CLI ships in the same repo and speaks the same frame
protocol over the same cable, on Linux, macOS and Windows. Build it with
npm run build:cli, put it on PATH with npm link,
and the console is a command away: 36KB bundled, about 30ms to start,
--json on every command for scripts.
ports finds the signer; device,
identities and apps read its state;
derive mints an identity on-device from a name;
identities remove retires one behind a typed-name
confirmation; logs streams the device log;
firmware update pushes a signed release, approved by the
physical button. The security model does not move: management frames
only, and no secret ever crosses the cable.
FIRST BOOT IN MINUTES
-
01
Plug a supported board into USB. See the boards.
-
02
Open sapwood.forgesworn.dev in a Chromium browser and follow the flasher wizard.
-
03
Provision a master (new mnemonic or existing nsec) and name your first identity.
-
04
Connect an app: Sapwood issues the
bunker://pairing for Bark, Cambium, or any NIP‑46 client.
Want every step with real screenshots? The web guide walks the whole console, from first flash to phone pairing. Terminal person? The CLI guide covers every command, with output.
THE WHOLE TREE
Heartwood
The core. Keys on a chip behind a physical button.
Sapwood
The management console. Shape your signer. You are here.
Cambium
The living layer on Android. A NIP‑55 signer that holds no keys.
Bark
The protective outer layer. NIP‑07 in your browser, keys nowhere near it.
Bray
The pack animal alongside the tree. Nostr for AI assistants and the terminal; happiest signing through a Heartwood.