Skip to content

feat(disko): add the caisson-disko and disko integrations - #91

Merged
clhodapp merged 2 commits into
mainfrom
feat/disko
Oct 16, 2026
Merged

clhodapp merged 2 commits into
mainfrom
feat/disko

Conversation

@clhodapp

@clhodapp clhodapp commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

What changes

caisson gets two disko integrations. In both, a disko configuration is a disk layout, and the NixOS configurations installed onto it are declared inside it:

caisson.caisson-disko.configurations.nas-1 = lib.caisson.caisson-disko.mkConfiguration {
  configModule = { lib, ... }: {
    disko.devices.disk.main = { device = "/dev/disk/by-id/…"; type = "disk"; content = { … }; };
    caisson.nixos.configurations.default = lib.caisson.nixos.mkConfiguration {
      configModule = ./nixos/nas-1;
    };
  };
};

caisson-disko, the native integration

  • The class is caisson-disko. The layout is evaluated with caisson's own evalModules over disko.devices, typed with disko's type library from the disko source the composition declares. This is the evaluator of ch-disko, brought into caisson.
  • The class declares assertions ({ assertion, message }, as in NixOS). A module of the class refuses a layout with one, and every output of the layout then fails with the messages. The hardware grounding moves to ch-hardware as a module of the class that uses them.
  • The outputs are ch-disko's layout product: serializableLayout, layoutHash, nixosConfig, meta, scripts and packages (each a function of a package set), and rootMountPoint.
  • The class default module adds the registered NixOS module caisson-disko-layout to the machines inside. It defines fileSystems, boot and swapDevices from the layout at default priority, and refuses a layout that produces settings under any other key. A machine gets nothing of disko itself, so the scripts that format and destroy disks are not reachable from it. The /etc/ch-disko identity files and the ch-disko.* options are not carried over. A machine module that needs its layout reads it as lib.caisson-core.evalManifest.nearest.caisson-disko.

disko, the upstream-compatible integration

  • The class is disko. A file written for disko is the module as it is, and the layout is evaluated as disko evaluates one on its own.
  • The class default module adds the registered NixOS module disko-layout to the machines inside. It imports disko's NixOS module from the same source and defines disko.devices from the layout at default priority. So disko's CLI against nixosConfigurations, disko-install (which overrides the disks with mkVMOverride), the image builder and the install test work on the machine.

Both

  • A layout is published as diskoConfigurations.<name>, as { disko.devices = <serializableLayout>; }, which disko's CLI evaluates again with its own evaluator.
  • The class default module passes up the NixOS configuration declared as default under the name of the layout, with the new lib.caisson.integrations.renameDefault. So the machine installed onto nas-1 is published as nixosConfigurations.nas-1, and is the node nas-1 of a colmena configuration that declares the layout. A layout that sets caisson.nixos.exported overrides that.
  • The README lists both, and both colmena integrations, with the one we recommend for new configurations.

Eval weight and caisson-core

The two integrations put the eval-weight scenario over its ceiling: caisson's overhead went from 4.06 MB to 4.45 MB against a 4.28 MB ceiling. Most of that cost came from caisson-core rebuilding the library for every module evaluation, and walking every overlay again each time. nix-caisson/caisson-core#50, now merged, walks a stage's overlays once. This branch locks caisson-core to its main, which has that change, and the overhead is 3.99 MB with the baseline unchanged.

Tests

The pinned-world suite pins disko and uses disko's example layouts as written:

  • caissonDiskoMachinesGetTheLayoutsSettings: a machine on a caisson-disko layout has no disko option and no disko scripts, is published under the name of the layout beside diskoConfigurations, and builds the same system as NixOS builds from disko's module and the same layout.
  • caissonDiskoPublishesWhatDiskosCommandReads: disko's own evaluator makes the same format script from the published layout as from the layout as written (the example with mdadm, ZFS, LUKS and LVM), and the scripts output is that script too.
  • caissonDiskoLayoutsNeedNoMachine and caissonDiskoAssertionsRefuseALayout.
  • diskoMachinesGetDiskosModule: a machine on a disko layout has config.disko.devices and builds the same system and the same format script as NixOS builds from disko's module and the same layout, and an override with mkVMOverride, as disko-install makes, replaces the disks.
  • diskoLayoutsInsideColmenaAreNodes: a layout inside a colmena configuration makes its machine the node named after the layout.

A unit test covers renameDefault. The signature tests and the argument-error suite cover both entry points.

Verification

  • nix flake check passes, the eval-weight gate included.
  • 18 of the 19 workspace flakes that use caisson evaluate with this branch. ch-disko fails, as expected: its own integration owns a module class named disko and selects caisson's default module of that class. ch-disko's integration is retired in favour of these, and ch-hardware, its one consumer, moves to caisson-disko, in follow-up pull requests.
  • With caisson overridden on both sides, every machine of ch-personal-machines has the same system derivation with this branch as with caisson's main.

🤖 Generated with Claude Code

A disko configuration is a disk layout, with the NixOS configurations
installed onto it declared inside it. Two integrations take it:

- caisson-disko, the native one, owns the `caisson-disko` class. The
  layout is evaluated with caisson's own `evalModules` over
  `disko.devices`, typed with disko's type library, and the class adds
  `assertions`, which refuse a layout. Its outputs are the layout
  product: the device tree as data and its hash, the NixOS settings the
  devices produce, disko's metadata, and the scripts and packages for a
  package set. The NixOS configurations inside get the layout's
  `fileSystems`, `boot` and `swapDevices` through the registered NixOS
  module `caisson-disko-layout`, and nothing of disko.
- disko, the upstream-compatible one, owns the `disko` class. A file
  written for disko is its module as it is. The NixOS configurations
  inside get the registered NixOS module `disko-layout`, which imports
  disko's NixOS module and defines `disko.devices` from the layout at
  default priority, so disko's command, `disko-install`, the image
  builder and the install test work on them.

Both publish the layout as `diskoConfigurations.<name>`, the device tree
with disko's internal attributes left out, which disko's command reads.
Both pass up the NixOS configuration declared as `default` under the
name of the layout, through `lib.caisson.integrations.renameDefault`.

caisson-core is locked to nix-caisson/caisson-core#50, which keeps the
eval-weight scenario under its ceiling with the two integrations added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nix-caisson/caisson-core#50 is merged; the locks move from its branch commit to its merge on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@clhodapp
clhodapp merged commit d2e60d7 into main Oct 16, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant