Home
Run untrusted code on the shared cluster with programmatic network control, durable workspaces and scale-to-zero apps.
The container platform runs code you don't fully trust — pipeline steps, codegen plugins, AI-agent sessions, user-supplied functions — on the shared cluster, with a kernel boundary (gVisor), a default-deny network, and a durable filesystem that isn't a PVC.
Everything is one ConnectRPC API at containers.xeonr.io, plus an operator console served from the same host. TypeScript callers should reach for the SDK rather than the protocol directly.
The three workload primitives
| What it is | Lifetime | Use it for | |
|---|---|---|---|
| Job | Run argv to completion, collect outputs | One run | Pipeline steps, codegen, batch work |
| Sandbox | A long-lived pet with a terminal and a workspace | Until suspended or deleted | Agent sessions, cloud dev environments |
| App | Replicated HTTP workload that scales to zero | Long-lived, instances disposable | Functions, request-serving code |
All three share the same environment (image), egress policy and namespace model. Jobs and sandboxes can attach a workspace; apps mount one read-only.
Endpoints
| Host | What |
|---|---|
containers.xeonr.io | ConnectRPC API + operator console |
<port>-<sandbox-id>.preview.containers.xnr.app | Sandbox preview URLs (ExposePort) |
<app-id>-<namespace>.apps.containers.xnr.app | App hostnames |
registry.containers.xeonr.io | Registry that built environments are pushed to |
What makes it different
Programmatic FQDN egress. A workload's network is default-deny at L3, with exactly one route out: the platform's CONNECT proxy. Which hosts it may reach is a per-job policy you set in the API — and can widen or narrow on a running sandbox with GrantEgress — with every allow and deny audited. NetworkPolicy can't do domain names; this can.
No credentials in the workload. The sandbox agent sidecar holds the pod's only credentials. Product secrets go to an adapter container, never the workload's environment.
Workspaces without PVCs. A workspace is a file API over content-addressed object storage, so it outlives any pod, can be written before one exists and read after it's gone, resumes on any node, and snapshots for free.
Get started
Quickstart
Client, environment, first job — in about five minutes.
TypeScript SDK
@xeonr/containers — the client library, instead of the raw protocol.
Concepts
Namespaces, environments, the isolation model, failure taxonomy.
Authentication
Machine API keys, human OIDC sign-in, roles.
Environments
Register a digest-pinned image, or build one from a spec.
Jobs
Run-to-completion workloads with inputs, outputs and streamed logs.
Sandboxes
Exec, persistent terminals, suspend/resume, preview ports.
Workspaces
The durable file API, snapshots, zip import/export.
Apps
Versions, hostname routing, scale-to-zero activation.
Egress
Policies, presets, live grants and the audit trail.
Warm pools
Pre-warmed single-shot pods for latency-sensitive lanes.
API Reference
Apps
Replicated HTTP workloads with immutable versions, hostname routing and scale-to-zero activation.
Console Sessions
Persistent terminal sessions that outlive the client attached to them, addressed by byte offset.
Container Files
A running workload's own container filesystem — the whole rootfs, not the workspace mounted into it. Read-mostly by default, since the hardened rootfs is read-only.
containers.api.v1.ClusterService
ClusterService manages where namespaces run (BYOC, platform-docs container-platform/docs/BYOC.md §2). A cluster is one operator install: one enrolment, one credential, one owner team. Two teams installing on the same physical cluster produce two records, and the platform neither knows nor needs to know that they share hardware. The platform's own fleet is a cluster like any other, flagged GLOBAL and `default`, which is where a namespace lands when nothing names a cluster. A namespace is placed on exactly one cluster when it is created (Namespace.cluster_id) and everything beneath it — sandboxes, jobs, apps, environments, volumes, pools, keys — runs there. Placement is immutable: moving a namespace is a migration, not an update. Who may place a namespace on a cluster is its visibility: PRIVATE is the owner team only; SHARED adds the teams holding a grant; GLOBAL is every team, within the everyone-grant. A grant also caps how much of the cluster that team's namespaces may hold in total (BYOC.md §5.4): the sum of a team's namespace quotas on a cluster must fit its grant, and the owner team's grant is implicit and unbounded. GetCluster and ListClusters carry allow_api_keys: a namespace key reaches the cluster its namespace is placed on and nothing else. The mutations do not, for the reason CreateNamespace does not: each needs a team role, and no key holds one.
containers.api.v1.TeamSettingsService
TeamSettingsService holds a team's container-platform preferences. Teams themselves live in Xeonr Auth; this is only what the platform remembers about one.
containers.api.v1.VolumeService
VolumeService manages platform-provisioned volumes: sparse ext4 disk images on node disk, attached by the platform's own CSI driver and mounted into a primitive via WorkspaceMount.volume (common.proto). How this differs from WorkspaceService, which is the question everyone asks: WorkspaceService is a CONTENT store. It knows files, dedupes blobs across every workspace, forks a snapshot for free because a fork is a metadata copy, and works identically whether or not anything is running. What it is bad at is being a filesystem: it has to be copied into the pod, one RPC per file, so start cost scales with file count and the big directories have to be excluded to keep it bearable. VolumeService is STORAGE. It knows bytes, not files. Nothing is copied at start, nothing is synced back, there is no ignore set, and size is a hard cap the filesystem enforces. What it is bad at is being content: a volume cannot be forked or diffed, it is opaque to anything that has not mounted it, and reaching it needs the node holding it to be up. They are complementary rather than competing. Content arrives via seed_snapshot_id and leaves via Archive; in between it is a filesystem. File operations are below. They route to the node holding the volume, which is the only thing that can open the image, and work whether or not a workload is running on it.
Egress
Named, reusable egress policies and the proxy's allow/deny audit trail.
Environments
The images workloads run on — register a digest-pinned image, or build a content-addressed one from an install spec.
Jobs
Run-to-completion workloads with argv, stdin, input files, collected outputs and streamed logs.
Namespaces
Tenancy control plane — namespaces, OIDC group bindings, quotas, internal egress targets and machine API keys. Admin only.
Sandboxes
Long-lived interactive sessions — exec, suspend/resume, live egress grants and preview URLs.
Warm Pools
Warm pools — pre-warmed, identity-free, single-shot pods claimed per lane.
Workspaces
Durable file API over content-addressed object storage — read/write/copy/move, snapshots and zip import/export.