Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Manifest and Service Startup

The manifest is the boot package and init configuration. It names embedded binaries, the single kernel-launched init process, kernel boot parameters, and the init-owned service graph used by focused executor manifests.

Current Behavior

tools/mkmanifest requires the repo-pinned CUE compiler, evaluates system.cue, embeds declared binaries, validates binary references and the init-owned authority graph under initConfig, serializes SystemManifest, and places manifest.bin into the ISO. The kernel receives that file as the single Limine module. The diagram below is intentionally large: it separates the default init-owned boot path from the focused spawn-proof path.

flowchart TD
    Cue[system.cue or system-spawn.cue] --> Mkmanifest[tools/mkmanifest]
    Binaries[release userspace binaries] --> Mkmanifest
    Mkmanifest --> Manifest[manifest.bin SystemManifest]
    Manifest --> Limine[Limine boot module]
    Limine --> Kernel[kernel parse and validate]
    Kernel --> InitCaps[init CapTable and CapSet page]
    InitCaps --> Init[enter initConfig.init process]
    Init --> ShellPath[default system.cue: spawn shell/remote CapSet gateway/services]
    Init --> SpawnPath[focused system-spawn.cue: standalone init executor]
    SpawnPath --> BootPackage[BootPackage.readManifest chunks]
    BootPackage --> Plan[capos-config ManifestBootstrapPlan validation]
    SpawnPath --> Spawner[ProcessSpawner.spawn]
    Spawner --> Children[init-spawned child processes]

The default manifest starts only initConfig.init from the kernel, and that process is now the standalone init ELF. Init receives the bootstrap authority needed to read BootPackage, validate initConfig.services, spawn the foreground shell, remote-session CapSet gateway, resident chat service, and other default services, then wait according to the manifest policy. The shell is an init-started service; it receives terminal, credential-store, session-manager, audit-log, and authority-broker caps, mints its own anonymous UserSession, and waits for an explicit login or setup command before upgrading. It never holds BootPackage or broad ProcessSpawner authority.

Focused shell-led manifests such as system-smoke.cue and system-shell.cue still put capos-shell directly in initConfig.init for narrow login/shell proofs. That compatibility path is tracked by the run-target/init-policy backlog and should not be confused with the default system.cue boot path.

The focused system-spawn.cue manifest still puts the standalone init ELF in initConfig.init. There, init receives ProcessSpawner, a read-only BootPackage cap, and Console. It reads bounded manifest chunks into a metadata-only capos-config::ManifestBootstrapPlan, validates binary references, authority graph structure, exports, cap sources, and interface IDs, then spawns the focused smoke services. Low-level spawn grants still model receiver selectors for hostile and compatibility proofs, but normal shell client @... grants omit selector syntax and preserve delegated client endpoint identity. Raw parent-capability grants must preserve the source hold metadata, endpoint-client grants may mint selectors only from an endpoint owner or a ProcessSpawner-returned parent endpoint facet without widening it to server authority, and kernel-source Endpoint, FrameAllocator, VirtualMemory, Timer, ThreadControl, ThreadSpawner, and EntropySource grants mint fresh child-local caps without receiver selectors. QEMU-only PersistentStore grants mount the root store through the same child-local kernel-source path when a focused proof manifest names that source. Endpoint kernel grants also return parent-side client facets as ProcessSpawner result caps so init can wire later service-sourced imports without ever holding child endpoint owner caps.

mkmanifest cue-to-capnp is the adjacent general conversion path for CUE-authored data that should not become part of SystemManifest. It evaluates the input with the same pinned CUE compiler, package mode, tag injection, and CAPOS_CUE_TAGS handling as the manifest path, then passes the exported JSON to the pinned Cap’n Proto compiler through capnp convert json:binary. The caller supplies the .capnp schema file, root struct type, output path, and optional Cap’n Proto import paths. This is schema-aware serialization for data messages rooted at arbitrary specified structs; it is not a live capability or interface-object serialization path.

Design

Manifest validation has three layers:

  • Kernel bootstrap references: binary names are unique, initConfig.init.binary resolves, referenced payloads are non-empty, and init kernel cap sources match their expected interface IDs.
  • Init-owned binary references: initConfig.services[*].binary references resolve before the executor spawns children.
  • Init-owned authority graph: service names, cap names, export names, and service-sourced references are unique and resolvable; re-exporting service-sourced caps is rejected.
  • Init-owned cap sources: expected interface IDs match kernel sources or declared service exports.

Kernel startup now resolves only initConfig.init.caps. Init performs service execution in two userspace passes. The preflight pass walks initConfig.services in manifest order, resolves kernel and service-sourced caps against init grants and prior exports, and rejects an unstartable graph before spawning children. The spawn pass grants caps in declaration order, records declared exports, keeps owned parent client facets for exported child endpoints, and attenuates endpoint exports to client-only facets for importers. After every child is spawned, init drops and flushes those parent facets before waiting on children; a dropped init facet therefore cannot owner-cancel queued, pending, or in-flight child endpoint state.

Invariants

  • The manifest is schema data plus an init config tree, not shell script or ambient namespace.
  • Omitted cap sources fail closed.
  • Cap names within one service are unique and are the names userspace sees in CapSet.
  • Service exports must name caps declared by the same service.
  • Service-sourced imports must reference a declared service export.
  • Endpoint exports to importers must be attenuated to client-only facets.
  • Init must not hold endpoint owner caps for child-local manifest endpoints.
  • expectedInterfaceId checks compatibility; it is not the authority selector.
  • Legacy receiver metadata travels with cap-table hold edges and endpoint invocation metadata. Spawn-time client endpoint minting may carry the requested child selector only from owner or trusted parent endpoint result sources instead of copying the parent’s hold selector. Client facets received through ordinary spawn grants are not selector-minting authority for later spawns. Caller-selected endpoint badges are transitional compatibility state; session-bound invocation context plus broker-granted service roots/facets is the target shared-service authority model.

Code Map

  • schema/capos.capnp - SystemManifest, NamedBlob, SystemConfig, KernelCapSource, and generic CueValue storage for initConfig.
  • capos-config/src/manifest.rs - manifest structs, initConfig CUE parsing, capnp encode/decode, metadata-only ManifestBootstrapPlan, and schema-version storage.
  • capos-config/src/validation.rs - kernel bootstrap, init-owned graph, binary-reference, and capability-source validation policy.
  • tools/mkmanifest/src/lib.rs and tools/mkmanifest/src/main.rs - host-side manifest build pipeline, binary embedding, and general CUE-to-Cap’n Proto data-message conversion.
  • kernel/src/main.rs - kernel manifest module parse and validation.
  • kernel/src/cap/mod.rs - bootstrap cap creation and CapSet entry construction for init.
  • kernel/src/cap/boot_package.rs - read-only manifest-size and chunked manifest-read capability.
  • kernel/src/cap/process_spawner.rs - init-callable spawn path for packaged boot binaries.
  • capos-rt/src/client.rs - typed BootPackage and ProcessSpawner clients.
  • init/src/main.rs - BootPackage manifest reader, graph preflight, generic spawn loop, hostile spawn checks, and child waits.
  • system.cue and system-spawn.cue - default init-owned login/service graph and focused init-owned spawn manifests using initConfig.

Validation

  • cargo test-config validates manifest decode, CUE conversion, graph checks, source checks, and binary reference checks.
  • cargo test-mkmanifest validates host-side manifest conversion, embedded binary handling, pinned CUE path/version checks, pinned Cap’n Proto path/version checks, and schema-aware JSON-to-binary conversion through capnp convert when CAPOS_CAPNP is available.
  • make run-smoke validates the focused shell-led scripted login manifest: single capos-shell init boot from system-smoke.cue, failed-auth redaction, successful password auth, broker-issued shell launch, terminal isolation, and clean halt.
  • make run is the operator-facing interactive boot path with the terminal UART on stdio and console/debug output logged separately.
  • make run-spawn validates the narrower system-spawn.cue graph: the kernel boot-launches only standalone init, init validates BootPackage metadata, ProcessSpawner launches each focused child service, grants Timer to the timer smokes, and init waits for them.
  • make generated-code-check validates schema-generated Rust stays in sync.

Open Work

  • The run-target/init-policy backlog still needs to migrate remaining focused shell-led manifests or preserve them as explicit exceptions, then add a manifest-loader or mkmanifest guard against accidental non-init default boot graphs.
  • Service object identity migration still needs to retire caller-selected endpoint badge syntax from normal manifest paths. Normal shell paths already reject explicit client-grant selector syntax; low-level hostile fixtures and manifest-scoped non-identity encodings such as TCP listen ports remain separate cases.