Skip to content

System Architecture

DevCell is a single-host control plane for development machines. The host is trusted; repositories, build tools, and coding agents are not. A typed Go API turns client intent into durable state, then a backend establishes the runtime boundary and a guest agent manages the workspace.

The clearest mental model is nesting: each outer ring owns policy and lifecycle for everything inside it. The project’s devcontainer stays the innermost, familiar layer—it never becomes the trust boundary.

Read the rings from the outside in. Isolation and authority live on the outer rings; developer tools and project code live in the center.

DevCell nested layersFive nested hexagons. Outermost is the DevCell Host with celld. Then the Firecracker cell boundary, CellOS with cell-agent, Docker and the Dev Container CLI, and the project workspace at the center.01 · DevCell HostNixOS · celld · policy · SQLite · Tailscale02 · Cell boundaryFirecracker · dedicated kernel · TAP · vsock03 · CellOSimmutable guest · cell-agent supervisor04 · Project runtimeDocker · Dev Container CLI05 · Workspacerepo · agent
01 HostAuthorityAuthenticates clients, persists operations, grants capabilities, owns storage and routing.
02 CellIsolationKVM microVM boundary. Dedicated guest kernel; host never hands out Docker or KVM sockets.
03 CellOSSupervisionBoots the guest, runs cell-agent, and exposes the typed GuestService over vsock.
04 RuntimeCompatibilityBuilds and runs the repository's existing Docker / Dev Container / Compose definition.
05 WorkspaceWorkloadUntrusted project code, services, builds, and coding agents—disposable by design.

CellOS is not a developer distro and does not replace the project’s environment. It is the thin trusted supervisor that runs the project’s environment. The container backend collapses rings 02–03 into a Docker-managed, shared-kernel runtime for the current demo; the API, durable state, guest contract, and user workflow stay the same.

Lifecycle is a directed graph, not a single happy path. Create and start are linear; once a cell is ready, work, exposure, and branching fan out. Checkpoint and fork produce a new cell identity without mutating the parent.

01Pairapprove client
02Createclone + plan
03Startbackend + guest
04Readydurable cell
from Ready
workOpen IDECursor · VS Code
workExec / agentGuestService
workPublish portshost routes
branchCheckpointquiesce + save
branchForknew cell + lineage
capacityStop / sleeprelease runtime
endDestroydrop identity

Every long-running edge above is an operation: durable steps and events in SQLite. Clients get IDs immediately, watch progress, and can reconnect after a daemon restart. Reconciliation compares desired cell records with backend reality instead of blindly replaying interrupted work.

The same nesting drawn as trust lanes. Clients talk only to the host; the host talks to the guest; the guest runs the project.

Clients Swift app · Go CLI · IDE · agent Connect / protobuf over HTTPS
↓ paired request
Trusted DevCell Host · NixOS celld
policySQLite ledgerstorageroutingsecrets
↓ backend lifecycle · guest RPC
Managed cell boundary Firecracker + CellOS
dedicated kernelvsockcell-agentDocker
↓ workspace plan
Untrusted workload devcontainer · services · builds · coding agents repository-owned code and dependencies
Layer Technology Responsibility
Client Swift/SwiftUI and Go Pair hosts, drive cells, render operations, open IDE sessions
Public API protobuf + Connect Versioned Host, Cell, Operation, Snapshot, Terminal, Port, Capability, Secret, and Guest services
Control plane Go celld Authentication, lifecycle orchestration, policy, event recording, reconciliation
Durable state SQLite Cells, machines, operations, steps, events, clients, grants, ports, volumes, snapshots, lineage
Host image NixOS + Disko + Nix flakes Reproducible appliance, partition layout, services, Firecracker and devcontainer tooling
Machine backend Firecracker/KVM or Docker Establish and own the runtime boundary
Host↔guest transport AF_VSOCK / Firecracker UDS; HTTP in container mode Typed calls from celld to cell-agent
Guest supervisor CellOS + Go cell-agent Workspace init, exec, services, ports, grants, snapshot hooks
Project runtime Docker + Dev Container CLI Build and run the repository-defined development environment
Private network Tailscale + host HTTP proxy Paired access to the appliance and workspace preview routes

A create request fans into durable state first, then into planning and machine provisioning. The client never waits on a single opaque RPC for the whole lifecycle.

Client
ACreateCellrepo · branch · resources
BWatch operationordered events
CStartCellwhen ready
celld + SQLite
1Validate + persistcell · op · first event
2Materialize sourceclone / copy repo
3Resolve planWorkspacePlan · MachineSpec
4backend.Createruntime descriptor
Backend → cell-agent
5backend.Startboot boundary
6InitializeWorkspacedevcontainer path

celld persists the operation before expensive or privileged work begins. If the daemon restarts mid-flight, interrupted operations are marked failed rather than silently replayed.

Every runtime implements one deliberately small Go interface:

type Backend interface {
Create(context.Context, MachineSpec) (Machine, error)
Start(context.Context, string) (Machine, error)
Stop(context.Context, string) (Machine, error)
Destroy(context.Context, string) (Machine, error)
Inspect(context.Context, string) (Machine, error)
Reconcile(context.Context, []Machine) error
}

Optional interfaces report capabilities, expose the guest endpoint, publish runtime descriptors, and checkpoint volumes. This keeps client semantics stable without pretending every backend has the same isolation or snapshot support.

Backend Boundary Guest path Snapshot behavior
Fake In-memory simulation None Metadata and lineage only
Container Docker process, network namespace, cgroup; shared host kernel Loopback HTTP to cell-agent Quiesce + workspace copy
Firecracker KVM microVM with dedicated guest kernel vsock via Firecracker UDS Metadata today; block and memory snapshots next

The machine path is more than spawning a binary. celld derives and owns every host artifact required to start and later clean up the cell.

01Stage mediakernel · initrd · writable rootfs copy
02Allocate networkTAP device · guest MAC · optional netns
03Allocate transportunique vsock CID · UDS path · port 5000
04Write configvCPU · memory · boot args · drives
05Stage jailchroot layout · copied media · jailer argv
06Launch + reconcileprocess identity · cleanup · orphan recovery

On stop or destroy, the backend terminates the microVM and removes TAP devices, vsock sockets, and per-cell runtime state. On daemon restart, it reconstructs live machine records and cleans orphaned host resources.

Cross-section of rings 03–05: CellOS supervises; Docker packages; the workspace does the work.

hostcelldGuestService client
vsock :5000
CellOS
supervisorcell-agentinit · exec · ports · grants · quiesce
project runtimeDocker + Dev Container CLIimage · Dockerfile · lifecycle commands
workspacerepository · services · coding agent

The container demo runs the same cell-agent contract over HTTP and launches the resolved devcontainer directly on the appliance. The Firecracker host dial path is implemented; a freshly built CellOS rootfs containing the vsock-listening agent completes live guest exec in the microVM path.

workloadVite :5173inside the cell
guestport discoverycell-agent reports service
hostcelld :8443/cells/:id/ports/5173
private clientTailscaleMac · browser · IDE

The cell requests exposure; the host owns publication. HTTP services receive stable host routes, while direct TCP endpoints use the appliance’s private Tailscale address. Credentials can follow the same pattern: the host stores and decrypts material, then supplies a scoped lease or brokered request rather than exposing an ambient credential directory.

Always durableControl-plane metadatacell · operation · event · snapshot lineage
Demo pathWorkspace checkpointquiesce services · copy filesystem · cold resume
Machine pathMicroVM stateblock diff · memory snapshot · demand-paged restore

These layers are intentionally distinct. Container sleep is checkpoint plus stop, followed by a cold start. It does not preserve RAM. A fork gets a new cell identity and lineage record; on the container path its workspace is restored from the checkpoint copy. Firecracker block/diff and memory snapshots are the remaining capacity layer.

Concern Source
API contract api/proto/devcell/v1/devcell.proto
Control-plane orchestration internal/celld/
Durable state internal/store/
Backend contract internal/hypervisor/hypervisor.go
Container runtime internal/hypervisor/container/
Firecracker runtime internal/hypervisor/firecracker/
Guest supervisor internal/cellagent/ and cmd/cell-agent/
Workspace resolution internal/workspace/
Appliance and CellOS images nix/hosts/, nix/images/, and nix/modules/
Swift client macos/DevCell/

Continue with CellOS Contract for guest RPCs, Storage and Snapshots for checkpoint semantics, or Security Model for the trust rules.