1Control plane
PCS writes desired state and signed commands only; it never calls Docker. Container lifecycle runs in host-runtime on the host. Private keys are only for probing and one-time bootstrap.
The PCS control plane manages hosts, deployments and Agent / API profiles, storing only Secret Store references for keys. host-runtime on each host executes signed commands. Schedulers dispatch over a recursive tree and node schedulers aggregate capability upward; a host can merge into another host to form a federation, and tasks that cross schedulers are pushed down, never copied. A sideload token lets one LAN device reach the same task path, and every task can move files in and out through the attachment and artifact channel.
PCS writes desired state and signed commands only; it never calls Docker. Container lifecycle runs in host-runtime on the host. Private keys are only for probing and one-time bootstrap.
A root scheduler can hold leaf builders or node schedulers; a node scheduler holds more builders and schedulers, recursively, with no depth limit. Every scheduler owns its own database.
W = round(1000 × Σ(weight × min(value, cap) / cap)): CPU 30% (8 cores), clock 15% (4 GHz), memory 20% (32 GB), storage 10% (256 GB), model 15% (10), API 10% (10). Schedulers do not score — W is 0.
A task carries difficulty D (0–1000, 0 = any). A scheduler only hands it to builders with W ≥ D, preferring the tightest fit so big machines are not held by small tasks.
A node scheduler adds its builders' W to its children's ΣW and reports it upward, all the way to the root. The ΣW the root sees is the whole federation's capacity.
Merging is one reference, pcs_hosts.parent_host_id. A host cannot merge into itself or its own descendant, and both sides need a root scheduler. Merging or detaching only changes the runtime parent — no container restarts.
Push down, never copy: the parent task stays QUEUED in its original database and child tasks dedupe on relay_parent_task_id; state and output mirror back, cancels forward down, max depth 8.
A host's role is containers, builder or scheduler; one host cannot be both builder and scheduler. In container mode a host has exactly one root scheduler plus any number of node schedulers.
Builders, schedulers, chat and terminal all read the host subtree: the local host and merged hosts are grouped and foldable, each header shows the hostname and count, and fold state persists per browser. A single host renders flat.
The control plane owns Agent and API profiles: role-to-Agent bindings live in role_agent_bindings, role-to-API bindings in role_api_bindings, scoped per host. Deployments receive references only; a scheduler neither parses profile contents nor touches keys.
API keys never enter the platform database: profiles hold only secret://<path> refs, values live in the Secret Store (file 0600). PCS neither echoes nor logs them; container instances resolve refs with a Secret Store instance JWT.
Dispatch stays deterministic; the scheduler Agent only explains queues, leases and "why is this one waiting". It calls the local builders MCP server (list_builders, builder_exec, builder_ask, task_status) to inspect or operate builders, outside the dispatch path.
A sideload is a curl token bound to one host, not an Agent: device → PCS → host's root scheduler, reusing the same task, lease and fencing path. Scopes are a closed set (tasks:read, tasks:write, builders:read, queue:read, console:run); the token is stored as a SHA-256 hash plus its last four characters.
Attachments go in through POST /attachments (24 MiB each) and are materialized under <workspace>/attachments/ before the command runs. requirements.console.collect walks the workspace (32 paths / 128 files, 64 MiB each, 256 MiB total) and pushes every file through the artifact channel, which recomputes SHA-256; downloads are byte-for-byte.
The plaintext token is shown once; deleting or expiring it takes effect on the next call. Presence is throttled to one write per 30 seconds, and the studio shows online within 120 seconds. Builders listed to a sideload are the host root scheduler's subtree — exactly what a submitted task can run on.