NumericalOS

Graph-driven userspace init

Linux userspace whose configuration is a content-hashed graph export, fail-closed under hash mismatch, with a POSIX shell floor and optional static fast path.

Revision 1eb4fb9 · docs · evidence

Abstract

Conventional init systems reconstruct a dependency graph from unit files at boot. NumericalOS inverts the order: a knowledge graph is the system of record; numos.state is a deterministic, content-addressed projection. There are no unit files on the target. Hash mismatch is a hard halt. Spec 1 implements and tests the shell floor. Kernel handoff has been observed under QEMU on x86_64: self-init completes (degraded=0); fleet on bare QEMU is PASS-degraded. Metal and other arches remain open.

1. The problem with configuration-as-files

A modern init system is, structurally, a dependency resolver over a set of declarations. The declarations live in files; the dependency graph is implicit in them. Three consequences follow.

The graph is never first-class. It is reconstructed at boot from text, and no artifact ever represents it directly. Questions like "what depends on this" are answered by re-parsing, not by traversal.

Drift is invisible. Two machines with the same role diverge one edit at a time, and nothing detects it because there is no canonical form to compare against.

Authorship does not scale with derivation. When a fleet's capabilities are themselves a registry — a set of operations a node can perform — hand-writing one unit file per operation is transcription, and transcription rots.

2. The inversion

NumericalOS treats a graph as the system of record and the machine as a projection of it. Four graphs, following the M/G/S/MGS convention of the Intrikata topology from which this project descends:

graphrolenode types
METApolicy — what may runadmission rules, capability grants, trust roots
GENESISbring-up — ordered stagesBootPhase
MGSsteady stateOSUnit
SHADOWfailure and residualHealthPredicate

A fifth graph, the Agent Swarm Extension Complex, closes the loop: a SHADOW predicate that fires opens a swarm invocation, and remediation lands back as a contribution node. Self-healing is not a special subsystem; it is the same graph machinery pointed at the machine's own failures.

2.1 The claim is literal

"Configuration comes from the graph" is easy to assert and easy to quietly violate — typically by hand-maintaining the one table the bootstrap needs before it can read anything. NumericalOS closes that specific hole: the architecture-detection table in the bootstrap is generated from ArchTarget nodes, and a test asserts the committed file still matches its generator. Adding an architecture is a data insert. If someone edits the generated file by hand, the suite fails.

2.2 Units are derived, not authored

Partially implemented as of this revision. The unit set is derived and exported. Floor numctl can write a capability document and record join outcomes (disabled/joined/failed). Op units are still not phase-required daemons; run-op is a dispatch edge to NUMOS_OP_RUNTIME, not a local op interpreter. A node can record identity and join state; it does not yet run topology ops itself.

A NumericalOS machine is a compute node in a topology: it boots, advertises its silicon and its supported operations, and receives scheduled work. Its unit set is therefore derived from the operations registry — 196 registered operations become 196 units, each depending on the join unit, alongside a small seeded set for mount, network, clock, identity, and join.

The honest consequence: a node's unit set changes when the registry changes. This is intended, and it is why the exported state is content-hashed. Drift becomes detectable rather than silent.

3. The artifact

One file, numos.state, is the machine's entire runtime input. It is line-oriented rather than JSON, for a reason that only appears at implementation time: the boot floor is POSIX shell, and shell cannot parse JSON without a parser. Shipping a JSON parser into a project whose premise is the smallest bootstrap is self-defeating. So the runtime format is one a shell can consume with grep and cut, and JSON survives only as a view for tooling.

Two properties make it trustworthy.

Determinism. The same graph state produces byte-identical output. The generation timestamp is excluded from the hashed body and every block is sorted, so registry ordering cannot leak into the artifact. A changed hash means the graph changed — never that the exporter felt different.

Content addressing. A C record carries the SHA-256 of every other line. Both the build-time verifier and the boot-time verifier recompute and compare. Editing the file by hand breaks the hash and the machine correctly refuses to boot from it.

Optional resource envelopes travel as separate R records rather than extra fields on U, so shell field indices for unit records stay stable. Declaring a limit the floor cannot honour (notably cpu_pct) is a named halt, not a silent ignore — the same truthfulness discipline as hash verification.

Getting two verifiers in two languages to agree on what "the body" means — blank lines, duplicate records, trailing content — is subtler than it sounds. Two verifiers that disagree produce a file one accepts and the other rejects, which is worse than either being wrong alone.

4. Fail-closed as a construction, not a policy

An unverified init is worse than a halted machine. Every abnormal path in NumericalOS halts with a named reason on the console and a nonzero exit: hash mismatch, unknown architecture, dependency cycle, dangling unit reference, malformed record, phase failure under a halt policy.

Two design decisions give that teeth.

Validation happens twice. Cycles and dangling references are rejected at export time, so a machine never discovers them as PID 1. They are also rejected at boot, because numinit may be handed a state file that never passed through the exporter. The last line of defence does not get to assume the first one ran.

Halting from shell is harder than it looks. In POSIX shell, exit inside a command substitution terminates only the subshell. A helper that halts from inside $(...) prints its message and lets the caller continue with status 0. Two conditions — a dependency cycle and a dangling reference — "booted successfully" this way during development, while printing a halt message. The fix was mechanical once seen; finding it required a test that asserted on exit status rather than on the presence of the message, because the broken version printed the message too.

That episode is the argument for the whole verification posture. A fail-closed system that has not been tested for whether its failures actually close is decorative.

5. Smallest bootstrap, all architectures

These pull against each other. "Smallest" argues for a compiled static binary; "all chip infrastructures" argues for something that runs anywhere. Picking one means lying about the other.

The resolution is a floor and a fast path. The floor is POSIX shell over a static busybox — zero compilation, runs on every architecture busybox targets. The fast path is a static numinit binary, smaller and with proper signal discipline, for architectures where one is published. Coverage is the union of the two, and the bootstrap prefers the binary and falls back to the shell.

Nine architectures are registered: x86_64, aarch64, riscv64, arm, powerpc64le, s390x, mips64el, x86, loongarch64. The registry records, per architecture, its uname -m aliases, its cross-compilation triple where one exists, and its busybox variant. Where the triple is null, the shell floor carries that architecture — which is the mechanism by which the "all chips" claim stays honest rather than aspirational.

6. What this buys

Configuration becomes queryable. The dependency structure is a graph before it is a file, so "what depends on this" is a traversal.

Drift becomes detectable. Deterministic export plus content addressing means two machines either have the same hash or they do not.

Capability and configuration converge. When units are derived from the operations registry, a node that gains a capability gains its unit without anyone editing a file.

Degradation is expressible. A phase failure under a degrade policy leaves the node running and advertising itself as degraded, so a coordinator stops scheduling onto it. The alternative — binary healthy-or-gone — discards information the fleet could use.

7. Limits (Spec 1)

Boot: observed under QEMU 10.2.2 on x86_64. Self-init graph profile: boot complete degraded=0 + steady state on both kernel+initrd and hybrid ISO / GRUB serial (-cdrom) paths. Fleet profile on bare QEMU (kernel+initrd): degraded=1 (net/clock/join). Not observed on metal, not observed on other arches. Shell/Python logic is covered by the unittest suite. Zero-compile-first development shaped the floor; live boot still requires numericalos-verify-boot for any new artifact.

Full residual list: evidence inventory. Documentation uses the same fail-closed rule as the runtime: no silent status upgrade.

8. Positioning

NumericalOS is not a distribution and does not compete with one. It ships no kernel and no package manager. It is a userspace and a configuration model that rides a kernel you already have, aimed at fleets where nodes are interchangeable compute rather than pets, and where the fleet's capability registry already exists as structured data.

The nearest relatives are declarative system builders and image-based immutable distributions. The distinction is where the source of truth lives: those systems treat a declarative file as canonical and build a machine from it, while NumericalOS treats a live graph as canonical and treats the file as a content-addressed projection with a hash the machine checks. The difference matters when the graph is also serving other consumers — a scheduler, an auditor, a swarm — and the machine is one reader among several.

9. Reproducing this

git clone https://numericalos.com/numericalos.git
cd numericalos
python3 -m unittest discover -s tests

No third-party dependencies. The repository is served as static files over dumb-HTTP — no forge, no account, no server-side code — so you can verify what you received against its history before running any of it. When the artifact you are about to build becomes PID 1, that property stops being a nicety.

To build a target on your own machine, and to close the boot gate this project cannot close for itself, see the agentic build skills.