ghostdock 0.0.20 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/bin/ghostdock.js +31 -0
- package/package.json +17 -24
- package/dist/cli-reference.md +0 -1808
- package/dist/cli.md +0 -934
- package/dist/index.js +0 -15878
package/dist/cli.md
DELETED
|
@@ -1,934 +0,0 @@
|
|
|
1
|
-
# Ghostdock CLI
|
|
2
|
-
|
|
3
|
-
Command-line access to your Ghostdock account — built for agents, but usable by humans too.
|
|
4
|
-
Authenticate once, then call Ghostdock's tools without leaving the terminal.
|
|
5
|
-
|
|
6
|
-
This document is written for an agent (or human) driving the CLI directly. It is also published at
|
|
7
|
-
`https://ghostdock.brainchimps.com/cli.md` so an agent can `curl`/fetch it without cloning this repo.
|
|
8
|
-
|
|
9
|
-
## Install / run
|
|
10
|
-
|
|
11
|
-
No install required — run it with `npx`:
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
npx ghostdock --help
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Or install it globally:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm install -g ghostdock
|
|
21
|
-
ghostdock --help
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
A global install also gives you `gdock`, a short name for the same CLI. Help
|
|
25
|
-
and hints use whichever name you typed. With `npx`, use `npx ghostdock`:
|
|
26
|
-
`npx gdock` does not work.
|
|
27
|
-
|
|
28
|
-
Inside this monorepo (for development), run from the repo root or `packages/cli`:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
bun run --cwd packages/cli build # bundles src/index.ts -> dist/index.js
|
|
32
|
-
bun run --cwd packages/cli dev -- --help # run from source without building
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Output: for people, and `--json` for scripts and agents
|
|
36
|
-
|
|
37
|
-
Every command prints for people by default: one line per event, a symbol, then the message.
|
|
38
|
-
|
|
39
|
-
```
|
|
40
|
-
$ ghostdock vm list
|
|
41
|
-
⚓ Marketing site quiet-harbor running
|
|
42
|
-
◌ teal-jetty stopped
|
|
43
|
-
$ ghostdock site publish ./dist
|
|
44
|
-
↗ https://foggy-teal-bollard.static.ghostdock.app
|
|
45
|
-
✓ Published site foggy-teal-bollard.
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
`⚓` ready, `✓` done, `↗` a URL, `◌` stopped or gone, `✗` failed, `▂▄▆` in progress. Every line
|
|
49
|
-
carries the name and id the next command needs.
|
|
50
|
-
|
|
51
|
-
Commands that wait show a progress line on stderr while they run. Starting a VM
|
|
52
|
-
(`vm create`, `vm wake`) prints how long each step took, measured on the server, each
|
|
53
|
-
step with its own time:
|
|
54
|
-
|
|
55
|
-
```
|
|
56
|
-
$ ghostdock vm wake quiet-harbor
|
|
57
|
-
⚓ quiet-harbor running
|
|
58
|
-
⚓ VM started in 125ms
|
|
59
|
-
✓ container started in 3.0s
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
The container line is missing when no container was started, or when the host is older and did
|
|
63
|
-
not report it. `vm status` prints the same lines for the last start. With `--json` they are
|
|
64
|
-
the `boot` field: `{ trigger, vm: { startedAt, readyAt, ms }, container: { … } | null }`, or
|
|
65
|
-
`null` when the command started nothing.
|
|
66
|
-
|
|
67
|
-
**Scripts and agents pass `--json`.** It prints the result as one JSON document on stdout, with
|
|
68
|
-
every field, and nothing else there. It works on every command and anywhere on the line:
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
ghostdock vm list --json | jq -r '.vms[].name'
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
- **stdout is the result, stderr is everything else**: notices (`Using organization acme …`),
|
|
75
|
-
hints and errors. Piping stdout never picks up a notice.
|
|
76
|
-
- **Errors** print as `✗ <what went wrong and what to try>` on stderr and exit non-zero, with or
|
|
77
|
-
without `--json`.
|
|
78
|
-
- **Colour** only on a terminal: piped output and `NO_COLOR=1` get the same text without colour
|
|
79
|
-
codes. `FORCE_COLOR=1` turns it back on.
|
|
80
|
-
|
|
81
|
-
## Global flags
|
|
82
|
-
|
|
83
|
-
```
|
|
84
|
-
ghostdock --version
|
|
85
|
-
ghostdock --base-url <url> <command>
|
|
86
|
-
ghostdock <command> --json
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
- `--version` / `-v` — print CLI version and exit
|
|
90
|
-
- `--base-url <url>` — API origin for this invocation (wins over `GHOSTDOCK_BASE_URL`)
|
|
91
|
-
- `--json` — print the result as one JSON document on stdout (see Output above)
|
|
92
|
-
|
|
93
|
-
## Commands
|
|
94
|
-
|
|
95
|
-
Commands are grouped by resource, like `gh` or `kubectl`: `ghostdock <resource> <action>`.
|
|
96
|
-
|
|
97
|
-
<!-- generated:command-groups:start (bun run sync:cli-reference; do not edit) -->
|
|
98
|
-
```
|
|
99
|
-
ghostdock app Published apps of an organization.
|
|
100
|
-
ghostdock docker Docker over the private network: a VM's Docker engine from this machine.
|
|
101
|
-
ghostdock env Manage organization environment variables and secrets.
|
|
102
|
-
ghostdock image Organization image catalog: OCI bookmarks, Dockerfiles and Compose files.
|
|
103
|
-
ghostdock login Sign in and store a device access token for this machine…
|
|
104
|
-
ghostdock logout Revoke the device session and remove stored credentials.
|
|
105
|
-
ghostdock network The private network: reach your VMs by address and name from this machine.
|
|
106
|
-
ghostdock organization Organizations you belong to.
|
|
107
|
-
ghostdock project Deployable projects, their deployments and environment.
|
|
108
|
-
ghostdock provider Providers of an organization.
|
|
109
|
-
ghostdock registry Log in to the organization container registry.
|
|
110
|
-
ghostdock site Static sites on the CDN.
|
|
111
|
-
ghostdock skill List and read Agent Skills (same catalog as MCP skill://index.json).
|
|
112
|
-
ghostdock snapshot VM snapshots.
|
|
113
|
-
ghostdock template
|
|
114
|
-
ghostdock tools List available agent tools.
|
|
115
|
-
ghostdock vm Create, run and manage VMs.
|
|
116
|
-
ghostdock whoami Show the account this CLI is currently authenticated as.
|
|
117
|
-
```
|
|
118
|
-
<!-- generated:command-groups:end -->
|
|
119
|
-
|
|
120
|
-
Run `ghostdock <command> --help` at any level for its subcommands or flags, e.g.
|
|
121
|
-
`ghostdock vm --help` or `ghostdock vm url create --help`.
|
|
122
|
-
|
|
123
|
-
Most commands are generated from the tool catalog — see **Invoking a tool** below. Every command
|
|
124
|
-
is listed in the [command index](#command-index); [`cli-reference.md`](cli-reference.md) has each
|
|
125
|
-
one's full description and flags.
|
|
126
|
-
|
|
127
|
-
### Choosing an organization
|
|
128
|
-
|
|
129
|
-
Every organization-scoped command acts on one organization, taken from the first of:
|
|
130
|
-
|
|
131
|
-
1. `--org <id-or-slug>` on the command
|
|
132
|
-
2. the `GHOSTDOCK_ORG` environment variable
|
|
133
|
-
3. the default set with `ghostdock organization use <id-or-slug>`, stored in
|
|
134
|
-
`~/.config/ghostdock/settings.json`
|
|
135
|
-
|
|
136
|
-
With one organization there is nothing to do: `login` makes it the default, and every command,
|
|
137
|
-
in any directory, uses it.
|
|
138
|
-
|
|
139
|
-
```bash
|
|
140
|
-
ghostdock organization use acme # the default (login sets one when it can)
|
|
141
|
-
ghostdock vm list # stderr: Using organization acme (default from ~/.config/ghostdock/settings.json)
|
|
142
|
-
ghostdock vm list --org beta # --org always wins
|
|
143
|
-
ghostdock organization current # which organization, and where it comes from
|
|
144
|
-
ghostdock organization use --clear
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
When the organization does not come from `--org`, the command says which one it uses on stderr,
|
|
148
|
-
so a default never acts silently. The default is stored next to the credentials, so it belongs to
|
|
149
|
-
the same login. **Scripts and CI should pass `--org` or set `GHOSTDOCK_ORG`** rather than depend on
|
|
150
|
-
(or change) a stored default, and use the organization id: renaming an organization changes its
|
|
151
|
-
slug, not its id.
|
|
152
|
-
|
|
153
|
-
### `ghostdock login`
|
|
154
|
-
|
|
155
|
-
Ghostdock uses a device-authorization flow: no password is ever typed into the terminal.
|
|
156
|
-
|
|
157
|
-
**Default (print-and-exit) — best when a human is present to click the link:**
|
|
158
|
-
|
|
159
|
-
```bash
|
|
160
|
-
ghostdock login
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
This prints a URL to open in a browser and exits `0` immediately — it does not prompt for input or
|
|
164
|
-
poll for approval. Approve the request in the browser, then complete login with
|
|
165
|
-
**`ghostdock login --code <paste-code>`**, redeeming the one-time code from the browser's
|
|
166
|
-
"Having trouble? Show code" link (see below).
|
|
167
|
-
|
|
168
|
-
Each `login` invocation starts a **new** device session. A later `login --wait` does **not** resume
|
|
169
|
-
polling for a prior plain `login`. To block until approval, run **`ghostdock login --wait` up
|
|
170
|
-
front** instead of plain `login`.
|
|
171
|
-
|
|
172
|
-
**`--wait` — poll until approved:**
|
|
173
|
-
|
|
174
|
-
```bash
|
|
175
|
-
ghostdock login --wait
|
|
176
|
-
# or with a custom timeout (seconds, default 300):
|
|
177
|
-
ghostdock login --wait --timeout 120
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
Prints the same URL, then polls the server every few seconds until the login is approved, denied,
|
|
181
|
-
or the timeout elapses. Exits `0` on success, non-zero otherwise.
|
|
182
|
-
|
|
183
|
-
**`--code` — paste-code fallback:**
|
|
184
|
-
|
|
185
|
-
If the CLI can't poll (e.g. it's running in a VM with no long-lived process, or the browser
|
|
186
|
-
approval happened on a different machine), the browser's "Having trouble? Show code" link reveals a
|
|
187
|
-
short one-time code. Redeem it directly:
|
|
188
|
-
|
|
189
|
-
```bash
|
|
190
|
-
ghostdock login --code <paste-code>
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
On success, credentials are written and the command exits `0`. If the code hasn't been approved
|
|
194
|
-
yet, it exits `1` — approve it in the browser first.
|
|
195
|
-
|
|
196
|
-
Credentials are stored per machine, in `~/.config/ghostdock/credentials.json` (see
|
|
197
|
-
[Credentials file](#credentials-file)), so one login works in every directory.
|
|
198
|
-
|
|
199
|
-
**Default organization after login.** Once logged in (with `--wait` or `--code`), `login` sets the
|
|
200
|
-
default organization when that is unambiguous:
|
|
201
|
-
|
|
202
|
-
- `--org <id-or-slug>` sets that one, e.g. `ghostdock login --wait --org acme`. If you are not a
|
|
203
|
-
member of it, no default is set and `login` exits `1`.
|
|
204
|
-
- A default that is still one of your organizations stays as it is.
|
|
205
|
-
- With exactly one organization, that one becomes the default.
|
|
206
|
-
- With several, a person at a terminal picks one from a numbered list (Enter skips). Without a
|
|
207
|
-
terminal (agents, CI) nothing is asked: `login` lists them and points to
|
|
208
|
-
`ghostdock organization use`.
|
|
209
|
-
|
|
210
|
-
See [Choosing an organization](#choosing-an-organization) for how commands pick it up.
|
|
211
|
-
|
|
212
|
-
### `ghostdock logout`
|
|
213
|
-
|
|
214
|
-
```bash
|
|
215
|
-
ghostdock logout
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
Revokes the device session on the server (best-effort — still clears local credentials even if the
|
|
219
|
-
server call fails, e.g. when offline) and deletes the credentials file. The default organization
|
|
220
|
-
stays.
|
|
221
|
-
|
|
222
|
-
### `ghostdock whoami`
|
|
223
|
-
|
|
224
|
-
```bash
|
|
225
|
-
ghostdock whoami
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
Prints who the stored access token belongs to and which server it talks to (`--json`:
|
|
229
|
-
`{ "userId": ..., "baseUrl": ... }`).
|
|
230
|
-
Transparently refreshes an expired access token using the stored refresh token before failing.
|
|
231
|
-
Exits `1` with a message if not logged in or the session can't be refreshed.
|
|
232
|
-
|
|
233
|
-
### `ghostdock tools`
|
|
234
|
-
|
|
235
|
-
Lists the tool catalog for the authenticated account:
|
|
236
|
-
|
|
237
|
-
```bash
|
|
238
|
-
ghostdock tools # name + description, one per line
|
|
239
|
-
ghostdock tools --json # the full catalog (including each tool's JSON Schema) as JSON
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
Requires login — prints a hint and exits `1` if there's no valid session.
|
|
243
|
-
|
|
244
|
-
### `ghostdock skill`
|
|
245
|
-
|
|
246
|
-
Lists and reads **Agent Skills** for the authenticated account — the same catalog MCP
|
|
247
|
-
clients discover at `skill://index.json` (SEP-2640 / Agent Skills discovery 0.2.0).
|
|
248
|
-
Prefer resources. The MCP tools `skill_list` and `skill_get` are fallbacks for clients that
|
|
249
|
-
cannot use `resources/list` and `resources/read` — skip them if those work.
|
|
250
|
-
|
|
251
|
-
```bash
|
|
252
|
-
ghostdock skill list # name, description, and skill:// URI per skill
|
|
253
|
-
ghostdock skill list --json # official discovery index ($schema + skills[])
|
|
254
|
-
ghostdock skill get skill://github/SKILL.md # print SKILL.md
|
|
255
|
-
ghostdock skill get github # same, by name
|
|
256
|
-
ghostdock skill get org_1/release-notes # organization skill
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
`--json` on `get` prints `{ uri, name, description, markdown }`. If the same name exists
|
|
260
|
-
in more than one organization, pass the `skill://` URI from the index.
|
|
261
|
-
|
|
262
|
-
Requires login — prints a hint and exits `1` if there's no valid session.
|
|
263
|
-
|
|
264
|
-
### Invoking a tool
|
|
265
|
-
|
|
266
|
-
Every catalog tool is a command at its own path, with one `--flag` per schema property
|
|
267
|
-
(`autoWake` -> `--auto-wake`). The one thing a command acts on is positional instead:
|
|
268
|
-
`ghostdock vm stop <vm>`, `ghostdock vm url delete <url-id>`,
|
|
269
|
-
`ghostdock env get <name>`. The organization is always the `--org` flag, by id or slug: a slug is easier to type, an id keeps
|
|
270
|
-
working after the organization is renamed (renaming changes the slug). The MCP tool name is the same path joined with
|
|
271
|
-
underscores: `ghostdock vm url create` calls the `vm_url_create` tool. Run
|
|
272
|
-
`ghostdock <command> --help` to see a command's full description, its flags and which are
|
|
273
|
-
required; a group's `--help` lists its commands with one line each. Output is a line per item
|
|
274
|
-
for people; `--json` prints the tool's result as it comes back over MCP.
|
|
275
|
-
|
|
276
|
-
```bash
|
|
277
|
-
ghostdock organization list
|
|
278
|
-
# • Acme org_123
|
|
279
|
-
ghostdock organization list --json
|
|
280
|
-
# {"organizations": [{"id": "org_123", "name": "Acme", "slug": "acme"}]}
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
Number/boolean flags are parsed from their string form; array/object flags take a raw JSON string
|
|
284
|
-
(e.g. `--tags '["a","b"]'`). Requires login — prints a hint and exits `1` if there's no valid
|
|
285
|
-
session, or the server's error message (e.g. "Not a member of this organization") on a `4xx`.
|
|
286
|
-
|
|
287
|
-
The tool list embedded in the CLI binary is generated at build time from the server's tool catalog
|
|
288
|
-
(`bun run sync-catalog` in `packages/cli`), so `--help` and flag parsing work offline; invoking a
|
|
289
|
-
tool still requires a network call and a valid session.
|
|
290
|
-
|
|
291
|
-
Command descriptions are short on purpose. Concepts and workflows live in the built-in Agent
|
|
292
|
-
Skills, the same documents MCP agents read:
|
|
293
|
-
|
|
294
|
-
```bash
|
|
295
|
-
ghostdock skill get vm # sources, manifests, lifecycle, providers, URLs and TCP
|
|
296
|
-
ghostdock skill get vm-boot # processes that must come back after idle-stop
|
|
297
|
-
ghostdock skill get environment # organization entries, bindings, local entries, secrets
|
|
298
|
-
ghostdock skill get publishing # sites publish vs projects publish, outcomes, redeploys
|
|
299
|
-
ghostdock skill get incus-setup # connecting your own Incus host
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
### VMs
|
|
303
|
-
|
|
304
|
-
Read `ghostdock skill get vm` before your first VM: what it can boot from, manifests,
|
|
305
|
-
idle-stop and auto-delete, providers, URLs.
|
|
306
|
-
|
|
307
|
-
Every VM has a name like `quiet-harbor`, unique within its organization, and every command
|
|
308
|
-
that takes a VM accepts it with the organization (`--org`, `GHOSTDOCK_ORG` or the default).
|
|
309
|
-
The long `vmId` in `--json` output works too, in the same organization. A name never changes
|
|
310
|
-
while the VM exists, so scripts can keep it; once a VM is deleted, its name may be given to
|
|
311
|
-
a new one later. The display name is a separate label you can edit. For example, create a VM,
|
|
312
|
-
then expose a URL:
|
|
313
|
-
|
|
314
|
-
```bash
|
|
315
|
-
ghostdock vm create --org org_123 --display-name "Marketing site"
|
|
316
|
-
ghostdock vm url create quiet-harbor --port 8080 --auto-wake true --public true
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
#### Containers in a VM
|
|
320
|
-
|
|
321
|
-
On Ghostdock Cloud a VM runs one Docker engine; everything in it is an ordinary container.
|
|
322
|
-
`vm ssh get`, `vm file`, `vm command` and `vm shell` land in one of them: `--container <name>`, else the
|
|
323
|
-
VM's default container, else the one running container. With several running and no default,
|
|
324
|
-
the CLI asks which one at the keyboard and offers to make it the default; without a terminal it
|
|
325
|
-
fails and lists the names. A command runs as `docker exec` does there: as the container's
|
|
326
|
-
`ghostdock.login.user`, else the image's `USER`, else root.
|
|
327
|
-
|
|
328
|
-
```bash
|
|
329
|
-
ghostdock vm container list quiet-harbor
|
|
330
|
-
ghostdock vm default-container quiet-harbor --container web # --clear true removes it
|
|
331
|
-
ghostdock vm command run quiet-harbor --container db --command 'pg_isready'
|
|
332
|
-
ghostdock vm container unlock quiet-harbor workstation
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
A shell session lives in its container: pass the same `--container` to every `shells` and
|
|
336
|
-
`commands` call on it.
|
|
337
|
-
|
|
338
|
-
#### Environment in a VM
|
|
339
|
-
|
|
340
|
-
A VM exports **nothing** by default (unless you boot from an organization snapshot or catalog
|
|
341
|
-
image whose manifest supplies defaults). `environment` has three parts: `organization` (plain same-name opt-ins from the
|
|
342
|
-
catalogue, see [`ghostdock env`](#ghostdock-env)), `bindings` (slot ← org entry remaps), and `local` (VM-only variables/secrets). A local entry overrides an
|
|
343
|
-
organization export of the same name. Prefer the CLI when setting secret values so they are not
|
|
344
|
-
pasted into the agent conversation.
|
|
345
|
-
|
|
346
|
-
```bash
|
|
347
|
-
# At create time, in one call:
|
|
348
|
-
ghostdock vm create --org org_123 \
|
|
349
|
-
--environment '{"organization":["VITE_API_URL","BUILD_TOKEN"],"bindings":[{"name":"DATABASE_URL","organization":"PROD_DATABASE_URL"}],"local":[{"name":"API_KEY","value":"sk_live","kind":"secret"}]}'
|
|
350
|
-
|
|
351
|
-
# Afterwards:
|
|
352
|
-
ghostdock vm env get quiet-harbor
|
|
353
|
-
ghostdock vm env select quiet-harbor --environment '["VITE_API_URL"]' \
|
|
354
|
-
--bindings '[{"name":"DATABASE_URL","organization":"PROD_DATABASE_URL"}]'
|
|
355
|
-
ghostdock vm env select quiet-harbor --environment '[]' # clears plain + remaps (omit bindings)
|
|
356
|
-
ghostdock vm env set API_KEY --vm quiet-harbor --value sk_live --kind secret
|
|
357
|
-
ghostdock vm env delete API_KEY --vm quiet-harbor
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
Values arrive as real environment variables, so read them with `process.env` / `$VAR` inside the
|
|
361
|
-
VM. **Do not pass secrets in `vm command run` strings** — the command text is retained and
|
|
362
|
-
readable through `vm command logs`. `vm env get` reports every organization entry
|
|
363
|
-
(selected + overriddenByLocal) and the VM's own local entries; `vm status` reports
|
|
364
|
-
just the resolved names.
|
|
365
|
-
|
|
366
|
-
New shell commands and SSH sessions see a change immediately. Processes already running keep the
|
|
367
|
-
values they booted with until restarted (pass `--restart` to `vm env select` /
|
|
368
|
-
`vm env set` / `vm env delete` to restart a running VM
|
|
369
|
-
instead).
|
|
370
|
-
|
|
371
|
-
### Images
|
|
372
|
-
|
|
373
|
-
Organization image catalog: OCI bookmarks (`image add`), stored Dockerfiles
|
|
374
|
-
(`image add-dockerfile`), and refs currently in use on VMs. `image list` and `image get`
|
|
375
|
-
cover the same catalog family as those add tools — each org row includes `kind`, a redacted
|
|
376
|
-
`manifest` (from `ghostdock.*` Docker/OCI labels), `requiredEnvironment`, and `requiredUrls` (same
|
|
377
|
-
shape as snapshots). `vm create` with `--source '{"type":"image","id":"..."}'` boots a catalog
|
|
378
|
-
row by id and applies its manifest (URLs + env) like an organization snapshot.
|
|
379
|
-
|
|
380
|
-
```bash
|
|
381
|
-
ghostdock image list --org org_123
|
|
382
|
-
ghostdock image get img_abc --org org_123
|
|
383
|
-
ghostdock image add --org org_123 --ref ghcr.io/acme/app:latest --label "Acme app"
|
|
384
|
-
ghostdock image add-dockerfile --org org_123 --name my-stack --dockerfile "$(cat Dockerfile)"
|
|
385
|
-
ghostdock vm create --org org_123 \
|
|
386
|
-
--source '{"type":"image","id":"img_abc"}' \
|
|
387
|
-
--environment '{"local":[{"name":"API_KEY","kind":"secret","value":"sk_test"}]}'
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
Booting with `--source '{"type":"dockerfile","content":"..."}'` parses labels inline without
|
|
391
|
-
persisting a catalog row. That JSON source is Dockerfile text only: COPY/ADD of local files fails.
|
|
392
|
-
`--source '{"type":"compose","files":{"compose.yaml":"..."}}'` boots Docker-in-Docker from those
|
|
393
|
-
inline files (must include `docker-compose.yml`/`yaml` or `compose.yml`/`yaml`) and runs
|
|
394
|
-
`docker compose up`; `ghostdock.*` service labels become the create-time manifest. A directory or
|
|
395
|
-
ZIP — Dockerfile build context, or a Compose project with extra files — is
|
|
396
|
-
[`ghostdock vm build`](#ghostdock-vm-build), not this command. Any OCI ref may still
|
|
397
|
-
be passed as `{ type: "image", ref }` even when it does not appear in `image list`. Catalog compose
|
|
398
|
-
rows still boot via `{ type: "image", id }`.
|
|
399
|
-
|
|
400
|
-
### `ghostdock site publish`
|
|
401
|
-
|
|
402
|
-
Publish a local directory or ZIP to the CDN (durable public URL, no VM):
|
|
403
|
-
|
|
404
|
-
```bash
|
|
405
|
-
ghostdock site publish --org org_123 ./dist
|
|
406
|
-
ghostdock site publish --org org_123 --zip ./site.zip
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
MCP `site_publish` is for small inline payloads. Use this command for a real directory or large ZIP.
|
|
410
|
-
|
|
411
|
-
### `ghostdock project publish`
|
|
412
|
-
|
|
413
|
-
Inspect a local source tree and publish (CDN when pre-built static, otherwise Compose from a DeploymentSpec).
|
|
414
|
-
Required secrets without values return `awaiting_configuration` instead of a live URL.
|
|
415
|
-
Re-invoke with `--environment` (same JSON shape as `vm create`) after configuring.
|
|
416
|
-
On `build_failed`, `start_failed`, or `verify_failed`, inspect the kept VM (unless verification tore it down), then re-invoke with `--spec` (JSON `DeploymentSpec`). The spec is executed on a fresh VM and stored for later replay. Do not pass `--spec` with `--replan`. Every terminal outcome stores the upload and returns authenticated `fileUrls`. Detected tests always run after the stack is up; pass `--require-verify` to refuse a deploy when they fail.
|
|
417
|
-
|
|
418
|
-
```bash
|
|
419
|
-
ghostdock project publish --org org_123 ./app
|
|
420
|
-
ghostdock project publish --org org_123 --auto-stop-interval-minutes -1 --zip ./app.zip
|
|
421
|
-
ghostdock project publish --org org_123 --project-id proj_123 ./app
|
|
422
|
-
ghostdock project publish --org org_123 ./app \
|
|
423
|
-
--environment '{"organization":["DATABASE_URL"],"local":[{"name":"API_KEY","value":"sk_live","kind":"secret"}]}'
|
|
424
|
-
ghostdock project publish --org org_123 ./app --spec '{"version":1,"run":{"kind":"static","outputDir":"."},"env":[]}'
|
|
425
|
-
ghostdock project publish --org org_123 --require-verify ./app
|
|
426
|
-
ghostdock project publish --org org_123 --provider prov_123 ./app
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
MCP `project_publish` is for small inline payloads. Use this command for a real directory or large ZIP.
|
|
430
|
-
|
|
431
|
-
### `ghostdock vm build`
|
|
432
|
-
|
|
433
|
-
Create a VM from a local Dockerfile or Compose directory. The CLI zips the directory (or sends
|
|
434
|
-
`--zip`) and the server builds it. MCP `vm_create` stays inline text only.
|
|
435
|
-
|
|
436
|
-
```bash
|
|
437
|
-
ghostdock vm build --org org_123 --kind dockerfile ./app
|
|
438
|
-
ghostdock vm build --org org_123 --kind compose --zip ./stack.zip
|
|
439
|
-
ghostdock vm build --org org_123 --kind dockerfile \
|
|
440
|
-
--provider prov_123 --display-name "API" ./app
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
The Dockerfile (`Dockerfile` or `dockerfile`) or a compose file (`docker-compose.yml`/`yaml`,
|
|
444
|
-
`compose.yml`/`yaml`) must sit at the directory root, or at the root of the ZIP. A ZIP that wraps
|
|
445
|
-
the project in one folder is unwrapped. Pass one directory or `--zip`, not both.
|
|
446
|
-
|
|
447
|
-
### `ghostdock vm file upload`
|
|
448
|
-
|
|
449
|
-
`vm file upload` is convenient for small payloads. For a local directory,
|
|
450
|
-
multiple files, or a large ZIP, use the dedicated multipart upload command instead:
|
|
451
|
-
|
|
452
|
-
```bash
|
|
453
|
-
ghostdock vm file upload quiet-harbor ./dist
|
|
454
|
-
ghostdock vm file upload quiet-harbor ./index.html ./assets
|
|
455
|
-
ghostdock vm file upload quiet-harbor --zip ./site.zip
|
|
456
|
-
ghostdock vm file upload quiet-harbor ./dist --container web --start
|
|
457
|
-
```
|
|
458
|
-
|
|
459
|
-
Each positional path may be a file or directory. Directory contents are uploaded recursively,
|
|
460
|
-
preserving their relative paths; a file is uploaded by its basename. A `vm file upload` call needs
|
|
461
|
-
at least one path or `--zip`. Uploading to a stopped VM resumes it automatically.
|
|
462
|
-
The files land in a container as the other `vm file` commands do (see
|
|
463
|
-
[Containers in a VM](#containers-in-a-vm)): `--container <name>`, else the default,
|
|
464
|
-
else the one running, and the CLI asks which one when it cannot tell. A stopped target container
|
|
465
|
-
is started after a "Start it?" at the keyboard, or at once with `--start`.
|
|
466
|
-
|
|
467
|
-
### `ghostdock env`
|
|
468
|
-
|
|
469
|
-
Manage the environment variables and secrets an organization offers to its VMs and projects.
|
|
470
|
-
A VM inherits nothing automatically — select the entries it needs on that VM.
|
|
471
|
-
|
|
472
|
-
```bash
|
|
473
|
-
ghostdock env list --org org_123
|
|
474
|
-
ghostdock env get VITE_API_URL --org org_123
|
|
475
|
-
ghostdock env set VITE_API_URL --org org_123 --value https://api.example.com
|
|
476
|
-
ghostdock env delete VITE_API_URL --org org_123
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
**Variables vs secrets.** A variable is readable by anyone who can see the organization; `env list`
|
|
480
|
-
prints its value inline. A secret can be set and replaced but never read back — it shows as
|
|
481
|
-
`<secret>` in `env list` and `env get` refuses it. Pass `--secret` to create one:
|
|
482
|
-
|
|
483
|
-
```bash
|
|
484
|
-
# Keeps the value out of shell history and the process list
|
|
485
|
-
printf %s "$STRIPE_KEY" | ghostdock env set STRIPE_SECRET_KEY --org org_123 --secret --value-stdin
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
`--secret` is only required when creating; updating an existing entry keeps its kind. To convert one,
|
|
489
|
-
pass `--kind variable` or `--kind secret` explicitly along with the new value:
|
|
490
|
-
|
|
491
|
-
```bash
|
|
492
|
-
ghostdock env set STRIPE_SECRET_KEY --org org_123 --kind variable --value not-secret-anymore
|
|
493
|
-
# Warning: STRIPE_SECRET_KEY was a secret and is now a variable — its value is readable by everyone in the organization.
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
Converting never reveals the old secret: `set` always replaces the value, so the value you supply in
|
|
497
|
-
that call is the one that becomes readable. The command prints what changed either way.
|
|
498
|
-
|
|
499
|
-
`env get` prints the bare value so it can be captured in a shell (`API=$(ghostdock env get
|
|
500
|
-
VITE_API_URL --org org_123)`). It also returns values too large for `env list`, which
|
|
501
|
-
withholds anything over 1024 characters rather than truncating it — a printed value is always the
|
|
502
|
-
complete value.
|
|
503
|
-
|
|
504
|
-
With `--json`, `list`, `get` and `set` print the tool's result instead. These commands wrap the
|
|
505
|
-
`env list`, `env get`, `env set` and
|
|
506
|
-
`env delete` tools, which are also available directly (and over MCP).
|
|
507
|
-
|
|
508
|
-
Names must be valid environment variable names, and names the VM runtime owns (`PATH`,
|
|
509
|
-
`HOME`, anything starting with `GHOSTDOCK_`, …) are rejected. Prefix a name with `VITE_`
|
|
510
|
-
only when browser code must read it: Vite inlines those into the published bundle, so a `VITE_`
|
|
511
|
-
secret is public.
|
|
512
|
-
|
|
513
|
-
### `ghostdock network`
|
|
514
|
-
|
|
515
|
-
Reach your organizations' VMs from this machine by private address and name, over
|
|
516
|
-
WireGuard ([ADR 0027](../../docs/adr/0027-private-sandbox-network.md)). Everything on a
|
|
517
|
-
VM's address is reachable: a container that publishes port 80 answers on
|
|
518
|
-
`http://quiet-harbor.acme.ghostdock.internal/`, as it would on `localhost` inside the VM.
|
|
519
|
-
Nothing reaches your machine from a VM.
|
|
520
|
-
|
|
521
|
-
```bash
|
|
522
|
-
ghostdock network connect # your organization's default provider; sudo once
|
|
523
|
-
ghostdock network connect helsinki # or name a provider (name or id)
|
|
524
|
-
ghostdock network ls --org acme # VMs, addresses, names, and what is reachable
|
|
525
|
-
curl http://quiet-harbor.acme.ghostdock.internal:8080/
|
|
526
|
-
open https://quiet-harbor--acme.ghostdock.net:8080/ # in a browser: HTTPS, any port
|
|
527
|
-
open https://quiet-harbor.ghostdock.net:8080/ # the short name, for the connect organization
|
|
528
|
-
ghostdock network connect --org beta # short names now mean beta's VMs
|
|
529
|
-
ghostdock network status
|
|
530
|
-
ghostdock network disconnect
|
|
531
|
-
```
|
|
532
|
-
|
|
533
|
-
- **One provider at a time.** Each provider is its own gateway, and a device reaches
|
|
534
|
-
only the VMs on the provider it connected through. Without an argument, `connect` takes
|
|
535
|
-
the organization (`--org`, `GHOSTDOCK_ORG`, the default from `organization use`) and its
|
|
536
|
-
default provider, else the platform default. Connecting through another provider
|
|
537
|
-
replaces the connection: same interface and address, new gateway. `network status` says which
|
|
538
|
-
provider you are connected through; `network ls` marks VMs elsewhere as
|
|
539
|
-
`not reachable: on <provider>` with the `connect` command that reaches them. A provider
|
|
540
|
-
without a private network (Incus, for now) is refused by the server; one your organization
|
|
541
|
-
may not use answers 403.
|
|
542
|
-
- **Needs `wg-quick`** (`brew install wireguard-tools`, `apt install wireguard-tools`). macOS
|
|
543
|
-
and Linux. On Windows, run the CLI in WSL: then only tools inside WSL reach VMs.
|
|
544
|
-
- **Tunnel MTU 1280**, so the tunnel works on networks with a smaller path than 1500 bytes
|
|
545
|
-
(DS-Lite, VPNs, mobile). A config written before 2026-10-20 has 1420: `network status` and
|
|
546
|
-
`network ls` then say *This machine's tunnel has MTU 1420, the network now uses 1280*. Run
|
|
547
|
-
`ghostdock network connect` again; until then TCP works, other large packets can be lost.
|
|
548
|
-
- **One key per machine**, kept in `~/.config/ghostdock/network/`.
|
|
549
|
-
Only the public key is sent. The device belongs to the login it was connected with:
|
|
550
|
-
`ghostdock logout` takes it out of the network, and so does not connecting for 90 days.
|
|
551
|
-
- **Names**: `<vm>.<org>.ghostdock.internal`, for every organization you are a member
|
|
552
|
-
of. A name always says its organization, so a browser origin never changes hands between
|
|
553
|
-
organizations. Only AAAA records exist: the network is IPv6, and the VM sees IPv4.
|
|
554
|
-
- **In a browser**, use the HTTPS name `https://<vm>--<org>.ghostdock.net:<port>`
|
|
555
|
-
(`network ls` shows it): any port, a real certificate, so the page is a secure context
|
|
556
|
-
(clipboard, `Secure` cookies, service workers). The host's `gdo-ingress` terminates TLS and
|
|
557
|
-
forwards to the VM's port; it serves only devices of the VM's organization, and
|
|
558
|
-
refuses background requests (fetch, forms, iframes, websockets) from pages outside that
|
|
559
|
-
organization; pages on another HTTPS name of the same organization, any port, may call it. The
|
|
560
|
-
VM sees the request from `198.18.0.0`, and your device's address in
|
|
561
|
-
`X-Forwarded-For`. The desktop image's Desktop opens only this way, never on the raw
|
|
562
|
-
address.
|
|
563
|
-
- **Short names** in a browser: `https://<vm>.ghostdock.net:<port>` means the VM of
|
|
564
|
-
this machine's organization: the one `network connect` resolved (`--org`, `GHOSTDOCK_ORG`,
|
|
565
|
-
the default from `organization use`). `connect` says which; `network status` too, and
|
|
566
|
-
`network ls` shows a VM's short name next to its full one when it is that
|
|
567
|
-
organization's. With one organization you need nothing else. To use another organization's
|
|
568
|
-
short names, connect again with `--org <other>`: there is no other way to change it, so a
|
|
569
|
-
short name never changes meaning behind your back (`cd` into another project does not
|
|
570
|
-
change it). Full names (`<vm>--<org>`) keep working for every organization and never
|
|
571
|
-
change meaning: use them in scripts, CI, `.env` files and links you share.
|
|
572
|
-
- **When the organization changes,** each short-name site clears its browser data once
|
|
573
|
-
(local storage, cache, cookies) before the other organization's VM sees a request, so
|
|
574
|
-
it never reads the first one's data. Cookies are cleared for the whole site, not only the
|
|
575
|
-
short name: every site under the net domain's registrable domain (`ghostdock.net`: every
|
|
576
|
-
VM app there, full names included; a net domain under the app's domain, as on staging:
|
|
577
|
-
the Ghostdock app too). `connect` names the site when the organization changes. A tab opened on a short name before the
|
|
578
|
-
change keeps the old page until you reload it: reload or close those tabs (`connect` says
|
|
579
|
-
so). The page *Switching organization* is that clearing and reloads by itself; *Clear this
|
|
580
|
-
site's data* means your browser could not clear it (Safari before 17): clear the site's
|
|
581
|
-
data in its settings, or use the full name.
|
|
582
|
-
- Tools may use short names too (`curl https://quiet-harbor.ghostdock.net:8080/`), but a
|
|
583
|
-
short name in a script means whatever this machine is connected with: prefer the full
|
|
584
|
-
name.
|
|
585
|
-
- **Browsers use the HTTPS name; tools keep the raw address.** A browser that opens
|
|
586
|
-
`http://quiet-harbor.acme.ghostdock.internal:3000/app` (or the raw IPv6 address) gets a
|
|
587
|
-
`308` to `https://quiet-harbor--acme.ghostdock.net:3000/app`. Any other browser request on
|
|
588
|
-
the raw address (`fetch`, images, scripts, forms, websockets) gets `403` with
|
|
589
|
-
`X-Ghostdock-Blocked: browser-https-only` and the HTTPS address in the body. This keeps
|
|
590
|
-
websites you visit while connected from using your connection against your VMs,
|
|
591
|
-
including through DNS rebinding.
|
|
592
|
-
- **What counts as a browser:** a `User-Agent` that starts with `Mozilla/`, which every
|
|
593
|
-
browser sends on its own requests. Browsers send no `Sec-Fetch-*` headers over plain
|
|
594
|
-
`http://` to an address like this, so those cannot be the signal. (Firefox lets a page
|
|
595
|
-
set its own `User-Agent` on a `fetch`; the `Host` check below stops that one.) Tools that send a
|
|
596
|
-
browser's `User-Agent` (Playwright, Puppeteer, their request APIs) count as browsers too:
|
|
597
|
-
point them at the HTTPS name. A frontend outside the VM (a dev server on your laptop)
|
|
598
|
-
calls the VM's API by its HTTPS name as well.
|
|
599
|
-
- **Tools** (`curl`, SDKs, test runners, Prometheus) pass untouched, and every other
|
|
600
|
-
protocol does too, as long as they address the VM by its IP address, its
|
|
601
|
-
`.internal` name (or a container's, `web.quiet-harbor.acme.ghostdock.internal`), or
|
|
602
|
-
`localhost`: any other `Host` gets `421` (`X-Ghostdock-Blocked: host-not-allowed`). That
|
|
603
|
-
check is what stops DNS rebinding for a page that sets its own `User-Agent`. A name of
|
|
604
|
-
your own in `/etc/hosts` gets 421 too.
|
|
605
|
-
- **One difference for tools:** a port where nothing listens accepts the connection and
|
|
606
|
-
then resets it, so port checks such as `nc -z` report it open; check with a real request
|
|
607
|
-
instead.
|
|
608
|
-
- **In the VM,** firewall rules for these clients belong in the input path
|
|
609
|
-
(`iptables -A INPUT`, an nft `hook input` chain): `FORWARD` and `DOCKER-USER` rules no
|
|
610
|
-
longer see them, because the guard connects to a published container port from inside
|
|
611
|
-
the VM.
|
|
612
|
-
- **The network pause** ([ADR 0033](../../docs/adr/0033-gdo-net-dead-mans-switch.md)): a
|
|
613
|
-
device that sent no traffic to a VM for its idle timeout (default 4 h), or whose session
|
|
614
|
-
since the last connect reached its maximum (default 12 h), is paused at the gateway. Your
|
|
615
|
-
organizations set both (Settings → Security). If you are in several, the strictest value
|
|
616
|
-
applies. `connect` ends with this device's own numbers and names the organization that set a
|
|
617
|
-
stricter one.
|
|
618
|
-
- **While paused**, names still resolve, but every port of a VM answers `Connection
|
|
619
|
-
refused`, and UDP and ping get *administratively prohibited*. Browsers get a pause page
|
|
620
|
-
with a *Reconnect* button, and Docker gets `Ghostdock: network access for this device is
|
|
621
|
-
paused (idle 4 h)`. Every `ghostdock` command prints `! Network access for this device is
|
|
622
|
-
paused (…). Run: ghostdock network connect` once.
|
|
623
|
-
- **To resume**, run `ghostdock network connect`, or click *Reconnect* in the web app (User
|
|
624
|
-
settings → Network devices). With the tunnel up and nothing changed, `connect` only
|
|
625
|
-
re-arms: no sudo, *Re-armed: network access for this device runs until 22:14 (pauses after
|
|
626
|
-
4 h idle).* *Pause now* in the web app pauses a device at once.
|
|
627
|
-
- DNS, WireGuard keepalives and ping do not count as traffic. A long stream does (a `docker
|
|
628
|
-
logs -f`, an open desktop tab).
|
|
629
|
-
- `ghostdock network devices` lists your devices with their state (*Active, pauses in 3 h 12
|
|
630
|
-
min*, *Paused: idle 4 h*, *Paused: 12 h session limit*, *Paused by you*, *Not connected
|
|
631
|
-
(…)*). `ghostdock network devices remove <id>` removes one.
|
|
632
|
-
- **`ghostdock network disconnect`** also removes the split-DNS files a reboot or a crashed
|
|
633
|
-
`wg-quick` left on macOS (`/etc/resolver/<zone>`), even when the tunnel is already down.
|
|
634
|
-
Without that, names of the private network hang while you are disconnected. `network status`
|
|
635
|
-
says when such a file is still there.
|
|
636
|
-
|
|
637
|
-
### `ghostdock docker context`
|
|
638
|
-
|
|
639
|
-
Point your own `docker` and `docker compose` at a VM's Docker engine, over the private
|
|
640
|
-
network with mutual TLS ([ADR 0032](../../docs/adr/0032-docker-api-over-gdo-net.md)). Connect
|
|
641
|
-
first: the context uses this machine's device.
|
|
642
|
-
|
|
643
|
-
```bash
|
|
644
|
-
ghostdock network connect
|
|
645
|
-
ghostdock docker context quiet-harbor --org acme
|
|
646
|
-
# ✓ Docker context ghostdock-acme-quiet-harbor (in use)
|
|
647
|
-
# tcp://quiet-harbor.acme.ghostdock.internal:2376
|
|
648
|
-
# Certificate for this device, valid until 2026-11-20.
|
|
649
|
-
# → docker ps
|
|
650
|
-
docker ps
|
|
651
|
-
docker compose up -d
|
|
652
|
-
ghostdock docker context north-pier --no-use # create only: docker --context ghostdock-acme-north-pier ps
|
|
653
|
-
```
|
|
654
|
-
|
|
655
|
-
- **One Docker context per VM**, `ghostdock-<org>-<vm>`, for
|
|
656
|
-
`tcp://<vm>.<org>.ghostdock.internal:2376`. Running the command again updates it;
|
|
657
|
-
without `--no-use` it also becomes Docker's current context (`docker context use`). A
|
|
658
|
-
`DOCKER_HOST` or `DOCKER_CONTEXT` in your shell wins over that: the command says so.
|
|
659
|
-
- **One client certificate per organization and machine**, in
|
|
660
|
-
`~/.config/ghostdock/docker/<organizationId>/`: `key.pem` (ECDSA P-256, made on this machine,
|
|
661
|
-
0600; only a certificate request is sent), `cert.pem` and `ca.pem`. The certificate names your
|
|
662
|
-
user, this machine's device and the organization, and lives 30 days. A new one replaces the
|
|
663
|
-
earlier one of this device for that organization: the old one stops working at once.
|
|
664
|
-
- **Renewal:** `ghostdock network connect` and `ghostdock docker context` renew every
|
|
665
|
-
certificate of this machine with less than 10 days left, and update the contexts they wrote
|
|
666
|
-
(`~/.config/ghostdock/docker/contexts.json`). An expired certificate fails Docker's TLS
|
|
667
|
-
handshake with Docker's own error: run `ghostdock docker context <vm>` again.
|
|
668
|
-
- **`no such host`** on a `ghostdock.internal` address means this machine is not connected:
|
|
669
|
-
run `ghostdock network connect`. The context's description in `docker context ls` says so
|
|
670
|
-
too.
|
|
671
|
-
- **Renamed organization:** the context's host keeps the old name, which stops resolving. Run
|
|
672
|
-
`ghostdock docker context <vm>` again to update the host.
|
|
673
|
-
- **Only from this device:** the VM checks every request with the app (membership, device,
|
|
674
|
-
the network pause). A copied key and certificate do not work from another machine; a refusal
|
|
675
|
-
comes back as Docker's `Error response from daemon: Ghostdock: …` with what to run.
|
|
676
|
-
- **Warnings:** a VM on another provider than this machine's connection (with the
|
|
677
|
-
`network connect` command that reaches it), and a VM whose base image is too old for
|
|
678
|
-
Docker over the network (restart it to update). A VM that cannot have a Docker engine
|
|
679
|
-
over the network (its provider has no private network, it has no address there yet, or a
|
|
680
|
-
name that is not a DNS label) gets no context, and the command says why.
|
|
681
|
-
- **A stopped VM** gets its context too: the first connection to it starts it (wake on
|
|
682
|
-
SYN), and its Docker engine answers once it runs. A start that takes longer than Docker's
|
|
683
|
-
32 s dial timeout fails that one command with Docker's `i/o timeout`; the next one works.
|
|
684
|
-
- **Needs Docker's CLI** (`docker` on `PATH`: Docker Desktop, OrbStack, or the CLI alone). The
|
|
685
|
-
Docker engine itself runs in the VM.
|
|
686
|
-
|
|
687
|
-
## Command index
|
|
688
|
-
|
|
689
|
-
Every command with its arguments and what it does. Run `ghostdock <command> --help` for its flags,
|
|
690
|
-
or read [`cli-reference.md`](cli-reference.md) for every command's full description and flags.
|
|
691
|
-
|
|
692
|
-
<!-- generated:command-index:start (bun run sync:cli-reference; do not edit) -->
|
|
693
|
-
#### app
|
|
694
|
-
|
|
695
|
-
| Command | What it does |
|
|
696
|
-
| --- | --- |
|
|
697
|
-
| `ghostdock app list [flags]` | List the live published apps (sites) of an organization, with their URLs. |
|
|
698
|
-
|
|
699
|
-
#### docker
|
|
700
|
-
|
|
701
|
-
| Command | What it does |
|
|
702
|
-
| --- | --- |
|
|
703
|
-
| `ghostdock docker context <vm> [flags]` | Point Docker at a VM's Docker engine over the private network: plain `docker`… |
|
|
704
|
-
|
|
705
|
-
#### env
|
|
706
|
-
|
|
707
|
-
| Command | What it does |
|
|
708
|
-
| --- | --- |
|
|
709
|
-
| `ghostdock env delete <name> [flags]` | Delete a variable or secret. |
|
|
710
|
-
| `ghostdock env get <name> [flags]` | Print one variable value in full (secrets cannot be read). |
|
|
711
|
-
| `ghostdock env list [flags]` | List variables and secrets. |
|
|
712
|
-
| `ghostdock env set <name> [flags]` | Create or replace a variable or secret. |
|
|
713
|
-
|
|
714
|
-
#### image
|
|
715
|
-
|
|
716
|
-
| Command | What it does |
|
|
717
|
-
| --- | --- |
|
|
718
|
-
| `ghostdock image add --ref <string> [flags]` | Bookmark an OCI image ref in the organization’s image catalog. |
|
|
719
|
-
| `ghostdock image add-compose --name <string> [flags]` | Add a Compose project to the organization’s image catalog. |
|
|
720
|
-
| `ghostdock image add-dockerfile --name <string> --dockerfile <string> [flags]` | Add a Dockerfile to the organization’s image catalog. |
|
|
721
|
-
| `ghostdock image get <image-id> [flags]` | Get one catalog image with its spec, manifest and requirements. |
|
|
722
|
-
| `ghostdock image list [flags]` | List the images an organization can boot VMs from. |
|
|
723
|
-
| `ghostdock image remove <image-id> [flags]` | Remove an image from the organization’s catalog. |
|
|
724
|
-
| `ghostdock image update-compose <image-id> [flags]` | Replace a catalog Compose image’s files, reference, override and/or name. |
|
|
725
|
-
| `ghostdock image update-dockerfile <image-id> --dockerfile <string> [flags]` | Replace a catalog Dockerfile, optionally renaming it. |
|
|
726
|
-
|
|
727
|
-
#### login
|
|
728
|
-
|
|
729
|
-
| Command | What it does |
|
|
730
|
-
| --- | --- |
|
|
731
|
-
| `ghostdock login [flags]` | Sign in and store a device access token for this machine… |
|
|
732
|
-
|
|
733
|
-
#### logout
|
|
734
|
-
|
|
735
|
-
| Command | What it does |
|
|
736
|
-
| --- | --- |
|
|
737
|
-
| `ghostdock logout` | Revoke the device session and remove stored credentials. |
|
|
738
|
-
|
|
739
|
-
#### network
|
|
740
|
-
|
|
741
|
-
| Command | What it does |
|
|
742
|
-
| --- | --- |
|
|
743
|
-
| `ghostdock network connect [provider] [flags]` | Put this machine into the private network through one provider: WireGuard and… |
|
|
744
|
-
| `ghostdock network devices <command>` | Your devices in the private network. |
|
|
745
|
-
| `ghostdock network devices remove <id>` | Remove one of your devices from the private network. |
|
|
746
|
-
| `ghostdock network disconnect` | Take this machine out of the private network, and remove split DNS an earlier… |
|
|
747
|
-
| `ghostdock network ls [flags]` | VMs of an organization with their private addresses and names, and which are… |
|
|
748
|
-
| `ghostdock network status` | Whether this machine is connected, through which provider, and as which device. |
|
|
749
|
-
|
|
750
|
-
#### organization
|
|
751
|
-
|
|
752
|
-
| Command | What it does |
|
|
753
|
-
| --- | --- |
|
|
754
|
-
| `ghostdock organization current [flags]` | Show which organization commands use, and where it comes from. |
|
|
755
|
-
| `ghostdock organization list` | List the organizations you belong to, with their ids and slugs. |
|
|
756
|
-
| `ghostdock organization use [org] [flags]` | Set the default organization for commands run without --org (in every… |
|
|
757
|
-
|
|
758
|
-
#### project
|
|
759
|
-
|
|
760
|
-
| Command | What it does |
|
|
761
|
-
| --- | --- |
|
|
762
|
-
| `ghostdock project create --display-name <string> [flags]` | Create an empty project. |
|
|
763
|
-
| `ghostdock project deployment get <deployment-id> --project-id <string> [flags]` | Get one deploy attempt, with links to its stored files. |
|
|
764
|
-
| `ghostdock project deployment list <project-id> [flags]` | List a project’s deploy attempts, newest first. |
|
|
765
|
-
| `ghostdock project env delete <name> --project-id <string> [flags]` | Delete one of a project’s own variables or secrets. |
|
|
766
|
-
| `ghostdock project env get <project-id> [flags]` | Get a project’s stored environment. |
|
|
767
|
-
| `ghostdock project env select <project-id> --environment <array> [flags]` | Replace the organization entries a project exports. |
|
|
768
|
-
| `ghostdock project env set <name> --project-id <string> --value <string> --kind <string> [flags]` | Create or replace one of a project’s own variables or secrets. |
|
|
769
|
-
| `ghostdock project get <project-id> [flags]` | Get a project with its latest attempt and live deployment. |
|
|
770
|
-
| `ghostdock project list [flags]` | List an organization’s projects. |
|
|
771
|
-
| `ghostdock project publish [path] [flags]` | Inspect local source with the deploy agent and publish to the CDN or a VM. |
|
|
772
|
-
| `ghostdock project redeploy <project-id> [flags]` | Deploy a project’s stored source again, with its current environment. |
|
|
773
|
-
| `ghostdock project update <project-id> --display-name <string> [flags]` | Rename a project. |
|
|
774
|
-
|
|
775
|
-
#### provider
|
|
776
|
-
|
|
777
|
-
| Command | What it does |
|
|
778
|
-
| --- | --- |
|
|
779
|
-
| `ghostdock provider disconnect <provider> [flags]` | Disconnect one of the organization’s own providers. |
|
|
780
|
-
| `ghostdock provider list [flags]` | List the providers an organization can create VMs on. |
|
|
781
|
-
| `ghostdock provider rename <provider> --name <string> [flags]` | Rename one of the organization’s own providers. |
|
|
782
|
-
| `ghostdock provider set-default <provider> [flags]` | Set the provider used when a create omits provider. |
|
|
783
|
-
| `ghostdock provider start-incus [flags]` | Start connecting an Incus host as a provider. |
|
|
784
|
-
| `ghostdock provider verify-incus <provider> [flags]` | Check or finish connecting an Incus host. |
|
|
785
|
-
|
|
786
|
-
#### registry
|
|
787
|
-
|
|
788
|
-
| Command | What it does |
|
|
789
|
-
| --- | --- |
|
|
790
|
-
| `ghostdock registry credentials [flags]` | Print registry host, username, and the one-hour password. |
|
|
791
|
-
| `ghostdock registry login [flags]` | Fetch a one-hour password and run docker login --password-stdin. |
|
|
792
|
-
|
|
793
|
-
#### site
|
|
794
|
-
|
|
795
|
-
| Command | What it does |
|
|
796
|
-
| --- | --- |
|
|
797
|
-
| `ghostdock site publish [path] [flags]` | Publish a local directory or ZIP to the CDN. |
|
|
798
|
-
| `ghostdock site unpublish <site-id> [flags]` | Take a published static site offline. |
|
|
799
|
-
|
|
800
|
-
#### skill
|
|
801
|
-
|
|
802
|
-
| Command | What it does |
|
|
803
|
-
| --- | --- |
|
|
804
|
-
| `ghostdock skill get <uri>` | Print one SKILL.md (URI from the discovery index, or a skill name). |
|
|
805
|
-
| `ghostdock skill list` | List the Agent Skills discovery index. |
|
|
806
|
-
|
|
807
|
-
#### snapshot
|
|
808
|
-
|
|
809
|
-
| Command | What it does |
|
|
810
|
-
| --- | --- |
|
|
811
|
-
| `ghostdock snapshot create <vm> --name <string> [flags]` | Save a VM’s filesystem as a reusable organization snapshot. |
|
|
812
|
-
| `ghostdock snapshot delete <snapshot-id> [flags]` | Permanently delete an organization snapshot (provider artifact and record). |
|
|
813
|
-
| `ghostdock snapshot get <snapshot-id> [flags]` | Get one snapshot with its manifest and required environment, URLs and MCPs. |
|
|
814
|
-
| `ghostdock snapshot list [flags]` | List the snapshots an organization can boot VMs from. |
|
|
815
|
-
| `ghostdock snapshot update-manifest <snapshot-id> --manifest <object> [flags]` | Replace a snapshot’s manifest (URLs, environment, MCPs). |
|
|
816
|
-
|
|
817
|
-
#### template
|
|
818
|
-
|
|
819
|
-
| Command | What it does |
|
|
820
|
-
| --- | --- |
|
|
821
|
-
| `ghostdock template create --name <string> --title <string> --spec <object> [flags]` | Save a VM create request as a template of the organization. |
|
|
822
|
-
| `ghostdock template delete <template> [flags]` | Delete a template of the organization by its name. |
|
|
823
|
-
| `ghostdock template list [flags]` | List the templates to create a VM from (headless, desktop, nginx, …). |
|
|
824
|
-
| `ghostdock template update <template> [flags]` | Change a template of the organization by its name. |
|
|
825
|
-
|
|
826
|
-
#### tools
|
|
827
|
-
|
|
828
|
-
| Command | What it does |
|
|
829
|
-
| --- | --- |
|
|
830
|
-
| `ghostdock tools` | List available agent tools. |
|
|
831
|
-
|
|
832
|
-
#### vm
|
|
833
|
-
|
|
834
|
-
| Command | What it does |
|
|
835
|
-
| --- | --- |
|
|
836
|
-
| `ghostdock vm build [path] --kind <value> [flags]` | Create a VM from a local Dockerfile or Compose directory. |
|
|
837
|
-
| `ghostdock vm command get <command-id> --vm <string> --session-id <string> [flags]` | Get a shell command’s status and exit code. |
|
|
838
|
-
| `ghostdock vm command kill <command-id> --vm <string> --session-id <string> [flags]` | Interrupt a running shell command. |
|
|
839
|
-
| `ghostdock vm command logs <command-id> --vm <string> --session-id <string> [flags]` | Get a page of a shell command’s stdout and stderr. |
|
|
840
|
-
| `ghostdock vm command run <vm> --command <string> [flags]` | Run a shell command in a VM. |
|
|
841
|
-
| `ghostdock vm container list <vm> [flags]` | List the containers of a VM, running or not. |
|
|
842
|
-
| `ghostdock vm container lock <vm> <container> [flags]` | Lock a container against removal. |
|
|
843
|
-
| `ghostdock vm container logs <vm> <container> [flags]` | Read a container’s output, as docker logs does. |
|
|
844
|
-
| `ghostdock vm container restart <vm> <container> [flags]` | Restart a container, as docker restart does (stopping as docker stop does). |
|
|
845
|
-
| `ghostdock vm container start <vm> <container> [flags]` | Start a stopped container, as docker start does. |
|
|
846
|
-
| `ghostdock vm container stop <vm> <container> [flags]` | Stop a container, as docker stop does. |
|
|
847
|
-
| `ghostdock vm container unlock <vm> <container> [flags]` | Unlock a container so Docker can remove or recreate it. |
|
|
848
|
-
| `ghostdock vm create --source <object> [flags]` | Create a VM from a snapshot, OCI image, Dockerfile or Compose files. |
|
|
849
|
-
| `ghostdock vm default-container <vm> [flags]` | Show, set or clear the VM’s default container. |
|
|
850
|
-
| `ghostdock vm delete <vm> [flags]` | Permanently delete a VM and its files. |
|
|
851
|
-
| `ghostdock vm env delete <name> --vm <string> [flags]` | Delete one of a VM’s own variables or secrets. |
|
|
852
|
-
| `ghostdock vm env get <vm> [flags]` | Get a VM’s environment: selections, bindings and local entries. |
|
|
853
|
-
| `ghostdock vm env select <vm> --environment <array> [flags]` | Replace the organization entries a VM exports. |
|
|
854
|
-
| `ghostdock vm env set <name> --vm <string> --value <string> [flags]` | Create or replace one of a VM’s own variables or secrets. |
|
|
855
|
-
| `ghostdock vm file list <vm> [flags]` | List the files in a VM directory. |
|
|
856
|
-
| `ghostdock vm file read <path> --vm <string> [flags]` | Read a file from a VM: utf8 text, or base64 for small binaries. |
|
|
857
|
-
| `ghostdock vm file upload <vm> [path] [flags]` | Upload local files or directories to a VM's container, into its start folder… |
|
|
858
|
-
| `ghostdock vm list [flags]` | List the VMs of an organization, with their lifecycle and deadlines. |
|
|
859
|
-
| `ghostdock vm mcp create <vm> --name <string> --port <integer> [flags]` | Expose an MCP server running in a VM. |
|
|
860
|
-
| `ghostdock vm mcp delete <mcp-id>` | Delete an MCP endpoint of a VM. |
|
|
861
|
-
| `ghostdock vm mcp list <vm> [flags]` | List the MCP endpoints a VM exposes (name, port, path, autoWake). |
|
|
862
|
-
| `ghostdock vm mcp update <mcp-id> [flags]` | Change an MCP endpoint’s name, port, path or autoWake setting. |
|
|
863
|
-
| `ghostdock vm resize <vm> [flags]` | Change a VM’s CPU and/or memory. |
|
|
864
|
-
| `ghostdock vm resize-disk <vm> --disk-gib <number> [flags]` | Grow a VM’s disk. |
|
|
865
|
-
| `ghostdock vm shell close <session-id> --vm <string> [flags]` | Close a shell session. |
|
|
866
|
-
| `ghostdock vm shell create <vm> [flags]` | Open a shell session that keeps cwd and environment between commands. |
|
|
867
|
-
| `ghostdock vm ssh get <vm> [flags]` | Get temporary SSH access to a VM (command and token, 60 minutes). |
|
|
868
|
-
| `ghostdock vm ssh revoke <vm> [flags]` | Revoke a VM’s active SSH access. |
|
|
869
|
-
| `ghostdock vm status <vm> [flags]` | Get a VM’s status and lifecycle deadlines without waking it. |
|
|
870
|
-
| `ghostdock vm stop <vm> [flags]` | Stop a running VM without deleting its files. |
|
|
871
|
-
| `ghostdock vm storage delete <vm> --kind <string> --name <string> [flags]` | Delete a named volume or a top-level VM folder, with everything in it. |
|
|
872
|
-
| `ghostdock vm storage list <vm> [flags]` | List a VM’s volumes and VM folders. |
|
|
873
|
-
| `ghostdock vm tool call <name> --vm <string> --arguments <object> [flags]` | Call a tool on an MCP server inside a VM. |
|
|
874
|
-
| `ghostdock vm tool list <vm> [flags]` | List the tools of the MCP servers a VM exposes. |
|
|
875
|
-
| `ghostdock vm up <template> [flags]` | Create a VM from a template by its name: `ghostdock vm up nginx`. |
|
|
876
|
-
| `ghostdock vm update <vm> [flags]` | Change a VM’s display name, idle-stop interval or lifecycle. |
|
|
877
|
-
| `ghostdock vm url create <vm> --port <integer> [flags]` | Expose a VM port as a URL. |
|
|
878
|
-
| `ghostdock vm url delete <url-id>` | Delete a VM URL. |
|
|
879
|
-
| `ghostdock vm url list <vm> [flags]` | List the URLs that expose a VM’s ports, with protocol, access and title. |
|
|
880
|
-
| `ghostdock vm url update <url-id> [flags]` | Change a VM URL’s port, protocol, autoWake, public setting or title. |
|
|
881
|
-
| `ghostdock vm wake <vm> [flags]` | Start a stopped VM, or reset the idle-stop countdown of a running one. |
|
|
882
|
-
|
|
883
|
-
#### whoami
|
|
884
|
-
|
|
885
|
-
| Command | What it does |
|
|
886
|
-
| --- | --- |
|
|
887
|
-
| `ghostdock whoami` | Show the account this CLI is currently authenticated as. |
|
|
888
|
-
<!-- generated:command-index:end -->
|
|
889
|
-
|
|
890
|
-
## CLI settings
|
|
891
|
-
|
|
892
|
-
Environment variables read by the CLI process itself. For an organization's environment variables
|
|
893
|
-
and secrets, see [`ghostdock env`](#ghostdock-env).
|
|
894
|
-
|
|
895
|
-
| Variable | Purpose | Default |
|
|
896
|
-
| ------------------------------- | ------------------------------------------------------------- | --------------------------------- |
|
|
897
|
-
| `GHOSTDOCK_BASE_URL` | API origin the CLI talks to. Override for local dev / self-hosted instances. | Local/dev builds default to `http://localhost:3000`. npm-published builds default to the production API origin baked at publish time. Override with `--base-url` or this env var. |
|
|
898
|
-
| `GHOSTDOCK_ORG` | Organization (id or slug) for commands run without `--org`. Takes precedence over the default from `organization use`. | unset |
|
|
899
|
-
| `XDG_CONFIG_HOME` | Base directory for the CLI's per-machine state (`ghostdock/credentials.json`, `ghostdock/settings.json`, `ghostdock/network/`, `ghostdock/docker/`). | `~/.config` (native Windows: `%APPDATA%`) |
|
|
900
|
-
| `GHOSTDOCK_CREDENTIALS_PATH` | Absolute path to the credentials file, overriding the default. `settings.json` (the default organization) sits in the same directory, so each credentials file keeps its own default — handy for a second account. | `~/.config/ghostdock/credentials.json` |
|
|
901
|
-
|
|
902
|
-
Example for local development against a Nuxt dev server:
|
|
903
|
-
|
|
904
|
-
```bash
|
|
905
|
-
ghostdock --base-url http://localhost:3000 login --wait
|
|
906
|
-
# or
|
|
907
|
-
GHOSTDOCK_BASE_URL=http://localhost:3000 ghostdock login --wait
|
|
908
|
-
```
|
|
909
|
-
|
|
910
|
-
## Credentials file
|
|
911
|
-
|
|
912
|
-
Credentials are stored per machine as JSON in `~/.config/ghostdock/credentials.json`
|
|
913
|
-
(`$XDG_CONFIG_HOME/ghostdock/` when that is set, `%APPDATA%\ghostdock\` on native Windows; WSL
|
|
914
|
-
counts as Linux), with file permissions restricted to the owner (`0600`). `GHOSTDOCK_CREDENTIALS_PATH`
|
|
915
|
-
points the CLI at another file, e.g. for a second account. The file looks like this:
|
|
916
|
-
|
|
917
|
-
```json
|
|
918
|
-
{
|
|
919
|
-
"accessToken": "ext_at_...",
|
|
920
|
-
"refreshToken": "ext_rt_...",
|
|
921
|
-
"accessExpiresAt": "2026-07-30T12:00:00.000Z"
|
|
922
|
-
}
|
|
923
|
-
```
|
|
924
|
-
|
|
925
|
-
Access tokens are short-lived (1 hour); the CLI refreshes them automatically using the refresh token
|
|
926
|
-
(30-day rolling expiry) whenever a request gets a `401`. If both tokens are invalid or revoked (e.g.
|
|
927
|
-
after `ghostdock logout` from another session), re-run `ghostdock login`.
|
|
928
|
-
|
|
929
|
-
## Exit codes
|
|
930
|
-
|
|
931
|
-
- `0` — success (including the default `login` after only printing the URL — approval is still
|
|
932
|
-
pending, that's expected).
|
|
933
|
-
- `1` — failure: not logged in, session expired and unrefreshable, login denied/expired/timed out,
|
|
934
|
-
a missing/invalid tool flag, or a tool invocation error (e.g. not a member of the organization).
|