Reference / Clusters and instances
kix.toml
kix.toml is an optional configuration file placed beside flake.nix at the root of a Kix project. It names the version of Kix the project uses (kix), and it chooses the project’s builder: whether Kix evaluates clusters with the Nix in the Kix runtime and Kix’s local store (builder = "kix", the default) or with the machine’s installed Nix and /nix/store (builder = "nix"). Because kix.toml lives in the repository, every contributor and CI job uses the same Kix version and builder without passing extra flags or environment variables.
Location and format
Section titled “Location and format”Kix looks for kix.toml in the directory named by --flake (by default ., the current working directory). When --flake is a remote flake reference such as github:org/repo rather than a local directory, Kix uses the default builder ("kix").
1kix = "0.8"2builder = "nix"The file and both keys are optional. An absent kix.toml or an empty kix.toml is equivalent to:
1builder = "kix"kix.toml accepts only keys that the installed version of Kix recognizes. In this version of Kix, the valid settings are kix, builder, and the [upgrade] table. Unknown keys, unknown builder names, a kix value that is not a version, and TOML syntax errors stop the command before evaluation starts.
The kix setting
Section titled “The kix setting”kix names the version of Kix that runs for this project:
| Value | Accepts |
|---|---|
"0.8" | Any 0.8 patch release. Kix runs the newest 0.8 it has, the running one or an installed one. |
"0.8.3" | Only Kix 0.8.3. |
"0.9.0-rc.1" | Only the prerelease 0.9.0-rc.1. |
A minor such as "0.9" never matches a prerelease. To try a prerelease in a project, name it in full, and change the setting back when the release is out.
Kix 0.7 and older refuse a kix.toml that sets kix, so the setting must name Kix 0.8 or newer. A value such as kix = "0.7" stops the command with an error.
Before Kix parses its command line, it reads kix from kix.toml in the directory named by --flake (or KIX_FLAKE), and then:
| Situation | What Kix does |
|---|---|
No kix.toml, or no kix setting | Runs |
| The running Kix matches, and no newer matching Kix is installed | Runs |
A matching Kix newer than the running one is installed in ~/.local/share/kix/ | Runs that Kix in its place, with the same arguments |
| No matching Kix is installed | Downloads the newest matching release from kix.run, checks its signature and SHA-256, prints Installing Kix <version> (this project needs <kix>), and runs it |
No matching Kix is installed, and KIX_AUTO_INSTALL=0 | Stops: This project needs Kix <kix> (kix.toml), and no Kix <kix> is installed. Automatic installs are off (KIX_AUTO_INSTALL=0). Run `kix self install <kix>`. |
KIX_AUTO_INSTALL set to 0, false, or no stops Kix from downloading versions. kix self, kix completions, kix init, kix help, and --help run in the version you typed, whatever kix.toml says. A remote flake reference such as github:org/repo is not read. To choose, Kix reads kix.toml and lists ~/.local/share/kix/. It runs no Nix and makes no network request unless it has to install. So a project with kix = "0.8" moves to a new 0.8 patch as soon as one is installed.
At this stage Kix reads only the kix setting. It ignores other keys and values it does not know, so an older Kix can hand a project over to the newer Kix it names. The Kix that runs the command then checks the whole file.
kix --version follows the same rules, except that it never downloads. When no matching Kix is installed, it prints the running version and then, on stderr, this project needs Kix <kix>, which is not installed. Any other kix command installs it.
The Kix that hands over sets KIX_SELECTED_BY to its own path for the Kix it runs, and kix --version and kix doctor print it. A Kix that finds KIX_SELECTED_BY set runs without choosing again.
Kix also checks that the Kix library in flake.lock has the same minor version as Kix and a patch version no newer than Kix’s. Set kix to the Kix library’s minor so that everyone on the project runs a Kix that can build it.
The builder setting
Section titled “The builder setting”| Value | Status | Nix binary and store | How Helm charts are rendered |
|---|---|---|---|
"kix" | Default | The nix in the Kix runtime (2.35.4), with Kix’s local store at $XDG_CACHE_HOME/kix/store (or ~/.cache/kix/store, overridden by KIX_STORE_ROOT) | Kix runs the helm programs in the Kix runtime outside Nix and writes chart tarballs and rendered JSON into Kix’s local store |
"nix" | Supported | nix and nix-store from PATH, using /nix/store and the machine’s nix.conf | Nix fetches charts as fixed-output derivations and runs helm template inside ordinary Nix builds during evaluation |
"remote" | Reserved | Remote build service (not yet implemented) | Refused by this version of Kix |
builder = "kix" (default)
Section titled “builder = "kix" (default)”When builder is "kix" (or when kix.toml is omitted), Kix runs the nix, nix-store, helm, kubectl, and sops binaries from the Kix runtime in libexec/kix/. It writes evaluated manifests and rendered Helm charts into Kix’s local store at $XDG_CACHE_HOME/kix/store (or ~/.cache/kix/store when XDG_CACHE_HOME is unset).
This mode requires no Nix installation on the machine, no Nix daemon, no /nix directory, no root access, and no Linux user namespaces.
builder = "nix"
Section titled “builder = "nix"”When kix.toml sets builder = "nix", Kix runs nix and nix-store from PATH against the machine’s /nix/store. It inherits the machine’s and user’s Nix configuration (nix.conf), including binary caches (substituters), remote build machines (builders), and access-tokens.
Use builder = "nix" when your project needs any of the following:
- Shared Nix binary caches or remote builders configured in
nix.conf. - Plain
nix buildornix flake checkon clusters that include Helm charts. - The
packages.<system>.cluster-<name>-activationflake output for scripts or CI pipelines that build activations directly withnix build.
Under builder = "nix", both kix and plain nix commands render Helm charts inside ordinary Nix derivations using the official Helm release binary pinned in kix/lib/helm-versions.json (4.3.1 for helmVersion = "4" and 3.19.1 for helmVersion = "3", matching the binaries shipped in libexec/kix/). Both builders pass the same helm template flags, so a chart renders the same way under either builder. For the Helm clusters in the Kix repository, both builders give identical manifests.
Even when builder = "nix", Kix still runs kubectl, sops, and any direct CLI helm invocations from the Kix runtime in libexec/kix/ rather than PATH.
builder = "remote" (reserved)
Section titled “builder = "remote" (reserved)”builder = "remote" is reserved for a build service that builds the project on another machine. This version of Kix refuses it:
1<path>/kix.toml sets builder = "remote", but remote builders are not supported yet. Set builder = "kix", or remove the settingThe [upgrade] table
Section titled “The [upgrade] table”The [upgrade] table sets how kix upgrade picks the release it moves the project to:
1[upgrade]2min-age = "7d"| Key | Value | Effect |
|---|---|---|
min-age | A number of days, such as "7d" | kix upgrade picks only releases at least this old, by their release date. |
Tracking kix.toml in Git
Section titled “Tracking kix.toml in Git”Nix flakes only see files that Git tracks. When kix.lib.mkFlake evaluates your flake, it reads ${inputs.self}/kix.toml inside Nix and exposes the chosen builder at legacyPackages.<system>.kixConfig.builder.
Before evaluating a cluster, kix compares the kix.toml file on disk with legacyPackages.<system>.kixConfig.builder. If you create kix.toml with builder = "nix" and do not stage it in Git, Nix does not copy kix.toml into the flake source tree, the Kix library falls back to "kix", and kix stops with an error:
1./kix.toml is not tracked by Git, so Nix ignores it. Run `git add kix.toml`Stage kix.toml whenever you add or change it:
❱ git add kix.toml Two other conditions must hold for the CLI and the flake library to agree:
flake.nixmust passinputs(which includesself) tokix.lib.mkFlake { inherit inputs; ... }, somkFlakecan locate${inputs.self}/kix.toml.- The
kixflake input locked inflake.lockmust be new enough to exposekixConfig. If the locked library predateskix.tomlsupport,kixprompts you to runkix lib update.
Requirements for builder = "nix"
Section titled “Requirements for builder = "nix"”When a project sets builder = "nix", the machine running kix must meet these requirements:
- Nix 2.24 or later on
PATH. The Kix library uses the|>pipe operator (pipe-operators), which Nix added in 2.24. - Upstream Nix, not Lix. Lix reports
(Lix, like Nix)innix --versionand is refused because this builder relies on upstream Nix’s flake and pipe-operator behavior. allow-import-from-derivationenabled (true). This is the default in Nix. Whenbuilder = "nix",scope.helm.importChartandkix.helmChartbuild a derivation that runshelm templateand import the rendered JSON during evaluation (Import From Derivation, or IFD). Ifallow-import-from-derivationis set tofalseinnix.conf, evaluating a cluster that uses Helm charts fails.- No
trusted-usersrequirement. Thenixbuilder uses ordinary fixed-output derivations for chart downloads and standard derivations for chart rendering. Your user account does not need to be listed intrusted-userson the Nix daemon. KIX_STORE_ROOTmust be unset.KIX_STORE_ROOTonly redirects the local store of thekixbuilder. IfKIX_STORE_ROOTis set in the environment for a project withbuilder = "nix",kixstops and asks you to unsetKIX_STORE_ROOT.
Run kix doctor in the project directory to check kix.toml, the machine’s nix binary, allow-import-from-derivation, and whether the Nix store trusts your user:
❱ kix doctor Flake outputs when builder = "nix"
Section titled “Flake outputs when builder = "nix"”Setting builder = "nix" in kix.toml changes what kix.lib.mkFlake exports in your flake:
-
packages.<system>.cluster-<name>-activationis exported. This output creates a directory linkingactivation(theActivationresource manifest),kix-packages.json,kix-scorecard.json,kix-extra-images.json,kix-image-sources.json,kix-interface-*.json, andkix-activation-index.json. You can build it withnix buildand pass the result tokix diff --from. Projects using the defaultkixbuilder omit this output because they evaluate into~/.cache/kix/storewithout building derivations in/nix/store. -
packages.<system>.cluster-<name>andchecks.<system>.*support Helm charts. Under the defaultkixbuilder, Kix renders Helm charts outside Nix, so plainnix buildandnix flake checkcannot build clusters that use Helm charts. Underbuilder = "nix",mkFlakerenders Helm charts through Nix, sopackages.<system>.cluster-<name>and the cluster checks (schema-cluster-<name>,rules-cluster-<name>, andpi-wiring-cluster-<name>) work with plainnix buildandnix flake check. -
legacyPackages.<system>.kixClustersNix.<name>is used bykix. AlongsidelegacyPackages.<system>.kixClusters.<name>,mkFlakeexposeskixClustersNix.<name>evaluated with the Nix Helm route. Whenbuilder = "nix", thekixCLI evaluateskixClustersNix.<name>sokix build,kix plan, andkix deployshare the exact derivations thatnix buildproduces. -
legacyPackages.<system>.kixLibholds the library for the builder. It haskixandpackages, as a cluster function receives them, with Helm charts rendered by Nix underbuilder = "nix". A flake that mergesmkFlakeinto a larger flake uses it for its own checks.
Running nix directly on a nix project
Section titled “Running nix directly on a nix project”When you invoke kix, it automatically passes --extra-experimental-features "nix-command flakes pipe-operators" to nix. When you run nix build or nix flake check directly from your shell, enable those three experimental features on the command line or in nix.conf:
❱ nix build --extra-experimental-features "nix-command flakes pipe-operators" .#cluster-prod-activation Restricting systems for nix flake check
Section titled “Restricting systems for nix flake check”By default, kix.lib.mkFlake generates outputs for four platforms: x86_64-linux, aarch64-linux, aarch64-darwin, and x86_64-darwin. nix flake check checks only the machine’s own platform unless you pass --all-systems.
If a cluster uses Helm charts under builder = "nix", evaluating that cluster imports the output of a chart-rendering derivation (import-from-derivation). With --all-systems, Nix must build those derivations for every platform the flake lists. On a machine without remote builders for the other platforms, nix flake check --all-systems fails when it tries to build a chart derivation for another platform.
To avoid needing builders for platforms you do not use, pass systems to kix.lib.mkFlake with only the systems your team and CI build on:
1{2 inputs = {3 nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";4 kixpkgs.url = "github:kix-run/kix";5 kixpkgs.inputs.nixpkgs.follows = "nixpkgs";6 };7
8 outputs = inputs:9 inputs.kixpkgs.lib.mkFlake {10 inherit inputs;11 systems = [ "x86_64-linux" ];12 clusters.prod = ./clusters/prod.nix;13 };14}Validation and error messages
Section titled “Validation and error messages”| Condition | Error message |
|---|---|
| Invalid TOML syntax | <path> is not valid TOML: line <N>: <reason> |
Unknown key in kix.toml | <path> has an unknown setting `<key>` (Kix <version> supports: builder, kix). Check the spelling, or upgrade Kix if the project needs a newer version |
kix is not a version, such as kix = 8 or kix = "latest" | <path> sets kix = <value>, which is not a Kix version. Write a minor such as kix = "0.8", an exact version such as kix = "0.8.3", or a prerelease such as kix = "0.9.0-rc.1" |
kix is a number, such as kix = 0.8 | <path> sets kix = 0.8 as a number. Write it in quotes: kix = "0.8" |
kix names Kix 0.7 or older, such as kix = "0.7" | <path> sets kix = "0.7", but Kix 0.7 and older cannot read this setting. Name Kix 0.8 or newer, or remove the line. |
kix names a version that is not installed, with KIX_AUTO_INSTALL=0 | This project needs Kix <kix> (kix.toml), and no Kix <kix> is installed. Automatic installs are off (KIX_AUTO_INSTALL=0). Run `kix self install <kix>`. |
Unknown builder value | <path> sets builder = "<value>", which is not a known builder (Kix <version> supports: kix, nix, remote). Check the spelling, or upgrade Kix if the project needs a newer version |
builder without quotes, such as builder = 3 | <path> sets builder to a number. Write the builder's name in quotes, such as builder = "kix" (Kix <version> supports: kix, nix, remote) |
builder = "remote" | <path> sets builder = "remote", but remote builders are not supported yet. Set builder = "kix", or remove the setting |
builder = "nix" in kix.toml, but kix.toml is not tracked by Git | <path> is not tracked by Git, so Nix ignores it. Run `git add kix.toml` |
builder = "nix" in kix.toml, but the flake publishes no legacyPackages.<system>.kixConfig | <path> sets builder = "nix", which this project's flake does not support. If flake.nix calls kixpkgs.lib.mkFlake, run `kix lib update` to update the Kix library in flake.lock. If flake.nix builds Kix outputs directly (for example with kixpkgs.lib.forPkgs), switch to kixpkgs.lib.mkFlake as shown in "Use mkFlake in a consuming repo" in the docs |
KIX_STORE_ROOT set when builder = "nix" | KIX_STORE_ROOT is set, but it does not apply to this project. The project's builder is "nix", which uses the machine's Nix and its store. Unset KIX_STORE_ROOT |
nix not found on PATH when builder = "nix" | this project uses the `nix` builder (`builder = "nix"` in kix.toml), but `nix` is not on PATH. Install Nix 2.24 or later, or remove `builder = "nix"` from kix.toml |
Nix older than 2.24 on PATH | this project uses the `nix` builder (`builder = "nix"` in kix.toml), which requires Nix 2.24 or later, but `nix --version` reported <version>. Upgrade Nix, or remove `builder = "nix"` from kix.toml |
Lix on PATH | this project uses the `nix` builder (`builder = "nix"` in kix.toml), which does not support Lix (`nix --version` reported <version>). Install Nix 2.24 or later, or remove `builder = "nix"` from kix.toml |