@pipod/cli 0.1.6 → 0.1.7

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/man/pipod.1.md ADDED
@@ -0,0 +1,852 @@
1
+ # pipod(1) -- run pi coding-agent sessions in server-managed pods
2
+
3
+ ## SYNOPSIS
4
+
5
+ ```
6
+ Usage:
7
+ pipod [options] launch a pod for this project and start pi
8
+ pipod [options] -- <pi args…> launch and pass arguments to pi: prompt words,
9
+ --model <id>, --thinking <level>, --tui-mode <mode>,
10
+ -e/--extension <path>, --skill <path>,
11
+ --prompt-template <path> (each repeatable)
12
+ pipod <command> [options] run a command
13
+ pipod help [command|topic] print the full manual entry
14
+
15
+ Sign in first with `pipod login`. A pod-scoped PI_POD_SERVER_TOKEN also counts as
16
+ signed in. While signed out, only login, whoami, init, doctor, update, help, and
17
+ version are available.
18
+
19
+ Pod commands:
20
+ list [pod] List pods; `list <pod>` shows one machine's group (ls)
21
+ attach [pod] Reconnect to a pod session (a)
22
+ stop [pod…] Stop pods now (files kept; attach restarts them)
23
+ fork <pod> Launch a new pod forked from a pod's session
24
+ rename <pod> <name> Rename a pod
25
+ send [pod] <path> Copy host files into a pod
26
+ receive [pod] <path> Copy pod files into the current directory
27
+ archive [pod…] Hide pods from the list (files kept; restore brings them back)
28
+ restore [pod…] Bring archived pods back
29
+ gc Report retention state; --delete removes reclaimable pods
30
+
31
+ Account commands:
32
+ login Sign in to a pi pod server via Zitadel
33
+ logout Revoke this session and delete the stored credentials
34
+ whoami Show the signed-in account
35
+ account Open the Zitadel self-service console
36
+ org-admin Open the Zitadel Console for this organization
37
+ billing Open Stripe Checkout or the billing portal (authenticated)
38
+ credentials Connect account model-provider sign-ins
39
+
40
+ Configuration commands:
41
+ init Scaffold .pi-pod/ config, env, env.example, and init.sh
42
+ templates Manage account templates
43
+ push Upload a local config layer to its server bundle
44
+ pull Write a server bundle into its local config layer
45
+ diff Show local vs server drift for a config layer
46
+ secrets Manage server and project secret scopes
47
+ settings Show or edit one server settings config directly
48
+ jobs Manage server-scheduled jobs
49
+
50
+ Maintenance commands:
51
+ doctor Check auth, server, org, and launch-resolution layers
52
+ update Upgrade pi pod itself
53
+
54
+ Launch options:
55
+ --template <name|id> Launch from an account template
56
+ --on <pod|self> Co-locate the new pod on an existing pod's machine
57
+ --reuse Restart this project's newest stopped pod instead of creating one
58
+ --no-seed Start the pod with an empty workspace (skip workspace seeding)
59
+ --dry-run Resolve and print the launch plan; create nothing
60
+
61
+ General options:
62
+ -y, --yes Skip supported confirmations
63
+ -v, --verbose Debug logging (secrets redacted)
64
+ --version Print CLI, Node, and bundled Pi versions
65
+ -h, --help Show help
66
+
67
+ Topics (pipod help <topic>):
68
+ setup First-time setup, in order, and who does each step
69
+ layers How org, user, and template settings combine
70
+ launch What a launch does: templates, workspace seeding, Pi resources
71
+ config Every config.json key (man pipod-config)
72
+ files Every file pipod reads or writes
73
+ environment Environment variables
74
+
75
+ `pipod <command> --help` is a command's usage; `pipod help <command>` is its full
76
+ manual entry; `man pipod` is the whole manual.
77
+ ```
78
+
79
+ ## DESCRIPTION
80
+
81
+ pi pod runs pi sessions in pods: sandboxes on a pi pod server, which you attach to from a
82
+ terminal or the phone apps and leave running when you detach. You use one server, as a
83
+ member of one organization on it.
84
+
85
+ What a pod starts with is decided on the server, from settings layers: the organization's
86
+ defaults, your own defaults, and a template, which is the environment for one project. Each
87
+ layer holds pod config (pipod-config(5)), an init script that runs in every pod at launch, a
88
+ bake script that is built into the pod image once, and Pi files. Secrets are stored apart from
89
+ the layers and reach pods as environment variables. `pipod help layers` explains how they
90
+ combine.
91
+
92
+ Every server layer has a local source of truth: a directory you edit with any editor, then
93
+ upload with `pipod push`. `pipod pull` writes the server's copy back, and `pipod diff`
94
+ compares the two.
95
+
96
+ ## SETUP
97
+
98
+ Setting pi pod up for yourself or an organization, in order. A person has to do the steps
99
+ marked (person): each needs a browser, a hidden prompt, or a decision about access or money.
100
+ An agent can do the rest with the commands shown, but should show the person every change
101
+ before applying it.
102
+
103
+ ### 1. A server and an account (person)
104
+
105
+ On your own server, the host's owner installs it (docs/self-host.md in the pipod repository)
106
+ and creates accounts with `selfhost/add-user <email>` on the host, adding `--owner` for
107
+ someone who may change organization settings. On a server someone else runs, ask its owner
108
+ for an account.
109
+
110
+ ### 2. Install the CLI and sign in (person)
111
+
112
+ ```
113
+ npm install -g @pipod/cli # Node 22.19 or later
114
+ pipod login --server <url>
115
+ pipod doctor
116
+ ```
117
+
118
+ `login` opens a browser, or prints a code to confirm on another device. `doctor` checks the
119
+ sign-in, the server, your organization and roles, and what a launch here would resolve.
120
+
121
+ ### 3. Model providers (person)
122
+
123
+ `pipod credentials connect` connects every provider your local pi is signed in to;
124
+ `pipod credentials connect <provider>` signs in to one. The sign-ins belong to your account
125
+ and apply to every pod you launch.
126
+
127
+ ### 4. Organization defaults
128
+
129
+ Only with the org:manage permission (`pipod whoami` lists yours); otherwise skip to step 5.
130
+ These reach every member's next pod: pod size, network policy, a default model, tools baked
131
+ into the image, shared setup. Change one key with `pipod settings org set <key> <value>`, or
132
+ the whole layer from its local source:
133
+
134
+ ```
135
+ pipod pull org # writes ~/.pi-pod/org/
136
+ # edit config.json, init.sh, bake.sh, pi/
137
+ pipod diff org
138
+ pipod push org
139
+ ```
140
+
141
+ Values for secrets the whole organization shares: `pipod secrets set org <NAME>` (person).
142
+ Organization policy (limits rather than defaults) is set in the web dashboard,
143
+ `<server>/dashboard/`.
144
+
145
+ ### 5. Your own defaults
146
+
147
+ Your model and thinking level, your Pi settings, personal setup such as a git identity:
148
+
149
+ ```
150
+ pipod settings user set pi.model <provider>/<model>
151
+ pipod settings user set pi.thinking high
152
+ ```
153
+
154
+ or the whole layer: `pipod pull user`, edit ~/.pi-pod/config.json and ~/.pi/agent/, then
155
+ `pipod diff user` and `pipod push user`.
156
+
157
+ ### 6. A template for each project
158
+
159
+ In the project's directory:
160
+
161
+ ```
162
+ pipod init # writes .pi-pod/
163
+ # edit .pi-pod/config.json, init.sh, and bake.sh
164
+ pipod --dry-run # what a launch would resolve; creates nothing
165
+ pipod # the first launch offers to create the template and pin it
166
+ ```
167
+
168
+ Without a launch, `pipod templates create <name> --from-here` creates it; then pin it by
169
+ adding `"template": "<name>"` to .pi-pod/config.json. Afterwards the project stays its
170
+ source: edit the files, `pipod diff`, `pipod push`. Its secret values:
171
+ `pipod secrets set template/<name> <NAME>` (person), or `.pi-pod/env` on this machine. To
172
+ tell its pods' agents what access the template is meant to have:
173
+ `pipod templates edit <name> --agent-instructions <file>`.
174
+
175
+ ### Rules for an agent
176
+
177
+ - Never put a secret value on a command line or in a chat; transcripts are stored. Name the
178
+ secret and let the person type it into `pipod secrets set`.
179
+ - Run `pipod diff <layer>` before `pipod push <layer>`: a push replaces the whole layer.
180
+ With no terminal, push declines instead of asking, so show the person the diff, then run
181
+ `pipod push <layer> --yes`.
182
+ - Organization changes reach every member's next pod, and `pipod templates share` cannot be
183
+ undone: confirm both with the person first.
184
+ - Iterate with `pipod doctor` and `pipod --dry-run`; both create nothing.
185
+
186
+ ## LAYERS
187
+
188
+ Each launch is resolved on the server from these layers, lowest first:
189
+
190
+ ```
191
+ built-in defaults
192
+ organization defaults
193
+ org-wide template (when the launch uses one)
194
+ your user layer
195
+ personal template (when the launch uses one)
196
+ organization policy (limits, applied last)
197
+ ```
198
+
199
+ The template is the one the launch names: `--template`, or the `template` pinned in the
200
+ project's .pi-pod/config.json. Within the layers:
201
+
202
+ - config merges key by key, and the later layer wins; an array replaces the one below it.
203
+ - init scripts all run, in layer order, and so do bake scripts.
204
+ - Pi files merge the same way, file by file, except that settings.json package lists add
205
+ up. They hold no credentials: models.json and mcporter.json name a secret as `$NAME`,
206
+ and the server refuses a literal key.
207
+
208
+ Organization policy holds limits rather than defaults: maximum idle and archive times,
209
+ allowed providers, a required template, network rules, concurrency. It clamps the merged
210
+ result, and `pipod doctor` and `pipod --dry-run` report every clamp. It is set in the web
211
+ dashboard by someone with the policy:write permission.
212
+
213
+ Where each layer's source lives, and the commands that change it:
214
+
215
+ ```
216
+ org ~/.pi-pod/org/: config.json, init.sh, bake.sh, pi/, env
217
+ pipod pull|diff|push org; pipod settings org set (org:manage)
218
+ user ~/.pi-pod/config.json and ~/.pi/agent/
219
+ pipod pull|diff|push user; pipod settings user set
220
+ template a project: .pi-pod/config.json, init.sh, bake.sh, env, and .pi/
221
+ pipod pull|diff|push [template [<name>]]; pipod templates
222
+ ```
223
+
224
+ What belongs where: the organization layer holds what everyone needs (pod size, network
225
+ policy, shared tools); your user layer holds your preferences (model, Pi settings, git
226
+ identity); a template holds one project's environment (cloning and installing it, the hosts
227
+ it needs, its secrets). A project's own files reach pods only through its template, after
228
+ `pipod push`. The web dashboard, `<server>/dashboard/`, edits the same layers.
229
+
230
+ Secrets have their own order, lowest first: org, user, template, then the project's
231
+ .pi-pod/env on the machine you launch from. `pipod secrets list` shows which layer each
232
+ name comes from.
233
+
234
+ ## LAUNCH
235
+
236
+ `pipod` with no command launches a pod for the current directory and attaches to it.
237
+ `pipod --dry-run` resolves the same launch and prints it without creating anything.
238
+
239
+ The launch uses the template named by `--template`, or else the one pinned in the project's
240
+ .pi-pod/config.json. In a project with a .pi-pod/config.json and no pinned template, the
241
+ first launch offers to create a template from the project and pin it.
242
+
243
+ Workspace seeding: launching from a directory with no .pi-pod/config.json seeds the new pod
244
+ from that directory (its git repository root when inside one). A clean, pushed checkout whose
245
+ remote tip matches HEAD is cloned at that exact commit; anything else (dirty trees, unpushed
246
+ commits, private remotes without usable credentials, plain directories) is streamed in as a
247
+ tar archive, without git-ignored paths, node_modules, or .pi-pod/env. Private-remote
248
+ credentials are forwarded only after a prompt (`--yes` approves it) and are never stored.
249
+ `--dry-run` prints the decision without prompting or creating a pod. Forks, reused pods,
250
+ `--on` co-location, and `--no-seed` never seed. A project with a .pi-pod/config.json gets its
251
+ workspace from its init scripts instead.
252
+
253
+ Arguments after `--` go to pi: prompt words start the session, and `--model`, `--thinking`,
254
+ and `--tui-mode` apply to this launch. Per-launch Pi resources (`--extension`, `--skill`,
255
+ `--prompt-template`) name files or directories inside the pod as absolute paths and add to
256
+ the pod's configured Pi resources for that launch; anything else Pi-related belongs in the
257
+ `pi.args` config.
258
+
259
+ `--reuse` restarts this project's newest stopped pod instead of creating one. `--on <pod>`
260
+ starts the new pod on an existing pod's machine, sharing its files; `--on self` does that
261
+ from inside a pod.
262
+
263
+ ## COMMANDS
264
+
265
+ ### pipod login
266
+
267
+ ```
268
+ Usage: pipod login [--server <url>] [--issuer <url>] [--org <alias>] [--device] [--token <jwt>]
269
+
270
+ Sign this machine in to a pi pod server via Zitadel (authorization code + PKCE,
271
+ in your browser). Where no browser can open here (over SSH, on a headless
272
+ server), it prints a page and a code to confirm on any other device instead.
273
+ The session is stored in ~/.pi-pod/auth.json.
274
+
275
+ Options:
276
+ --server <url> Server to sign in to (default: the previous session's server,
277
+ $PI_POD_ACCOUNT_URL, or the production server)
278
+ --issuer <url> OIDC issuer (default: $PI_POD_ISSUER, else the one the
279
+ server publishes); needed only for a server too old to
280
+ publish its own
281
+ --org <alias> Only sign in to the organization with this primary domain;
282
+ omit it to sign in to your own organization
283
+ --device Sign in with a code on another device even if a browser
284
+ could open here
285
+ --token <jwt> Use an existing access token instead of the browser flow (dev/CI)
286
+ ```
287
+
288
+ A person finishes the sign-in, in a browser or with the printed code; an agent can start
289
+ `pipod login` and wait for it. Signing in works before you belong to an organization, but
290
+ then nothing is permitted and `login` says access is pending organization membership: the
291
+ server's owner adds you (`selfhost/add-user` on a self-hosted host), or an organization owner
292
+ grants you a role in the Zitadel Console (`pipod org-admin`).
293
+
294
+ ### pipod logout
295
+
296
+ ```
297
+ Usage: pipod logout
298
+
299
+ Revoke the current account session and delete ~/.pi-pod/auth.json. Pod
300
+ operations are unavailable until the next `pipod login`.
301
+ ```
302
+
303
+ ### pipod whoami
304
+
305
+ ```
306
+ Usage: pipod whoami
307
+
308
+ Show the signed-in server, user, permissions, active organization, and console
309
+ links. Exits 1 when signed out.
310
+ ```
311
+
312
+ ### pipod account
313
+
314
+ ```
315
+ Usage: pipod account
316
+
317
+ Open the Zitadel self-service console in your browser to manage profile,
318
+ password, MFA, and active sessions.
319
+ ```
320
+
321
+ ### pipod org-admin
322
+
323
+ ```
324
+ Usage: pipod org-admin
325
+
326
+ Open the Zitadel Console in your browser. Organization owners manage members
327
+ and role grants there.
328
+ ```
329
+
330
+ ### pipod billing
331
+
332
+ ```
333
+ Usage: pipod billing checkout [--plan standard|pro] [--trial]
334
+ pipod billing portal
335
+ pipod billing change --plan standard|pro [--yes]
336
+ pipod billing change preview --plan standard|pro
337
+ pipod billing change confirm --quote <quoteId> [--yes]
338
+
339
+ Authenticated Stripe Checkout and billing portal. Checkout sends trial:false
340
+ (paid) unless --trial. Closed public trial refuses --trial with 402. Change
341
+ previews a Standard<->Pro plan change and confirms it only after an explicit
342
+ yes; stale quotes are never auto-confirmed. Return
343
+ pages do not grant a plan.
344
+ ```
345
+
346
+ Billing exists only on the hosted service; a self-hosted server has none. Paying, and
347
+ changing plans, are a person's decisions: an agent may run `preview`, never `confirm`.
348
+
349
+ ### pipod credentials
350
+
351
+ ```
352
+ Usage: pipod credentials [action]
353
+
354
+ Manage account-scoped model-provider sign-ins. Connected credentials apply to
355
+ every pod you launch; OAuth refresh tokens stay in server custody and never
356
+ reach pods or this machine.
357
+
358
+ Actions:
359
+ list Saved credentials and connectable providers (default)
360
+ connect Connect every provider your local pi is signed in to:
361
+ API keys are imported, everything else is a fresh
362
+ account login; ready credentials are left alone
363
+ connect <provider> Sign in to a provider (OAuth by default)
364
+ reconnect <provider> Redo the sign-in for a saved credential
365
+ test <provider> Verify a saved credential against the provider
366
+ remove <provider> [--yes] Delete a saved credential (alias: rm)
367
+
368
+ connect options:
369
+ --api-key Enter an API key instead of the OAuth flow
370
+ --api-key --from-pi Import the API key your local pi resolves for that
371
+ provider (auth.json or env) instead of typing it.
372
+ OAuth grants are never imported.
373
+ ```
374
+
375
+ `connect` and `reconnect` need a person, for the browser sign-in or the hidden key prompt;
376
+ `list` and `test` do not. A model-provider key is a credential here, not a secret: a template
377
+ refuses one.
378
+
379
+ ### pipod init
380
+
381
+ ```
382
+ Usage: pipod init [--force]
383
+
384
+ Scaffold project configuration under .pi-pod/ in the current directory:
385
+ config.json, env.example, env (mode 600), and init.sh.
386
+
387
+ Options:
388
+ --force Overwrite scaffold files that already exist
389
+ ```
390
+
391
+ The files are the local source of the project's template. config.json starts with every
392
+ setting commented out: uncomment only what this project must decide for itself
393
+ (pipod-config(5)). init.sh runs in each new pod, in an empty workspace, so it usually clones
394
+ the repository and installs dependencies. Add .pi-pod/bake.sh for setup that belongs in the
395
+ image. env holds the project's secret values and is added to .gitignore; env.example lists
396
+ their names and is committed.
397
+
398
+ ### pipod templates
399
+
400
+ ```
401
+ Usage: pipod templates [action]
402
+
403
+ Manage pod templates on the pi pod server. A template stores config, init and
404
+ bake scripts, Pi settings files, named secrets, and agent instructions.
405
+ Templates are personal by default: only their owner sees and launches them.
406
+ --org at creation or `templates share` makes one org-wide.
407
+
408
+ Agent instructions are added to the agent's system prompt in every pod launched
409
+ from the template, with the hosts and secrets the pod actually has: say what
410
+ access the template is meant to have. They guide the agent and enforce nothing;
411
+ the template's secrets and egress decide what a pod can reach. A pod's child
412
+ pods and the jobs it schedules launch from the pod's own template.
413
+
414
+ Actions:
415
+ list List templates with scope and key counts (default)
416
+ show <name|id> Show config, scripts, agent instructions, Pi settings, and
417
+ secret names
418
+ create <name> Create a template
419
+ edit <name|id> Update a template's name, description, config, scripts, or
420
+ agent instructions
421
+ share <name|id> Make a personal template org-wide (cannot be undone)
422
+ rm <name|id> Delete a template (alias: delete)
423
+
424
+ create/edit options:
425
+ --name <name> New name (edit only)
426
+ --description <text> Set the description
427
+ --config <file> Store this config file (same shape as .pi-pod/config.json)
428
+ --from-here create only: store this project's authored config,
429
+ scripts, and sanitized Pi files (contradicts --config)
430
+ --init-script <file> Store this init script
431
+ --bake-script <file> Store this bake script
432
+ --agent-instructions <file>
433
+ Store this file as the agent instructions (an empty
434
+ file removes them); `pipod push` leaves them alone
435
+ --org create only: make the template org-wide from the start
436
+ --with-secrets With --from-here: also upload project env values as
437
+ template secrets
438
+ -y, --yes Skip confirmations (rm)
439
+ ```
440
+
441
+ A template is one project's environment. Keep a project as its source: accept the first
442
+ launch's offer, which creates the template and pins it in .pi-pod/config.json, or run
443
+ `create --from-here` and add `"template": "<name>"` to that file yourself. Then change it
444
+ with `pipod diff` and `pipod push` from the project.
445
+ A personal template sits above your user layer and an org-wide one below it
446
+ (`pipod help layers`); making one org-wide needs the org:manage permission.
447
+
448
+ ### pipod push
449
+
450
+ ```
451
+ Usage: pipod push [template [<name>] | user | org] [--dir <path>]
452
+ [--with-secrets] [--yes]
453
+
454
+ Replace a server config bundle with its local source, whole. The layer names
455
+ both sides; edit the local files with any editor, then push. A diff preview
456
+ precedes the confirmation.
457
+
458
+ Layers and their local source:
459
+ template [<name>] This project: .pi-pod/config.json, its init and bake
460
+ scripts, Pi files under .pi/, and the project env file
461
+ (secrets, with --with-secrets or a prompt). Without
462
+ <name> the project's pinned template is used.
463
+ user ~/.pi-pod/config.json and ~/.pi/agent/ (settings.json,
464
+ models.json, mcporter.json, subagents.json, agents/)
465
+ org ~/.pi-pod/org/: config.json, init.sh, bake.sh, pi/…, and
466
+ an optional env file whose values become org secrets
467
+
468
+ Inside a project the layer defaults to template; elsewhere it is required.
469
+ Provider credentials, hooks, mcpServers, and model credential values never
470
+ leave this machine.
471
+
472
+ Options:
473
+ --dir <path> org only: read the org source from <path> instead
474
+ --with-secrets Also upload the layer's env values as secrets
475
+ -y, --yes Apply the replacement without the confirmation prompt
476
+ ```
477
+
478
+ Whatever the local source lacks is removed from the server layer, so start from
479
+ `pipod pull` when the server may have changes this machine does not. With no terminal to
480
+ confirm on, push declines unless `--yes` is given.
481
+
482
+ ### pipod pull
483
+
484
+ ```
485
+ Usage: pipod pull [template [<name>] | user | org] [--dir <path>] [--yes]
486
+
487
+ Write a server config bundle into its local source files (see
488
+ `pipod push --help` for the layer → directory table). A diff preview
489
+ precedes the confirmation; nothing is written when the two already match.
490
+
491
+ What pull keeps from the local files:
492
+ config.json client-only keys: $schema, template, secretResolver,
493
+ pi.chords, pi.sessionNaming
494
+ settings.json hooks and mcpServers (and packages when hostConfig.packages
495
+ is off)
496
+ models.json credential values the push had dropped
497
+ agents/ files the bundle no longer contains are removed
498
+
499
+ Secrets stay on the server; their names are listed. The user layer has no
500
+ local script files, so user bundle scripts are shown but not written.
501
+
502
+ Options:
503
+ --dir <path> org only: write the org source to <path> instead
504
+ -y, --yes Apply the local changes without the confirmation prompt
505
+ ```
506
+
507
+ ### pipod diff
508
+
509
+ ```
510
+ Usage: pipod diff [template [<name>] | user | org] [--dir <path>]
511
+
512
+ Compare a config layer's local source with its server bundle (see
513
+ `pipod push --help` for the layer → directory table). Secrets compare by
514
+ name only. Exits 1 when they differ, 0 when they match.
515
+
516
+ Options:
517
+ --dir <path> org only: read the org source from <path> instead
518
+ ```
519
+
520
+ ### pipod secrets
521
+
522
+ ```
523
+ Usage: pipod secrets [action]
524
+
525
+ Manage the secret layers pods see. Requires account or pod-token auth. Server
526
+ scopes are org, user, and template/<name>; project is this project's dotenv
527
+ file, the highest-precedence layer for launches from the project.
528
+
529
+ Actions:
530
+ list Every secret a pod launched here would see,
531
+ which layer wins, and who set it (default)
532
+ set <scope> <NAME> Store a secret, its value read from a hidden
533
+ prompt or stdin (never the command line)
534
+ rm <scope> <NAME> Remove a secret (aliases: remove, unset)
535
+ sync <scope> Upload a dotenv file to a server scope
536
+
537
+ sync options (scope must be org, user, or template/<name>):
538
+ --file <path> Dotenv file to upload (default: ~/.pi-pod/secrets/<scope>.env)
539
+ --prune Also delete server secrets that are not in the file
540
+ --dry-run Show what would change without writing
541
+
542
+ Values may be op:// references; they resolve just-in-time (at upload for
543
+ server scopes, at launch for the project file) and the references themselves
544
+ are never stored on the server.
545
+ ```
546
+
547
+ Precedence, lowest first: org, user, template, project. A pod receives its secrets as
548
+ environment variables, and anything running in it can read them all. Stored values cannot be
549
+ read back, only replaced.
550
+
551
+ Keep values out of command lines and chats: a person types them at `set`'s hidden prompt,
552
+ or `sync` reads a dotenv file kept at mode 600. op:// references resolve through the
553
+ 1Password CLI (`op`) on this machine. Model-provider keys belong in `pipod credentials`.
554
+
555
+ ### pipod settings
556
+
557
+ ```
558
+ Usage: pipod settings <user|org> [show | edit | set <key> <value> | unset <key>]
559
+
560
+ Show or edit a persistent settings bundle on the server: your own user bundle,
561
+ or the org-wide defaults (org scope needs the org:manage permission). Edits
562
+ change only the config; scripts and Pi files stay as they are — replace the
563
+ whole bundle from local files with `pipod push user` or `pipod push org`.
564
+ Edits use compare-and-swap on the bundle version, so concurrent changes fail
565
+ cleanly instead of overwriting each other.
566
+
567
+ Actions:
568
+ show Print the settings bundle as JSON (default)
569
+ edit Edit the config in $VISUAL/$EDITOR, then save
570
+ set <key> <value> Set one dotted key to a JSON value, or to the text as
571
+ a string: pipod settings user set pi.model provider/model
572
+ unset <key> Remove one dotted key, so the layers below decide it
573
+ ```
574
+
575
+ Keys are those of pipod-config(5). `set` changes the server only: a later `pipod push` of the
576
+ same layer replaces it with the local source, so after a `set`, run `pipod pull` before
577
+ editing that source.
578
+
579
+ ### pipod jobs
580
+
581
+ ```
582
+ Usage: pipod jobs [action] [args] [--quiet] [--yes] [--project] [--org]
583
+
584
+ Manage scheduled jobs the pi pod server runs for you: at each trigger it
585
+ launches a pod from the job's template and sends the job's prompt. Local job
586
+ files in .pi-pod/jobs/ (project) or ~/.pi-pod/jobs/ (user) are the reviewable
587
+ source; `jobs push` promotes them to the server. <job> is an id, short ref
588
+ (j-…), or name.
589
+
590
+ Actions:
591
+ list List server jobs (default)
592
+ show <job> Show a job's schedule, template, model, and prompt
593
+ runs <job> List a job's recent runs
594
+ run <job> Run an active job once, now; its schedule is unchanged
595
+ activate <job> Activate a job
596
+ pause <job> Pause a job's schedule
597
+ resume <job> Resume a paused job
598
+ rm <job> Remove a job; its schedule stops firing
599
+ push [job…] Create or update server jobs from local job files
600
+ pull <job> Write a server job to a local job file
601
+ diff [job…] Show local vs server drift; exits 1 when drifted
602
+
603
+ Options:
604
+ --org push: create org-scoped jobs or promote matching user jobs
605
+ (promotion is one-way)
606
+ --project pull: write into this project's .pi-pod/jobs/ instead of
607
+ ~/.pi-pod/jobs/
608
+ -q, --quiet list: print job ids only, one per line
609
+ -y, --yes Skip confirmations; pull: overwrite an existing local file
610
+ ```
611
+
612
+ A job file is `<name>.json` (comments allowed), and its file name is the job's name:
613
+
614
+ ```
615
+ {
616
+ "description": "Triage new issues every morning",
617
+ "trigger": { "type": "cron", "cron": "0 6 * * *" },
618
+ "template": "my-service",
619
+ "model": "anthropic/claude-opus-4-7",
620
+ "prompt": "Review yesterday's new issues and post a triage summary."
621
+ }
622
+ ```
623
+
624
+ `trigger` is a cron expression, evaluated in UTC, or `{ "type": "at", "times": [...] }` with
625
+ up to 100 ISO 8601 timestamps that each name their timezone. Runs must be at least 5
626
+ minutes apart, since each run is a pod. `model` (provider/model-id) is required.
627
+ `promptFile` names a file beside the job file instead of `prompt`; prompts are at most 64 KiB
628
+ and must say everything the run needs, since it starts in a fresh pod. A job runs on its own
629
+ until paused, so agree its schedule with the person before `pipod jobs push`.
630
+
631
+ ### pipod list
632
+
633
+ ```
634
+ Usage: pipod list [pod] [--all] [--archived] [--template <name|id>] [--quiet]
635
+
636
+ Alias: ls
637
+
638
+ List pods on the signed-in server with stable short refs (p-…). The project is
639
+ the directory's git repository (or the directory, or its .pi-pod/ config): a
640
+ listing shows that project's pods when it has any — its pinned template's when
641
+ it pins one — and every pod otherwise. Co-located pods are grouped under the pod
642
+ whose machine they share, with an ON column naming it.
643
+ With a pod argument, show just that machine's group: the pod and everything
644
+ co-located on it.
645
+
646
+ Status says where a pod's files are: a stopped pod keeps them on disk and restarts on
647
+ attach; an archived workspace is restored on next use, which takes longer the bigger it is.
648
+ Pods you archive stay hidden unless --archived is passed.
649
+
650
+ Options:
651
+ -a, --all Every pod; ignore the current project and its template pin
652
+ --archived Include logically archived pods
653
+ --template <name|id> Only pods launched from that template (whole account)
654
+ -q, --quiet Print pod ids only, one per line
655
+ ```
656
+
657
+ ### pipod attach
658
+
659
+ ```
660
+ Usage: pipod attach [pod] [--yes] [-- <prompt…> [--tui-mode <mode>]]
661
+
662
+ Alias: a
663
+
664
+ Reconnect to a pod session through the server gateway. Name the pod by id,
665
+ short ref (p-…), or name; omit it when this project has exactly one pod.
666
+ Quitting detaches: the pod keeps running until the server's idle policy reaps
667
+ it or `pipod stop` stops it. Raw pod shells are not available.
668
+ Attaching to an archived pod offers to restore it first.
669
+
670
+ After --:
671
+ <prompt…> Words are sent to the session as a startup prompt
672
+ --tui-mode <mode> Local TUI layout for this attach: regular or fullscreen
673
+
674
+ Options:
675
+ -y, --yes Restore an archived pod without asking
676
+ ```
677
+
678
+ ### pipod stop
679
+
680
+ ```
681
+ Usage: pipod stop [pod…]
682
+
683
+ Stop pods now by id, short ref (p-…), or name; omit the argument when this
684
+ project has exactly one pod. Stopped pods keep their files and `pipod attach`
685
+ restarts them. Stopping a pod that hosts co-located pods stops those too.
686
+ ```
687
+
688
+ ### pipod fork
689
+
690
+ ```
691
+ Usage: pipod fork <pod> [--session <path>] [launch options] [-- <pi args…>]
692
+
693
+ Launch a new pod whose session starts as a fork of <pod>'s current session.
694
+ <pod> is an id, short ref (p-…), or name. The workspace is not copied —
695
+ commit and push first if the new pod needs those changes. --on is not
696
+ supported: a fork launches a new sandbox, not a co-located pod.
697
+
698
+ Options:
699
+ --session <path> Fork a specific session file instead of the newest
700
+ --template <name|id> Launch the new pod from an account template
701
+ --dry-run Resolve and print the launch plan; create nothing
702
+ -y, --yes Skip supported confirmations
703
+ ```
704
+
705
+ ### pipod rename
706
+
707
+ ```
708
+ Usage: pipod rename <pod> <name>
709
+
710
+ Rename a server-managed pod. <pod> is an id, short ref (p-…), or the current
711
+ name.
712
+ ```
713
+
714
+ ### pipod send
715
+
716
+ ```
717
+ Usage: pipod send [pod] <path> [--yes]
718
+
719
+ Copy a host file or directory into a pod through the server. Omit the pod when
720
+ this project has exactly one. Sending to an archived pod offers to restore it
721
+ first.
722
+
723
+ Options:
724
+ -y, --yes Restore an archived pod without asking
725
+ ```
726
+
727
+ ### pipod receive
728
+
729
+ ```
730
+ Usage: pipod receive [pod] <path> [--yes]
731
+
732
+ Copy a file or directory from a pod into the current local directory. <path>
733
+ may be a workdir-relative path or an absolute path inside that workdir, such
734
+ as foo or /workspace/foo. The destination must not already exist. Omit the
735
+ pod when this project has exactly one. Receiving from an archived pod offers
736
+ to restore it first.
737
+
738
+ Options:
739
+ -y, --yes Restore an archived pod without asking
740
+ ```
741
+
742
+ ### pipod archive
743
+
744
+ ```
745
+ Usage: pipod archive [pod…] [--all] [--template <name|id>] [--idle <duration>] [--dry-run] [--yes]
746
+
747
+ Archive pods by id, short ref (p-…), or name. Archiving hides pods from
748
+ `pipod list` (`pipod list --archived` shows them); it never deletes work, and
749
+ `pipod restore` brings them back. Archiving a pod that hosts co-located pods
750
+ archives those too.
751
+
752
+ Options:
753
+ -a, --all Archive every pod (cannot be combined with pod refs)
754
+ --template <name|id> Only pods launched from that template (whole account)
755
+ --idle <duration> Only pods whose last activity is older than this (4h, 2d, 30m)
756
+ --dry-run Print the matching pods; archive nothing
757
+ -y, --yes Skip the bulk confirmation
758
+ ```
759
+
760
+ ### pipod restore
761
+
762
+ ```
763
+ Usage: pipod restore [pod…] [--all] [--yes]
764
+
765
+ Bring archived pods back by id, short ref (p-…), or name. Restoring a host
766
+ restores the co-located pods archived with it. `pipod attach` then starts the
767
+ pod; a workspace in cold storage takes longer the bigger it is.
768
+
769
+ Options:
770
+ -a, --all Restore every archived pod (cannot be combined with pod refs)
771
+ -y, --yes Skip the --all confirmation
772
+ ```
773
+
774
+ ### pipod gc
775
+
776
+ ```
777
+ Usage: pipod gc [--delete] [--yes]
778
+
779
+ List the archived and failed pods that can be deleted for good; --delete deletes
780
+ them. (The server stops idle pods and moves stopped workspaces to cold storage on
781
+ its own schedule; that never deletes anything.)
782
+
783
+ Options:
784
+ --delete Permanently delete the reclaimable pods
785
+ -y, --yes Delete without a confirmation prompt
786
+ ```
787
+
788
+ ### pipod doctor
789
+
790
+ ```
791
+ Usage: pipod doctor [--template <name|id>]
792
+
793
+ Check each layer a launch depends on: account auth, server reachability and
794
+ version, organization membership and roles, secret references, and the
795
+ server-resolved settings bundle chain for this directory. Works while signed
796
+ out to diagnose auth problems. Exits non-zero when a layer fails.
797
+
798
+ Options:
799
+ --template <name|id> Plan the checked launch with this template
800
+ ```
801
+
802
+ ### pipod update
803
+
804
+ ```
805
+ Usage: pipod update [--dry-run]
806
+
807
+ Upgrade pi pod itself: a registry install updates to the latest published
808
+ version; a git checkout pulls its upstream and rebuilds.
809
+
810
+ Options:
811
+ --dry-run Report what an update would do without changing anything
812
+ ```
813
+
814
+ ## FILES
815
+
816
+ ```
817
+ ~/.pi-pod/auth.json this machine's sign-in (pipod login)
818
+ ~/.pi-pod/config.json this machine's preferences, and the config of your
819
+ user layer (pipod-config(5))
820
+ ~/.pi/agent/ your Pi files, the rest of your user layer:
821
+ settings.json, models.json, mcporter.json,
822
+ subagents.json, agents/
823
+ ~/.pi-pod/org/ the organization layer's source: config.json,
824
+ init.sh, bake.sh, pi/, env
825
+ ~/.pi-pod/secrets/ dotenv files for pipod secrets sync
826
+ ~/.pi-pod/jobs/ your job files
827
+ .pi-pod/config.json a project's config and its template pin
828
+ .pi-pod/init.sh runs in each of the project's new pods
829
+ .pi-pod/bake.sh built into the project's pod image
830
+ .pi-pod/env the project's secret values; never committed
831
+ .pi-pod/env.example the names of the project's secrets; committed
832
+ .pi-pod/jobs/ the project's job files
833
+ .pi/ the project's Pi files, as in ~/.pi/agent/
834
+ ```
835
+
836
+ ## ENVIRONMENT
837
+
838
+ ```
839
+ PI_POD_ACCOUNT_URL the server pipod login uses with no --server and no
840
+ previous session
841
+ PI_POD_ISSUER the OIDC issuer pipod login uses, for a server too old
842
+ to publish its own
843
+ PI_POD_SERVER_URL set in every pod: pipod there signs in with the pod's
844
+ PI_POD_SERVER_TOKEN own token, which reaches only the pods it launched
845
+ VISUAL, EDITOR the editor for pipod settings edit
846
+ NO_COLOR plain output without color
847
+ ```
848
+
849
+ ## SEE ALSO
850
+
851
+ pipod-config(5), https://github.com/pi-pod/pipod, and docs/self-host.md there for running
852
+ a server.