Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Packaging and Desktop Shell

Status: proposed — consolidated 2026-09-01 from material already designed in 001-system-overview.md, 050-ui-dashboard.md, 060-configuration.md, 061-security.md, and 070-roadmap.md. No new design decisions were made here, except where flagged as a new Open Question below.

Scope

Distribution of the single pam binary (cargo-binstall, release process) in its two roles — central orchestrator (pam serve, needs a PostgreSQL DSN) and worker (pam worker) — for the supported worker platforms: macOS (primary) and Linux (secondary); Windows out of scope, mobile excluded (ADR-011/ADR-012). Includes the confirmed Tauri v2 desktop shell (ADR-006; Electron recorded as fallback).

Distribution

One pam binary, two roles selected by subcommand — pam serve (central orchestrator: axum HTTP API + embedded SPA + run dispatch + worker registry, needs a reachable PostgreSQL DSN) and pam worker (outbound-only registration, no inbound listener, supervises tmux sessions on the host’s dedicated pam socket) — the same binary can run both roles on one machine to recover a single-machine deployment (001-system-overview.md § Distribution Topology). Each role reads its own platform data dir (config.toml/token for the orchestrator, worker.toml/provider catalog/per-run logs for a worker), resolved via the directories crate — full paths and precedence rules are 060-configuration.md § Platform Data Dir, not duplicated here.

Platform Targets

Accepted 2026-08-29 (ADR-011): worker hosts target Unix only — macOS primary, Linux secondary; Windows is out of scope (no tmux), mobile is excluded. Code and CI stay platform-neutral (CI already builds and tests on Linux, ubuntu-latest); the interactive tmux gates (spawn, reconcile, attach) remain macOS-verified until a Linux environment is set up for manual verification (OQ-9, 071-risks-and-open-questions.md). The central orchestrator itself has no platform restriction beyond PostgreSQL reachability — ADR-011 binds worker hosts specifically, not pam serve.

Production Build

trunk build --release compiles the Leptos/WASM SPA into web/dist/; rust-embed includes that directory in the compiled binary; Axum serves the embedded files at / (index.html/, assets/*/assets/*, all non-API routes fall back to index.html for SPA routing) while API routes stay under /api/v1 unaffected (050-ui-dashboard.md § Production Build). This is what the Phase 3 embedding test proves: renaming web/dist away on disk after the binary is built still serves the SPA, showing embedding rather than static-file serving (063-testing-strategy.md § Test Pyramid by Phase).

Desktop Shell (Tauri v2)

Accepted 2026-08-29 (ADR-006): a Tauri v2 shell around the same embedded SPA, confirmed as a monitoring/viewing thin client that never executes work — every user action is forwarded as an API request only, and the orchestrator + its workers perform all actual work (050-ui-dashboard.md § Desktop Shell). Target platforms mirror the worker split: macOS + Linux desktops, Windows out of scope, mobile excluded; the shell is platform-independent by construction since it just loads the orchestrator URL.

Rationale for Tauri v2 over Electron: web-first (the embedded SPA already works standalone) suffices for single-operator local use; OS webview reuse costs 5-10 MB versus a bundled Chromium’s ~150 MB; the shell reuses the existing Rust core with no Node.js sidecar; and the security surface drops a Node.js runtime entirely, which matters because the shell needs no local capabilities. Electron is a recorded fallback for an ecosystem gap (e.g. a macOS auto-update issue), not a current alternative — the SPA uses only standard web APIs, so either shell stays viable without a rewrite.

Security posture (least privilege): Tauri v2 capabilities ship with everything disabled — no invoke, no Electron-style ipcRenderer/ remote equivalents used from SPA code (061-security.md § Shell Least-Privilege). This follows directly from the monitoring-only role: a client that never executes work locally needs no filesystem or shell capability to disable-by-exception, so the default-disabled posture is the complete posture, not a starting point to relax later.

Implementation is scheduled for Phase 6, not yet built: the Tauri app loads PAM_API_URL, optionally spawns pam serve as a child process (sidecar mode, process management only — the sidecar is still the same pam serve binary, not shell-specific code), bridges IPC for tray icon / notifications / window management, and reuses the Rust core directly (050-ui-dashboard.md § Implementation Note).

Phase 6 Packaging Gate

070-roadmap.md § Phase 6 scopes two deliverables: implementing the Tauri v2 shell as a wrapper (sidecar daemon or linked core; the web UI codebase stays single-source, no shell-specific fork), and cargo-binstall metadata plus release polish (app icon, naming, packaging defaults). The phase gate: a built .app/dmg launches on the dev Mac, starts or attaches to the same core, and passes the Phase 3 embedding gate through the shell webview; cargo-binstall metadata is present and validates locally via a dry run (no network publish required) — cross-ref 063-testing-strategy.md § Test Pyramid by Phase for how this gate fits the overall test pyramid. As of this consolidation, no cargo-binstall metadata exists yet in the workspace Cargo.toml files — Phase 6 has not started in code.

Open Questions