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.
Subcommands
Section titled “Subcommands”| Subcommand | Purpose |
|---|---|
set <KEY> | Resolve a tag in the registry and write the pin |
check | Verify every pin still resolves, by digest |
list | Show what the pin file holds |
Finding the pin file
Section titled “Finding the pin file”Every subcommand takes --pins-file <PATH>. Without it, Kix uses the first of:
pins.jsonin the working directory;pins.jsonin the directory named by--flake, when that is a local path;- the only pin file under the Git repository root (
pins.json, or a single*pins.jsonwhose header declaresmanagedBy).
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>
Section titled “kix pin set <KEY>”1kix pin set <KEY> [--option <PATH>] [--tag <TAG>] [--repository <REPO>]2 [--digest <DIGEST> | --no-resolve] [--source-rev <REV>]3 [--promoted-by <WHO>] [--note <TEXT>] [--init] [--force]4 [--pins-file <PATH>]| Argument or flag | Meaning |
|---|---|
<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-resolve | Write 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. |
--init | Create 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. |
--force | Rewrite 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
Section titled “kix pin check”1kix pin check [--key <KEY>]... [--source-rev <REV>] [--allow-unresolved]2 [--offline] [--pins-file <PATH>]| Flag | Meaning |
|---|---|
--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-unresolved | Report a pin with no digest as a warning instead of a failure. |
--offline | Check the file’s shape without contacting any registry. |
--pins-file <PATH> | Pin file to use. |
Each pin gets one verdict:
| Verdict | When |
|---|---|
ok | The digest exists and the tag still resolves to it, or --offline was given |
warn | The digest exists but the tag now points elsewhere or could not be checked, or the pin has no digest and --allow-unresolved was given |
fail | The digest could not be verified in the registry, the reference is invalid, or the pin has no digest |
The file
Section titled “The file”1{2 "version": 2,3 "managedBy": "kix pin",4 "images": {5 "web": { "repository": "ghcr.io/acme/web", "tag": "main", "digest": "sha256:…" }6 },7 "instances": {8 "monitoring/grafana": {9 "image": { "repository": "docker.io/grafana/grafana", "tag": "13.1.3", "digest": "sha256:…" }10 }11 }12}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
Section titled “kix pin list”1kix pin list [--pins-file <PATH>]Prints each pin’s reference, digest, source revision, who promoted it and when, and its note.
Output
Section titled “Output”-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.
Exit status
Section titled “Exit status”| Code | Meaning |
|---|---|
0 | set or list succeeded; check found no failure |
1 | check 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) |
Examples
Section titled “Examples”❱ 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"