images.md RawHistoryFolder

Images Command

Push, list, and prune runtime/registry images.

gordon images

gordon images <subcommand>

Subcommands:

  • push - Tag and push an image to the Gordon registry (never deploys).
  • list - List runtime images and registry tags.
  • prune - Prune dangling runtime images and old registry tags.
  • tags - List registry tags for a specific repository.

Note: Images commands require remote mode (--remote + --token, or configured remotes).

gordon images push

Tag and push an image to the Gordon registry. Push transfers OCI content only: it never deploys. Deploy separately with gordon apps deploy after applying the manifest that references the pushed tag.

Synopsis

gordon images push [image] [options]

Arguments

Argument Description
[image] Image name to push (optional). If omitted, auto-detected from Dockerfile labels or current directory name

Options

Option Description
--build Build the image first using docker buildx
-f, --file Path to Dockerfile (default: ./Dockerfile, used with --build)
--platform Target platform for buildx (default: linux/amd64)
--build-arg Additional build args (repeatable, KEY=VALUE)
--tag Override pushed version tag (default: tag ref from CI, then git describe --tags --dirty)
--remote, -r Remote name or URL (e.g., prod, https://gordon.mydomain.com)
--token Authentication token for remote

Description

gordon images push tags the selected image for the Gordon registry and pushes it.

If you do not pass --remote and no active remote is configured, Gordon tries to infer the correct saved remote by probing your saved remotes for the image. It auto-selects only when exactly one remote matches. If multiple remotes match, or a saved remote cannot be probed safely, the command stops and asks you to use --remote explicitly.

The registry comes from the target Gordon instance. A bare image name such as myapp or myapp:v1 is pushed to the target's server.registry_domain, read from /admin/auth/verify (any admin-scoped token, no admin:status:read needed). A fully qualified reference such as registry.example.com/myapp must name that same registry; otherwise the push is rejected so Gordon credentials are never sent to another registry. Hosts listed in server.legacy_registry_domains are rejected too: use the canonical registry or a bare name.

Domain-style push targets are retired: push an image name, then gordon apps apply the manifest that references the pushed tag.

  • The version tag defaults to a CI tag ref (like refs/tags/v1.2.3) when available, then falls back to git describe --tags --dirty (for example v1.2.3-4-gabc1234 or v1.2.3-dirty). If no tag is found, latest is used.
  • When --build is set, the command builds with docker buildx build --load and injects VERSION, GIT_TAG, GIT_SHA, and BUILD_TIME into the build environment plus any --build-arg values. To use these in your Dockerfile, declare them with ARG (e.g., ARG VERSION) then reference via ENV or in build steps.
  • Use -f/--file to build from a Dockerfile outside the current directory root.
  • The version tag and latest are both pushed (unless the version is latest).

Authentication

When used with --remote, gordon images push authenticates in two ways:

  • Admin API (tag listing for inference): uses --token or $GORDON_TOKEN as Bearer token
  • Registry push: automatically exchanges the token for a short-lived (5 min) registry access token via /auth/token -- no docker login required

This means CI/CD pipelines only need a single secret (GORDON_TOKEN). The token needs push plus at least one admin:* scope, because the admin API rejects tokens without one; push,pull,admin:apps:read is the minimum. A push,pull token only works with docker login and docker push.

Version Auto-Detection

Gordon reads version tags from CI environment variables (in priority order):

CI System Variable Example
GitHub Actions $GITHUB_REF refs/tags/v1.2.0
GitHub Actions $GITHUB_REF_TYPE + $GITHUB_REF_NAME tag + v1.2.0
GitLab CI $CI_COMMIT_TAG v1.2.0
Azure DevOps $BUILD_SOURCEBRANCH refs/tags/v1.2.0
Any git describe --tags v1.2.3-4-gabc1234
Fallback - latest

Examples

# Build, push (auto-detect image name)
gordon images push --build --remote https://gordon.example.com

# Push an image
gordon images push myapp --remote https://gordon.example.com

# Push a fully qualified ref
gordon images push registry.example.com/myapp:v1.2.3 --build --remote https://gordon.example.com

# Push existing local image with an explicit tag
gordon images push myapp --tag v1.2.0 --remote https://gordon.example.com

# Build for ARM and pass build args
gordon images push myapp --build --platform linux/arm64 --build-arg CGO_ENABLED=0 --remote https://gordon.example.com

# Build from a custom Dockerfile path
gordon images push myapp --build -f docker/app/Dockerfile --remote https://gordon.example.com

# CI/CD usage (single env var, no docker login needed)
export GORDON_TOKEN="your-token"
gordon images push myapp --build --remote https://gordon.example.com

Notes

  • Remote mode required. See CLI Overview for targeting options.
  • --build requires Docker with Buildx. Docker Desktop includes it; on Linux, install the docker-buildx-plugin package.
  • Gordon uses native registry uploads instead of shelling out to docker push. Image layers are sent in 50MB chunks, which stays under Cloudflare's 100MB per-request limit so proxied pushes keep working. Keep the server's max_blob_chunk_size larger than the client chunk size; the default 95MB works out of the box.

gordon images list

gordon images list
gordon images list --json

Shows image rows with repository, tag, size, creation time, image id, and dangling status. Rows that exist only in the registry (not currently present in the runtime cache) are included with unavailable runtime fields shown as -.

Flags:

Flag Description
--json Output images as JSON

JSON Output

gordon images list --json
[
  {
    "repository": "myapp",
    "tag": "latest",
    "size": "148MB",
    "created_at": "2026-03-13T10:15:00Z",
    "image_id": "sha256:abc123def456",
    "dangling": false
  }
]

gordon images prune

gordon images prune [--dry-run] [--keep-releases <n>] [--dangling] [--registry] [--no-confirm]

By default, prune removes dangling runtime images and applies registry tag retention (keeping latest + 3 previous non-latest tags per repository). A confirmation prompt is shown before destructive operations.

A prune only ever deletes resources it can positively prove safe. Every other candidate is reported as protected or unknown and left in place; the command still succeeds. See Prune safety.

Flags:

Flag Default Description
--dry-run false Run the full inventory and planning, then report; nothing is deleted
--keep-releases 3 Number of previous non-latest tags to keep per repository (latest is always preserved)
--dangling false Restrict scope to dangling runtime images only
--registry false Restrict scope to registry tag retention only
--no-confirm false Skip the confirmation prompt

Scope resolution

  • No scope flags (default): both runtime and registry cleanup run.
  • --dangling: only runtime dangling images are pruned; registry is skipped.
  • --registry: only registry tag retention runs; runtime is skipped.
  • --dangling --registry: both scopes run (same as default, but explicit).

Retention semantics

  • latest is always preserved when present.
  • --keep-releases counts non-latest tags, ordered by most recent first.
  • A tag named by durable app state survives beyond the retention window.
  • --keep-releases=0 skips registry tag and blob cleanup entirely; dangling runtime prune still runs.

Prune safety

Gordon prunes by ownership, not by name or age. Each candidate gets one verdict:

Verdict Meaning
eligible Every fact needed to prove the resource safe was read completely, and no durable record claims it. It is deleted.
protected A durable fact claims it: a desired or active app service (including stopped apps), a recovery inhibition, a staged or committed apply intent, an unfinished operation journal entry, container use, a pending upload, an ownership record, or the OCI closure of any of those. It survives.
unknown A fact needed to prove it safe was missing, unreadable, or unsupported. It survives.

Runtime images used by any container, running or stopped, always survive. Registry blobs reachable from a retained or protected manifest survive, including blobs shared with another tag. When a retained manifest cannot be read, the blobs whose safety depended on it become unknown rather than eligible.

Both --dry-run and the executed prune return the same report: the verdict counts, the deleted identities, any deletion failures, every inventory gap, and the skipped candidates with their reason codes. A prune that deletes nothing is a success.

gordon images tags

gordon images tags <repository>
gordon images tags <repository> --json

Lists all tags in the Gordon registry for the specified repository.

Flags:

Flag Description
--json Output repository and tags as JSON

JSON Output

gordon images tags myapp --json
{
  "repository": "myapp",
  "tags": ["latest", "v1.2.0", "v1.1.0"]
}

Examples

# List images
gordon images list

# Prune everything with defaults (dangling + registry, keep latest + 3)
gordon images prune

# List tags for a repository
gordon images tags myapp

# Prune dangling runtime images only
gordon images prune --dangling

# Prune registry tags only, keeping latest + 5 previous
gordon images prune --registry --keep-releases 5

# Inspect what prune would remove without applying
# (also lists every skipped candidate with its reason)
gordon images prune --dry-run

# Skip confirmation prompt
gordon images prune --no-confirm

Required Permissions

  • The list subcommand requires admin:status:read.
  • The prune subcommand requires admin:config:write.
  • The tags subcommand requires admin:status:read.
source
1# Images Command
2
3Push, list, and prune runtime/registry images.
4
5## gordon images
6
7```bash
8gordon images <subcommand>
9```
10
11Subcommands:
12
13- `push` - Tag and push an image to the Gordon registry (never deploys).
14- `list` - List runtime images and registry tags.
15- `prune` - Prune dangling runtime images and old registry tags.
16- `tags` - List registry tags for a specific repository.
17
18> **Note:** Images commands require remote mode (`--remote` + `--token`, or configured remotes).
19
20## gordon images push
21
22Tag and push an image to the Gordon registry. Push transfers OCI content
23only: it never deploys. Deploy separately with `gordon apps deploy` after
24applying the manifest that references the pushed tag.
25
26### Synopsis
27
28```bash
29gordon images push [image] [options]
30```
31
32### Arguments
33
34| Argument | Description |
35|----------|-------------|
36| `[image]` | Image name to push (optional). If omitted, auto-detected from Dockerfile labels or current directory name |
37
38### Options
39
40| Option | Description |
41|--------|-------------|
42| `--build` | Build the image first using `docker buildx` |
43| `-f, --file` | Path to Dockerfile (default: `./Dockerfile`, used with `--build`) |
44| `--platform` | Target platform for buildx (default: `linux/amd64`) |
45| `--build-arg` | Additional build args (repeatable, `KEY=VALUE`) |
46| `--tag` | Override pushed version tag (default: tag ref from CI, then `git describe --tags --dirty`) |
47| `--remote, -r` | Remote name or URL (e.g., prod, https://gordon.mydomain.com) |
48| `--token` | Authentication token for remote |
49
50### Description
51
52`gordon images push` tags the selected image for the Gordon registry and pushes it.
53
54If you do not pass `--remote` and no active remote is configured, Gordon tries to
55infer the correct saved remote by probing your saved remotes for the image.
56It auto-selects only when exactly one remote matches. If multiple remotes match,
57or a saved remote cannot be probed safely, the command stops and asks you to use
58`--remote` explicitly.
59
60The registry comes from the target Gordon instance. A bare image name such as
61`myapp` or `myapp:v1` is pushed to the target's `server.registry_domain`, read
62from `/admin/auth/verify` (any admin-scoped token, no `admin:status:read`
63needed). A fully qualified
64reference such as `registry.example.com/myapp` must name that same registry;
65otherwise the push is rejected so Gordon credentials are never sent to another
66registry. Hosts listed in `server.legacy_registry_domains` are rejected too: use
67the canonical registry or a bare name.
68
69Domain-style push targets are retired: push an image name, then
70`gordon apps apply` the manifest that references the pushed tag.
71
72- The version tag defaults to a CI tag ref (like `refs/tags/v1.2.3`) when available,
73  then falls back to `git describe --tags --dirty` (for example
74  `v1.2.3-4-gabc1234` or `v1.2.3-dirty`). If no tag is found, `latest` is used.
75- When `--build` is set, the command builds with `docker buildx build --load`
76  and injects `VERSION`, `GIT_TAG`, `GIT_SHA`, and `BUILD_TIME` into the build
77  environment plus any `--build-arg` values. To use these in your Dockerfile,
78  declare them with `ARG` (e.g., `ARG VERSION`) then reference via `ENV` or
79  in build steps.
80- Use `-f/--file` to build from a Dockerfile outside the current directory root.
81- The version tag and `latest` are both pushed (unless the version is `latest`).
82
83### Authentication
84
85When used with `--remote`, gordon images push authenticates in two ways:
86
87- **Admin API** (tag listing for inference): uses `--token` or `$GORDON_TOKEN` as Bearer token
88- **Registry push**: automatically exchanges the token for a short-lived (5 min) registry access token via `/auth/token` -- no `docker login` required
89
90This means CI/CD pipelines only need a single secret (`GORDON_TOKEN`). The token
91needs `push` plus at least one `admin:*` scope, because the admin API rejects
92tokens without one; `push,pull,admin:apps:read` is the minimum. A `push,pull`
93token only works with `docker login` and `docker push`.
94
95### Version Auto-Detection
96
97Gordon reads version tags from CI environment variables (in priority order):
98
99| CI System | Variable | Example |
100|-----------|----------|---------|
101| GitHub Actions | `$GITHUB_REF` | `refs/tags/v1.2.0` |
102| GitHub Actions | `$GITHUB_REF_TYPE` + `$GITHUB_REF_NAME` | `tag` + `v1.2.0` |
103| GitLab CI | `$CI_COMMIT_TAG` | `v1.2.0` |
104| Azure DevOps | `$BUILD_SOURCEBRANCH` | `refs/tags/v1.2.0` |
105| Any | `git describe --tags` | `v1.2.3-4-gabc1234` |
106| Fallback | - | `latest` |
107
108### Examples
109
110```bash
111# Build, push (auto-detect image name)
112gordon images push --build --remote https://gordon.example.com
113
114# Push an image
115gordon images push myapp --remote https://gordon.example.com
116
117# Push a fully qualified ref
118gordon images push registry.example.com/myapp:v1.2.3 --build --remote https://gordon.example.com
119
120# Push existing local image with an explicit tag
121gordon images push myapp --tag v1.2.0 --remote https://gordon.example.com
122
123# Build for ARM and pass build args
124gordon images push myapp --build --platform linux/arm64 --build-arg CGO_ENABLED=0 --remote https://gordon.example.com
125
126# Build from a custom Dockerfile path
127gordon images push myapp --build -f docker/app/Dockerfile --remote https://gordon.example.com
128
129# CI/CD usage (single env var, no docker login needed)
130export GORDON_TOKEN="your-token"
131gordon images push myapp --build --remote https://gordon.example.com
132```
133
134### Notes
135
136- Remote mode required. See [CLI Overview](./index.md) for targeting options.
137- `--build` requires Docker with Buildx. Docker Desktop includes it; on Linux,
138  install the `docker-buildx-plugin` package.
139- Gordon uses native registry uploads instead of shelling out to `docker push`.
140  Image layers are sent in 50MB chunks, which stays under Cloudflare's 100MB
141  per-request limit so proxied pushes keep working. Keep the server's
142  `max_blob_chunk_size` larger than the client chunk size; the default `95MB`
143  works out of the box.
144
145## gordon images list
146
147```bash
148gordon images list
149gordon images list --json
150```
151
152Shows image rows with repository, tag, size, creation time, image id, and dangling status.
153Rows that exist only in the registry (not currently present in the runtime cache) are included with unavailable runtime fields shown as `-`.
154
155Flags:
156
157| Flag | Description |
158|------|-------------|
159| `--json` | Output images as JSON |
160
161### JSON Output
162
163```bash
164gordon images list --json
165```
166
167```json
168[
169  {
170    "repository": "myapp",
171    "tag": "latest",
172    "size": "148MB",
173    "created_at": "2026-03-13T10:15:00Z",
174    "image_id": "sha256:abc123def456",
175    "dangling": false
176  }
177]
178```
179
180## gordon images prune
181
182```bash
183gordon images prune [--dry-run] [--keep-releases <n>] [--dangling] [--registry] [--no-confirm]
184```
185
186By default, prune removes dangling runtime images **and** applies registry tag retention (keeping `latest` + 3 previous non-`latest` tags per repository). A confirmation prompt is shown before destructive operations.
187
188A prune only ever deletes resources it can positively prove safe. Every other candidate is reported as `protected` or `unknown` and left in place; the command still succeeds. See [Prune safety](#prune-safety).
189
190Flags:
191
192| Flag | Default | Description |
193|------|---------|-------------|
194| `--dry-run` | `false` | Run the full inventory and planning, then report; nothing is deleted |
195| `--keep-releases` | `3` | Number of previous non-`latest` tags to keep per repository (`latest` is always preserved) |
196| `--dangling` | `false` | Restrict scope to dangling runtime images only |
197| `--registry` | `false` | Restrict scope to registry tag retention only |
198| `--no-confirm` | `false` | Skip the confirmation prompt |
199
200### Scope resolution
201
202- **No scope flags** (default): both runtime and registry cleanup run.
203- **`--dangling`**: only runtime dangling images are pruned; registry is skipped.
204- **`--registry`**: only registry tag retention runs; runtime is skipped.
205- **`--dangling --registry`**: both scopes run (same as default, but explicit).
206
207### Retention semantics
208
209- `latest` is always preserved when present.
210- `--keep-releases` counts non-`latest` tags, ordered by most recent first.
211- A tag named by durable app state survives beyond the retention window.
212- `--keep-releases=0` skips registry tag and blob cleanup entirely; dangling runtime prune still runs.
213
214## Prune safety
215
216Gordon prunes by ownership, not by name or age. Each candidate gets one verdict:
217
218| Verdict | Meaning |
219|---------|---------|
220| `eligible` | Every fact needed to prove the resource safe was read completely, and no durable record claims it. It is deleted. |
221| `protected` | A durable fact claims it: a desired or active app service (including stopped apps), a recovery inhibition, a staged or committed apply intent, an unfinished operation journal entry, container use, a pending upload, an ownership record, or the OCI closure of any of those. It survives. |
222| `unknown` | A fact needed to prove it safe was missing, unreadable, or unsupported. It survives. |
223
224Runtime images used by any container, running or stopped, always survive. Registry blobs reachable from a retained or protected manifest survive, including blobs shared with another tag. When a retained manifest cannot be read, the blobs whose safety depended on it become `unknown` rather than eligible.
225
226Both `--dry-run` and the executed prune return the same report: the verdict counts, the deleted identities, any deletion failures, every inventory gap, and the skipped candidates with their reason codes. A prune that deletes nothing is a success.
227
228## gordon images tags
229
230```bash
231gordon images tags <repository>
232gordon images tags <repository> --json
233```
234
235Lists all tags in the Gordon registry for the specified repository.
236
237Flags:
238
239| Flag | Description |
240|------|-------------|
241| `--json` | Output repository and tags as JSON |
242
243### JSON Output
244
245```bash
246gordon images tags myapp --json
247```
248
249```json
250{
251  "repository": "myapp",
252  "tags": ["latest", "v1.2.0", "v1.1.0"]
253}
254```
255
256## Examples
257
258```bash
259# List images
260gordon images list
261
262# Prune everything with defaults (dangling + registry, keep latest + 3)
263gordon images prune
264
265# List tags for a repository
266gordon images tags myapp
267
268# Prune dangling runtime images only
269gordon images prune --dangling
270
271# Prune registry tags only, keeping latest + 5 previous
272gordon images prune --registry --keep-releases 5
273
274# Inspect what prune would remove without applying
275# (also lists every skipped candidate with its reason)
276gordon images prune --dry-run
277
278# Skip confirmation prompt
279gordon images prune --no-confirm
280```
281
282## Required Permissions
283
284- The `list` subcommand requires `admin:status:read`.
285- The `prune` subcommand requires `admin:config:write`.
286- The `tags` subcommand requires `admin:status:read`.
287
288## Related
289
290- [CLI Commands](./index.md)
291- [Images Configuration](../config/images.md)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close