Files
start-os/ARCHITECTURE.md
Matt Hill 2b70b67824 MCP MVP
2026-03-15 23:35:32 -06:00

7.4 KiB

Architecture

StartOS is an open-source Linux distribution for running personal servers. It manages discovery, installation, network configuration, backups, and health monitoring of self-hosted services.

Tech Stack

  • Backend: Rust (async/Tokio, Axum web framework)
  • Frontend: Angular 21 + TypeScript + Taiga UI 5
  • Container runtime: Node.js/TypeScript with LXC
  • Database/State: Patch-DB (git submodule) - storage layer with reactive frontend sync
  • API: JSON-RPC via rpc-toolkit (see core/rpc-toolkit.md), MCP for LLM agents (see core/mcp/ARCHITECTURE.md)
  • Auth: Password + session cookie, public/private key signatures, local authcookie (see core/src/middleware/auth/)

Project Structure

/
├── assets/              # Screenshots for README
├── build/               # Auxiliary files and scripts for deployed images
├── container-runtime/   # Node.js program managing package containers
├── core/                # Rust backend: API, daemon (startd), CLI (start-cli)
├── debian/              # Debian package maintainer scripts
├── image-recipe/        # Scripts for building StartOS images
├── patch-db/            # (submodule) Diff-based data store for frontend sync
├── sdk/                 # TypeScript SDK for building StartOS packages
└── web/                 # Web UIs (Angular)

Components

  • core/ — Rust backend daemon. Produces a single binary startbox that is symlinked as startd (main daemon), start-cli (CLI), start-container (runs inside LXC containers), registrybox (package registry), and tunnelbox (VPN/tunnel). Handles all backend logic: RPC API, MCP server for LLM agents, service lifecycle, networking (DNS, ACME, WiFi, Tor, WireGuard), backups, and database state management. See core/ARCHITECTURE.md.

  • web/ — Angular 21 + TypeScript workspace using Taiga UI 5. Contains three applications (admin UI, setup wizard, VPN management) and two shared libraries (common components/services, marketplace). Communicates with the backend exclusively via JSON-RPC. See web/ARCHITECTURE.md.

  • container-runtime/ — Node.js runtime that runs inside each service's LXC container. Loads the service's JavaScript from its S9PK package and manages subcontainers. Communicates with the host daemon via JSON-RPC over Unix socket. See container-runtime/CLAUDE.md.

  • sdk/ — TypeScript SDK for packaging services for StartOS (@start9labs/start-sdk). Split into base/ (core types, ABI definitions, effects interface, consumed by web as @start9labs/start-sdk-base) and package/ (full SDK for service developers, consumed by container-runtime as @start9labs/start-sdk).

  • patch-db/ — Git submodule providing diff-based state synchronization. Uses CBOR encoding. Backend mutations produce diffs that are pushed to the frontend via WebSocket, enabling reactive UI updates without polling. See patch-db repo.

Build Pipeline

Components have a strict dependency chain. Changes flow in one direction:

Rust (core/)
  → cargo test exports ts-rs types to core/bindings/
    → rsync copies to sdk/base/lib/osBindings/
      → SDK build produces baseDist/ and dist/
        → web/ consumes baseDist/ (via @start9labs/start-sdk-base)
        → container-runtime/ consumes dist/ (via @start9labs/start-sdk)

Key make targets along this chain:

Step Command What it does
1 cargo check -p start-os Verify Rust compiles
2 make ts-bindings Export ts-rs types → rsync to SDK
3 cd sdk && make baseDist dist Build SDK packages
4 cd web && npm run check Type-check Angular projects
5 cd container-runtime && npm run check Type-check runtime

Important: Editing sdk/base/lib/osBindings/*.ts alone is NOT sufficient — you must rebuild the SDK bundle (step 3) before web/container-runtime can see the changes.

Cross-Layer Verification

When making changes across multiple layers (Rust, SDK, web, container-runtime), verify in this order:

  1. Rust: cargo check -p start-os — verifies core compiles
  2. TS bindings: make ts-bindings — regenerates TypeScript types from Rust #[ts(export)] structs
    • Runs ./core/build/build-ts.sh to export ts-rs types to core/bindings/
    • Syncs core/bindings/sdk/base/lib/osBindings/ via rsync
    • If you manually edit files in sdk/base/lib/osBindings/, you must still rebuild the SDK (step 3)
  3. SDK bundle: cd sdk && make baseDist dist — compiles SDK source into packages
    • baseDist/ is consumed by /web (via @start9labs/start-sdk-base)
    • dist/ is consumed by /container-runtime (via @start9labs/start-sdk)
    • Web and container-runtime reference the built SDK, not source files
  4. Web type check: cd web && npm run check — type-checks all Angular projects
  5. Container runtime type check: cd container-runtime && npm run check — type-checks the runtime

Data Flow: Backend to Frontend

StartOS uses Patch-DB for reactive state synchronization:

  1. The backend mutates state via db.mutate(), producing CBOR diffs
  2. Diffs are pushed to the frontend over a persistent WebSocket connection
  3. The frontend applies diffs to its local state copy and notifies observers
  4. Components watch specific database paths via PatchDB.watch$(), receiving updates reactively

This means the UI is always eventually consistent with the backend — after any mutating API call, the frontend waits for the corresponding PatchDB diff before resolving, so the UI reflects the result immediately.

MCP Server (LLM Agent Interface)

StartOS includes an MCP (Model Context Protocol) server at /mcp, enabling LLM agents to discover and invoke the same operations available through the UI and CLI. The MCP server runs inside the StartOS server process alongside the RPC API.

  • Tools: Every RPC method is exposed as an MCP tool with LLM-optimized descriptions and JSON Schema inputs. Agents call tools/list to discover what's available and tools/call to invoke operations.
  • Resources: System state is exposed via MCP resources backed by Patch-DB. Agents subscribe to startos:///public and receive debounced revision diffs over SSE, maintaining a local state cache without polling.
  • Auth: Same session cookie auth as the UI — no separate credentials.
  • Transport: MCP Streamable HTTP — POST for requests, GET for SSE notification stream, DELETE for session teardown.

See core/ARCHITECTURE.md for implementation details.

Further Reading