Omnis

ADR-0012 — The system is one declarative configuration, applied as generations

  • Status: Accepted · Date: 2026-09-06
  • Refines: ADR-0005 · Completes: ADR-0003, ADR-0006

Context

notes/transcript.md §7 treats settings.json as a switchboard: a bag of keys the UI writes and the daemon reads. ADR-0005 put configuration in versioned files, which is right but says nothing about shape.

Two problems remain unsolved by a settings bag. First, once subsystems, packages, profiles, and guest environments are all configuration, an unstructured key-value file cannot express the dependencies between them. Second — and more seriously — ADR-0003 promises every modification is reversible and ADR-0006 promises every agent action is attributable, and neither record says by what mechanism. Both are currently aspirations.

Decision

The configuration is a single declarative specification the system converges toward, in the NixOS sense: you describe the desired state, evaluation produces a system, and applying it creates a generation.

  • One declaration, in Nix. Not a format of our own that compiles to Nix — that means owning a language and a compiler, which ADR-0011 forbids. Using the Nix module system directly gives typed options, merge semantics, mkDefault/mkForce, imports, and nixpkgs for nothing.
  • It declares the whole system: enabled subsystems, packages and toolchains, profiles and themes, guest environments, remote access, and secret references — never secret values (ADR-0010).
  • Applying it produces a generation with a parent, a diff, and an author. Generations are listable, diffable, and roll back.
  • Runtime mutations write the declaration. A change made through the modification surface (ADR-0003) is staged into the specification and applied by convergence. It is not an overlay and not a side-channel.

Why this completes two earlier records

ADR-0003's reversibility becomes a mechanism. "Any change an agent makes can be inspected, diffed, and rolled back" stops being a design intention and becomes omnis rollback — the same operation for a typo, a bad profile, and a misbehaving agent.

ADR-0006's attribution gets a natural unit. A generation has an author. An agent reconfiguring your system produces a reviewable change with a parent commit, not an untraceable mutation. Audit answers what happened; generations answer what the system now is, and who made it so.

This is the reason to prefer declarative here. It is not tidiness — it is that the safety properties already promised have no other credible implementation.

Alternatives rejected

  • A settings bag (settings.json), as the transcript proposes. Cannot express dependencies between subsystems, packages, and environments; cannot roll back; gives attribution nowhere to live. It is adequate for appearance and inadequate for a system definition.
  • Our own declarative format compiled to Nix. Friendlier syntax, and it costs a language, a parser, a type system, an error-reporting story, and a compiler — to reach a place the Nix module system already occupies. The friendliness belongs in the GUI editing structured options, not in a second language.
  • Imperative configuration with a snapshot/undo layer. Snapshots capture state without capturing intent, so a rollback cannot explain what it undid, and two concurrent changes cannot be merged.
  • Declarative base with runtime overlays that are never written back. The tempting middle. It guarantees drift: the running system stops matching the declaration, and the declaration stops being the source of truth exactly when you need it to be.

Consequences

  • Nix is a hard dependency and a real learning curve. Users who never open the file are served by the GUI writing structured options for them; users who do open it meet Nix. That cost is accepted in exchange for the module system and nixpkgs.
  • Convergence is not instant. Some changes apply live; others need a subsystem restart. The configuration schema has to say which, or the UI will lie about when a change took effect.
  • Every setting needs a typed option definition — which ADR-0003's introspection requirement demands anyway, so the two land together.
  • Secrets stay outside the declaration, referenced by name only. A declaration is diffable, shareable, and frequently pasted into an issue.
Omnis