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.binaryresolves, referenced payloads are non-empty, and init kernel cap sources match their expected interface IDs. - Init-owned binary references:
initConfig.services[*].binaryreferences 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.
expectedInterfaceIdchecks 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 genericCueValuestorage forinitConfig.capos-config/src/manifest.rs- manifest structs,initConfigCUE parsing, capnp encode/decode, metadata-onlyManifestBootstrapPlan, 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.rsandtools/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.cueandsystem-spawn.cue- default init-owned login/service graph and focused init-owned spawn manifests usinginitConfig.
Validation
cargo test-configvalidates manifest decode, CUE conversion, graph checks, source checks, and binary reference checks.cargo test-mkmanifestvalidates 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 throughcapnp convertwhenCAPOS_CAPNPis available.make run-smokevalidates the focused shell-led scripted login manifest: singlecapos-shellinit boot fromsystem-smoke.cue, failed-auth redaction, successful password auth, broker-issued shell launch, terminal isolation, and clean halt.make runis the operator-facing interactive boot path with the terminal UART on stdio and console/debug output logged separately.make run-spawnvalidates the narrowersystem-spawn.cuegraph: the kernel boot-launches only standaloneinit, init validates BootPackage metadata, ProcessSpawner launches each focused child service, grants Timer to the timer smokes, and init waits for them.make generated-code-checkvalidates 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-
initdefault 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.