Partition model
SpaceOS uses a partition to group services from one project. The partition
sets their memory limit, communication rules, and supervisor. Each service
still runs in its own virtual machine or container sandbox. Use the same
partition names in build.yaml and run.yaml.
Configure and inspect a partition
Use the same partition and service names in both manifests. In build.yaml,
declare the service and the interfaces it may use:
partitions: payload: services: - name: classifier image: ghcr.io/<your-org>/classifier:1 runtime: oci isolation: runc interfaces: - type: frame_bus apids: [0x120, 0x12F] send_to: [ground]In run.yaml, assign resources and route the frames:
partitions: payload: memory: 512 apids: [0x120, 0x12F] send_to: [ground] services: - name: classifier isolation: runc cpus: [0, 1]Build the composition and check the placement before booting it:
space build . -t classifier:devspace run classifier:dev --runtime run.yaml --dry-runspace run classifier:dev --runtime run.yamlInspect the running partition:
space ps --jsonspace report --jsonspace logs classifierThe report names the payload partition, its 512 MB memory limit, the two CPU
assignments, and the allowed APID range. A mismatched service name or an
unavailable backend fails during --dry-run.
Partitions
A partition is the unit that receives memory and communication rules. SpaceOS runs each service in that partition with one of these isolation methods:
- A Solo5 micro-VM. A unikernel service is its own sealed guest, launched
by a Solo5 tender:
hvtwhere the board offers hardware virtualization through/dev/kvm, or the seccomp-confinedsptwhere it does not. There is no general-purpose OS inside the guest. - A runc sandbox. A Linux service runs as an OCI container with a read-only root, user namespace, default-deny seccomp profile, and cgroup limits. It shares the kernel of dom0, the SpaceOS control domain, so its isolation is weaker than a micro-VM’s.
A multi-service partition boots its own init process (the supervisor, pid1
by default) which starts the declared services in dependency order and
reports lifecycle and health. Memory is assigned per partition and CPUs per
service in run.yaml; what the partition contains is
declared in build.yaml.
Services in one project may share communication rules while keeping separate sandboxes.
Service interfaces
A service declares typed interfaces at build time; the runner wires them at launch. There are four 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.
space-net, the isolated SpaceOS network switch, rejects connections not listed in the signed release. - Data link. Carries large sensor products over a spacecraft serial fabric such as SpaceWire or SpaceFibre, or over a high-bandwidth virtual queue. Its settings name the link, direction, and maximum rate.
- 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 run.yaml.
Isolation layers
Partition level. A micro-VM partition is 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. A runc partition is isolated by kernel namespaces and cgroups, a weaker boundary. The strength of the guarantee is a property of the substrate, the mechanism that actually runs the service.
Service level. Within a multi-service partition, the supervisor keeps
services in separate processes with declared dependencies, healthchecks, and
restart policy. Services communicate through their declared interfaces; there
is no shared memory between services. For co-located bulk exchange, enable
the partition block device (disk: true). The frame bus is sized for
telemetry and command messages.
Isolation backends
The service-level isolation field selects the concrete backend:
hvt: Solo5 on KVM. The unikernel path with hardware VM isolation.spt: Solo5 seccomp tender. The unikernel path where KVM is unavailable.runc: OCI container. Any Linux application, shared dom0 kernel.qemu: QEMU launcher for Unikraft images (x86_64 only).host: host-native process, for development and test fixtures.auto: let the runtime pick a compatible backend.firecracker: KVM-backed micro-VM for Linux images.
Flight-domain boundary
The spacecraft’s safety-critical flight software (attitude control, orbit propagation, command and data handling, typically a real-time operating system running a framework such as F-Prime) is a separate trust domain, not a SpaceOS partition. It boots on its own authority, runs its own fault protection, and is backstopped by a hardware watchdog. SpaceOS observes it over a spacecraft bus and may relay commands that carry its authority. Boot, supervision, and recovery remain under the flight domain’s control.
A partition can be bus-facing: trusted to exchange telemetry and commands with the flight domain over the frame bus. That is a relay role, not ownership of the flight software.
Hardware acceleration
An accelerator broker opens the GPU, FPGA, or AI engine for a service. Before opening the device, the broker checks the service and device listed in the signed release. A service receives no device access by default.
- Linux services (
isolation: runc) reach accelerators through the device nodes the target profile grants (for example/dev/drifor a GPU). - Unikernel services use host-mediated delegation: the guest calls a narrow API and the host forwards it to the device, the same shape as Solo5’s 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. Targets without both disable passthrough and preserve the isolation boundary.
The delegation path is a named interface per accelerator class, not a generic passthrough:
| Accelerator | Interface | Exercised on |
|---|---|---|
| GPU (NVIDIA) | vAccel | Jetson TX2i |
| FPGA | ukAccel | Xilinx Versal |
| AI engine | Vitis AI | VCK190 |
| Many-core | OpenCL [roadmap] | Kalray MPPA |
For a GPU shared between services, a broker multiplexes the device so each service sees its own queue rather than the raw hardware.
The target profile lists its accelerators. A service that needs one runs only on a target that lists the matching device.
Manifest references
The two manifests use the same partition names as keys:
build.yaml defines… | run.yaml defines… |
|---|---|
| Supervisor override (optional) | How much memory to allocate |
| What services to bundle | Which CPUs to assign per service |
| Service interfaces and dependencies | Per-service isolation backend |
| Per-service healthcheck probe | APID ownership and send_to flow policy |
| Whether to enable the partition disk | Relay shape and ground endpoint |
The same composition can run with different placements: 512 MB on a development laptop or 128 MB on a constrained on-board computer, without rebuilding. Board facts (kernel, device tree, firmware, secure-boot keys) belong to neither file; they are properties of a connected target.