Verified OTA
Over-the-air software updates pass through a server-side kill switch and, in hardened mode, through a cryptographic signature check before installation. A compromise of our repository cannot push unsigned code to strict-mode devices.
Protections that run on the speaker itself, beyond the cloud.
The firmware is auditable, config files are locked down to one process, pairing is gated by a short-lived single-use code, and every update cycle goes through a server-side kill switch. An admin can also push a forced update to a single device if a critical fix needs to land fast — while the fleet-wide kill switch remains authoritative.
Over-the-air software updates pass through a server-side kill switch and, in hardened mode, through a cryptographic signature check before installation. A compromise of our repository cannot push unsigned code to strict-mode devices.
The config file holding your tokens on the device is set to 600 permissions — readable only by the Twoody process, and never by other local processes.
For professional deployments, the device can be configured to only accept certificates issued by Let's Encrypt's root authorities, closing the door on a rogue CA.
Device pairing goes through a single-use, time-limited, attempt-limited code. A bystander trying to pair hits a near-immediate block.
A single ENV variable (TWOODY_DEVICE_UPDATES_BLOCKED=true) halts the nightly OTA across the entire fleet. If we detect a regression in a release that's already been cut, we block further propagation instantly without shipping anything to devices.
An admin can mark a single device as requiring an immediate update — the device polls this flag on a short loop and applies the update out of the normal cycle, showing an 'updating' overlay. Clears automatically on success or rollback.
If an update fails health checks after install, the device rolls back to the previous working SHA and reports rolled_back telemetry. We can see how many devices rolled back per release and hold any promotion that isn't landing cleanly.
Every update outcome is reported via POST /devices/:device_id/update_events with from_sha and to_sha. The admin sees a per-device history — we know the firmware state of every device without sending secret data back.
Every device in the fleet pulls updates with a dedicated, read-only deploy key scoped to the firmware repository alone. No device can write back to our repos or reach our other projects. If a device is ever compromised (theft, malware, physical access), the blast radius is bounded to that device — it cannot push malicious code that the rest of the fleet would then pull.
The device polls GET /devices/:id/update_check on a short loop. The server returns three pieces of information: a fleet-wide blocked flag (the kill switch), an informational min_sha floor, and a per-device force_update flag.
On update night, the device checks blocked first — if true, the cycle is skipped entirely. Otherwise, it runs auto-update.sh which git-fetches, runs tests against a known-good suite, and swaps the firmware atomically. Every outcome (succeeded, failed, rolled_back) is reported back via POST /devices/:device_id/update_events with the from_sha and to_sha, so the fleet's state is visible per-device in the admin.
Pairing codes are 6 digits, expire after 10 minutes, and can be validated at most a handful of times before being invalidated. Each attempt is rate-limited at the CDN (10 per 15 min per IP). A bystander who gets physical proximity to your device still can't complete pairing without your account — the code is generated on your authenticated session and tied to your user.
Once paired, the device receives an X-User-Token bearer just like any other client. Unpairing revokes that token like any other session — the device becomes a paperweight to our API until someone re-pairs it.
Every device polls GET /admin/devices/:device_id/settings.json every 5 minutes for runtime tunables (VAD aggressiveness, Whisper mode, OpenAI voice, retention windows, enrollment mode). The endpoint is authenticated with the device's own X-User-Token.
We authoritatively merge three layers on read — schema defaults → household fleet defaults → per-device overrides — so the device always gets a coherent snapshot. An admin can tune a single device, a household, or roll a new default across the whole fleet without redeploying.