Skip to main content
Tascarrel is alpha software and may break. We’re looking for your feedback — share it on GitHub.
Documentation

System Architecture

Tascarrel divides runtime responsibilities across the host, each workspace virtual machine, and each pod:

Tascarrel UI or tascarrelctl


tascarrel server (hostd)
          │  private virtio-serial connection

        guestd
          │  runc: pod lifecycle and process supervision

         Pod
          ├── podd (PID 1 and pod-local initialization)
          ├── task processes
          └── podctl client

Host Daemon

The tascarrel server runs the host daemon (hostd). That daemon owns configuration, QEMU processes, repository credentials and caches, SOPS providers, network enforcement, the web API, and upstream Git publication. It is the only component that should need host-side project credentials.

The UI uses HTTP and WebSocket endpoints authenticated by a host-owned browser session. A pairing key created through tascarrelctl delegates that session from hostd’s private Unix control socket. Published HTTP routes receive separate, route-scoped credentials derived from the browser session.

Workspace Guest

Each workspace VM runs guestd, which manages images, Btrfs state, pod services, network plumbing, processes, chats, and typed requests from the host. The VM has no general-purpose virtual NIC or host filesystem mount.

The host and guest daemons communicate through a private QEMU virtio-serial channel. Operations that cross the main trust boundary stay with the component that owns the authority: for example, a pod proposes a Git update, then hostd applies policy and uses upstream credentials.

Pod Runtime

The guest daemon uses runc to create pod namespaces, mounts, and devices, then starts and supervises task processes. The podd process runs as PID 1 inside the pod, performs pod-local initialization, and manages optional Docker. It does not launch or supervise task processes.

The podctl client connects through an authenticated pod-private socket whose listener assigns the workspace and pod identity.

Control calls, subscriptions, and Git smart-protocol streams share that socket through Tascarrel’s multiplexer. A caller cannot select a sibling pod merely by inventing another identifier.

Typed Protocol

Sidex schemas define actions, outputs, errors, identifiers, and subscriptions, then generate Rust and TypeScript bindings. Most subscriptions begin with a snapshot and emit ordered changes. Large chats bootstrap their turns, timeline, attachments, and prompt queue in bounded chunks before live changes begin. Resumable stores let the UI rebuild state after a connection is interrupted.