Sovereign OS Roadmap
Status Legend
- ✅ Complete — implemented and qualified on supported hardware
- 🟡 In progress — implementation or hardware qualification is active
- ⚪ Planned — accepted direction, not yet started
- ⏳ Pending decision — research or an RFC must close the design boundary
Current Position
✅ Phase 01 — Flashable Raspberry Pi Image POC
The Raspberry Pi 5 image build, flash, first-boot, Pi-hole, persistent DATA partition, local routing, first-login, and Sovereign Console health experience have been exercised on physical hardware.
🟡 Milestone 01.1 — Appliance Update Foundation
The signed appliance updater can inspect, prepare, back up, stage, activate, health-check, commit, recover, and roll back versioned releases while preserving the dedicated DATA partition. An initial signed update transaction passed Raspberry Pi qualification.
The first fully versioned appliance-release qualification, from preview.9 to preview.10, exposed service-readiness and systemd dependency races. Automatic rollback worked and restored preview.9. The fixes were qualified on Raspberry Pi 5 hardware in a clean preview.11 base to preview.12 update campaign: an interrupted-at-validating recovery, a forced target-health rollback, and a successful activation all held with reboot persistence and no regression to Console, DNS, Pi-hole, Nginx, SSH, credentials, or the dedicated DATA partition. See the preview.12 appliance update qualification report.
Persistent-data restore, bounded retention (prune), and signed trust rotation (rotate-trust) are all implemented and hardware-qualified on Raspberry Pi 5, most recently against a real 0.1.0-preview.13 base image built and flashed with all three shipped in for the first time — see the preview.14 appliance update qualification report and the prune and trust rotation hardware qualification report. Production signing-key custody is decided (ADR-0006), and the production key (sovereign-production-1) is now generated, provisioned into the image-builder trust store, and proven end-to-end: v0.1.0-preview.17 is a real production-signed release that has been built, published, discovered, installed, and restored from on Raspberry Pi 5 hardware — see the first production-signed release, install, and restore qualification reports. prune and rotate-trust have not yet been exercised as part of a real signed-release install cycle.
Unattended automatic installation remains disabled until the manual, health-gated update path and its operational controls are qualified.
Milestone Sequence
1. Complete Appliance Update Qualification
Status: ✅ Complete
User outcome: Install a compatible Sovereign appliance release without reflashing or losing persistent data.
Qualification pair:
- preview.11: clean flashable base containing the systemd and readiness fixes;
- preview.12: signed, versioned installed-device update built from the same source revision.
The physical qualification on Raspberry Pi 5 proved:
- update compatibility and signature verification;
- staging without changing the active release;
- interruption recovery (interrupted at
validating, automatic boot-time restore of preview.11); - forced health-check failure and automatic rollback;
- successful activation and commit;
- reboot persistence;
- preservation of Pi-hole configuration, credentials, update state, and the dedicated DATA mount; and
- no regression to Console, DNS, Pi-hole, Nginx, or SSH.
See the preview.12 appliance update qualification report for full evidence.
2. Production Update Operations
Status: 🟡 In progress
Depends on: Completed preview.11 to preview.12 qualification
User outcome: A supportable update mechanism with trustworthy release and recovery operations.
Planned work:
- automate persistent-data restore verification —
sovereign-update restoreis implemented and hardware-qualified against real Pi-hole state on Raspberry Pi 5, including a forced-health-failure rollback path, twice now: once manually deployed, and again on a realpreview.13base image that shipped it natively (see BACKUP_AND_JOURNAL.md and the restore and preview.14 qualification reports); it still has not shipped through a release used by anyone beyond qualification, and is not yet wired into automatic update rollback for future data migrations; - define bounded retention and cleanup for old releases, backups, journals, and failed transactions —
sovereign-update prune [--dry-run]is implemented and hardware-qualified on Raspberry Pi 5 against real backups, releases, and transaction journals, including confirming the live device stays healthy through an aggressive real deletion pass (see BACKUP_AND_JOURNAL.md and the prune and trust rotation qualification report). Now wired into a dailysovereign-update-prune.timer(jittered, catches up on boot if a run was missed), hardware-verified running under its own hardened sandbox on Raspberry Pi 5; not yet shipped through a release beyond qualification, and an actual unattended timer-elapsed run has not been separately observed; - establish production signing-key custody, rotation, and revocation — decided in ADR-0006 (password-manager-held key, hardware key as a future upgrade). Routine rotation/revocation is implemented as
sovereign-update rotate-trust(signed, atomic, refuses any change that would leave a channel with no trusted key — see update/README.md's "Trust Rotation v1" section) and hardware-qualified on Raspberry Pi 5, including the realistic single-key rotation handoff, immediate enforcement of revocation, and the lockout protection (see the prune and trust rotation qualification report). The production key (sovereign-production-1, Ed25519, scoped to bothpreviewandstable) has now been generated under that custody decision and its public half is baked into the image-builder overlay's trust store, so future base images trust it out of the box; the private half lives only as an encrypted secret in the maintainer's password manager.v0.1.0-preview.17is the first release signed with it, published, discovered, and — as of a fullprepare/backup/stage/activaterun on the same Raspberry Pi 5 — genuinely installed: the device now runs0.1.0-preview.17,update_state: committed, confirmed across a cold reboot. See the discovery and install qualification reports. That install campaign also found and fixed a real regression:sovereign-proof.servicefailing on any boot afterpruneremoves the base image's own (now-inactive) release directory —proof-initnow only performs that check during first-boot bootstrap.restorehas since also been qualified against the real pre-activation backup that install created: correctly rejected a version-mismatched restore by default, then recovered an injected canary correctly under--forcewith no regression — see the production-signed restore qualification report.prune/rotate-truststill haven't been exercised as part of an actual signed-release install cycle — doing so meaningfully needs either a second real release or a genuine key rotation, not a manufactured scenario. Getting a rotation manifest onto already-flashed devices without an operator manually running the command still depends on the Update Discovery work in item 3 below; - approve the update RFC and production manifest policy;
- publish release compatibility, rollback limitations, and recovery guidance — published as docs/operations/update-recovery-and-compatibility.md, written for the device operator rather than a contributor; and
- qualify every supported source-to-target update path on real hardware. A
0.1.0-preview.17→0.1.0-preview.18attempt surfaced a real structural gap: the installed updater's appliance file allowlist was fixed at flash time and couldn't learn about a new file added by the release introducing it. Fixed and hardware-qualified the same day — the validator now rejects only missing required files, not unrecognized ones, and classifies appliance scripts by shebang instead of a hardcoded name set; the exact real stuck transaction was recovered through tocommittedon real hardware, confirmed persistent across a reboot — see the finding and its fix qualification report. This does not touch the larger, still-unresolved question of delivering new systemd units/base-image content via update at all (see item 6 below) — only the narrower file-allowlist symptom.
3. Update Discovery and Console Controls
Status: 🟡 In progress
Depends on: Production Update Operations for the Console-facing and installation-triggering bullets below; the device-side check-and-notify bullet was deliberately scoped in RFC-0015 to not depend on it (no Console change, no production key) and has already started.
User outcome: Learn about and install x+1 from Sovereign Console without using the command line or reflashing.
Planned work:
- publish signed update-channel metadata over HTTPS, and periodically check for compatible updates without sending household data — accepted in RFC-0015 and implemented as
sovereign-update check, reusing the existing signed-manifest verification unchanged, with no new trust logic, no Console change, and no production key required. Runs daily viasovereign-update-check.timer, hardware-verified on Raspberry Pi 5 against the real live GitHub API, including the positive "update found" path against a genuinely published (non-draft) release — see update/README.md's "Update Discovery v1" section and the positive-path qualification report. That campaign also surfaced a real gap, now fixed:build-image.yml's release-publish step never uploaded the update-candidate manifest/bundle at all, and its filename collided with the image's own provenance file (nowimage-manifest.json). The workflow now conditionally uploads the unsigned update-candidate assets whenbuild_update_candidateis selected; an operator still has to sign and upload the.sigoffline before a release becomes discoverable; - Console authentication — the prerequisite ADR-0005 itself named before any mutating Console action can exist. Decided and implemented in ADR-0007: a separate Console-specific credential (
sovereign-console-password), a loopback-only, systemd-hardened login backend (sovereign-console-auth,/api/v1/auth/*), session cookies with CSRF protection, and per-source rate limiting without lockout, with a sign-in UI wired into Console's topbar. Unit-tested (tests/test_console_auth.py) and hardware-qualified on Raspberry Pi 5 — see the console authentication hardware qualification report. A real signed-release install attempt (v0.1.0-preview.18) surfaced a structural finding bigger than Console auth itself — see the finding — since fixed:.18is genuinely installed via a real update on real hardware,console-auth's binary included. The base-image content it also needs (systemd unit,sysusers.dgroup, directory bootstrap) was then deployed manually and permanently to the qualification device — real, accepted drift against what any future image build produces until the next reflash, not something an update can deliver (tracked at item 6 below). Console authentication is now genuinely live and working on real hardware; - the first Console-triggered privileged action — decided and implemented in ADR-0008: a file-existence trigger picked up by a
systemdpath-activated, root-owned oneshot runner, scoped to exactly one action,sovereign-update check. Hardware-qualified on Raspberry Pi 5 — the full chain (auth/CSRF gating, the trigger actually firing, a real check running as root, the result surfacing back to Console, cooldown enforcement) verified correctly, after finding and fixing two real defects (a missingReadWritePaths=grant, and a static-group name that collided with an unrelated service's ownDynamicUseridentity) — see the qualification report.prepare/backup/stage/activate(an actual install trigger) are explicitly out of scope for this pass — deliberately smaller blast radius first; - show version, channel, release notes, download size, reboot requirements, and rollback limitations in Console;
- provide user-triggered download and installation;
- report download, verification, staging, activation, validation, rollback, and completion states; and
- retain a CLI recovery path independent of Console.
The initial policy is notify and require approval. Automatic download and maintenance-window installation follow only after repeated field qualification. Every automatic policy retains signature verification, health-gated activation, and automatic rollback.
4. Local Conversation and Capabilities
Status: ⚪ Planned; research and RFC work may proceed in parallel
Depends on: Stable appliance update boundary
User outcome: Ask Sovereign local questions, inspect system and Pi-hole status, and explicitly use privacy-transparent, self-hosted web-search tooling.
Milestone 01.2 will deliver:
- a Sovereign-owned conversation experience;
- provider-neutral local inference and model-management contracts;
- a Raspberry Pi 5 benchmark of llama.cpp and Ollama;
- a typed capability registry and deterministic executor;
system.healthand read-only Pi-hole capabilities;- opt-in
web.searchthrough a locally operated SearXNG instance; - restricted
web.fetch, citations, privacy indicators, and audit events; and - real-hardware qualification within DNS-latency, memory, power, and thermal budgets.
5. Home Automation Integration
Status: ⚪ Planned
Depends on: Qualified capability executor
User outcome: Ask about and safely control allowlisted home entities through the same Sovereign conversation boundary.
The first slice is read-only Home Assistant entity discovery, state, and history. Later slices may propose allowlisted actions, but deterministic policy outside the model must authorize them and require confirmation according to risk. The model never receives unrestricted Home Assistant, shell, Docker, or network access.
6. Full Base-OS Updates
Status: ⏳ Architecture decision pending
Depends on: Stable appliance updater and persistent partition contract
User outcome: Update Debian, kernel, firmware, Docker, and early system services without reflashing.
The current updater covers versioned Sovereign appliance releases; it does not make base-OS package transactions atomic. The long-term milestone must select and qualify an A/B root-filesystem or equivalent immutable deployment design with:
- persistent DATA independent of either system slot;
- atomic boot-slot selection;
- boot and health confirmation;
- automatic fallback to the previous system;
- signed system artifacts; and
- an external recovery-image path.
This milestone closes the remaining “flash once” gap.
Progress Summary
- ✅ Concept paper and master plan
- ✅ Phase 01 appliance architecture decision
- ✅
rpi-image-genassessment, proof build, and automated ARM64 image pipeline - ✅ Flashable Raspberry Pi 5 image exercised on hardware
- ✅ Docker-based Pi-hole,
/dns/*routing, and persistent DATA - ✅ First-login credential-change and optional SSH-key flow
- ✅ Sovereign Console read-only health page qualified on Raspberry Pi 5
- ✅ Signed update transaction, interruption recovery, rollback, and persistence demonstrated on Raspberry Pi 5
- ✅ Fully versioned appliance-release qualification (preview.11 to preview.12), including readiness hardening
- 🟡 Persistent restore automation, retention, and production signing operations
- 🟡 Update discovery and Sovereign Console update controls
- ⏳ Local inference benchmark and conversation/capability RFCs
- ⚪ SearXNG-backed web-search capability
- ⚪ Home Assistant capability integration
- ⏳ A/B or equivalent full base-OS update architecture
Phases
- 00 Master Plan
- 01 Flashable Pi-hole Image POC
- Console Foundation
- 01.1 Appliance Update Foundation
- 01.2 Local Conversation and Capabilities
Project Documentation
- Documentation index
- Initial target user
- Core preview use cases
- Preview scope and non-goals
- System overview
- Preview threat model
- ADR-0001: Phase 01 appliance architecture
- RFC-0010: Raspberry Pi image deployment
- Image release checklist
- ADR-0002: Installation images and update artifacts
- ADR-0004: Provider-neutral assistant and web search
- ADR-0005: Sovereign Console namespace and health boundary
- RFC-0014: Appliance update system
- Preview.12 appliance update qualification report