Architecture

A deliberate split: the CLI handles intent, the agent handles reality.

Relay is easier to operate because the system boundary is plain. The Node CLI computes local state and speaks to the server. The Go agent owns workspaces, buildpacks, container builds, logs, databases, and process control.

Deploy path
1. relay computes manifest
2. agent answers diff plan
3. changed files upload
4. buildpack selects build plan
5. runtime.Build() images
6. container swaps
7. preview URL prints

relay CLI

Computes the local file manifest and hashes.

Uploads changed files or bundles to the current sync session.

Starts, stops, and restarts apps through the agent API.

Streams logs and prints deploy status to the terminal.

relayd agent

Stores app state and deploy history in SQLite.

Materializes workspaces under the data directory.

Selects buildpacks, writes Dockerfiles, and routes builds through a pluggable runtime backend.

Performs container swaps and keeps one previous image for rollback. Docker is the default backend; vessel is available as a per-app alternative.

Storage

Boring storage is a feature.

The data model is intentionally local and inspectable. If something breaks, you should be able to answer basic questions with files and a SQLite shell.

relay.db

Deploy history, app state, secrets, and project service records.

logs/

One log file per deploy, readable by humans and streamable to the CLI.

workspaces/

Per-app repo snapshots, staging paths, and sync state between deploys.

plugins/

Server-installed buildpack plugin definitions kept under the data directory.

Workspace shape
data/
  relay.db
  token.txt
  logs/
    <deployId>.log
  workspaces/
    <app>__<env>__<branch>/
      repo/
      staging/
  plugins/
    buildpacks/
Runtime engine

All container operations route through a single interface.

ContainerRuntime abstracts build, run, stop, network, log, and image operations. Docker is the default backend. The engine is stored per-app in app state — set it to vessel for workloads that need the Windows-native container backend.

ContainerRuntime interface

Covers RunDetached, Remove, IsRunning, ContainerIP, PublishedPort, Exec, NetworkConnect, EnsureNetwork, RemoveNetwork, RemoveVolume, Build, RemoveImage, ListImages, and LogStream.

Docker (default)

DockerRuntime implements all interface methods via the Docker CLI. DOCKER_BUILDKIT=1 is set for builds. This is the backend relayd starts with.

vessel (alternative)

VesselRuntime is the Windows-native container backend. Set engine to "vessel" in app config. Supports exec, companion services with host-alias routing, and managed named volumes. Docker and vessel coexist on the same server.

Vessel constraints

Vessel lanes are forced to port mode and edge traffic. Blue-green slot swaps are not supported. Exec, companion services, named volumes, and stable bridge IPs all work.

Engine selection
# Set per-app via /api/apps/config
{ "engine": "docker" }  // default
{ "engine": "vessel" }  // Windows-native

// vessel enforces
// mode:         "port"  (forced)
// traffic_mode: "edge"  (forced)
// no blue-green slots
// companions + exec + volumes: ok
Boundary

Relay is not pretending to be a generic build cloud.

That constraint is what keeps the architecture legible. It is a deploy agent for workloads you own, not a universal remote execution fabric.

See the CLI guide