Brief
What had to change
"Your Linux server, finally usable from your phone." MSO is an open-source, mobile-friendly visual shell for a Linux server you own: it brings a real terminal, file manager, live system metrics and a BYOK AI assistant into one private browser workspace without running a full remote desktop. The concrete case it names: "Fix a server issue from your phone — check system health, open a real terminal, inspect logs, and restart a service without opening a laptop."
Approach
How the work was shaped
Shipping here is a script, not a habit: production is systemd with no webhook, so `bun run ship` encodes the one order that cannot be got wrong — commit, regenerate the derived changelog and amend it into that same commit, push through the gates, build, restart — and then curls the served CSS chunk to prove the restart actually landed, because a chunk mismatch leaves every asset 404ing. Those gates live in a committed `scripts/gates.sh` rather than `.git/hooks/pre-push`, after an installer silently overwrote the untracked hook and dropped the audit and build guards; the build guard compiles a throwaway copy of HEAD out-of-tree on purpose, since `next build` would wipe the `.next` the live process is serving. Feature work runs as parallel coding-agent packages on strictly disjoint file sets, each reviewed against its own diff, and a 13-agent parity audit across the three ways something can drive the box — the in-browser assistant, MCP, and the `mso` CLI — put up 58 claims of which 53 survived adversarial verification; the fix was a `lib/mcp/parity.test.ts` gate rather than a merged registry, on the grounds that the two catalogs legitimately differ and “the defect was never duplication, it was silence”. The Browser app is a real anti-fingerprinting Firefox streamed over noVNC because the two cheaper designs were built and failed first: a Playwright sidecar, then a sandboxed iframe that X-Frame-Options refuses on most of the real web.
Outcome
What the result changed
1,249 tests, enforced by a committed pre-push gate after an installer silently dropped it
Constraints that shaped the system.
- 01
Public Alpha / Developer Preview. "The core auth, filesystem bounds, terminal, metrics, and slice architecture are implemented, but the project is still early and unaudited. Expect rough edges, breaking changes, and missing production hardening."
Constraint - 02
Explicitly NOT an operating system, Linux distribution, desktop environment, VPS provider, or production-grade security platform. It runs on top of Linux as a normal non-root Node process.
Constraint - 03
No multi-user support, and no third-party security audit (both stated as "No" in the README's own comparison table).
Constraint - 04
Must be put behind Tailscale, a VPN, or a TLS reverse proxy with tight access control. "Do not expose the raw app port to the public internet." An authenticated session "can read allowed files and run commands as the user that owns the process. Treat it like SSH in a browser."
Constraint - 05
`exec.run` is not sandboxed — cwd is bounded to the write roots but the command runs in the login shell as the service user, and the destructive-command denylist is "a short accident tripwire, not a guard".
Constraint - 06
BYOK means you own the key, not that data stays on the box: everything the AI reads is sent to the model provider and re-sent every turn. Device approval is "an allowlist, not standards-based 2FA". Agents and Skills group tools for convenience and are "not a permission boundary".
Constraint - 07
Not yet formally tested across a distro matrix — tested only on Ubuntu 22.04 and 24.04. Windows host, macOS host, non-systemd service install and root deployment are all unsupported.
Constraint - 08
The shell skins (macOS / Windows / iOS / Android) are "UI preferences, not the core product"; the browser UI is "one frontend, not the product" — the `mso` CLI reaches the same API.
Constraint - 09
node-pty has no Linux prebuild and is listed under `trustedDependencies`; install with bun or its postinstall is skipped and the whole `/api/v1` surface fails to load.
Constraint
