Capabilities
Endowments
An endowment is a name a program requests, which the shop may deny. That is the whole
definition — it describes the request, not the power. $posix_file is an endowment
because a shop may refuse it, and $cores, a number saying how many processors the
machine has, is an endowment for exactly the same reason.
A module declares what it wants by referencing a $name. The build collects those
declarations across the whole program and asks policy. What a granted name is, how it
reaches an actor, and how a program narrows one for someone else are covered in
Endowments.
The gate is compilation
Authority is decided once, when a program is built, and it is not revisited.
Policy answers one question: may this be built? If it compiled here, it runs. There is no second decision at start — no re-checking of claims, no re-deriving of the closure, no authorization record to authenticate. A start is the mechanical execution of a plan that was already decided.
This is what keeps the runtime small enough to boot a console. Verification at start would have to be performed by code that arrived through the same channel as the thing it is checking, which establishes nothing while costing every actor start.
Two consequences follow, and both are intended:
The boot cart is trusted by ruling. A runtime has to start somewhere, and the medium it starts from cannot be authorized by code that has not run yet. So the C floor checks that a cart is interpretable — its profile and ABI stamp match this binary — and nothing further. That is a type check, not a security check.
Policy is not retroactive. Tighten your policy tomorrow and yesterday’s cached realization still starts, because it is a cache hit and the gate is behind it. Rebuilding is what applies a new decision. This is deliberate: the alternative is a check at every start, which is the thing this design exists to avoid.
Reaching outside the closure
A shop draws artifacts from its mounts — a git repository, a local store, a cart, a bundle, another shop, a folder on disk. Mounting is therefore the act that decides what can enter.
There is no $mount endowment. The clerk mounts, and the question is only what it knows how
to mount: a directory, its own .pit store, a git repository, an archive — one module each.
A game can only run what was put in front of it because it carries no module that could reach
further, which is the same rule as the rest of this page rather than a special one.
Two lookups behave differently, and the difference is where a hostile mount could lie:
- Content lookups verify themselves. Ask for
blake2:7f7f…and the bytes prove what they are. A bad mount can fail; it cannot substitute. - Catalog lookups are trust. A row saying this locator, or this derivation key, resolves to that hash is an assertion you cannot check. That is the layer where a per-mount policy belongs when one is wanted — may this mount answer derivation-key lookups, or only supply content by hash?
See The Store.
The C floor
C is where the capability system ends. A native module runs with the full authority of the process: it calls syscalls directly and reads memory directly, answering to the operating system alone. That is the price of C, and it is the reason C is treated as a distinct decision rather than one endowment among many.
So a C import is deniable. Programs and modules declare the native providers they
require, and the executable manifest carries both the per-unit claims and their
transitive aggregate. A deny_c policy requires the transitive native-provider closure
to be empty, and traces every native claim back to the unit that imported it.
Accepting a C import is unconditional. Once accepted, that module holds full native authority, and the guarantee the rest of the system provides stops at its edge. Every C import is declared, surfaced transitively, and visible before it is accepted.
Because C is the surface that has to be audited, the runtime keeps as little of it as possible. Cold boot maps a cart, reads a fixed header, loads the engine image, and enters the first actor; everything after that — mounting, resolving, realizing, starting — is pit. See Booting.
Compiling and loading
Two operations produce or load code, and they sit on opposite sides of the C floor.
Compiling source to mcode, and lowering mcode into a Mach pool, both produce confined code. Bytecode exercises only the endowments its actor holds, so producing it is as safe as running it. A runtime that ships a compiler can accept new pit source, compile it, and run the result inside the same capability model — which is what makes a moddable game possible, and it needs no special mechanism: a mod is compiled on the player’s machine, by the player’s shop, gated by the player’s policy.
Generating native code, and loading arbitrary native code at run time, produce C-floor code instead. Those are build-selected powers, along with the four debugging endowments: a cake configuration links their providers or builds without them, so what an artifact can reach is a structural property of the binary.
A player artifact omits the compiler and the general-purpose loader. It may still contain a fixed native image and entry, when its sealed realization selects the native execution form and the device’s policy accepted that exact image and its target. The distinction is between generating or loading native code on demand and running one specific native image that was authorized in advance.
Policy sees the whole closure
Policy decides over a closure — a program together with the exact set of modules it imports — because authority is a property of the combination. A program of twenty modules where one module is the gate that constrains the other nineteen is a different proposition from those nineteen standing alone; adding the gate makes the program safer. Modules declare what they want; the closure is granted or denied as a whole, and a different closure is a different artifact with its own decision.
The closure is knowable because use() takes a string literal. $start does not have to:
starting an actor by a name computed at run time is allowed, and an executable that does
it is flagged as allowing guest code, because the set of actors it may start is not
knowable at build time. A policy can require literal-only starts — which is the right
setting for a sealed cart, where nothing new will ever arrive to be started.
Policy also sees who is asking, so the same closure may be granted for a developer on their own machine and withheld from a guest.
What policy decides is a deployment’s business: a developer’s machine grants freely, a
shipped moddable game constrains what mods may hold, and a sealed cartridge carries a
decision already made. A policy configuration is default-deny — a configuration that
names nothing grants nothing — while a development configuration may grant every claimed
endowment at once with a ["*"] wildcard.
Three mechanisms, three jobs
Trust in pit is assembled from three independent parts, and none substitutes for another:
- Mounts decide what may enter. What a shop can reach is what it has mounted.
- Hashes verify bytes. Every object is named by the hash of its content, so what arrived is what was named.
- Endowments make execution safe. What code may do is decided by the endowments it holds, granted when it was built.