Repository navigation
Expand file tree
/
Copy pathcli-commands.qmd
More file actions
960 lines (657 loc) · 26.4 KB
/
Copy pathcli-commands.qmd
File metadata and controls
960 lines (657 loc) · 26.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
---
title: "CLI Command Reference"
description: "Every CLI command with flags, examples, and exit codes"
---
## Overview
The Appbay CLI is a single compiled binary built with Bun. It directly imports `@appbay/core` and operates entirely offline — it does not use a tRPC client or require the Appbay server to be running. Commands that deploy containers invoke `docker compose` directly.
## Global flags
| Flag | Description |
|---|---|
| `--help` | Show help for any command |
| `--version` | Print CLI version |
| `--server <url>` | Override server URL (default: `http://localhost:3000`) |
| `--token <token>` | Override auth token (alternative to `APPBAY_TOKEN` env var) |
## Commands
### `appbay setup`
The guided path, and the one most people should start with: it runs `init`, creates the
secret vault, and brings up the edge, in order, asking only for what it cannot infer.
```bash
appbay setup --domain home.lan
appbay setup --domain example.com --email you@example.com --ingress-provider caddy --yes
appbay setup --status
```
| Flag | Default | Description |
|---|---|---|
| `--domain <domain>` | (prompted) | Base domain for ingress routing |
| `--project <name>` | (prompted) | Project name |
| `--email <email>` | (prompted) | ACME email, for Let's Encrypt certificates |
| `--ingress-provider <p>` | `traefik` | Edge to install: `traefik` or `caddy` |
| `--yes` | `false` | Non-interactive: accept all defaults |
| `--status` | — | Report what is already set up, and change nothing |
| `--reset` | — | Stop discovered apps and remove generated configs |
⚠️ The administrator `setup` creates is the **edge** administrator, which guards apps behind
the reverse proxy — and since RFC-001 §1 that is the SAME account that signs in to the web
control plane, which no longer has one of its own. It needs the `authp/admin` role to reach
the control plane. See [Credentials](../guide/credentials.qmd) — the two are deliberately
separate and are never synchronised.
**Exit codes:** 0 = success, 1 = a step failed.
### `appbay install`
Install an app from the catalog into `$APPBAY_HOME/etc/apps/<name>/`.
```bash
appbay install jellyfin
appbay install nextcloud --set ADMIN_USER=me --set TZ=Europe/Berlin
appbay install adminer --as adminer-staging # a second copy
```
| Flag | Default | Description |
|---|---|---|
| `--set <pairs...>` | — | Input values as `KEY=VALUE`, repeatable |
| `--as <name>` | the catalog name | Install under a different app name |
| `--force` | `false` | Overwrite an app of the same name |
| `--no-validate` | `false` | Skip post-install validation |
`--as` splits the catalog lookup from the install location, which is what makes a second copy
possible: without it both were the same value, so installing an entry twice overwrote it.
⚠️ Not the same axis as `namespace:`. A namespace disambiguates two *deployments* of one
installed app; `--as` gives you two *installations*, each with its own directory, manifest and
config. Use `--as` when the copies should differ in what they are, `namespace:` when they differ
only in where they run.
Installing copies the upstream files unmodified and writes an `appbay.yaml` beside them.
Nothing is deployed until you run [`appbay up`](#appbay-up).
### `appbay catalog`
Browse and manage catalog sources.
```bash
appbay catalog list
appbay catalog search media
appbay catalog info jellyfin
appbay catalog add-source https://github.com/you/your-catalog
appbay catalog update
```
### `appbay shell` · `appbay exec` · `appbay run`
Reach into a running app.
```bash
appbay shell jellyfin # interactive shell in the service container
appbay exec jellyfin -- ls /config # run a command in the running container
appbay run jellyfin -- /bin/backup.sh # one-off command in a fresh container
```
`shell` and `exec` require the app to be running; `run` starts a container for the command
and removes it afterwards.
### `appbay init-system`
Bootstrap a **fresh host** to run Appbay: installs the container runtime and sets up
ownership and access for the Appbay tree. Written for RHEL-family hosts, where the defaults
differ enough to matter.
```bash
sudo appbay init-system # --owner service (default)
sudo appbay init-system --owner operator
```
`--owner service` creates a no-login system service account, which is the right choice for a
homelab or worklab box. `--owner operator` uses your own account instead.
### `appbay init`
Scaffold the `$APPBAY_HOME` directory structure and seed system app definitions.
```bash
appbay init
appbay init --dir /opt/appbay
appbay init --project homelab --domain homelab.example.com --yes
```
| Flag | Default | Description |
|---|---|---|
| `--dir <path>` | `~/.appbay` | Override `$APPBAY_HOME` location — **persisted**, see below |
| `--project <name>` | (prompted) | Name of the default project |
| `--domain <name>` | (prompted) | Base domain for ingress routing |
| `--yes` | `false` | Non-interactive: accept all defaults |
Creates: `etc/apps/`, `etc/projects/`, `etc/presets/`, `var/lib/renders/`, `var/lib/state/`, `var/log/`. Seeds system app definitions if absent.
::: {.callout-warning}
## `--dir` changes where *every* later command looks
`--dir` is not scoped to this one run: it writes the path to `~/.config/appbay/home`, so
every subsequent `appbay` invocation on this account resolves there until you change it.
Undo it with [`appbay home clear`](#appbay-home), or repoint with `appbay home set <path>`.
To initialise a throwaway install **without** touching that default — what a test or a
journey script wants — set the environment variable instead, which `init` honours as a
runtime override and deliberately does not persist:
```bash
APPBAY_HOME=/tmp/scratch/home appbay init --project t --domain t.local --yes
```
:::
**Exit codes:** 0 = success, 1 = filesystem error.
### `appbay server start`
Start the Appbay server as a Docker Compose stack.
```bash
appbay server start
appbay server start --open
```
| Flag | Default | Description |
|---|---|---|
| `--open` | `false` | Open the web UI in a browser after start |
Creates `appbay_shared` network, starts the appbay-server container, waits for health check, prints the server URL.
**Exit codes:** 0 = server healthy, 1 = start failed, 2 = health check timeout.
### `appbay server stop`
Stop the server container.
```bash
appbay server stop
```
**Exit codes:** 0 = stopped, 1 = error.
### `appbay server status`
Check whether the Appbay server is running. Prints the server URL and start time if running, or a "not running" message if it is not.
```bash
appbay server status
```
**Exit codes:** 0 = always (status is informational).
### `appbay up`
Deploy one or more apps.
```bash
appbay up jellyfin
appbay up ollama webui tts
appbay up --collection ai-stack
appbay up --all
```
| Flag | Default | Description |
|---|---|---|
| `--collection <name>` | (none) | Deploy all apps in a collection |
| `--all` | `false` | Deploy all discovered apps |
Runs the full pipeline: compile, apply overlays, write renders, and bring up via `docker compose up -d`.
**Exit codes:** 0 = deployed, 1 = compile or deploy error.
### `appbay apply`
Compile and review a plan, then deploy with explicit confirmation. Separates compile and deploy for review workflows.
```bash
appbay apply jellyfin
appbay apply ollama webui --dry-run
appbay apply jellyfin --yes
appbay apply --all --yes
```
| Flag | Default | Description |
|---|---|---|
| `--dry-run` | `false` | Show the plan without applying |
| `--yes` | `false` | Skip confirmation prompt and deploy immediately |
| `--all` | `false` | Apply all discovered apps |
**Exit codes:** 0 = applied (or dry run complete), 1 = compile or deploy error.
### `appbay down`
Stop one or more running apps.
```bash
appbay down jellyfin
appbay down webui tts
appbay down --all
```
| Flag | Default | Description |
|---|---|---|
| `--all` | `false` | Stop all discovered apps |
**Exit codes:** 0 = stopped, 1 = error.
### `appbay delete`
Remove an app definition and stop its containers.
```bash
appbay delete myapp --keep-volumes --force
```
| Flag | Default | Description |
|---|---|---|
| `--keep-volumes` | `false` | Keep Docker volumes after deletion |
| `--force` | `false` | Skip confirmation prompt (required to proceed) |
Without `--force`, the command exits with an error and instructions. Before removing anything, it requires the discovered app to resolve to its own direct directory under the apps root; aliases and escaped paths are refused. When a rendered file or running container requires `docker compose down`, every project container must carry ownership for this Appbay home; unknown, missing or foreign ownership stops the deletion. A render-less project with only exited containers needs no runtime mutation and can be deleted directly.
**Exit codes:** 0 = deleted, 1 = not found, confirmation required, unsafe path, unknown runtime state, foreign/missing ownership, or stop failure.
### `appbay restart`
Restart one or more apps.
```bash
appbay restart jellyfin
appbay restart webui tts
appbay restart --all
```
| Flag | Default | Description |
|---|---|---|
| `--all` | `false` | Restart all discovered apps |
**Exit codes:** 0 = restarted, 1 = error.
### `appbay pull`
Pull the latest Docker images for one or more apps.
```bash
appbay pull jellyfin
appbay pull ollama webui
appbay pull --all
```
| Flag | Default | Description |
|---|---|---|
| `--all` | `false` | Pull images for all discovered apps |
Uses the rendered compose file if available, otherwise falls back to the source compose.
**Exit codes:** 0 = all pulls succeeded, 1 = one or more failed.
### `appbay compile`
Run the compiler pipeline without deploying.
```bash
appbay compile jellyfin
appbay compile jellyfin webui
appbay compile # compiles all discovered apps
```
| Flag | Default | Description |
|---|---|---|
| `--output <dir>` | `var/lib/renders/` | Write rendered output to a custom directory |
Runs the full compile pipeline and writes rendered compose and auxiliary files. Available offline (no server needed).
**Exit codes:** 0 = compiled, 1 = error.
### `appbay validate`
Validate app definitions against Zod schemas.
```bash
appbay validate jellyfin
appbay validate --all
```
Reports errors with file paths, field names, and expected types. Available offline.
**Exit codes:** 0 = valid, 1 = validation errors found.
### `appbay eject`
Export a fully standalone Compose project.
```bash
appbay eject jellyfin
appbay eject jellyfin --output ./exported/
```
| Flag | Default | Description |
|---|---|---|
| `--output <path>` | `./appbay-eject/<app>/` | Output directory |
Produces a directory with `docker-compose.yml` and `.env` that can be run with `docker compose up` without Appbay. Available offline.
**Exit codes:** 0 = ejected, 1 = error.
### `appbay status`
Show app configuration and metadata. Available offline.
```bash
appbay status
appbay status jellyfin
appbay status jellyfin --json
```
| Flag | Description |
|---|---|
| `--json` | Output as JSON |
Without an app name, shows a summary table of all discovered apps (name, services count, traits count, errors). With an app name, shows full detail: directory, project, environment, services (with service-level traits), app-level traits, overlays, and upstream configuration.
**Exit codes:** 0 = success, 1 = app not found.
### `appbay logs`
Show or stream app logs.
```bash
appbay logs jellyfin
appbay logs jellyfin redis --follow
appbay logs jellyfin --tail 100
```
| Flag | Default | Description |
|---|---|---|
| `-f, --follow` | `false` | Stream logs in real time |
| `--tail <n>` | (Docker default) | Number of lines to show from the end |
The optional second positional argument filters to a specific service within the app.
**Exit codes:** 0 = success, 1 = error.
### `appbay doctor`
Run prerequisite and health checks.
```bash
appbay doctor
```
Checks: Docker connectivity, Compose version, server health, disk space, system app status.
**Exit codes:** 0 = all checks passed, 1 = one or more checks failed.
### `appbay secrets init`
Initialize the local secrets vault. Auto-generates a master password if none provided.
```bash
appbay secrets init
appbay secrets init --password mypassword
```
### `appbay secrets set`
Store a secret in the vault. Key format: `KEY` for default scope, `APP/KEY` for app-scoped.
```bash
appbay secrets set DB_PASSWORD myvalue
appbay secrets set kestra/DB_PASSWORD myvalue
```
Warns if the secret already exists, with database-specific guidance.
### `appbay secrets get`
Retrieve a secret value from the vault.
```bash
appbay secrets get DB_PASSWORD
appbay secrets get kestra/DB_PASSWORD
```
### `appbay secrets delete`
Delete a secret from the vault.
```bash
appbay secrets delete DB_PASSWORD
appbay secrets delete kestra/DB_PASSWORD
```
### `appbay secrets vault`
List all secrets stored in the vault, grouped by scope. Shows metadata only — never values.
```bash
appbay secrets vault
appbay secrets vault --scope kestra
```
### `appbay secrets scan`
Discover secret-like env vars in an app's compose and .env files. Suggests vault URI mappings for unmanaged secrets.
```bash
appbay secrets scan kestra
```
### `appbay secrets import`
Scan an app and auto-create vault entries for unmanaged secret-like variables.
```bash
appbay secrets import kestra
appbay secrets import kestra --dry-run
```
### `appbay secrets export`
Export vault contents to a KeePass .kdbx file.
```bash
# `secrets export` was removed with the kdbx work; use `appbay secrets list`
appbay secrets list
```
### `appbay secrets import-kdbx`
Import secrets from a KeePass .kdbx file into the vault.
```bash
appbay secrets import-kdbx secrets.kdbx --password mypass
```
### `appbay secrets check`
Verify that all secret URI references across all apps can be resolved.
```bash
appbay secrets check
```
### `appbay secrets list`
List secret URI references for an app (or all apps). Prints URIs only — never values.
```bash
appbay secrets list
appbay secrets list jellyfin
```
### `appbay edge migrate`
Switch the ingress provider without a window in which the host has no edge. The target
edge must already be seeded (`appbay init --ingress-provider <target>`). The command
validates the candidate while the current edge is still serving (compile, and for caddy a
`caddy validate` in the edge image with the deploy environment), backs up the outgoing
edge's configuration, stops it, starts the target, checks that the target is running by its
label, and restores the outgoing edge on any failure.
```bash
appbay edge migrate --to caddy
```
Exit 0 when migrated; exit 1 when refused (a foreign process holds :80 or :443, the
candidate did not validate, or the runtime could not be asked) or when the target did not
come up and the outgoing edge was restored.
### `appbay edge users list`
List Caddy Security local edge users.
```bash
appbay edge users list
```
### `appbay edge users create`
Create a Caddy Security local edge user.
```bash
appbay edge users create newuser --email user@example.com --roles user
appbay edge users create newuser --email user@example.com --generate --reveal
```
### `appbay edge users reset-password`
Reset a Caddy Security local edge user's password.
```bash
appbay edge users reset-password username
```
### `appbay admin` — retired
RFC-001 §1 removed AppBay's own accounts. The control plane is a stack behind the Caddy
Security edge like any other app, so the account that signs in to AppBay is an edge user:
```bash
appbay edge users reset-password alice --generate --reveal
```
Running `appbay admin` prints this and exits non-zero, so a script that still calls it fails
rather than appearing to succeed.
::: {.callout-important}
## One store now, and a role instead of a second password
There is no longer a separate credential domain for the control plane. What distinguishes it is
the **role**: its edge route carries an admin-only policy (`authp/admin`), narrower than an
app's default, because it is the one stack that can reach the container runtime socket. So
"can open Grafana" still does not imply "can reconfigure the installation".
:::
### `appbay rebuild-cache`
Regenerate the SQLite metadata cache from filesystem state.
```bash
appbay rebuild-cache
```
Deletes the existing `appbay.db`, creates a fresh database with Drizzle migrations, and populates all tables from filesystem sources. Available offline.
**Exit codes:** 0 = rebuilt, 1 = error.
### `appbay update`
Check for and apply CLI and system app updates.
```bash
appbay update
appbay update --check
appbay update --system-only
```
| Flag | Default | Description |
|---|---|---|
| `--check` | `false` | Check for updates without applying |
| `--system-only` | `false` | Only pull system app Docker images |
**Exit codes:** 0 = updated, 1 = pull failed, 2 = restart failed.
### `appbay list`
List all discovered apps. Available offline.
```bash
appbay list
appbay list --json
```
| Flag | Description |
|---|---|
| `--all` | Include apps with discovery errors (default: all apps shown anyway) |
| `--json` | Output as JSON array |
Reads from `$APPBAY_HOME/etc/apps/` and shows each app's name, project, environment, whether an `appbay.yaml` exists, and the compose filename. Does not require Docker or the server to be running.
**Exit codes:** 0 = success.
### `appbay ps`
Show container runtime status for apps. Runs `docker compose ps` against rendered compose files.
```bash
appbay ps
appbay ps jellyfin
appbay ps jellyfin redis
appbay ps --json
```
| Flag | Default | Description |
|---|---|---|
| `--all` | `false` | Include apps without rendered compose files |
| `--json` | `false` | Output as JSON |
Prefers the rendered compose file in `var/lib/renders/`; falls back to the source compose.
**Exit codes:** 0 = success, 1 = docker compose failed or no apps found.
### `appbay config`
Get or set configuration values in an app's `appbay.yaml`. Uses dot-separated key paths.
```bash
appbay config jellyfin # show all config
appbay config jellyfin upstream.source # read a single key
appbay config jellyfin upstream.source my-app # set a value
```
Values are auto-coerced: `"true"` → boolean, `"42"` → number, everything else stays string.
**Exit codes:** 0 = success, 1 = app or key not found.
### `appbay env`
Manage environment variables in an app's `.env` file (`$APPBAY_HOME/etc/apps/<app>/.env`).
```bash
appbay env jellyfin # list all variables
appbay env jellyfin DB_HOST # get a variable
appbay env jellyfin DB_HOST db # set a variable
appbay env jellyfin DB_HOST --delete # delete a variable
```
| Flag | Default | Description |
|---|---|---|
| `--list` | `false` | List all variables |
| `--delete` | `false` | Delete the specified variable |
**Exit codes:** 0 = success, 1 = app not found or key not found.
### `appbay presets`
Manage named app selection presets. Presets save which apps are selected together for quick recall. Stored as YAML in `$APPBAY_HOME/etc/presets/`.
```bash
appbay presets save ai-dev --apps "ollama,webui,whisper"
appbay presets load ai-dev
appbay presets list
appbay presets delete ai-dev
```
#### `appbay presets save <name>`
| Flag | Description |
|---|---|
| `--apps <list>` | Comma-separated app names to include |
| `--description <desc>` | Optional description |
#### `appbay presets load <name>`
Prints the app list from the preset. Typically piped to `appbay up`:
```bash
appbay up $(appbay presets load ai-dev)
```
#### `appbay presets list`
List all saved presets with their app lists.
#### `appbay presets delete <name>`
Delete a preset by name.
### `appbay open`
Open an app's URL in the default browser.
```bash
appbay open jellyfin
```
Resolves the app's ingress URL from the ingress trait configuration and opens it.
**Exit codes:** 0 = opened, 1 = no ingress configured.
### `appbay url`
Print an app's URL without opening the browser. Resolves the ingress trait or falls back to compose port mappings.
```bash
appbay url jellyfin
appbay url jellyfin --lan
appbay url jellyfin --internal
```
| Flag | Description |
|---|---|
| `--lan` | Show the LAN address |
| `--internal` | Show the internal Docker network address |
**Exit codes:** 0 = success, 1 = app not found.
### `appbay version`
Print the Appbay CLI version.
```bash
appbay version
```
**Exit codes:** 0 = always.
### `appbay home`
Print, explain or repoint the resolved `$APPBAY_HOME` path.
```bash
appbay home # print the resolved path, and nothing else
appbay home --explain # show every tier and which one wins
appbay home set <path> # persist a new home for future commands
appbay home clear # forget the persisted home
```
Bare `appbay home` prints only the path, so `cd $(appbay home)/etc/apps` keeps working.
**Resolution order** — the first tier with a value wins:
| # | Tier | Set by |
|---|---|---|
| 1 | `$APPBAY_HOME` | the environment; a runtime override that always wins |
| 2 | `/etc/appbay/config` | `appbay init-system` (a host-level decision) — holds `home:` and nothing else |
| 3 | `~/.config/appbay/home` | `appbay init --dir`, or `appbay home set` |
| 4 | `~/.appbay` | built-in default |
::: {.callout-note}
## Why tier 2 is a file and not a systemd unit
RFC-001 proposed replacing it with `Environment=APPBAY_HOME=` in a unit. Measured on a real
host, a unit's environment reaches the processes systemd starts and nothing else: the service
saw the home, an operator's login shell saw nothing. Tier 2 serves that second case — an
operator typing `appbay …` — which is precisely where a per-operator `~/.config/appbay/home`
would otherwise win. Deleting it made the CLI resolve a personal path over a service install.
:::
`--explain` prints all four with the winner marked, and warns when the resolved path
does not exist, has no `etc/` (never initialised), or is a saved pointer under a temp
directory that will not survive a reboot.
`set` writes tier 3 and **refuses** when tier 1 or 2 would shadow it — a saved path that
a higher tier overrides is a setting that reports success and changes nothing. It also
refuses a path that does not exist. `--force` overrides both refusals; when forced past a
shadowing tier it says so rather than claiming the resolved home changed.
`clear` removes tier 3 and reports the tier now in force. Use it to undo an
`appbay init --dir` that pointed at a directory you no longer want — including a
throwaway one that has since been deleted.
**Exit codes:** 0 = printed, explained, set or cleared; 1 = `set` refused (shadowed by a
higher tier, or the path is missing or not a directory).
### `appbay info`
Print system information relevant to Appbay: OS/arch, Docker version, Docker Compose version, GPU availability, `$APPBAY_HOME` path, and number of discovered apps.
```bash
appbay info
```
**Exit codes:** 0 = always.
### `appbay size`
Show disk usage for app definitions and Docker volumes.
```bash
appbay size
appbay size jellyfin
```
**Exit codes:** 0 = always.
### `appbay fixfs`
Fix filesystem permissions for app volume directories. Sets ACLs for common container UIDs (linuxserver.io 911, nginx 101, etc.) so containers can read/write their data directories without running as root.
```bash
appbay fixfs jellyfin
appbay fixfs jellyfin --uid 911
appbay fixfs jellyfin --dry-run
```
| Flag | Description |
|---|---|
| `--uid <n>` | Grant access to a specific UID |
| `--gid <n>` | Grant access to a specific GID |
| `--dry-run` | Show what would change without applying |
**Exit codes:** 0 = success.
## Inspection and diagnostics
### `appbay stats`
Resource usage for running containers. Streams by default.
```bash
appbay stats
appbay stats --no-stream # one snapshot, then exit
```
| Flag | Description |
|---|---|
| `--no-stream` | Print a single snapshot instead of streaming |
### `appbay dive`
Inspect an image's layers and where its disk usage goes.
```bash
appbay dive ollama # by app name
appbay dive nginx:latest # by image reference
```
### `appbay smi`
Show NVIDIA GPU information, as seen by the host.
```bash
appbay smi
```
Useful before adding a `gpu` trait — see [Traits](../guide/traits.qmd). A host with no NVIDIA
GPU reports that plainly rather than failing obscurely.
## AI models
### `appbay models`
Manage models held by the Ollama system app.
```bash
appbay models ls
appbay models rm llama3
```
| Subcommand | Description |
|---|---|
| `ls` | List downloaded models |
| `rm <model>` | Remove a model |
### `appbay ollama`
Run the Ollama CLI **inside** the Ollama container, passing arguments through unchanged.
```bash
appbay ollama list
appbay ollama run llama3
appbay ollama show llama3
```
## Configuration profiles
### `appbay profile`
Save and restore named configuration profiles.
```bash
appbay profile save homelab
appbay profile ls
appbay profile set homelab
appbay profile rm homelab
```
| Subcommand | Description |
|---|---|
| `save <name>` | Save the current configuration under a name |
| `set <name>` | Restore a saved profile |
| `ls` | List saved profiles |
| `rm <name>` | Delete a saved profile |
## Public tunnels
### `appbay tunnel`
Create a Cloudflare quick tunnel exposing a local app publicly, without touching your edge
or DNS.
```bash
appbay tunnel jellyfin
appbay tunnel jellyfin --port 8096
```
| Flag | Description |
|---|---|
| `--port <port>` | Override the port to tunnel |
::: {.callout-warning}
## A quick tunnel is public and unauthenticated
It publishes the app on a Cloudflare-generated hostname that anyone with the URL can reach.
It does **not** pass through the Caddy Security edge, so an `auth` trait on the app does not
apply to traffic arriving this way. Use it for a demo or a temporary share, not as a way to
publish something permanently.
:::
### `appbay tunnel-down`
Stop all running Cloudflare tunnels.
```bash
appbay tunnel-down
```
## MCP
### `appbay mcp inspector`
Launch the MCP inspector for debugging Model Context Protocol servers.
```bash
appbay mcp inspector
appbay mcp inspector http://localhost:3001
```
## Retired commands
`appbay auth` and `appbay authelia` still exist as **stubs that exit non-zero**. They print
what replaced them and change nothing.
Authelia was AppBay's authentication edge until S25 replaced it with the integrated Caddy
Security edge. `appbay admin` joined them when RFC-001 §1 removed AppBay's own accounts.
Authentication now lives entirely in `appbay edge` — one store for the people who sign in to
your deployed apps and to AppBay itself.
## Shell integration
### `appbay completion`
Generate shell completion scripts for bash or zsh.
```bash
appbay completion bash >> ~/.bashrc
appbay completion zsh >> ~/.zshrc
```
**Exit codes:** 0 = always.