Skip to content

SynVirt Roadmap

Synced read-only from /home/synnet/mirrors/synvirt-product/docs/roadmap.md. Edit at the source, not here.

The SynVirt roadmap is tracked by version number only. Calendar targets (months, quarters, “Hito N — April 2026” style deferrals) were retired. Version numbers are stable commitments; dates drift.

The authoritative current version is whatever iso-builder/VERSION says. Read it; don’t assume. As of this revision it reads 0.15.0 (release id <semver>+build.<N>, e.g. 0.15.0+build.1175; the -FixN suffix was retired 2026-06-23).


Version Name Status
0.6.x Standalone only, live-build ISO, storage modes Shipped
0.7.0 Host roles + VM dashboard MVP + synvirt-libvirt Shipped
0.7.1–0.7.5 Vendoring, wizard hardening, ZFS cachefile, admin-record Shipped
0.7.6 Fix release (XML boot conflict, tty1 TUI, 20 GB sys) Shipped
0.7.7 Boot-splash interactive recovery screen Shipped
0.7.8 Hotfix — duplicate openapi.json route panic at daemon startup Shipped
0.8.0 Web Console module — original SPICE shape (gateway + guest-tools ISO + USB policy). Replaced wholesale in 0.9.0-alpha.2 by VNC-only. Shipped (legacy)
0.8.1 Hardening series over 0.8.0 (metrics, VmDetail, XP install flow) Shipped
0.8.2 Production-prep hardening — fonts, i18n, Cache-Control, panic sweep Shipped
0.9–0.15.0 VNC + WebRTC Direct Console (SPICE removed), migrator, snapshots/clone, telemetry, data-plane splits (R1 synvirt-network, R2 synvirt-storaged), cluster control plane + Backup P1, federation/Cloud Shipped (current line: 0.15.0)
Roadmap RBAC, S3 backup engine (P2+), advanced placement/affinity rules Planned
Roadmap Replica role (async cross-cluster DR) + live-migration polish Planned
1.0 GA Role composition GA, air-gap signed USB update, confidential compute Planned

Within the 0.7.x line, any decision that touches ZFS-on-root boot chain (ZFSBootMenu vs GRUB + ext4 /boot), distributed block replication layering (LINSTOR / DRBD on top of zvols), or boot-environment lifecycle is re-opened in 0.9, not sooner — that is when the replica trait and crates/storage-replica stabilise enough to validate the stack end-to-end.


Standalone node only. Live-build ISO (preseed retired in 0.5). Browser wizard + daemon install API. Two storage modes (single_disk_zfs, multi_disk). Diagnostic synvirt/debug user with auto-cleanup on first boot after wizard completion. Vue 3 + Pinia + Tailwind dashboard stub served after setup.completed.

The pre-0.6 history (Foundation MVP, preseed + d-i, Ratatui first-boot unattended driver, br-mgmt, DCUI, setup wizard) is archived in the git log and in superseded ADRs. It is not part of the forward roadmap.


Shipped — 0.7.0 — Host roles + VM dashboard MVP

Section titled “Shipped — 0.7.0 — Host roles + VM dashboard MVP”

Introduce host role composition (HCI / Compute / Storage) so operators can start deploying SynVirt as something other than a single standalone node. Ship the first real VM management experience in the dashboard.

  • Host roles — CLAUDE.md §6 + docs/architecture/host-roles.md. HCI (compute + storage on the same node), Compute-only, Storage-only. Role selection persisted in /etc/synvirt/host-role.
  • synvirt-libvirt cratevirsh subprocess wrapper, 30-second timeout, async API. All libvirt interaction routed through this crate.
  • VM management dashboard MVPcrates/web-ux (Vue 3 + Pinia + Tailwind + Lucide, everything vendored). Create, start, stop, pause, delete. Dark theme default.
  • Daemon Basic Auth via PAM — admin login backed by local PAM (auth required pam_unix.so), password bcrypt-hashed in a daemon admin-record. Session JWT, CSRF, rate limit on /api/v1/auth/*.
  • Console TUIcrates/console (20 screens on tty1), crates/boot-splash for tty1 boot progress, shared crates/tui-theme. Emergency root shell available on tty2 via Troubleshooting screen (default off).

Standalone + HCI + Compute + Storage roles. No clustering yet.


Shipped — 0.7.1 through 0.7.5 — Hardening series

Section titled “Shipped — 0.7.1 through 0.7.5 — Hardening series”

Five fix/polish releases between 0.7.0 and 0.7.6. Collected here because none introduced a new top-level feature.

  • 0.7.1 — Vendoring polish: every npm/pnpm/cargo dependency pinned and offline-buildable. No network fetches during ISO build.
  • 0.7.2 — Wizard storage modes: single_disk_zfs vs multi_disk surfaced in the wizard with per-mode validation; picker logic moved to paso 3 with auto-pick by recommended_for_system.
  • 0.7.3 — Diagnostic synvirt/debug user with first-boot auto-cleanup (synvirt-debug-cleanup.service, gated by ConditionPathExists=/etc/synvirt/setup.completed).
  • 0.7.4 — Vue 3 dashboard hardening: error boundaries, loading states, optimistic updates, keyboard-navigable tables.
  • 0.7.5 — ZFS cachefile seeded at install so zfs-import-cache.service actually activates on first boot; admin record seeded at install time so the post-install dashboard has credentials on its first render; light theme shipped as default.

Standalone + host roles.


Fix the bugs exposed by operator acceptance testing on the 0.7.5 live ISO. No new features.

  • VM create XML — libvirt domain XML no longer emits a conflicting boot element when os/boot and per-disk boot order coexist.
  • Post-install TUI on tty1crates/console takes tty1 (masks getty@tty1) so the operator sees the branded menu instead of the bare Debian getty.
  • Dashboard redirect — redirects honour the incoming Host: header instead of hard-coding the management IP.
  • Install-log breadcrumbs — every install stage writes a breadcrumb to /var/log/synvirt/install.log; on failure the daemon returns the last 5 breadcrumbs in /api/install/status.
  • Boot-splash watchdogcrates/boot-splash times out after 45 s if systemd never signals READY; prints a fallback message and drops to the console TUI.
  • Live-TUI Starting screen — the live ISO shows a “Starting” screen while the daemon boots, then gates on /readyz before painting the welcome screen.
  • Fixed 20 GB system partition — no wizard input for system-partition size; always 20 GB ext4 on p3. Reduces operator error and shrinks the test matrix.

Standalone + host roles (same as 0.7.0).


Shipped — 0.7.7 — Boot-splash recovery

Section titled “Shipped — 0.7.7 — Boot-splash recovery”

Close the last known operator-facing gap in the boot-splash: make Failed steps actionable. Before 0.7.7, a failed step showed a silent next to one line and the 45 s watchdog eventually released tty1 without any indication of which service had wedged or what the operator could do. 0.7.7 turns that into an interactive recovery screen.

  • Interactive recovery view — when any of the 12 boot steps flips to Failed, crates/boot-splash swaps the splash for a recovery screen with a red degrade banner (✗ Step NN of 12 failed: <label>), a context block with reason + systemd unit + watchdog reminder, and five keyboard actions: R retry, I reimport ZFS pools (conditional on ImportPools being the failure), L emergency shell on tty3, D toggle verbose boot log, B reboot.
  • Unit-aware retryStep now carries unit_name: Option<&'static str>. Steps tied to a systemd unit (udev, zfs-import-cache, openvswitch-switch, systemd-networkd, libvirtd, synvirt-daemon, chrony) retry via systemctl restart <unit>; internal-check steps retry by resetting to Pending so the watcher re-evaluates.
  • Watchdog still enforced — the 0.7.6 MAX_WAIT = 45 s bound applies in recovery mode too, so an ignored recovery prompt never blocks the post-install Direct Console forever.
  • Crate version paritysynvirt-boot-splash, synvirt-tui-theme, and synvirt-console all bumped to 0.7.7 so the displayed CARGO_PKG_VERSION taglines match iso-builder/VERSION.

Standalone + host roles (same as 0.7.0).


Shipped — 0.7.8 — Hotfix: daemon startup panic

Section titled “Shipped — 0.7.8 — Hotfix: daemon startup panic”

Unbreak the 0.7.7 ISO. Operator testing on 192.168.128.129 showed the Live-TUI stuck on Starting… indefinitely — root cause was a duplicate axum route in the daemon that panicked at router construction and prevented port 443 from ever opening. 0.7.8 is a single-fix hotfix.

  • Removed duplicate GET /api/v1/openapi.json registration in crates/daemon/src/web/routes.rs. Both an explicit .route("/api/v1/openapi.json", get(openapi_json)) and the SwaggerUi::new("/docs").url("/api/v1/openapi.json", spec) merge registered a handler for the same method+path, so axum 0.7 panicked with Overlapping method route. Handler for GET /api/v1/openapi.json already exists at the end of build_router — 29 ms after main(), before the listener bound. systemd then cycled the unit 15 times in 20 s and hit Start request repeated too quickly, leaving the unit FAILED permanently. The SwaggerUi merge already registers both the /docs UI and the JSON spec URL, so the explicit route was pure duplication. Fix drops the redundant route line, the orphaned openapi_json handler, and its IntoResponse / Json imports.
  • Crate version bumpsynvirt-boot-splash, synvirt-tui-theme, synvirt-console, iso-builder/VERSION all bumped to 0.7.8 so the running TUIs advertise the shipped version.

Standalone + host roles (same as 0.7.0).


Planned — 0.8 — Operator-facing virtualisation features

Section titled “Planned — 0.8 — Operator-facing virtualisation features”

Turn the 0.7.x VM MVP into something operators ship production workloads on. Multi-user, RBAC, snapshots, and a browser-based VM console.

  • VM snapshots and clone — ZFS zvol snapshots with operator-visible lifecycle; clone from snapshot via zfs clone + libvirt redefine.
  • Browser console — VNC web console (noVNC) proxied over WebSocket from the daemon to crates/web-ux*. SPICE was deleted in 0.9.0-alpha.2.
  • ISO upload from the browser — multipart upload to /api/v1/media, backed by a dataset on rpool (or the compute role’s dedicated pool) with SHA-256 verification.
  • Time-series graphs — CPU / RAM / disk / net per VM and per host. Embedded time-series store; no external dependency.
  • Dashboard pool management — create, extend, import, export ZFS pools from the UI for the Storage role.
  • Multi-user + RBAC — roles: admin, operator, viewer. Session history, audit log (who did what, when).
  • Backup role — writes VM-level backups to an S3-compatible endpoint with object lock / immutable retention. New role: a node can be designated Backup-only.
  • crates/compute trait — compute-facing logic extracted from the daemon into a trait so the Compute and HCI roles share one implementation.

Standalone + host roles + Backup role.


Planned — 0.9 — Cross-cluster replication and migration

Section titled “Planned — 0.9 — Cross-cluster replication and migration”

Asynchronous DR across two clusters. Live-migration polish so moving a VM between compute nodes is boring. Begin predictive maintenance.

  • Replica role — a node dedicated to receiving async replicas from a source cluster.
  • crates/replica + crates/storage-replica — replication trait on top of ZFS send/receive incremental streams, scheduled by the daemon.
  • Live migration polish — CPU feature negotiation, pre-flight compatibility check, progress reporting, fallback to offline migration on feature mismatch.
  • Predictive maintenance ML — local-only models (no cloud upload). Trains on the host’s own time-series and SMART data to flag likely disk failures, thermal trends, and memory-pressure patterns.
  • Re-evaluation of deferred decisions — ZFSBootMenu vs GRUB integration, single vs shared ESP for boot environments, LINSTOR / DRBD layering choices. Pinned to 0.9 because the replica trait stresses the storage stack enough to produce signal.

Standalone + host roles + Backup role + Replica role. Clustering still out of scope.


Planned — 1.0 — Role composition GA + enterprise hardening

Section titled “Planned — 1.0 — Role composition GA + enterprise hardening”

Full role-composition GA with air-gap updates, confidential-computing primitives, GPU passthrough, and first-class Spanish localisation for the Mexico / LATAM market.

  • Role composition GA — any combination of HCI / Compute / Storage / Backup / Replica on a single host, or split across a cluster.
  • Air-gap update via signed USB — the daemon accepts update bundles from a USB stick signed by the SynVirt release key; no internet connectivity required during upgrade.
  • Confidential computing — TDX and SEV-SNP support exposed as a VM attribute; dashboard surfaces attestation state.
  • GPU passthrough UI with SR-IOV — operator picks a physical GPU (or SR-IOV VF) and attaches it to a VM from the dashboard.
  • es_MX i18n catalog — first shipped locale. All UI strings, console TUI screens, and daemon-emitted operator messages gain a Spanish translation. Other locales are a post-1.0 task.
  • Commercial enablement — tiered per-CPU-socket licensing portal integration, SLA definitions, onboarding runbook.

All roles in any composition.


Items we know we want to answer eventually but have not pinned to a specific version yet. Written down so they don’t get lost.

  • WebRTC console transport (post-1.0 evaluation). noVNC has been the single console path since 0.9.0-alpha.2. WebRTC is the candidate successor — lower latency, native browser pipeline, no RFB-over-TCP framing — but only as a replacement, not a coexistence path. Trial after 1.0 ships and the operator base has a stable VNC baseline to compare against. SPICE is not coming back regardless of how that evaluation lands.
  • Compile our own kernel. Today we ship Debian 13’s stock linux-image-amd64 (kernel 6.12 LTS). A SynVirt-owned kernel build would let us: strip unused subsystems to shrink boot time and attack surface; pin exactly the KVM / OVS / ZFS patches we need; control our own CVE backports; and ship a minimal signed image for air-gap updates. Open questions: build infrastructure (reproducible builds, signing key management, CI time), maintenance cost vs shipping stock, whether DKMS for OpenZFS still makes sense against a custom kernel (probably replace with in-tree build), and when the payoff justifies the ongoing tax. Likely candidate window: between 0.9 and 1.0 so the confidential-computing and air-gap-update features land on a kernel we control.
  • Clustering primitives (etcd Raft, distributed scheduler, anti-affinity, rolling cluster upgrade). Previously pencilled in for a post-1.0 “Cluster mode” but deliberately not pinned to a version. Re-open after 1.0 ships.
  • ARM / RISC-V support. Currently out of scope (x86-64 only). Will be revisited when a customer segment actually asks for it; until then the engineering cost is not justified.
  • Kubernetes integration. Out of scope as a platform — SynVirt is a VM hypervisor, not a container orchestrator. Operators run Kubernetes inside SynVirt VMs. The open question is whether we ship a first-class “Kubernetes node pool” VM template in some future version to make that pattern one click.

  • Container orchestration as a platform feature (see above).
  • Public cloud integration as a replicator target — the replica role in 0.9 targets SynVirt → SynVirt, not SynVirt → public cloud. Customers asking for cloud DR get the Backup role (0.8) pointed at S3-compatible object lock storage.
  • Windows as the host OS. SynVirt ships its own live-build ISO based on Debian 13 trixie. The dev workstation runs whatever the developer prefers; the product runs its own OS.

These items surfaced during the 0.14.0 release cycle but are not blockers for the release itself. Tracked here instead of in an external issue tracker.

  • 34 clippy errors with -D warnings flag accumulated in migrator, live, and adapter crates. All pre-existing, not introduced by the SPICE removal or noVNC work.
  • Specific patterns observed: unused imports, push_str with single char (should be push), redundant guards, manual character pattern matches.
  • Suggested approach: dedicated branch, cargo clippy --workspace --fix --allow-dirty as starting point, manual review, single commit chore: clippy sweep across workspace.
  • Owner: TBD
  • Target: before next minor bump (0.15.0)

Migrate disk::allocate_qcow2 to vm_layout::ensure_qcow2

Section titled “Migrate disk::allocate_qcow2 to vm_layout::ensure_qcow2”
  • crates/synvirt-libvirt/src/vm.rs currently has #[allow(deprecated)] on a call to disk::allocate_qcow2.
  • Replacement is synvirt_core::storage::vm_layout::ensure_qcow2 which is already in tree.
  • Migration is mechanical: replace the call site, drop the allow attribute, run tests.
  • Owner: TBD
  • Target: 0.15.0
  • v0.14.0 introduced POST /api/console/:vm_uuid (UUID-based, JWT HS256, 30s TTL, aud=vnc) for the new noVNC flow.
  • The legacy path POST /api/v1/auth/ticket + GET /api/v1/vms/:name/console/vnc still coexists and uses valid_name() which rejects VM names with spaces (e.g. “Windows Server 2022”).
  • Effect: VMs with names containing spaces only work via the new UUID-based path. Legacy path silently rejects them with 400.
  • Suggested action: deprecate the legacy path, document the breakage window, remove in 0.16.0 after one minor cycle of dual operation.
  • Owner: TBD
  • Target: deprecation 0.15.0, removal 0.16.0

Linter / rust-analyzer revert investigation

Section titled “Linter / rust-analyzer revert investigation”
  • During v0.14.0 cycle, three separate runs observed the linter or rust-analyzer auto-import bringing back removed symbols: spice_socket_dir, video_migration imports/paths/schemas, and related fields. Each time required a manual pickup commit.
  • Hypothesis: rust-analyzer auto-import on save, or a pre-commit hook running cargo fix against a stale cache.
  • Suggested action: review .vscode/settings.json (if present), .cargo/config.toml, and any pre-commit hooks. Disable auto-import for symbols whose modules have been deleted.
  • Owner: TBD
  • Target: investigate before 0.15.0 work starts

synvirt.toml legacy fields cleanup on synvirt-01

Section titled “synvirt.toml legacy fields cleanup on synvirt-01”
  • /etc/synvirt/synvirt.toml on synvirt-01 still contains spice_enabled = true and rdp_enabled = true. The daemon ignores unknown fields silently (serde default), so this is cosmetic only.
  • Cleanup happens automatically on next config deploy that touches console flags. No action needed.
  • Owner: N/A (self-healing)
  • Target: opportunistic