valis / Reference / API reference

Fabric - API reference

Exported surface for the fabric subsystem. Part of the API reference.

Package valis/src/fabric

Conditions

owner-key-required

Signalled fail-closed when start-fabric finds an existing durable store (a head in any form) but no owner keyfile. No new DID is minted on this path — the owner key must be acquired out of band. A clean install (no store head AND no keyfile) auto-creates the keyfile instead.

Generic functions

owner-key-required-keyfile

(owner-key-required-keyfile condition)

Undocumented: this exported symbol needs a docstring.

Functions

loopback-host-p

(loopback-host-p host)

Return T when HOST names a loopback interface — IPv4 127.0.0.1, IPv6 ::1, or the symbolic name localhost (case-insensitive). Mirrors seven's own loopback allowlist; kept here so valis does not import from seven's CLI package.

register-module-mailbox

(register-module-mailbox name)

Register a mailbox named NAME on the live valis bus and return the mailbox-dir. Signals an error if the fabric is not running (valis-bus is nil) — that is a programmer error: a module should not try to register its mailbox before start-fabric has run.

start-fabric

(start-fabric port &key (host "127.0.0.1") (keyfile (merge-pathnames "keyfile" (%valis-data-root))) (revocation-path (merge-pathnames "revocation" (%valis-data-root))) (pub-data-dir nil) (store-data-dir nil) (pub-store-backend :store) (evacuative nil) (local-domains nil) (dns-zone-source nil) (dns-descriptor-version +descriptor-admission-contract-version+) (dns-udp-fd nil) (dns-tcp-fd nil) (dns-udp-port nil) (dns-tcp-port nil) (dns-serve-make-exchange nil) (mail-resolver (build-mail-resolver)) (edge-tcp-fd nil) (edge-tcp-port nil) (edge-credential-cell nil) (mail-tcp-fd nil) (mail-tcp-port nil) (owner-fd nil) (owner-port +owner-terminus-port+) (session-max-idle *session-max-idle-seconds*))

Bring up the 9P fabric: build the namespace tree (the /proto, /bus, /id, /cap, /pub children), then start seven's listener on HOST:PORT against a fresh valis-root. PORT 0 selects an ephemeral port; the bound port is readable via (listener-port nine-p-listener).

SESSION-MAX-IDLE bounds how long an owner session may go untouched before its next operation fences it, in seconds, or NIL for no bound. It defaults to whatever the deployment has already configured, and that is NIL out of the box: an upgrade must not start cutting sessions off that nobody asked it to cut off. A node that wants the bound sets it, and RECOMMENDED-SESSION-MAX-IDLE-SECONDS is the value to reach for absent a reason to differ.

KEYFILE is the path the factotum custody store is rooted at; it carries the owner's Ed25519 secret seed so the same did:key survives image restarts. REVOCATION-PATH is the persistence path of the capability revocation store. Both default to keyfile and revocation under the XDG valis data root (<xdg-data-home>/valis/), so a bare (start-fabric port) roots durable state where a launcher can point it with $XDGDATAHOME. Tests pass scratch paths so a test run never reads or writes the operator's real owner key.

PUB-DATA-DIR is the root directory for the publication filesystem store. Defaults to nil, which resolves to <xdg-data-home>/valis/publications/ at start time. Tests pass a temporary directory so no test run touches the operator's real publication data.

PUB-STORE-BACKEND selects which backend serves /pub. :store (the default) wires the durable content-addressed store rooted at its own data directory. :fs wires the POSIX filesystem store under PUB-DATA-DIR — retained so an operator can fall back to the v1 backend. Any other value signals.

STORE-DATA-DIR is the durable store's own root, distinct from PUB-DATA-DIR (the head and blocks are decoupled from the POSIX publication layout). Defaults to nil, which resolves to <xdg-data-home>/valis/pub-store/ at start time. Tests pass a temporary directory so no test run accretes into the operator's durable store.

The durable default starts empty on first boot: a fresh content-addressed store serves an empty /pub. Existing fs-store publications under PUB-DATA-DIR are NOT migrated into the durable store (migration is a later phase). An operator who needs continuity of existing /pub content on the first durable boot should pass :pub-store-backend :fs.

For a non-loopback HOST, fabric-auth-enabled-p must be T — seven's start-listener does not gate the host string itself, so this is the in-process equivalent of seven's CLI validate-loopback-host check.

EVACUATIVE selects the stand-up regime over an existing durable head. Default nil is the coincident regime: a stand-up over an existing head shares the store unfenced, performing no head bump and no fence — a scaling peer must never fence a sibling. Non-nil is the evacuative regime: the stand-up fences the superseded instance as its first durable act, appending the prior generation's fence to the revocation log, advancing the head over the same root tree, then sweeping the prior writer's live grants. A genesis create takes no fence — there is no prior generation to supersede. So a bare (start-fabric port) keeps the prior coincident behavior.

LOCAL-DOMAINS is the set of mail domains this fabric delivers locally (a list of domain strings). It answers the router's recipient-local-p seam: a recipient in one of these domains delivers into the owner's inbox, and any other recipient is non-local. Defaults to nil — fail-closed: with no configured local domain every recipient is non-local, so nothing is locally delivered and the open-relay guard governs every relay attempt.

MAIL-RESOLVER is the outbound MX resolver the /mail axis threads into the /ctl drain, defaulting to one built from operator config via build-mail-resolver. It resolves a relay recipient's MX over the real wire (DoT) at drain time. Defaults fail-closed: with no DoT upstream configured — or runciter's real-wire resolver absent — build-mail-resolver yields nil, and a nil resolver makes the drain DEFER every relay entry (there is no smarthost fallback), so mail never leaves over an unresolved or unauthenticated channel. A caller may inject a resolver directly.

DNS-ZONE-SOURCE is the zone-data-source the DNS view binds over at boot (in production a pg-zone-source over the operator's own zone data). Defaults to nil: a bare (start-fabric port) binds no DNS adapter and keeps the prior DNS-seam behavior exactly, and — because this boot bound nothing — leaves any same-name adapter bound elsewhere untouched on every teardown path. A non-nil source first clears the descriptor-admission precondition, then binds the DNS view. The precondition runs inside this bring-up's unwind, so a refused precondition leaves no DNS adapter behind. No :53 socket is opened here; this wires the bind path only, and no foreign module code is admitted on it.

DNS-DESCRIPTOR-VERSION is the descriptor-admission contract version threaded into that precondition. Defaults to this valis's own supported version, so a bare boot always clears; a caller (a descriptor steered in from upstream) supplying a version that skews from the supported set refuses the boot bind fail-closed through the same precondition. The precondition also refuses when the pinned admission chokepoint symbol is absent. The owner-vouched-hash admission of a steered descriptor runs on the path where the descriptor is actually steered in, upstream of which this precondition is the gate.

EDGE-TCP-FD is the inherited, already-listening :443 descriptor fulcrum steers in (production); nil in dev, where the :443 edge self-binds loopback on EDGE-TCP-PORT instead (nil selects an ephemeral loopback port). When EDGE-TCP-FD is present EDGE-TCP-PORT is unused — the adopted descriptor is already bound. EDGE-CREDENTIAL-CELL is the shared mercer server credential the :443 listener holds by reference — the same cell a renewal reloads, so the public surface never drops. The :443 edge is cert-gated: it wires only when the cell holds a usable chain+key, and start-tls-serve refuses otherwise, so a bare boot (nil cell, no issued cert) leaves :443 dark and still completes bring-up. Defaults nil so the prior behavior of a boot that wires no public edge is unchanged.

Returns the listener handle. On failure, the namespace seam variables and nine-p-listener are left nil so a subsequent stop-fabric or start-fabric sees a clean slate.

stop-fabric

(stop-fabric)

Stop the 9P fabric cleanly. Idempotent — calling on an already-stopped fabric is a no-op. Clears nine-p-listener, the edge seam's cached sessions and grant, and all namespace seam variables so a subsequent start-fabric begins from a known state. The edge seam is reset first, before the 9P listener stops, so the seam never holds a session into a partially-torn-down tree.

Variables

*fabric-auth-enabled-p*

Policy flag for non-loopback binds. When T, start-fabric will bind a non-loopback host because valis-root's node-auth returns a NoiseXX responder and seven's Tauth/Tattach path will use it to require a real handshake before admitting the attach. When NIL, start-fabric refuses a non-loopback bind. A full capability check will eventually replace the meaning of this flag; until then it is the policy gate.

*nine-p-listener*

The seven listener handle for the 9P fabric port, or nil when stopped. Set by start-fabric; cleared by stop-fabric. Read by stop-fabric and by run-foreground to advertise the bound port.

*owner-terminus-listener*

The keyed listener serving the owner 9P fabric over an inherited owner-port descriptor, or nil when no owner terminus is up. It is a SECOND keyed listener against the same valis-root as nine-p-listener — the loopback fabric stays the local management path and the owner terminus is the routable addition, present only when start-fabric is given an :owner-fd. Set by start-fabric; stopped and cleared by stop-fabric and by start-fabric's own failure unwind.

+owner-terminus-port+

The stable port valis records for the routable owner 9P terminus. 564 is IANA's registered 9P (styx/p9) port. The port valis actually serves on is owned by the host agent's config: it binds the routable owner port and exec-inherits the descriptor, and valis adopts that descriptor regardless of this value — the adopted socket's own bound port is authoritative. This is the value passed to the owner-terminus listener when no descriptor overrides it.