Skip to content
Install the CLI

Reference CLI

pin

kix pin reads and writes a pin file: committed JSON that records which digest each image reference resolved to. A cluster definition reads an image pin with pins.get "<key>". Kix applies an instance pin, keyed <namespace>/<instance>, to that instance’s image option itself. kix pin does not evaluate the flake or the cluster, so it works while evaluation is failing.

This page is hand-maintained. Check cli/kix-cli/src/cli.rs, cli/kix-cli/src/commands/pin.rs, and cli/kix-cli/src/commands/pin/locate.rs when in doubt.

SubcommandPurpose
set <KEY>Resolve a tag in the registry and write the pin
checkVerify every pin still resolves, by digest
listShow what the pin file holds

Every subcommand takes --pins-file <PATH>. Without it, Kix uses the first of:

  1. pins.json in the working directory;
  2. pins.json in the directory named by --flake, when that is a local path;
  3. the only pin file under the Git repository root (pins.json, or a single *pins.json whose header declares managedBy).

Several candidates at step 3 is an error; pass --pins-file. When Kix chose the file itself, it prints which one it used.

kix pin set <KEY> [--option <PATH>] [--tag <TAG>] [--repository <REPO>]
[--digest <DIGEST> | --no-resolve] [--source-rev <REV>]
[--promoted-by <WHO>] [--note <TEXT>] [--init] [--force]
[--pins-file <PATH>]
Argument or flagMeaning
<KEY>Pin name, as the cluster definition reads it with pins.get "<KEY>", or <namespace>/<instance> for an instance pin.
--option <PATH>For an instance pin, the image option it sets, as a path in the instance’s config such as sidecar.image. Default: image.
--tag <TAG>Tag to promote to. Required for a new pin; otherwise the existing tag is kept.
--repository <REPO>Repository including the registry host. Required for a new pin; otherwise the existing repository is kept.
--digest <DIGEST>Record this digest instead of asking the registry, for example in an air-gapped promotion. Use sha256: followed by 64 hexadecimal characters (lowercase or uppercase). Conflicts with --no-resolve.
--no-resolveWrite the pin without a digest. Kix then never checks that the tag exists, and prints a warning.
--source-rev <REV>Source revision the image was built from. kix pin check --source-rev compares against it. Kept from the existing pin when omitted.
--promoted-by <WHO>Who promoted it. Defaults to the CI run (ci:<workflow>#<run> on GitHub Actions, or the job URL on GitLab, Jenkins, and Buildkite), otherwise user@host.
--note <TEXT>A note for readers of the file. Kix never reads it. Re-pinning the same image keeps an existing note, while promoting to a different image drops the old note unless --note supplies a new one. --note "" clears it.
--initCreate the pin file, or add a pin name that is not in it yet. Without it, an unknown pin name or a missing file is an error. A new instance pin needs no --init, because evaluation refuses a pin for an instance the cluster does not have. A new file is created next to the flake.
--forceRewrite a pin file that kix pin did not write, discarding its comments and layout.
--pins-file <PATH>Pin file to use. See Finding the pin file.

Kix asks the registry for the tag’s manifest digest and refuses a tag that does not exist. When the repository, tag, digest, and source revision are unchanged, the file is not rewritten, so re-promoting the same image produces no commit. Registry credentials come from KIX_REGISTRY_USERNAME and KIX_REGISTRY_PASSWORD, then the Docker credential helpers and auths in the Docker config; anonymous access is tried when none apply.

kix pin check [--key <KEY>]... [--source-rev <REV>] [--allow-unresolved]
[--offline] [--pins-file <PATH>]
FlagMeaning
--key <KEY>Check only this pin, or every pin of the instance <namespace>/<instance>. Repeatable. Default: all pins.
--source-rev <REV>Fail when a pin records a different source revision. A short and a full SHA match when one is a prefix of the other. Pins that record no revision are skipped.
--allow-unresolvedReport a pin with no digest as a warning instead of a failure.
--offlineCheck the file’s shape without contacting any registry.
--pins-file <PATH>Pin file to use.

Each pin gets one verdict:

VerdictWhen
okThe digest exists and the tag still resolves to it, or --offline was given
warnThe digest exists but the tag now points elsewhere or could not be checked, or the pin has no digest and --allow-unresolved was given
failThe digest could not be verified in the registry, the reference is invalid, or the pin has no digest
{
"version": 2,
"managedBy": "kix pin",
"images": {
"web": { "repository": "ghcr.io/acme/web", "tag": "main", "digest": "sha256:…" }
},
"instances": {
"monitoring/grafana": {
"image": { "repository": "docker.io/grafana/grafana", "tag": "13.1.3", "digest": "sha256:…" }
}
}
}

kix pin set refuses to write a file Kix would refuse to read, such as a repository or tag outside the OCI reference grammar. It writes keys in sorted order, so a diff shows only what moved. A file with no instance pins is written as version 1 and without instances, which a Kix that reads only version 1 still reads. Each pin has the fields listed under kix.pins.

kix pin list [--pins-file <PATH>]

Prints each pin’s reference, digest, source revision, who promoted it and when, and its note.

-o json prints a JSON document for all three subcommands: for set, the pin file path, key, option (null for an image pin), resulting pin, whether it changed, and any dropped note (droppedNote); for check, each pin’s key, option, result, and message, the stale pins, and ok; for list, an object with images and instances, shaped as in the file. Any other -o value prints text.

CodeMeaning
0set or list succeeded; check found no failure
1check found a failed pin or a pin that is not current, or any subcommand hit an error (no pin file, unknown key, registry refused the tag)
❱ kix pin set web --repository ghcr.io/acme/web --tag v1.4.0 --init
❱ kix pin set web --tag v1.5.0 --source-rev "$GITHUB_SHA"
❱ kix pin check --source-rev "$GITHUB_SHA"