Architecture
Planet, Moon, and Comet — the three node roles that compose every SoyaOS deployment.
SoyaOS is one binary that can play three roles. A deployment is just a particular shape of those roles. Whether you run solo on a laptop or enterprise-private in a sealed datacenter, the role boundary and the protocol between roles never changes — only the topology does.
The three node roles
Comet
A Comet is an ephemeral worker. It runs a single Agent invocation, streams its output, and exits. Comets are stateless — they pull the SoyaPack bundle from a Moon, mount a sandboxed /workdir, and emit Scope events as they progress.
Mental model: a Comet is a fast, opinionated
kubectl execfor one Agent run.
Concretely a Comet:
- Subscribes to a Moon for work over an outbound HTTPS WebSocket.
- Materializes the SoyaPack into a temporary directory, verifies its signature, and refuses to run if the capability allowlist isn’t satisfiable on this host.
- Streams stdout and Scope events back through the same WebSocket.
- Self-terminates after
idle_timeout(default 300s) ormax_runs(default unlimited).
Moon
A Moon is a per-tenant control surface. It hosts the API surface that developers and users talk to, holds the SoyaPack registry, mints API keys, and brokers Scope events. A Moon does not run Agents itself; it dispatches to Comets.
Mental model: a Moon is the “team workspace”. One per company / studio / household.
Inside a Moon:
- The OpenAI-compatible endpoint (
/v1/chat/completions) — takes amodel: "soya:*"request, resolves it to a SoyaPack version, picks a Comet, returns a streaming response. - The SoyaPack registry — versioned, content-addressed bundles backed by S3-compatible object storage.
- The auth surface — issues API keys and capability tokens; verifies signed packs on push.
- The Scope broker — multiplexes per-run events to subscribers (Studio, Developer Portal, webhooks).
Planet
A Planet is the federation root. It owns identity (who you are), billing (when there is billing), and cross-Moon routing. In solo deployments there is no separate Planet — Planet, Moon and Comet collapse into one process.
Mental model: a Planet is the “constellation operator”. Optional for single-tenant deployments.
A Planet’s responsibilities:
- Identity — OIDC issuer for users and Moons; signs SSO assertions.
- Routing — maps a tenant URL (
tenant.moon.example.com) to a specific Moon. - Cross-Moon contracts — the only entity that can authorize a SoyaPack to run on a Moon outside its origin tenant.
How a request flows
- Client calls the OpenAI-compatible endpoint on a Moon:
POST /v1/chat/completionswithmodel: "soya:compo". - The Moon resolves
soya:compo→ a specific SoyaPack version (e.g.soya:[email protected]) and picks a warm Comet (or cold-starts one). - The Comet executes the Agent inside its sandbox, calling out to upstream LLMs via the capability allowlist, and streams Scope events back through the Moon.
- The Moon multiplexes those events to subscribers (Studio, Developer Portal, webhooks).
- When the Agent completes, the Comet emits a final artifact JSON and self-terminates (or returns to the warm pool, depending on
idle_timeout).
A concrete event trace
For a single soya:compo invocation, the Scope event stream looks roughly like:
00.000 run_started run_id=run_018f… pack=soya:[email protected] comet=cmt-a3
00.012 stage_started stage=outline
00.087 tool_called tool=fetch_reference args={url:…} # capability check: egress.host
00.412 tool_completed tool=fetch_reference ok=true
00.514 llm_request upstream=claude-sonnet-4-6 prompt_tokens=1842
01.823 llm_response completion_tokens=612
01.834 stage_completed stage=outline artifacts=[outline.v1]
01.835 stage_started stage=writer
…
04.219 run_completed ok=true artifacts=[outline.v1, guide.v1]
Every event is JSON, every event has the same envelope (run_id, ts, kind), and every event is signed by the Comet’s run key — see Scope events & observability.
Why this split?
- Scaling shape: Comets are cattle, Moons are pets, Planets are almost-pets. You can run a million Comets behind one Moon. A Moon scales vertically until ~10k concurrent runs; past that, shard tenants across Moons.
- Security: every Agent runs inside a Comet’s capability allowlist; the Moon never executes user code. A compromised Comet cannot reach the Moon’s secrets — the Comet only ever sees its own short-lived run key.
- Federation: many Moons can hang off one Planet, or roll up to many Planets in
enterprise-clouddeployments. A Planet can fail without taking Moons offline — Moons cache their identity certs and continue serving until the cert expires.
Mapping roles to editions
| Edition | Where Comet runs | Where Moon runs | Where Planet runs |
|---|---|---|---|
solo | in-process | in-process | n/a (collapsed) |
cluster | your LAN / VPC | your VPS | n/a or your VPS |
cloud | soyaos.ai | soyaos.ai | soyaos.ai |
hybrid | your VPC | soyaos.ai | soyaos.ai |
ent-cloud | soyaos.ai (dedicated) | soyaos.ai (dedicated) | soyaos.ai (region-pinned) |
ent-private | customer-operated | customer-operated | customer-operated |
See Editions for the full matrix; see Capabilities & sandbox for what a Comet can and cannot do.