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.
System at a glance
Section titled “System at a glance”Connect / protobuf over HTTPS
repository-owned code and dependencies
The container backend collapses the cell lane into a Docker-managed, shared-kernel runtime for the current demo. The API, durable state, guest contract, and user workflow stay the same; backend capabilities make the weaker isolation explicit.
Technology map
Section titled “Technology map”| 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, end to end
Section titled “A create request, end to end”celld persists the operation before expensive or privileged work begins. Clients receive stable IDs immediately and can reconnect to the event stream later. If the daemon restarts, reconciliation compares desired cell records with backend state instead of replaying interrupted actions blindly.
The backend contract
Section titled “The backend contract”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 |
Firecracker launch pipeline
Section titled “Firecracker launch pipeline”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.
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.
Inside the cell
Section titled “Inside the cell”CellOS is the narrow trusted guest layer. Project code does not run as part of the host daemon and does not receive the host Docker socket.
GuestService clientinit · exec · ports · grants · quiesceimage · Dockerfile · lifecycle commandsThe 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.
Private networking and ports
Section titled “Private networking and ports”inside the cellcell-agent reports service/cells/:id/ports/5173Mac · browser · IDEThe 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.
State, checkpoints, and forks
Section titled “State, checkpoints, and forks”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.
Where to read the code
Section titled “Where to read the code”| 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.