valis / Understanding the system
The epistemology of fully connected symbolic computers
What this document is
This is the historical design record of a question that shaped valis at its foundation: what a symbolic computer can know, and enforce, about who is acting on it, once that computer is permanently connected to a hostile network.
It exists because the answer is not obvious and is easy to mistake for something simpler than it is. A maintainer who understands only the mechanism will eventually propose a change that the mechanism permits and the reasoning forbids.
⚠ This document does not supersede anything. Two living documents carry the operational statements and continue to evolve:
- docs/REPL-AXIS.org holds the design of the evaluation axis: the placement decision, the shapes rejected and why, the transport obligations, and the questions still open. Its section The hierarchy, in the classical terms is the primary statement of the argument recounted here.
- docs/ARCHITECTURE.org holds the architecture of record, including Two planes of authority, and why the system is a federation of instances, and the capability model this reasoning acts upon.
⚠ REPL-AXIS.org carries its own status line marking it a draft for review.
That applies to the axis proposal it contains, not to the classical framing
this document draws on, which is settled and long committed.
Where those disagree with this document, they win: they are maintained against the code, and this one is a record of how the position was reached. What this adds is the reasoning around the resolution, the constraints that produced it, and the consequences a maintainer needs in order to judge a new proposal.
The question
⚠ A note on two words used throughout. The operator is the person who runs an instance and holds its execution context. Owner appears only where the substrate's own vocabulary uses it, for the principal an application attaches as. They are the same person; the two words are not two roles.
A symbolic computer of the Lisp lineage is defined by a property that distinguishes it from most machines people now use: the running system is modifiable by the person operating it, at the level of the code, without stopping. That property is the reason such a machine is worth building. It is also the reason this question is hard.
The machines of that lineage sat on desks and were reached by the person sitting at them. The question of an anonymous remote party did not arise for them as an operating condition, whatever their designs may have contemplated.
⚠ That is an argument from circumstance, not from the literature. REPL-AXIS.org records that the lineage has not been read for this question, and withdraws an earlier impression of what it says on precisely these grounds. No claim about what those designs concluded is made here, and none should be inferred.
A modern instance is permanently reachable by an anonymous, adversarial, global network. The property that makes the machine worth building is now also the most consequential surface it exposes. The question this document records is how to keep that property without exposing it to the network.
The machine in classical terms
The argument becomes tractable when the machine is described in the layering every general-purpose computer already has. This framing is stated fully in REPL-AXIS.org and is summarised here because everything downstream depends on it.
A von Neumann machine is layered: hardware at the bottom; a kernel that owns it; a programming interface through which everything above is compelled to ask; and a userland above that boundary. A process does not reach into kernel memory and politely decline to abuse it. It cannot reach at all. It asks, and the asking is the interface. Every guarantee the machine offers rests on that compulsion, not on the good conduct of the programs running on it.
Mapped onto valis:
- The Lisp runtime is the kernel. The work of building the substrate has been the definition of its low level units, which is to say the kernel and its device drivers.
- The capability model is the programming interface. It is where designation, rights, expiry and revocation are made to mean something, and it is what every party other than the operator is compelled to ask through.
- Service modules and clients are userland. They act on capabilities designated to them and hold no ambient authority.
⇒ Anyone who can load arbitrary code into the kernel of an operating system, without being forced through its programming interface, holds all the authority there is to hold. This is not a risk assessment and not a claim about likely exploits. It follows from where the code runs. There is no authority in the machine unreachable from inside the kernel, so a party evaluating there holds every part of it at once, including the authority that would otherwise constrain them, and including the ability to make their holding it unobservable.
Why evaluation is irreducible
The tempting response is to permit a restricted evaluation: a safe subset, an audited language, a sandbox, a package boundary. Each of these was considered. None of them holds, and the reason is structural rather than a matter of implementation quality.
A Common Lisp image loads every form at the same authority. Packages are an
organisational device and not a boundary. The reader reaches evaluation. The
standard library supplies ambient authority in every direction. Evaluation
reaches load, every macro expander, the debugger, the capability layer itself,
and any key resident in memory. An image that could not evaluate could not have
been built.
⛔ A restricted evaluator is therefore a category error rather than a weak design. It is an attempt to make a kernel module loader safe by inspecting the module. The loader is the hazard; what is loaded is beside the point.
⚠ This is worth stating flatly because it will be proposed again. It is the first idea a capable engineer has on meeting the problem, it sounds tractable, and a partial implementation appears to work. The property it fails to deliver is not caught by testing, because nothing about a sandbox that leaks announces itself.
The consequence for the capability model
The capability model carries authority in tokens that chain back to the operator's root. Each delegation link must satisfy structural conditions: the child's designation lies within the parent's subtree, the child's rights are a subset of the parent's, the parent itself carries the right to delegate, and the child must not outlive the parent.
Three of those four express less than the parent. Evaluation has no "less than". There is no half of it, no attenuated form, no expiry that binds it once it has run: a party who can evaluate can redefine the verifier, read the revocation store, or mint a root token directly. The guarantees hold for grants that operate through the model and say nothing about a grant that operates underneath it.
⇒ Only designation still does real work. One cannot hold less of a kernel. One can only decide who is permitted to name the door. This is why placement is treated as the entire security question for the evaluation axis rather than a detail of it.
The resolution: bound the context, not the evaluation
If evaluation cannot be attenuated, then evaluation is the wrong object to attenuate. The object to bound is the context.
The substrate already applies confinement in this direction, and it is worth being precise about which direction that is. Confinement is outward: it governs what a node may reach and what may reach it. It does not govern what the party holding that node may do inside it, and it was never intended to. A node that confined its own operator would be a machine held against the person running it, which is the opposite of the project's purpose.
Applied to one instance, this is a statement about firewalls and namespaces. Applied across instances, it is the answer to the question this document poses.
An instance that executes but holds no data has a context that is total over itself and confers exactly its outward reach. That reach is capability-mediated 9P to the instances that do hold the data. Those mounts attenuate exactly as the capability model describes: each carries a grant hash, revocation actively evicts it, an expiry applies, and a read-only grant is wrapped so that the write operation has no name at all.
⇒ The attenuation happens at the 9P boundary, never at the evaluation boundary. A party holds complete authority over a context that holds nothing, and reaches the operator's data only through grants the operator can withdraw. Holding that context was never the same as holding the data.
Therefore: plural machines, not one partitioned machine
This is why the system is a collection of cooperating valis instances rather than one image serving many parties. A second party is given a second instance and not a confined region of the first.
⚠ The alternatives are not unexplored ground. Isolation within one image and a hosted evaluator with no ambient authority were both recorded as guesses before the decision was reached. Each attempts to manufacture a second context inside a single image, which is the thing the irreducibility argument says cannot be done. Federated instances is what was arrived at after those attempts rather than instead of them.
⇒ A better answer to the irreducibility of evaluation would change this design and would be welcome. What should not happen is a maintainer spending the same effort rediscovering that the in-image route does not hold. Bring a better answer; do not re-run the failed one.
The side-car
The shape intended for an operator's own tools is the side-car: a local valis instance that an owner-facing application boots and attaches to as owner, whose namespace is then composed with a remote instance by mounting a capability into its view.
The design notes are in the ubik repository, as docs/SIDE-CAR-CONCEPT.org,
recorded there as a deferred work item with the boot mode itself still on its
list of what is missing. Read them for the mechanism. They frame the side-car in
terms of latency, offline resilience, and namespace composition, all of which are
true and useful. This document records the security-architectural reason the same
construct is the general answer: the side-car holds the execution context, the
remote instance holds the data, and the only path between them is a capability
the operator can withdraw.
⚠ A side-car is an execution context, so its authority needs an anchor of its own. The ubik notes record key custody for the side-car as open, including the option of an ungated local-only boot. This argument rules against that option: it would rest the most consequential authority in the arrangement on nothing.
What crosses between instances, and what never does
Two distinct things travel between cooperating instances, and conflating them is the most likely future design error in this area.
- Capability-mediated namespace access. An instance mounts a subtree of another instance by presenting a grant. This is the only data path the design admits: no privileged side-channel, no direct socket that bypasses it. ⚠ The mount primitive exists and resolves designations locally; carrying a mount across an instance boundary is not yet built, and the ubik notes record how it should reach a remote instance as an open question.
- Attestations. Administration and service installation are intended to be mediated by consensus over material signed by other instances holding operator authority, including instances a vendor maintains for the benefit of its clients.
⛔ What crosses is an attestation that an artifact is legitimate. What never crosses is access to the context that installs the artifact. Consensus supplies trust in the thing installed, never a route into the machine installing it. The local execution context remains the only thing that applies it.
⚠ The seam for the second already exists: module admission runs through a
content hash plus an operator vouch carrying the :admit right. Federating
administration changes the signer of that vouch from the operator alone to a
quorum, and requires no new mechanism. This is also why :admit belongs
with the execution context rather than with the data rights it is currently
listed beside.
The two planes, and where they are stated
Authority divides into two planes, and only one of them is described by the rights vocabulary: the data plane, which is reading and editing projections of the operator's data, and the execution context, which is loading code, installing a service, and changing what the node is.
⇒ The statement of record is Two planes of authority, and why the system is a federation of instances, and it is not reproduced here. A copy would become a competing version the moment that section is edited, with nothing to link the two.
The consequence worth carrying into any design discussion is short: a question of the form "which right is evaluation" is malformed. Neither an existing right nor a new one can carry it, because both would enter a vocabulary whose central promise is that a child grant is a subset of its parent, while meaning every right at once plus the power to mint more.
Where this is going
The reasoning above is not only a constraint to respect. It describes a destination, and work should be designed toward it rather than merely kept compatible with it.
⚠ Marked plainly, because the layers below differ both in what commits the system to them and in how much of each exists. Layers one and three are what the argument above commits the system to. Layers two and four are what the project's purpose commits it to, and the argument constrains their shape rather than producing them.
⛔ What is built, and the era it is built in. This is pre-release founding development. One instance holding one whole execution context for one operator is built. A second instance cooperating with it is not: the mount primitive resolves a verified designation against the local assembler root, so carrying a mount across an instance boundary does not exist yet. Everything below describes where the design is going, not where it is. ⚠ Do not read the ordering as a schedule. Nothing here is sequenced.
One whole machine per operator
The unit is not an account, a tenant, or a partition. It is a whole instance with a whole execution context, held by one operator who can reach into it completely. Plurality is the mechanism by which the Lisp machine property survives connection, so the number of instances is expected to grow with the number of people, not with the number of services.
⇒ Design implication. No seam should assume there is one instance, one operator, or one node that is authoritative for everything. A design that works only when there is a single instance is a design that will have to be rebuilt.
The instance subsumes the operator's infrastructure
An operator today runs a shell host, a web server, a mail system, a nameserver, and a package distribution as separate pieces of software with separate administration and separate trust. The intent is that these collapse into the Lisp machine as service modules over one namespace and one capability model.
Serving names and serving a site are already inside. Mail has its substrate built and its wire legs outstanding. Distribution currently runs on ordinary infrastructure and is intended to move.
⇒ Design implication. When a capability the operator needs is currently supplied by external infrastructure, the question is not how valis integrates with it, but what it looks like as a module over the namespace. Integration is the interim; absorption is the destination.
Composition across instances the operator holds
An operator with capabilities into several instances should see one namespace composed from all of them, assembled locally in their own side-car rather than centrally by any one node. Multi-instance composition is the ordinary case, not an advanced feature: an operator's view is built from what they hold grants to, wherever it lives.
⇒ Design implication. Anything that assembles a view should treat the local instance as one contributor among several, and anything that names a resource should survive that resource living on a different instance than the one being asked.
A community of instances that vouch for each other
Instances are intended to hold material for one another and to attest to one another. Two loads are identified and they are distinct: recovery, where a quorum of remote instances lets an operator reconstitute an identity; and administration, described above.
⛔ They rest on different properties, and only one of those properties is in place. Conflating them would credit recovery with a guarantee it does not have.
- The administration load rests on a property that is already structural: the storage layer is not trusted to ignore what it holds, it is unable to name it, and that inability is proven across the durability cluster by its import graph rather than by a runtime check that could be skipped.
- The recovery load needs something further: the remote holder must be unable to read the material it holds. A remote operator holds host control over their own instance and can read whatever their own store contains. The property that would close this is content encryption carried in the capability name, so the storage layer never sees plaintext, and ARCHITECTURE.org records that as deliberately deferred. It is not yet in place.
⚠ This is the furthest layer, and the distance to it differs in kind. The layers above extend seams the system already has; this one needs machinery that has not been designed. A node cannot stand itself up from data sharded across deployed hosts, and what is missing there is undesigned rather than merely unimplemented: the encryption property named above is one piece, and nothing yet describes how a quorum is composed, discovered, or held.
⇒ So read this layer as the direction of travel rather than as pending work. A plan that assumes any of it as a dependency is planning against something that does not exist. What it is good for is keeping today's seams from foreclosing it.
⇒ Design implication. A mechanism that needs a privileged route into a subscriber's instance is the wrong shape for this destination and will have to be rebuilt. Design for an artifact that can be attested and verified locally.
Direction for work built on valis
This section exists so a maintainer can place a new project without re-deriving the argument.
If you are building a service module
You are in userland. Act only on capabilities designated to you, hold no ambient authority, own the transport for your connections and the service logic of your protocol, and read the operator's data through the namespace rather than around it. ⚠ The half most often tripped over is outbound: a module opens no socket and binds no source address, and everything it sends travels through valis's dial seam. Nothing else in this document constrains you beyond what docs/CONSTELLATION.org already says. The reasoning matters to you only if you find yourself wanting to evaluate code on someone's behalf.
If you are building an owner-facing application
Attach to a local instance as owner and compose remote subtrees into that instance's view by capability. Do not open a direct privileged path from the application to a remote instance: the object-capability model is the federation path, and an application that reaches around it has moved the trust boundary without saying so.
⚠ The side-car is the intended form of that local instance, and it cannot be booted from an application yet: the boot mode is on the ubik notes' list of what is missing. Keep the composition seam so that nothing has to move when it arrives.
If you are building something that runs code for another party
This is the case the document exists for. Give them an instance. Do not give them a region, a sandbox, a restricted evaluator, or an audited subset inside your instance. Their instance holds their execution context; anything of yours they need arrives as a grant you can revoke. What they hold completely is their own context, and it contains nothing of yours.
The cost of a whole instance is proportionate to the authority being handed over. Anything cheaper attenuates the appearance of that authority and not the authority itself.
If you are building distribution or administration
Design the artifact to be attested, not the channel to be privileged. A distribution mechanism that needs a route into a subscriber's execution context has the shape wrong. The correct shape is a signed statement about an artifact, verified locally, applied by the local execution context under its own operator's authority.
⇒ The seam already exists, so this is concrete rather than aspirational.
Module admission takes a content hash plus a vouch carrying the :admit right.
Design so that federating administration changes only the signer of that
vouch, from the operator alone to a quorum, and nothing else.
Questions worth asking of any proposal in this area
- Does it create a second context, or partition an existing one? The second is the error.
- Does anything cross an instance boundary other than a capability or an attestation? If so, what is it, and why is the capability model insufficient?
- Does it require confining the operator of a machine on that machine? If so it is solving the wrong problem.
- Does any authority it introduces sit beside the capability model rather than inside it? Anything beside the model is the thing that can never be hardened away later.
What this arrangement costs
Recorded plainly, because a design record that lists only benefits is not one.
- An absence guarantee became a gate guarantee. Every node now carries the development listener, which is strictly harder to prove than a binary that never contained it. A gate is worth what its tests are worth, and it must hold on every node rather than on one build flavour.
- Plural instances cost real resources. Federation is not free, and an arrangement that would have been one process is now several with a network between them.
- The honest scope of any claim is over the designated path. No evidence available establishes that no path in an image of this size reaches evaluation under some other name. What can be claimed is that the axis is the only path offering evaluation as a service to a party outside the image, and that everything else able to evaluate is already inside the trust boundary because it is the image itself. A broader claim would be false, and a reader who caught it would be right to distrust the narrow one too.
- A state actor holding the hardware wins. This is stated in the research record and is not softened here. The achievable goal is detection and key destruction, not defence at that level.
What remains open
These are recorded as open and should not be read as leaning. The live versions are in REPL-AXIS.org.
- Whether revocation must interrupt an evaluation already running or only prevent the next one.
- How a recovery quorum is discovered without the discovery itself being the disclosure.
- The minimum coherent state at which a node can verify an operator key and serve a small control surface. A low floor shrinks the window that needs bootstrap authority at all, and shrinking that window is a better answer than adding a second authority to cover it.
Withdrawn since this list was written: the question of how the durable form of the axis is registered was posed against the namespace manifest, where the axis does not belong. Module registration is a separate mechanism, in which a module is designated by a content score rather than by a name in a frame. It is recorded as withdrawn rather than answered, because the question does not arise in that form. The reasoning is in REPL-AXIS.org.
What the resolution preserves, and what it spends
The property worth protecting is unchanged and undiluted: a machine its operator can reach into and change while it runs. For the operator of an instance that property is total, and confining them was never attempted, because it is the wrong problem rather than a hard one.
What the resolution spends is plurality. Each operator gets a whole machine, reachable by them completely, and reaching anyone else only by permission that can be withdrawn.
🄯 Brian O'Reilly <fade@deepsky.com>, 2026