Process topology and chassis

Aether uses the word engine for an actor runtime, not for every process in the operator stack. A normal agent-driven session has several boundaries:

agent or human client
└─ MCP → stable tunnel → aether-mcp coordinator
                               │ framed Aether RPC
                               ▼
       hub chassis ───── content-addressed binary/component stores
               ├── engine proxy ── child substrate: headless chassis
               └── engine proxy ── child substrate: desktop chassis

The tunnel keeps the client-facing MCP connection stable. aether-mcp translates tool-shaped JSON into typed Aether mail and maintains operator-side caches. The hub owns fleet supervision, stored artifacts, and routing identity: it mints each process-local engine_id and assigns it to the child proxy. Each child substrate owns an independent registry, scheduler, actor set, and live runtime state.

The four chassis profiles

The aether-chassis-* crates assemble the shared runtime into purpose-specific profiles. The exact capability set is code and feature dependent, so treat this table as intent rather than a hardcoded manifest.

ProfileEntry binaryPrimary job
Desktopaether-desktopwindow, GPU/input/audio integration and interactive frames
Headlessaether-headlesstimer-driven engine without a desktop event loop
Hubaether-hubsupervise child engines, store artifacts, and route RPC
Bloomeryaether-bloomeryjournal-driven engine: the bundle driver over one journal root, with deny-by-default HTTP egress and the aether.bloomery.workspace actor, which imports digest-pinned images into the journal through the Docker Engine API

Their builders live under crates/aether-chassis-{desktop,headless,hub,bloomery}. Shared runtime mechanism remains in aether-substrate; each shared native actor remains in its own aether-<capability> crate.

“Headless” is a process/profile statement, not permission to assume every capability is absent. Some capabilities have explicit headless implementations or unsupported marker actors so callers get a deterministic reply instead of a missing mailbox. Check the chassis builder and live handlers for the exact engine.

What the hub owns

The hub's FleetServer is the fleet control plane. It owns:

  • spawn and termination requests;
  • the live proxy set and heartbeat state;
  • recently departed engine records;
  • binary and component artifact stores;
  • selector resolution, materialization, persistence, and eviction policy;
  • routing a per-engine RPC call to the right proxy.

A FleetProxy represents one connected child. It is not the child's actor registry mirrored in full. Mail, replies, inventory queries, and lifecycle events still cross the RPC boundary.

This is why engine_id must be carried explicitly by operator tools: mailbox lineage is only meaningful within the selected engine.

What a child substrate owns

Every engine has its own:

  • mailbox registry and lineage namespace;
  • mail rings and scheduler state;
  • native capability instances selected by its chassis;
  • wasm component instances and trampoline state;
  • lifecycle/settlement graph and per-actor evidence;
  • configuration overlay resolved at boot.

Terminating a child destroys that live state. Uploaded artifacts live in the hub store and can outlive one engine; loaded component instances do not.

One tool call end to end

A per-engine MCP call crosses two distinct translations:

tool JSON
  → textual recipient resolution through selected engine inventory
  → engine returns the canonical path
  → schema-aware encode in aether-mcp
  → WireFrame / MailEnvelope naming the path over hub RPC
  → proxy selects engine, sends the path on as written
  → child RPC server resolves the path on arrival and proves it Live (ADR-0230)
  → scheduler dispatches typed bytes to an actor
  → reply and settlement events travel back
  → tool projects bounded JSON/evidence

Failures at these layers look different. A schema error happens before mail is sent. An unknown engine fails at the fleet boundary. An unknown recipient fails inside the selected engine during address resolution. Canonical lineage and ADR-0166 short paths share that engine-owned seam; the MCP coordinator keeps no alias table and never hashes operator paths. A handler error or non-settling descendant happens after dispatch. A path that names nothing live, or an actor still starting, is refused at the engine's RPC receipt and closes the call with ReplyEnd Err(RpcError::NotPresent) naming the path. Start diagnosis at the earliest layer supported by evidence; the recovery runbook is organized that way.

Components at boot versus after boot

The hub can stage stored component bytes and a JSON-derived config into a boot manifest for a new substrate. The child loads those components during startup and binds its RPC port only once every requested instance is live, so it is reachable only when ready. Alternatively, operator tools can load or replace components after the engine is live.

Both paths resolve registry selectors. Neither treats an arbitrary local wasm path as a component identity. Upload first, select second. See Component registry and replacement.

Distribution is a different topology

cargo xtask package produces a shippable package depot: a selected desktop or headless chassis binary alongside a content-addressed pack/ of the chosen components and their config. It is not the same thing as the development hub fleet. The depot's autoload path builds the component set at process boot without requiring an MCP coordinator or hub artifact store.

Read Distribution and packaging before changing autoload or packaging behavior.

Implementation and decisions

  • Shared chassis traits and frame loop: crates/aether-substrate/src/chassis/
  • Process composition: crates/aether-chassis/src/ + the per-chassis crates
  • One-shot process execution capability: crates/aether-process/ (Accepted ADR-0157)
  • Fleet, proxy, and stores: crates/aether-fleet/src/
  • Framed RPC: crates/aether-rpc/src/
  • MCP translation: crates/aether-mcp/src/
  • ADR-0034 and ADR-0073: the hub as a substrate, and the runtime/chassis split
  • ADR-0072 and ADR-0118: the framed RPC protocol and the workspace's own wire format
  • ADR-0074: one actor model for native capabilities and wasm guests
  • ADR-0089: stable tunnel boundary
  • ADR-0115 and ADR-0116: binary and component registries
  • ADR-0157 (Accepted): one-shot process execution capability