bivdi

Six primitives

The model

A conventional operating system is organised around process, file and socket. Bivdi is organised around six primitives — and it is those six, not the kernel, that are the architecture.

Source of record: docs/spec.md in the Bivdi repository.

The kernel is an implementation detail of the model, not the place the model is invented. That is why the same model runs over a hardened Linux runtime today and a microkernel tomorrow, and why a program written against one runs on the other unchanged.

IDENTITY + CAPABILITY + OBJECT + EVENT + DESIRED STATE + RESOURCE
PrimitiveWhat it isWhat it replaces
IdentityCryptographic identity for a person, device, workload, service, object or organisationuid, hostname — but cryptographic rather than ambient
CapabilityAn unforgeable handle granting one specific right to one resourcefile descriptor — but unforgeable, attenuable and revocable
ObjectTyped, content-addressed data with metadata, relationships and versionsfile — but typed and versioned
EventA structured, first-class record of changelog line, inotify — but typed and queryable
Desired stateA declarative specification of what should beconfig file plus init script — but reconciled
ResourceCPU, memory, GPU, NPU, storage, network, device — with budgetsimplicit kernel resources

Capabilities#

A capability is an unforgeable handle that both points at a resource and grants a right to it. Forgery is unrepresentable, not merely hard: a capability is an index the kernel validates on every use, not a bit pattern its holder can inspect or manufacture.

Four properties are decided, and they are what everything else rests on.

  • Unforgeable. Enforced by the kernel, never by convention.
  • Transferable. A holder may pass a capability on — but only if it holds it.
  • Attenuable. A holder may derive a strictly weaker capability: read-only, one subtree, one deadline. Attenuation never requires authority and is never reversible.
  • Revocable. The granter may invalidate a capability and its entire derived subtree at once.

There is no root, and there is a root capability#

"No root" does not mean there is no highest authority. It means the authority is not ambient. A root capability exists per machine and per identity; it is held in hardware, requires explicit local action, is never granted to a program or an agent, and is used only for recovery, key rotation and ownership change.

There is nothing to escalate to, because there is no path from "I am running" to "I hold more."

Two tiers of authority#

Conflating authority in use with authority at rest is a common design error. Bivdi separates them.

TierScopePersistenceForgery
Kernel capabilityLocal, live, inside a component's capability spaceDies with its processUnrepresentable by construction
Durable tokenTransferable, offline-verifiablePersisted, transmittedCryptographically infeasible
Proposed, not decided

The durable-token construction — a macaroon-style chain where any holder may append a restriction and re-chain without contacting an authority — is a proposal. So is the warden service that bridges the two tiers by verifying a presented token and then acting with its own kernel capability. The concept is settled by the decided capability model; the encoding and the kernel boundary are not.

The powerbox: the gesture is the grant#

Capability systems have historically foundered on the human interface, not on the formalism. Bivdi's answer is the powerbox pattern: when you pick a file in a system-drawn dialog, that selection is the capability assignment. The application receives exactly the object you chose — not the directory listing, not the path, not the ability to look again tomorrow.

This reduces the number of security dialogs rather than adding to them, because the user is already expressing intent through an ordinary gesture. Whether it works in practice is an open question the project has written down rather than assumed away.

Leases#

Permissions are leases, not permanent flags. "Microphone for five minutes." "Until this task ends." A lease is the default shape of a grant, not an optional extra, and it is what stops permission hoarding: authority that is never renewed simply stops existing.

The object store#

The object store replaces the filesystem as the conceptual centre. It is an unprivileged, restartable service with access only to the block devices it was handed.

Three primitives are decided:

PrimitiveDescription
BlobAn immutable byte sequence named by its content hash. Identity is content, so deduplication and integrity verification are inherent.
CellA mutable single-slot holder of a blob reference, updated only by compare-and-swap. This is the only mutation primitive.
CatalogA persistent map from names to blobs, cells and sub-catalogs, reached only by capability — no root catalog, no /, no way to walk upward.

Two components handed two different catalogs inhabit disjoint universes and cannot discover each other. There is no global namespace in which to name something you were not given.

Because a cell is the only way to mutate anything, every lost-update race is a visible compare-and-swap loop rather than a locking discipline someone forgot to follow.

What follows from immutability#

  • Deep immutability. Writes are append-only; mutation creates a new node pointing at immutable parents. Rollback is a pointer change.
  • Transactions. Changes commit atomically. There is no partially-written state and no fsck.
  • Snapshots. A snapshot is a retained root — O(1) to take, free to hold. "What did this look like on Tuesday?" is a query, not a restore from backup.
  • Crypto-shredding. Because history is immutable, deletion destroys the key rather than rewriting the past.

Files survive as contracts#

Bivdi does not kill the file. Objects have a canonical serialised form and can always be exported and imported as files; legacy programs see objects as files through a virtual filesystem view. The file is a stable contract for exchange — it is simply not the storage model.

Bounded scope, deliberately#

The object store offers transactions, snapshots, indexes, event streams and replication. It does not replace PostgreSQL, Kafka, or large-scale object storage. Databases remain applications that use the store's primitives. A system service that tries to be a database is how operating systems get too big to reason about.

Declarative state#

Users, applications and administrators describe desired state. The system continuously reconciles observed state toward it.

Desired State → Reconciler → Observed State → Actions → New Observed State

An update creates a new immutable generation rather than mutating the running system. Activation is transactional and health-checked; a generation that fails its checks rolls back automatically, and rollback is a pointer change rather than an undo script.

One line matters more than it looks: reconciliation suits configuration and workloads; interactive data uses direct transactional operations. A person editing a document expects an immediate response, not eventual convergence. Designs that declare everything usually discover this the hard way.

Events#

Every change produces a structured, typed record: object lifecycle, workload lifecycle, capability grant, use and revocation, device attach and remove, policy change, generation activation and rollback.

Applications, automation, synchronisation and observability consume the same fabric. Events are typed records defined in the interface definition language, not text that each consumer has to parse and guess at. A shared correlation identity traces one user action through applications, IPC, services, storage and the network.

Workloads#

The execution unit is a workload: immutable code, an explicit capability set, and a resource budget. The isolation that containers provide on Linux is built in rather than bolted on.

Budgets are explicit and enforced — memory, CPU time, energy, latency class (realtime, interactive, batch, background) and I/O bandwidth. There are no unbounded queues; an exhausted budget degrades predictably instead of hanging the machine. CPU time is itself a capability: a scheduling context is granted, and admission control at bind time rejects oversubscription, so a reservation is guaranteed rather than hoped for.

Four execution environments, one model:

EnvironmentUse
WASI componentsThe native application format — portable, capability-oriented, strongly isolated
NativeMaximum performance, hardware access, systems software
Linux ABIUnmodified Linux binaries via user-space syscall translation
Micro-VMA real Linux or Windows kernel, isolated, for heavyweight legacy workloads

The manifest is the security boundary#

A workload's manifest is the security boundary in human-readable form. A competent reviewer should be able to read one manifest and state exactly what the workload can do — and if they cannot, the design is wrong regardless of its formal properties.

A manifest declares the component's identity as a content hash, the code to load, the explicit list of capabilities it receives, its declared absences ("no network", "no storage writes", "no spawning"), its resource budgets, its restart policy, and its provenance information.

Nothing is implicit. No wildcards, no inherited handles, no authority derived from the environment. Default-deny is not a setting; it is what an empty manifest means.