Platform architecture · v4.5 · 2026-11-13

Multi-Node AI Agent Compute & Scheduling Platform

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 control plane Root scheduler Node scheduler Leaf builder Agent / API profiles Secret Store MCP builders Sideload token Files in / out Capability score W Task difficulty D Aggregated ΣW Host merge Cross-scheduler relay
Figure 1 · Control plane and hosts PCS writes desired state only; host-runtime runs the containers
Admin app (browser) Agent studio · builders · tasks Chat · terminal · folded by host Single page · no roles HTTPS LAN device · sideload curl · sdl_ token · scopes attachments ↔ artifacts HTTPS · sdl_ PCS control plane Host onboarding · deploy & signed commands · Agent / API profiles · audit Host registry Local / SSH remote parent_host_id tree Deploy plans Pinned image digests CPU · memory · disk Agent profiles role_agent_bindings model · CLI / HTTP API profiles role_api_bindings llm · secret:// refs Secret Store Keys never in platform DB file 0600 · instance JWT Audit & events Who changed which host Every action traceable Outbound long poll · idempotent signed commands Host A (local) · runs admin app / PCS Probed and bootstrapped in place, no SSH host-runtime Polls desired state · runs commands Container ports / volumes / network Docker is only touched host-side scheduler Root scheduler :8443 Tasks · leases · console runs Files in/out · MCP builders builder × N build Agent + sshd root shell Host B (SSH remote) Private key AES-256-GCM encrypted; the API returns fingerprints only host-runtime One-time bootstrap, then dials PCS No long-lived SSH session after that bundle and command keys on the host builder × N build Agent + sshd root shell scheduler B's root · can merge Tasks · leases · sched Agent MCP builders · exec / ask PCS never calls Docker directly; private keys are only for probing and one-time bootstrap. Container sshd accepts only the host login key injected at deploy time (root, key-only). A sideload is not an Agent: the device only talks to PCS, which resolves the host's root scheduler; the token never sees the scheduler address or its credentials.
Figure 2 · Logical view Recursive scheduling tree, capability aggregation and host merge
Host A · root domain Host of the root scheduler · runs multiple containers Root scheduler Host A · container · ROOT Queue · dispatch · leases · ledger Sees the whole federation's capacity ΣW 168 ↓ dispatch tasks · ↑ report capability Builder W 24 Ubuntu 24.04 8 cores · 3.2 GHz 32G RAM · 500G disk Model / API folded in Builder W 16 Ubuntu 22.04 4 cores · 2.8 GHz 16G RAM · 200G disk Model / API folded in Node scheduler S1 ΣW 68 2 leaf builders + 1 node Routes by ΣW in its subtree Then picks a builder by W Builder W 20 Ubuntu 22.04 16G / 200G Builder W 12 Ubuntu 24.04 8G / 120G Node scheduler ΣW 36 S2 · can nest child nodes ⋯ A host runs many containers (builders / schedulers); a bare host taking a role is one or the other. Each host has at most one root scheduler — its single entry point inward and outward. Host B · merged into A SSH remote host · still its own root domain Host B's root scheduler ΣW 60 Inside: still B's root scheduler Outside: A's node scheduler Internal dispatch chain unchanged Builder W 32 Ubuntu 24.04 24G / 400G Builder W 28 Ubuntu 22.04 16G / 300G B reports its ΣW to A's root through its outward identity. Merged into A · outward role becomes node Capability score W W = w1·cores + w2·clock + w3·memory + w4·storage + w5·model + w6·API Computed when a builder is created; weights normalize to a comparable score. Dispatch: task difficulty D ≤ builder W; take the tightest fit. Aggregate: ΣW = Σ leaf W + Σ child scheduler ΣW (recursive). The root's 168 is the whole federation's available capacity. Parent → child: dispatch tasks; child → parent: report capability Host merge (federation)
Figure 3 · Host merge The same subtree, seen differently: degraded outside, unchanged inside
Before merge After merge Host A · root domain Root scheduler A ROOT Builder W 24 Builder W 16 Host B · root domain Root scheduler B ROOT Builder W 32 Builder W 28 Merge Host A · root domain + B subtree Root scheduler A ROOT B's root scheduler Outward = node · ΣW 60 Inside still B's root Builder W 32 Builder W 28 B's chain is untouched; only the root identity drops a level toward A.
Figure 4 · Cross-scheduler relay Push down, never copy: state and output mirror back up the chain
Root scheduler · Host A The task first enters the federation Task T · QUEUED target: b-1 (under merged host B) No such instance locally Parent stays here, never copied task_relays · ACTIVE Claim candidates exclude the parent No double execution Poll child: state / summary / output mirrored back Cancel parent → forward the cancel to the child Workflow subtasks never relay; state stays in one DB POST /v1/tasks · relay parent_task_id · depth+1 Node scheduler · Host B A's node outward, B's root inward Child task T' · deduplicated relay_parent_task_id = T Redelivery never creates a second task Not local → push one level down Leaf builder b-1 W ≥ D · claims and runs stdout / stderr → child result Child state, summary and output flow back up The parent ends up with the runner's stdout / stderr Max depth 8; if nobody fits, it queues here Relay semantics 1. Target instance: local if present, else the direct child rosters, hop by hop. 2. No target: local if a builder has W ≥ D; else pick a child by capacity. D > 0: tightest fit first (max_builder_score ascending). D = 0: idler child first (idle_builder_count descending). 3. Push down, never copy: parent stays QUEUED and is excluded from claims. 4. Dedup: relay_parent_task_id is unique; redelivery never creates a second task. 5. Mirror: poll child state and output; multi-hop reads the nested child_result. 6. Cancel: parent cancel → POST /v1/tasks/:id/cancel on the child, forwarded down. 7. Max depth 8; if the subtree cannot take it, the task queues where it is. 8. An unreachable child only adds sync_failures; nothing runs twice. Nodes report capacity metrics; that is how the parent picks a child.

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.

2Recursion

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.

3Capability score W

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.

4Dispatch by difficulty

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.

5Aggregate upward

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.

6Host merge

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.

7Cross-scheduler relay

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.

8Role rules

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.

9Admin views

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.

10Agent / API profiles

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.

11Secret Store

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.

12Scheduler Agent & MCP

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.

13Sideload tokens

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.

14Files in and out

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.

15Trust boundary

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.