`diff`
kix diff evaluates and builds a cluster, then compares the result with an
old side: the live cluster by default, or a directory passed with --from.
It never changes the cluster.
This page is hand-maintained. Check cli/kix-cli/src/cli.rs and
cli/kix-cli/src/commands/diff.rs when in doubt.
Synopsis
Section titled “Synopsis”kix diff <CLUSTER> [--from <DIR>] [-o text|json|yaml|markdown] [--flake <FLAKE>] [--context <CONTEXT>] [--no-cache]| Argument or flag | Meaning |
|---|---|
<CLUSTER> | Cluster name to evaluate and build from the flake. This is the new side of the comparison. |
--from <DIR> | Use a directory as the old side instead of the live cluster. See Old side. |
-o, --output | text (default), json, yaml (the JSON document as YAML), or markdown for pull request comments. |
--flake <FLAKE> | Flake to evaluate. Defaults to the current directory. |
--context <CONTEXT> | Kubeconfig context for the live cluster. Ignored with --from. |
--no-cache | Re-evaluate from Nix instead of reading the evaluation cache. |
Old side
Section titled “Old side”| Old side | How to select it | Needs cluster access |
|---|---|---|
| Live cluster | Omit --from | Yes |
| Previous build | --from <DIR> where <DIR> contains kix-packages.json, such as the result of nix build .#cluster-<name>-activation | No |
| Saved manifests | --from <DIR> where <DIR> holds YAML written by kix snapshot save or kix export --for audit | No |
For the live cluster, Kix reads only the fields it applied to each managed
resource. Kubernetes records which tool set each field through server-side
apply, and Kix keeps its own fields and drops the rest: server defaults,
status, fields set by controllers or kubectl, and the bookkeeping
annotations Kix writes after every apply. A cluster that matches its build
reports no differences.
A manifest directory must carry the Kix annotations that name each resource’s
package and identity hash. The default kix export mode strips them, so use
--for audit when the old side comes from an export.
Every old side goes through the same comparison. The live cluster and a snapshot of it produce the same report.
What is compared
Section titled “What is compared”The report is organised by package. Each package lands in one group:
| Group | Meaning |
|---|---|
| added | The package is in the build but not on the old side |
| removed | The package is on the old side but not in the build |
| changed | The package exists on both sides and at least one resource differs |
| unchanged | Every resource in the package matches |
Within a changed package, each resource is reported as one of:
| Resource line | Meaning |
|---|---|
+ added or - removed | The resource exists on one side only |
~ modified | The content differs. Text output shows each differing path with a unified diff of the values. |
~ via dependency | Only the identity hash changed, because a dependency of this resource changed. The content is the same. Text output marks these “via dependency”; JSON and Markdown call them dep-affected. |
Two more sections follow the packages:
- Cluster-level resources groups resources that belong to no package, such
as namespaces and custom resource definitions. Text output labels the
group
cluster-level resources; JSON uses the key_cluster. - Activation shows the old and new activation record names when they differ. A build whose content matches the old side keeps the same record name, so this line appears only alongside other changes.
When a stateful resource appears to have moved between packages or names, the report adds a “Stateful migrations detected” section. It is informational; Kix does not migrate data.
Output formats
Section titled “Output formats”A summary line, one block per namespace with each package’s status and
resource lines, the cluster-level group, the activation line, then either the
migration section or No differences found. Colour follows --no-color and
the NO_COLOR environment variable.
JSON and YAML
Section titled “JSON and YAML”One document with a packages object and, when present, a migration_pairs
array.
| Key | Content |
|---|---|
packages.summary | Counts of added, removed, changed, and unchanged packages |
packages.added, packages.removed | Arrays of { key, version, resources } |
packages.changed | Array of package changes: key, old_version, new_version, added_resources, removed_resources, modified_resources (each { resource, diff_count }), dep_affected_resources |
packages.cluster_level | The same shape as one changed package, with key _cluster, or null |
packages.activation | { old, new } record names, or null when unchanged |
packages.unchanged | Number of unchanged packages |
Resource identifiers have the form Kind/name@namespace. Package keys have
the form namespace/name.
Markdown
Section titled “Markdown”GitHub-flavoured Markdown: a plan summary, a <details> block per changed
package, the cluster-level and activation sections, and the migration section
when present.
Exit status
Section titled “Exit status”| Code | Meaning |
|---|---|
0 | No differences |
2 | At least one difference, or a stateful migration was detected |
1 | Evaluation, build, or cluster error |
The status is the same for every output format, so a CI job can write Markdown to a file and still branch on the result.