Skip to content

Status

Everything in the first list runs today and is under test. Everything under the roadmap is a design or a deliberate deferral with no code behind it.

Implemented and tested

  • Emet authoring language. Hindley-Milner types with generics, records with row-polymorphic field access and update ({ r | port = 443 }), case/if with exhaustiveness checking, single-constructor patterns in argument position (withPort p (Config spec) = …), numbers with infix operators, string interpolation, recursion and mutual recursion, Char, tuples and unit, and a minimal Elm-modeled module system (module … exposing, import … [as …] [exposing …], file = module). A program compiles a fleet: main : List Scroll. Diagnostics are Elm-style: source spans, did-you-mean, one report per error.
  • The four glyphs. aptPackage, systemdService, the filesystem glyph (file / directory / symlink), lineInFile — every field evaluated to a finished value before it ships. Higher-level shapes are Emet functions that lower to these. See The four glyphs.
  • The binary manifest. emetc build emits a content-addressed Manifest (postcard bytes, BLAKE3 per-scroll ids, format_version 5 guard), with --text and --json views. Determinism is enforced by golden-byte and round-trip tests. See Manifest format.
  • Sealed secrets on the wire. Secretspec.get "KEY" resolves a secret declared in secretspec.toml at compile time and seals it to the fleet key, so a manifest carries ciphertext and stays safe to store, cache, and hand to CI. Interpolating one yields literal chunks around a sealed hole golemd opens at enact, keeping the rest of a config file reviewable. Encryption is deterministic, so an unchanged secret is a Noop and a rotated one re-enacts exactly the units that read it. See Trust model.
  • Recursive scrolls and per-leaf failure isolation. A Scroll is a tree; each leaf is the unit of enact, retry, and rollback. One leaf’s failure never rolls back a sibling. See Reversible reconcile and A failing unit.
  • The retry and on_exhaust cascade. A per-leaf retry budget (delay, backoff, jitter, attempt cap, wall-clock cap) resolved nearest-wins over the scroll’s policy chain and golemd.toml’s [retry], with on_exhaust = rollback (default) or keep.
  • golemd ingest + diff. Decode a manifest, select this host’s scroll, and diff it against the journal into ordered GlyphOps by glyph key and content id. Within a host: apt installs batched into one invocation, duplicate glyphs deduplicated, and units enacted in bounded parallel.
  • Reversible reconcilers. Each glyph’s apply captures an Inverse receipt; reverse restores it exactly. Upgrade, removal, and rollback all derive from this. See Reversible reconcile.
  • Async apply with live progress. POST /manifest answers 202 { reconcile_id } and the reconcile runs detached; golemctl apply polls it and renders a live per-unit tree, plain lines under --json or a pipe, and --reattach resumes an attempt whose connection dropped.
  • golemctl plan. The same compile, no POST: what an apply would do, plus the systemd reloads it would trigger, changing nothing. --against-host adds a second, opt-in block checked against the live host — its filesystem, systemd, and dpkg, read right now — beside the journal-only diff.
  • notifies reloads. A scroll declares units to reload once anything in or under it lands changed; a branch’s list unions down over every descendant leaf.
  • Fleet fan-out, client-side. golemctl fleet apply|plan|status fans a verb over a TOML inventory concurrently, one connection per host. One host’s failure never stops the others, and a host the manifest names no scroll for is skipped untouched.
  • golemctl. apply, plan, fleet, state, history, show. HTTP: POST /manifest, POST /plan, GET /reconciles/latest, /reconciles/:id, /state, /revisions, /revisions/:id, /status. See the CLI reference.
  • SSH transport and the authorization gate. The agent binds loopback and requires Authorization: Bearer <token> against a configured token file; golemctl takes an ssh:// target or an inventory ssh host, opens the forward itself, and carries the secret. See Trust model.
  • Firewall drop-ins. An exposed Quadlet workload emits one complete .nft file per port opening under /etc/nftables.d/, plus the base chain and the oneshot unit that loads them — never a line appended to a shared file. See the Quadlet library.
  • The lichess fleet in Emet. A real multi-host deploy authored against a shared Emet library (examples/lichess/), compiling to scrolls of the four glyphs. See the tour.

Roadmap — not built

  • Per-user identity. The agent binds loopback and requires one shared bearer token, reached over an SSH forward golemctl opens — that much is built. What is not: knowing which person submitted. Per-user tokens, an audit trail, and SSO group mapping arrive with an authentik-issued token replacing the shared secret. Manifest signing is not on the roadmap; the tunnel already holds that boundary. See Trust model.
  • Daemon-to-daemon propagation. Fan-out today is client-side: golemctl fleet opens one connection per host from the operator’s machine. A golemd that hands a manifest to its peers — no operator machine in the loop — is designed (ADR 0039) and unbuilt.
  • Cross-host orchestration. Each golemd acts only on its own scroll and knows nothing of its peers. There is no coordinator, no ordered drain, and no health-gated rollback across hosts: fleet apply reports each host’s outcome, and one host’s failure neither stops nor reverses another’s.
  • Resource kinds beyond the four glyphs. Containers, ingress, and DNS are Emet abstractions — shipped or still to write — that lower to the four glyphs rather than becoming agent primitives. No DNS provider exists today. Secrets went a different way: they are a value type on the wire, listed above, rather than a resource kind.
  • Host-side secret resolution. A secret is sealed at compile time and ships as ciphertext. The Reference variant, which would name a provider for the host to answer — an instance role, a TPM, a local agent — is defined on the wire and refused at enact, naming the provider and telling you to recompile the manifest sealed.
  • Large-file and binary inverses. A file glyph’s inverse holds the prior contents inline in the journal. Out-of-line blob storage for large or binary files is deferred, so a very large managed file is not a shape to rely on yet.
  • Ownership written from Emet. A filesystem entry’s Perms carries owner and group beside mode on the wire, and golemd enacts both: it resolves each name to a uid/gid, chowns the path, and diffs ownership the way it diffs a mode. The gap is the authoring surface — file, directory, and symlink take no owner or group field, so every authored entry ships them unset and leaves ownership to the host. This is why mode = "0600" is the mode to write for a secret: emetc refuses a sealed value in a file that group or other may read, and the 0640 its error offers needs the entry to name a reading group, which the language cannot yet say. See The four glyphs.

What is gone

The older model — Blueprints, Hosts, Workloads, Services, Ingress as engine resource kinds, refcounting ownership across blueprints, and the Nickel authoring surface — has been removed. State is now per-scroll: a node’s desired state is one whole scroll, not a set of named blueprints that refcount shared resources.