Partition model
A payload computer runs work from more than one party: your classifier, a
partner's compression service, the downlink handler. SpaceOS groups the
services of one project into a partition, which sets their memory,
communication rules, and supervisor, and is the unit that owns a machine of its
own. One space.yaml names the partitions and what runs inside them.
Configure and inspect a partition
A partition is a key under run.partitions. Under it you declare the services,
the interfaces each one may use, the memory the partition gets, and the CPUs each
service is pinned to:
schema: space.projectversion: "1"
build: output: _build/spaceos
run: partitions: payload: memory: 512 apids: [0x120, 0x12F] services: - name: classifier image: ghcr.io/<your-org>/classifier:1 runtime: oci isolation: runc cpus: [0, 1] interfaces: - type: frame_bus apids: [0x120, 0x12F] send_to: [sdls-downlink] - name: sdls-downlink image: ghcr.io/parsimoni-labs/sdls-downlink:1 runtime: oci isolation: runc interfaces: - type: frame_bus apids: [0x130, 0x13F] relay: from: payload to: [ground] ground: port: 8080 socket: /tmp/spaceos/ground.socksend_to names peer services on the bus. ground is reserved and refused
there: frames reach ground through the relay. The partition declares no egress
list of its own, because relay is the one place the flow topology is written.
$ space show --sbom | sed -n '1,4p'No signed SBOM at _build/spaceos/spaceos.spdx.json yet; printing the SBOM computed from space.yamlSpaceOS Software Bill of Materials
kernel ghcr.io/parsimoni-labs/uniboot-kernel/node:6.18.39-62332cf6bcc6@sha256:21e9b2669e2347dd0a9b7703a248bf191ef91e412ae6b720f3d3768f6cfbbd8fBuild the service image, then rehearse the placement before booting it. The
rehearsal names the payload partition, its 512 MB memory limit, the CPU set,
and the allowed APID range. A mismatched service name or an unavailable backend
fails the rehearsal:
$ chmod +x classifier.sh$ space build app.yaml -t classifier:devBuilding an app from app.yaml✓ classifier:dev built in ...Run it here: space run classifier:dev$ space run --dry-runLocal target: macos-vmm@sha256:4c549a833d4e9801bdc6f6e55485e64b23d5d33e0190ba713a20131f114a65da+vzBoot image: not validated (not in the local store: ghcr.io/parsimoni-labs/uniboot-kernel/node:6.18.39-62332cf6bcc6@sha256:21e9b2669e2347dd0a9b7703a248bf191ef91e412ae6b720f3d3768f6cfbbd8f); build firstimage: _build/spaceospartitions: payload 512 MB apids 0x120, 0x12f services: classifier runc cpus 0, 1 sdls-downlink runcrelay: payload -> ground (sdls)ground: port 8080 socket /tmp/spaceos/ground.sock
1 partition, 512 MB totalDry run complete; no workload started.Boot image: not validated reports that only the service image is built; a boot
also needs the system image that carries the kernel and the partition init. The
boot and the report both use the local runner. Build it, boot it, then inspect
the running partition:
space build . -t classifier:devspace run classifier:devspace status --jsonspace logs classifierPartitions
A partition is the unit that receives memory and communication rules, and it is
a tenant: its workloads run in a machine that belongs to it alone, so two
partitions never share a kernel. Inside that machine, each service runs behind
the backend its isolation field names:
- A virtual machine of its own.
hvtboots a unikernel on the CPU's virtualization hardware through a Solo5 tender.firecrackerboots a virtual machine under Firecracker, andqemuboots a Unikraft image under the x86-64 emulator on any host. - A container.
runcruns an OCI container in the partition's machine, with a read-only root, its own user namespace, a default-deny seccomp profile, and cgroup limits. seccomp is the Linux filter on a process's system calls, and a default-deny profile refuses every call its allow-list does not name. These controls hold the partition's services apart from each other; the machine holds the partition apart from other partitions. - A confined process.
sptruns a Solo5 unikernel as a seccomp-confined process, for machines without hardware virtualization. - A host process.
hostruns the binary uncontained on a development machine, for test fixtures.
Isolation backends lists every backend, what the machine must provide for it, and which target profiles offer it.
The hypervisor underneath a virtual machine belongs to the target, and you do
not name it in isolation. A unikernel built against the Solo5 host interface
runs unmodified on any host that implements it, so a change of hypervisor
leaves the composition alone. That interface is thirteen calls, declared in
Solo5's solo5.h: exit and abort, setting the thread-local storage base, two
clocks (monotonic and wall), yield until a deadline or an I/O event, console
write, and acquire, read, and write for one network device and one block
device each. KVM on Linux is the
hypervisor the target profiles select. Xen arrives in the next release
[v1.1], and separation kernels are agreed direction [roadmap]: a mission
that needs a verified boundary chooses it by the hypervisor its target
profile names. Isolation backends
describes each one.
A multi-service partition boots its own init process, the supervisor, which is
pid1 by default. The supervisor starts the declared services in dependency
order and reports their lifecycle and health. Memory is assigned per partition
and CPUs per service, beside the services themselves.
Service interfaces
A service declares typed interfaces at build time; the runner wires them at launch. There are five kinds:
- Frame bus. Carries fixed-size telemetry and command messages between
services and ground. Each message carries an
APID, the stream label used to sort
messages. The
send_tolist controls where a service may send it. - IP. Provides a standard IP network. The service binds ports on its declared bridges, and connections not listed in the signed release are rejected.
- Host network. Publishes named TCP ports from the node into the service.
It is capability-gated. The service binds those ports in the node's own
network namespace, so they are reachable on the
node's addresses and the container loses its network isolation; a service
may declare it only under
runc, and never beside anipinterface. - Data link. Carries large sensor products over a spacecraft serial fabric such as SpaceWire or SpaceFibre, or over a high-bandwidth virtual queue. The declaration names the link, and the signed release decides whether the service may attach to it.
- Supervision page. A small shared-memory page between the host and the
guest carrying heartbeat, mission time, health, and the safe-mode command
word.
space-runnerowns the host side and can put the service in safe mode.
Authorization and APID routing
Each signed release lists what every service may read, write, or open. An APID
is the 11-bit CCSDS number used to label a telemetry or command stream. The
number helps receivers sort messages. It does not grant permission to send
them. Declare the APID range and allowed destinations in space.yaml.
Isolation layers
Partition level. Each partition runs in a machine of its own, isolated by the CPU's virtualization hardware. A fault, a crash, or a radiation-induced bit flip (a single-event upset) in one partition cannot reach another through memory, and a kernel defect reached from one partition's container stays inside that partition's machine. With several partitions on a node, the runner boots one Firecracker VM per partition to hold its containers. When a release names a single partition, the node itself is that partition's machine: no other partition shares it, and the container controls alone stand between its services and the control plane, as Tenant machines describes.
Service level. A multi-service partition's supervisor keeps its services
in separate processes with declared dependencies, healthchecks, and restart
policy. Services communicate through their declared interfaces; there is no
shared memory between services. The frame bus is sized for telemetry and
command messages, so co-located services that need bulk exchange enable the
partition block device (disk: true).
Flight-domain boundary
The spacecraft's safety-critical flight software is a separate trust domain and never a SpaceOS partition. It handles attitude control, orbit propagation, and command and data handling, usually on a real-time operating system running a framework such as F-Prime. It boots on its own authority and runs its own fault protection, with a hardware watchdog behind it. SpaceOS observes it over a spacecraft bus and may relay commands that carry its authority. Boot, supervision, and recovery stay with the flight domain, as SpaceOS on the spacecraft describes.
A partition can be bus-facing, meaning it is trusted to exchange telemetry and commands with the flight domain over the frame bus. A bus-facing partition relays; it does not own the flight software.
Hardware acceleration
A GPU, an FPGA, or an AI engine on the payload computer is a shared device that no partition
should reach by default. SpaceOS puts a broker in front of it: a workload asks
for an accelerator by role, such as inference, and never names a device. The
accelerator schema names two device kinds, GPU and FPGA. The broker speaks
vAccel, and it opens a session only under a grant signed for that run on that
target. vAccel is an open-source API through which a virtual machine or a
container asks the host to run an accelerator operation, such as an inference,
on the device; ukAccel is the same interface for Unikraft unikernels.
No shipped target profile declares an accelerator, so no workload reaches one on a supported target. The delivery paths below are agreed direction [roadmap]:
- Linux services (
isolation: runc) reach the device nodes the target profile grants, such as/dev/drifor a GPU. - Unikernel services use host-mediated delegation. The guest calls a narrow API and the host forwards it to the device, as Solo5 already does for virtual block and network devices.
- Direct passthrough, where the guest drives the device itself, requires a dedicated device and an IOMMU, the hardware that limits which memory a device may reach. A target without both keeps passthrough off.
Each accelerator class has its own named delegation interface [roadmap]. The last column names the board where each interface ran in a bench demonstration; no shipped profile carries that board.
| Accelerator | Interface | Bench demonstration |
|---|---|---|
| GPU (NVIDIA) | vAccel | Jetson TX2i |
| FPGA | ukAccel | Xilinx Versal |
| AI engine | Vitis AI | VCK190 |
| Many-core | OpenCL | Kalray MPPA |
When services share a GPU, the broker multiplexes the device so that each service sees its own queue [roadmap].
The target profile lists its accelerators, and a service that needs one runs
only on a target that lists the matching device [roadmap]. Moving a service
to an accelerated board keeps its name and its image: space deploy --plan
checks the target's profile and names the accelerator granted to each service
before it prepares the release [roadmap].
Partition and service declarations
One partition key carries both halves of the same statement:
| The partition declares... | Each service under it declares... |
|---|---|
| Supervisor override (optional) | The image or artifact it is built from |
| How much memory the partition gets | Which CPUs it is pinned to |
| APID ownership and the bus endpoints it needs | Its interfaces, dependencies and isolation backend |
| Whether the partition disk is enabled | Its healthcheck probe |
The relay shape and the ground endpoint sit beside partitions in the same
run: section. The same project runs with different placements without
rebuilding: 512 MB on a development laptop, or 128 MB on a constrained on-board
computer. Board facts such as the kernel, device tree, firmware, and secure-boot
keys belong to no project. They are properties of a connected target.