v3.3.0 b164fe9

apps.md RawHistoryFolder

Apps Commands

Validate, persist, inspect, and operate applications.

All mutations are executed by the daemon through the admin API. Without a reachable daemon the commands fail with daemon-unavailable instead of writing locally. Mutations are idempotent: every request carries a client-generated key, and the daemon binds that key to the exact request. Repeating a key replays the recorded result; reusing it for a different request is refused. An interrupted operation is never executed twice, so an ambiguous outcome is re-queried by key before any retry (never retry under a fresh key). Unknown apps are reported as app not found and create no state.

Local and remote targets

With no --remote/GORDON_REMOTE selected, commands discover the daemon's owner-only administration socket. The CLI checks $XDG_RUNTIME_DIR/gordon/admin.sock when set, then /run/user/<uid>/gordon/admin.sock, then ~/.gordon/run/admin.sock. It accepts only a safe owner-owned socket. This works with auth.enabled=false: the socket carries no bearer token and grants the local-owner principal only app administration and app log reads. An explicit remote is authoritative and never falls back to the socket. See Local-only Mode.

gordon apps

Subcommands

Subcommand Description
apply Validate and persist an app manifest
operations Inspect app operation journals
list List applications
show Show desired and active state for an app
diff Show the normalized desired-vs-active diff
secrets Manage app secret values
deploy Activate an app revision
restart Restart an app from pinned digests
stop Stop an app (preserves all data)
start Start a stopped app from active state
remove Remove app workloads (volumes and secrets are retained)
status Show effective vs observed state for an app
logs Show logs for an app service

gordon apps apply

gordon apps apply --file blog.toml [--dry-run] [--deploy] [--json]

Validates a manifest file and persists it as desired state (or dry-runs). With --deploy, chains exactly the accepted revision into a deploy after persistence succeeds; the two outcomes are reported separately because a deploy may fail after the apply succeeded.

When the daemon accepts the deploy asynchronously (HTTP 202), the command reuses the same by-key watch as gordon apps deploy: it polls the operation journal until terminal, prints progress only when the operation or step state changes, and never reissues the deploy. A terminal partial/failed deploy exits nonzero while still reporting the successful apply. Ctrl-C stops only local polling: the daemon-side operation keeps running and the command prints how to resume it.

With --json, stdout carries exactly one final combined document after the deploy reaches a terminal state:

{
  "apply": { "app": "blog", "resulting_revision": "rev-b", "pending": true },
  "deploy": { "op": "op-1", "app": "blog", "status": "success", "outcome": "success" }
}

No initial running document is emitted, and progress, transient warnings, and Ctrl-C resume guidance go to stderr.

--dry-run and --deploy cannot be combined.


gordon apps list

gordon apps list [--json]

Lists applications with one row per app. States are applied when no revision is active, pending when desired state awaits activation, stopped when stopped intent is set, and otherwise active. A non-success last operation is appended to active in parentheses.


gordon apps show

gordon apps show APP [--json]

Shows desired revision and acceptance status, pending state, per-service effective revision, container, digest, and single-writer mark (see apps status), the resources the app owns (volumes, secret paths, image references — never secret values), stopped intent, and the last operation with its outcome.


gordon apps operations show

gordon apps operations show APP --key KEY [--json]

Recovers one operation journal entry by its client-generated request key. --key is required. Use it to re-query an ambiguous mutation outcome before retrying: repeating the same key replays the recorded result, while a key reused for a different request is refused.

Flags

Flag Description
--key Request key (required)
--json Output as JSON

gordon apps operations watch

gordon apps operations watch APP --key KEY [--json]

Polls the operation journal by request key until the operation reaches a terminal state, then renders the terminal journal. It never reissues the mutation, so it is the safe way to resume after an interrupted deploy or to follow an operation started elsewhere. Progress is printed only when the operation or step state changes; unchanged polls are not repeated.

Exit status is nonzero for terminal partial/failed outcomes and for an interrupted watch. Ctrl-C stops only local polling: the daemon-side operation is not cancelled and keeps running, and the command prints the command to resume. With --json, stdout carries exactly one final document and progress goes to stderr.

Flags

Flag Description
--key Request key (required)
--json Output as JSON

gordon apps diff

gordon apps diff APP [--json]

Shows the normalized desired-vs-active diff (added, removed, changed).


gordon apps secrets

Values are accepted via KEY=VALUE arguments (discouraged: shell history) or stdin. Names must already exist in desired or active state. Only key names are ever echoed back — never values. Secrets are service-scoped: --service is required for set and delete, and optional for list where it filters to one service.

gordon apps secrets list

gordon apps secrets list APP [--service SVC] [--json]

Lists registration metadata for an app's secrets — service, key, name, source, and presence — never secret values. --service filters to one service.

Flags

Flag Description
--service Filter by service
--json Output as JSON

JSON Output

[
  {"service": "web", "key": "DATABASE_URL", "name": "app_database_url", "source": "desired", "presence": "unknown"}
]

gordon apps secrets set

gordon apps secrets set APP --service SVC KEY=VALUE… [--json]
gordon apps secrets set APP --service SVC --stdin [--json]
gordon apps secrets set APP --service SVC --stdin --key KEY [--json]

Reads values in one of three ways:

  • KEY=VALUE arguments: the value must be a single line of 1–65536 bytes.
  • --stdin: reads KEY=VALUE lines; blank and whitespace-only lines are ignored and every non-blank value byte is preserved.
  • --stdin --key KEY: reads one raw value for KEY; a single trailing newline is stripped and the value must still be a single non-empty line.

--key requires --stdin and cannot be combined with KEY=VALUE arguments. An empty value is rejected, so KEY= is invalid.

The service and its secret keys must be declared in the manifest and applied first: gordon apps apply → gordon apps secrets set → gordon apps deploy.

Running containers keep the values they were created with. Apply new values with gordon apps deploy APP --service SVC: deploy sees the changed secret and recreates the service. restart does not apply new values.

Flags

Flag Description
--service Service the secrets belong to (required)
--stdin Read KEY=VALUE lines, or one raw value with --key
--key Secret key for single-value stdin mode
--json Output as JSON

JSON Output

{"app": "blog", "service": "web", "keys": ["DATABASE_URL"]}

gordon apps secrets delete

gordon apps secrets delete APP KEY --service SVC [--json]

Deletes the registered value for KEY.

Flags

Flag Description
--service Service the secret belongs to (required)
--json Output as JSON

gordon apps deploy

gordon apps deploy APP [--revision REV] [--service SVC | --all] [--json]

Activates a revision (default: desired head). An app with several services needs --service NAME (one service) or --all (every service); without either, the command fails before any change and lists the services. A single-service app needs neither. apps apply --deploy always deploys every service.

Flag Description
--revision REV Revision to activate (default: desired head)
--service NAME Deploy one service only
--all Deploy every service
--json Output as JSON

Deploy is the only command that applies changes. It recreates a service when its image digest, spec, app environment, or secret values changed. A new image behind the same tag (for example latest) has a new digest and is deployed. A service already running with all of these unchanged keeps its container and is reported unchanged. Services with host binds or devices are always replaced, so bind and device policy changes apply on deploy. A service the revision no longer declares is retired during deploy and reported removed; its volumes and secrets are retained.

Fail-fast across services: the first failure stops the deploy, successful services are preserved, later services stay unchanged.

When the daemon accepts the deploy and runs the two phases in the background (HTTP 202), the command polls the operation journal by key until it is terminal and prints concise progress only when the operation or step state changes. It never reissues the mutation. In --json mode stdout carries one final document and progress goes to stderr. Ctrl-C stops only local polling (the daemon-side operation keeps running) and prints the gordon apps operations watch command to resume.


gordon apps restart

gordon apps restart APP [--service SVC | --all] [--json]

Restarts the same container. Nothing is applied: new secret values, env, image, or config need gordon apps deploy. Traffic is withdrawn, the container restarts, readiness is checked, and traffic returns. If the container no longer exists, restart rebuilds it from its pinned digest. An app with several services needs --service NAME or --all.


gordon apps stop

gordon apps stop APP [--json]

Persists the durable stopped intent and stops exact containers. All data (volumes, secrets) is preserved. Stopped apps stay stopped across reboot.


gordon apps start

gordon apps start APP [--json]

Clears the stopped intent and ensures running from active state.


gordon apps remove

gordon apps remove APP [--json]

Withdraws workloads. Volumes and secrets are retained as owned orphans under the old internal UUID; removing frees the name but never implicitly attaches retained resources to a new app reusing the name. Each withdrawn service is reported removed.

There is deliberately no purge: destructive volume deletion requires a separately accepted destructive-action contract.


gordon apps status

gordon apps status APP [--json]

Shows effective vs observed state per service.

A service line ends with single-writer when the service has volumes or binds (restart_unsafe: true in --json), and a legend line follows the list. The mark is informational and needs no action. When such a service is replaced, Gordon durably blocks boot and periodic recovery from restarting the old container, so it can never write to the same data as its replacement. Every service is replaced stop-before-start; see Updates. apps show uses the same mark.


gordon apps logs

gordon apps logs APP [--service SVC] [--follow] [--tail N] [--json]

Streams logs for a service in the app's active deployment. The app name and --service are the only accepted identity: domains and raw container IDs are never accepted. --service is required when the app has several services.


Workflow Example

# Push the image first (OCI transfer only)
gordon images push myapp --build --remote prod

# Apply the manifest that references the pushed tag
gordon apps apply --file blog.toml --remote prod

# Write secret values for registered names
gordon apps secrets set blog --service web DATABASE_URL=... --remote prod

# Deploy the accepted revision (polls 202 operations to terminal)
gordon apps deploy blog --remote prod

# Resume watching an interrupted or externally started operation
gordon apps operations watch blog --key <operation-key> --remote prod

# Inspect
gordon apps show blog --remote prod
gordon apps status blog --remote prod
source
1# Apps Commands
2
3Validate, persist, inspect, and operate applications.
4
5All mutations are executed by the daemon through the admin API.
6Without a reachable daemon the commands fail with `daemon-unavailable`
7instead of writing locally. Mutations are idempotent: every request carries a
8client-generated key, and the daemon binds that key to the exact request.
9Repeating a key replays the recorded result; reusing it for a different request
10is refused. An interrupted operation is never executed twice, so an ambiguous
11outcome is re-queried by key before any retry (never retry under a fresh
12key). Unknown apps are reported as `app not found` and create no state.
13
14## Local and remote targets
15
16With no `--remote`/`GORDON_REMOTE` selected, commands discover the daemon's
17owner-only administration socket. The CLI checks `$XDG_RUNTIME_DIR/gordon/admin.sock`
18when set, then `/run/user/<uid>/gordon/admin.sock`, then `~/.gordon/run/admin.sock`.
19It accepts only a safe owner-owned socket. This works with `auth.enabled=false`:
20the socket carries no bearer token and grants the `local-owner` principal only
21app administration and app log reads. An explicit remote is authoritative and
22never falls back to the socket.
23See [Local-only Mode](../config/auth.md#local-only-mode).
24
25## gordon apps
26
27### Subcommands
28
29| Subcommand | Description |
30|------------|-------------|
31| `apply` | Validate and persist an app manifest |
32| `operations` | Inspect app operation journals |
33| `list` | List applications |
34| `show` | Show desired and active state for an app |
35| `diff` | Show the normalized desired-vs-active diff |
36| `secrets` | Manage app secret values |
37| `deploy` | Activate an app revision |
38| `restart` | Restart an app from pinned digests |
39| `stop` | Stop an app (preserves all data) |
40| `start` | Start a stopped app from active state |
41| `remove` | Remove app workloads (volumes and secrets are retained) |
42| `status` | Show effective vs observed state for an app |
43| `logs` | Show logs for an app service |
44
45---
46
47## gordon apps apply
48
49```bash
50gordon apps apply --file blog.toml [--dry-run] [--deploy] [--json]
51```
52
53Validates a manifest file and persists it as desired state (or dry-runs).
54With `--deploy`, chains exactly the accepted revision into a deploy after
55persistence succeeds; the two outcomes are reported separately because a
56deploy may fail after the apply succeeded.
57
58When the daemon accepts the deploy asynchronously (HTTP 202), the command
59reuses the same by-key watch as `gordon apps deploy`: it polls the
60operation journal until terminal, prints progress only when the operation
61or step state changes, and never reissues the deploy. A terminal
62`partial`/`failed` deploy exits nonzero while still reporting the
63successful apply. Ctrl-C stops only local polling: the daemon-side
64operation keeps running and the command prints how to resume it.
65
66With `--json`, stdout carries exactly one final combined document after the
67deploy reaches a terminal state:
68
69```json
70{
71  "apply": { "app": "blog", "resulting_revision": "rev-b", "pending": true },
72  "deploy": { "op": "op-1", "app": "blog", "status": "success", "outcome": "success" }
73}
74```
75
76No initial running document is emitted, and progress, transient warnings,
77and Ctrl-C resume guidance go to stderr.
78
79`--dry-run` and `--deploy` cannot be combined.
80
81---
82
83## gordon apps list
84
85```bash
86gordon apps list [--json]
87```
88
89Lists applications with one row per app. States are `applied` when no revision is active, `pending` when desired state awaits activation, `stopped` when stopped intent is set, and otherwise `active`. A non-success last operation is appended to `active` in parentheses.
90
91---
92
93## gordon apps show
94
95```bash
96gordon apps show APP [--json]
97```
98
99Shows desired revision and acceptance status, pending state, per-service
100effective revision, container, digest, and `single-writer` mark (see
101[apps status](#gordon-apps-status)), the resources the
102app owns (volumes, secret paths, image references — never secret values),
103stopped intent, and the last operation with its outcome.
104
105---
106
107## gordon apps operations show
108
109```bash
110gordon apps operations show APP --key KEY [--json]
111```
112
113Recovers one operation journal entry by its client-generated request key.
114`--key` is required. Use it to re-query an ambiguous mutation outcome before
115retrying: repeating the same key replays the recorded result, while a key
116reused for a different request is refused.
117
118### Flags
119
120| Flag | Description |
121|------|-------------|
122| `--key` | Request key (required) |
123| `--json` | Output as JSON |
124
125---
126
127## gordon apps operations watch
128
129```bash
130gordon apps operations watch APP --key KEY [--json]
131```
132
133Polls the operation journal by request key until the operation reaches a
134terminal state, then renders the terminal journal. It never reissues the
135mutation, so it is the safe way to resume after an interrupted deploy or to
136follow an operation started elsewhere. Progress is printed only when the
137operation or step state changes; unchanged polls are not repeated.
138
139Exit status is nonzero for terminal `partial`/`failed` outcomes and for an
140interrupted watch. Ctrl-C stops only local polling: the daemon-side
141operation is not cancelled and keeps running, and the command prints the
142command to resume. With `--json`, stdout carries exactly one final document
143and progress goes to stderr.
144
145### Flags
146
147| Flag | Description |
148|------|-------------|
149| `--key` | Request key (required) |
150| `--json` | Output as JSON |
151
152---
153
154## gordon apps diff
155
156```bash
157gordon apps diff APP [--json]
158```
159
160Shows the normalized desired-vs-active diff (`added`, `removed`, `changed`).
161
162---
163
164## gordon apps secrets
165
166Values are accepted via `KEY=VALUE` arguments (discouraged: shell history) or
167stdin. Names must already exist in desired or active state. Only key names are
168ever echoed back — never values. Secrets are service-scoped: `--service` is
169required for `set` and `delete`, and optional for `list` where it filters to
170one service.
171
172### gordon apps secrets list
173
174```bash
175gordon apps secrets list APP [--service SVC] [--json]
176```
177
178Lists registration metadata for an app's secrets — service, key, name, source,
179and presence — never secret values. `--service` filters to one service.
180
181#### Flags
182
183| Flag | Description |
184|------|-------------|
185| `--service` | Filter by service |
186| `--json` | Output as JSON |
187
188#### JSON Output
189
190```json
191[
192  {"service": "web", "key": "DATABASE_URL", "name": "app_database_url", "source": "desired", "presence": "unknown"}
193]
194```
195
196### gordon apps secrets set
197
198```bash
199gordon apps secrets set APP --service SVC KEY=VALUE… [--json]
200gordon apps secrets set APP --service SVC --stdin [--json]
201gordon apps secrets set APP --service SVC --stdin --key KEY [--json]
202```
203
204Reads values in one of three ways:
205
206- `KEY=VALUE` arguments: the value must be a single line of 1–65536 bytes.
207- `--stdin`: reads `KEY=VALUE` lines; blank and whitespace-only lines are
208  ignored and every non-blank value byte is preserved.
209- `--stdin --key KEY`: reads one raw value for `KEY`; a single trailing newline
210  is stripped and the value must still be a single non-empty line.
211
212`--key` requires `--stdin` and cannot be combined with `KEY=VALUE` arguments.
213An empty value is rejected, so `KEY=` is invalid.
214
215The service and its secret keys must be declared in the manifest and applied
216first: `gordon apps apply` → `gordon apps secrets set` → `gordon apps deploy`.
217
218Running containers keep the values they were created with. Apply new values
219with `gordon apps deploy APP --service SVC`: deploy sees the changed secret and
220recreates the service. `restart` does not apply new values.
221
222#### Flags
223
224| Flag | Description |
225|------|-------------|
226| `--service` | Service the secrets belong to (required) |
227| `--stdin` | Read `KEY=VALUE` lines, or one raw value with `--key` |
228| `--key` | Secret key for single-value stdin mode |
229| `--json` | Output as JSON |
230
231#### JSON Output
232
233```json
234{"app": "blog", "service": "web", "keys": ["DATABASE_URL"]}
235```
236
237### gordon apps secrets delete
238
239```bash
240gordon apps secrets delete APP KEY --service SVC [--json]
241```
242
243Deletes the registered value for `KEY`.
244
245#### Flags
246
247| Flag | Description |
248|------|-------------|
249| `--service` | Service the secret belongs to (required) |
250| `--json` | Output as JSON |
251
252---
253
254## gordon apps deploy
255
256```bash
257gordon apps deploy APP [--revision REV] [--service SVC | --all] [--json]
258```
259
260Activates a revision (default: desired head). An app with several services
261needs `--service NAME` (one service) or `--all` (every service); without
262either, the command fails before any change and lists the services. A
263single-service app needs neither. `apps apply --deploy` always deploys every
264service.
265
266| Flag | Description |
267|------|-------------|
268| `--revision REV` | Revision to activate (default: desired head) |
269| `--service NAME` | Deploy one service only |
270| `--all` | Deploy every service |
271| `--json` | Output as JSON |
272
273Deploy is the only command that applies changes. It recreates a service
274when its image digest, spec, app environment, or secret values changed. A
275new image behind the same tag (for example `latest`) has a new digest and is
276deployed. A service already running with all of these unchanged keeps its
277container and is reported `unchanged`. Services with host binds or devices
278are always replaced, so bind and device policy changes apply on deploy.
279A service the revision no longer declares is retired during deploy and
280reported `removed`; its volumes and secrets are retained.
281
282Fail-fast across services:
283the first failure stops the deploy, successful services are preserved,
284later services stay unchanged.
285
286When the daemon accepts the deploy and runs the two phases in the
287background (HTTP 202), the command polls the operation journal by key until
288it is terminal and prints concise progress only when the operation or step
289state changes. It never reissues the mutation. In `--json` mode stdout
290carries one final document and progress goes to stderr. Ctrl-C stops only
291local polling (the daemon-side operation keeps running) and prints the
292`gordon apps operations watch` command to resume.
293
294---
295
296## gordon apps restart
297
298```bash
299gordon apps restart APP [--service SVC | --all] [--json]
300```
301
302Restarts the same container. Nothing is applied: new secret values, env,
303image, or config need `gordon apps deploy`. Traffic is withdrawn, the
304container restarts, readiness is checked, and traffic returns. If the
305container no longer exists, restart rebuilds it from its pinned digest. An
306app with several services needs `--service NAME` or `--all`.
307
308---
309
310## gordon apps stop
311
312```bash
313gordon apps stop APP [--json]
314```
315
316Persists the durable stopped intent and stops exact containers.
317All data (volumes, secrets) is preserved. Stopped apps stay stopped
318across reboot.
319
320---
321
322## gordon apps start
323
324```bash
325gordon apps start APP [--json]
326```
327
328Clears the stopped intent and ensures running from active state.
329
330---
331
332## gordon apps remove
333
334```bash
335gordon apps remove APP [--json]
336```
337
338Withdraws workloads. Volumes and secrets are retained as owned orphans
339under the old internal UUID; removing frees the name but never implicitly
340attaches retained resources to a new app reusing the name. Each withdrawn
341service is reported `removed`.
342
343There is deliberately no `purge`: destructive volume deletion requires a
344separately accepted destructive-action contract.
345
346---
347
348## gordon apps status
349
350```bash
351gordon apps status APP [--json]
352```
353
354Shows effective vs observed state per service.
355
356A service line ends with `single-writer` when the service has volumes or binds
357(`restart_unsafe: true` in `--json`), and a legend line follows the list. The
358mark is informational and needs no action. When such a service is replaced,
359Gordon durably blocks boot and periodic recovery from restarting the old
360container, so it can never write to the same data as its replacement. Every
361service is replaced stop-before-start; see [Updates](../concepts.md#updates).
362`apps show` uses the same mark.
363
364---
365
366## gordon apps logs
367
368```bash
369gordon apps logs APP [--service SVC] [--follow] [--tail N] [--json]
370```
371
372Streams logs for a service in the app's active deployment. The app name and
373`--service` are the only accepted identity: domains and raw container IDs are
374never accepted. `--service` is required when the app has several services.
375
376---
377
378## Workflow Example
379
380```bash
381# Push the image first (OCI transfer only)
382gordon images push myapp --build --remote prod
383
384# Apply the manifest that references the pushed tag
385gordon apps apply --file blog.toml --remote prod
386
387# Write secret values for registered names
388gordon apps secrets set blog --service web DATABASE_URL=... --remote prod
389
390# Deploy the accepted revision (polls 202 operations to terminal)
391gordon apps deploy blog --remote prod
392
393# Resume watching an interrupted or externally started operation
394gordon apps operations watch blog --key <operation-key> --remote prod
395
396# Inspect
397gordon apps show blog --remote prod
398gordon apps status blog --remote prod
399```
400
401## Related
402
403- [CLI Overview](./index.md)
404- [Images Commands](./images.md#gordon-images-push)
405- [Deployment](../deployment/index.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