@pipod/cli 0.1.6 → 0.1.8

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,856 @@
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
+ Inside a pod, signed in with the pod's own token, every launch (`--on self` included) and
264
+ every job it schedules uses the template that pod launched from; the server refuses any other.
265
+
266
+ ## COMMANDS
267
+
268
+ ### pipod login
269
+
270
+ ```
271
+ Usage: pipod login [--server <url>] [--issuer <url>] [--org <alias>] [--device] [--token <jwt>]
272
+
273
+ Sign this machine in to a pi pod server via Zitadel (authorization code + PKCE,
274
+ in your browser). Where no browser can open here (over SSH, on a headless
275
+ server), it prints a page and a code to confirm on any other device instead.
276
+ The session is stored in ~/.pi-pod/auth.json.
277
+
278
+ Options:
279
+ --server <url> Server to sign in to (default: the previous session's server,
280
+ $PI_POD_ACCOUNT_URL, or the production server)
281
+ --issuer <url> OIDC issuer (default: $PI_POD_ISSUER, else the one the
282
+ server publishes); needed only for a server too old to
283
+ publish its own
284
+ --org <alias> Only sign in to the organization with this primary domain;
285
+ omit it to sign in to your own organization
286
+ --device Sign in with a code on another device even if a browser
287
+ could open here
288
+ --token <jwt> Use an existing access token instead of the browser flow (dev/CI)
289
+ ```
290
+
291
+ A person finishes the sign-in, in a browser or with the printed code; an agent can start
292
+ `pipod login` and wait for it. Signing in works before you belong to an organization, but
293
+ then nothing is permitted and `login` says access is pending organization membership: the
294
+ server's owner adds you (`selfhost/add-user` on a self-hosted host), or an organization owner
295
+ grants you a role in the Zitadel Console (`pipod org-admin`).
296
+
297
+ ### pipod logout
298
+
299
+ ```
300
+ Usage: pipod logout
301
+
302
+ Revoke the current account session and delete ~/.pi-pod/auth.json. Pod
303
+ operations are unavailable until the next `pipod login`.
304
+ ```
305
+
306
+ ### pipod whoami
307
+
308
+ ```
309
+ Usage: pipod whoami
310
+
311
+ Show the signed-in server, user, permissions, active organization, and console
312
+ links. Exits 1 when signed out.
313
+ ```
314
+
315
+ ### pipod account
316
+
317
+ ```
318
+ Usage: pipod account
319
+
320
+ Open the Zitadel self-service console in your browser to manage profile,
321
+ password, MFA, and active sessions.
322
+ ```
323
+
324
+ ### pipod org-admin
325
+
326
+ ```
327
+ Usage: pipod org-admin
328
+
329
+ Open the Zitadel Console in your browser. Organization owners manage members
330
+ and role grants there.
331
+ ```
332
+
333
+ ### pipod billing
334
+
335
+ ```
336
+ Usage: pipod billing checkout [--plan standard|pro] [--trial]
337
+ pipod billing portal
338
+ pipod billing change --plan standard|pro [--yes]
339
+ pipod billing change preview --plan standard|pro
340
+ pipod billing change confirm --quote <quoteId> [--yes]
341
+
342
+ Authenticated Stripe Checkout and billing portal. Checkout sends trial:false
343
+ (paid) unless --trial. Closed public trial refuses --trial with 402. Change
344
+ previews a Standard<->Pro plan change and confirms it only after an explicit
345
+ yes; stale quotes are never auto-confirmed. Return
346
+ pages do not grant a plan.
347
+ ```
348
+
349
+ Billing exists only on the hosted service; a self-hosted server has none. Paying, and
350
+ changing plans, are a person's decisions: an agent may run `preview`, never `confirm`.
351
+
352
+ ### pipod credentials
353
+
354
+ ```
355
+ Usage: pipod credentials [action]
356
+
357
+ Manage account-scoped model-provider sign-ins. Connected credentials apply to
358
+ every pod you launch; OAuth refresh tokens stay in server custody and never
359
+ reach pods or this machine.
360
+
361
+ Actions:
362
+ list Saved credentials and connectable providers (default)
363
+ connect Connect every provider your local pi is signed in to:
364
+ API keys are imported, everything else is a fresh
365
+ account login; ready credentials are left alone
366
+ connect <provider> Sign in to a provider (OAuth by default)
367
+ reconnect <provider> Redo the sign-in for a saved credential
368
+ test <provider> Verify a saved credential against the provider
369
+ remove <provider> [--yes] Delete a saved credential (alias: rm)
370
+
371
+ connect options:
372
+ --api-key Enter an API key instead of the OAuth flow
373
+ --api-key --from-pi Import the API key your local pi resolves for that
374
+ provider (auth.json or env) instead of typing it.
375
+ OAuth grants are never imported.
376
+ ```
377
+
378
+ `connect` and `reconnect` need a person, for the browser sign-in or the hidden key prompt;
379
+ `list` and `test` do not. A model-provider key is a credential here, not a secret: a template
380
+ refuses one.
381
+
382
+ ### pipod init
383
+
384
+ ```
385
+ Usage: pipod init [--force]
386
+
387
+ Scaffold project configuration under .pi-pod/ in the current directory:
388
+ config.json, env.example, env (mode 600), and init.sh.
389
+
390
+ Options:
391
+ --force Overwrite scaffold files that already exist
392
+ ```
393
+
394
+ The files are the local source of the project's template. config.json starts with every
395
+ setting commented out: uncomment only what this project must decide for itself
396
+ (pipod-config(5)). init.sh runs in each new pod, in an empty workspace, so it usually clones
397
+ the repository and installs dependencies. Add .pi-pod/bake.sh for setup that belongs in the
398
+ image. env holds the project's secret values and is added to .gitignore; env.example lists
399
+ their names and is committed.
400
+
401
+ ### pipod templates
402
+
403
+ ```
404
+ Usage: pipod templates [action]
405
+
406
+ Manage pod templates on the pi pod server. A template stores config, init and
407
+ bake scripts, Pi settings files, named secrets, and agent instructions.
408
+ Templates are personal by default: only their owner sees and launches them.
409
+ --org at creation or `templates share` makes one org-wide.
410
+
411
+ Agent instructions are added to the agent's system prompt in every pod launched
412
+ from the template, with the hosts and secrets the pod actually has: say what
413
+ access the template is meant to have. They guide the agent and enforce nothing;
414
+ the template's secrets and egress decide what a pod can reach. A pod's child
415
+ pods and the jobs it schedules launch from the pod's own template.
416
+
417
+ Actions:
418
+ list List templates with scope and key counts (default)
419
+ show <name|id> Show config, scripts, agent instructions, Pi settings, and
420
+ secret names
421
+ create <name> Create a template
422
+ edit <name|id> Update a template's name, description, config, scripts, or
423
+ agent instructions
424
+ share <name|id> Make a personal template org-wide (cannot be undone)
425
+ rm <name|id> Delete a template (alias: delete)
426
+
427
+ create/edit options:
428
+ --name <name> New name (edit only)
429
+ --description <text> Set the description
430
+ --config <file> Store this config file (same shape as .pi-pod/config.json)
431
+ --from-here create only: store this project's authored config,
432
+ scripts, and sanitized Pi files (contradicts --config)
433
+ --init-script <file> Store this init script
434
+ --bake-script <file> Store this bake script
435
+ --agent-instructions <file>
436
+ Store this file as the agent instructions (an empty
437
+ file removes them); `pipod push` leaves them alone
438
+ --org create only: make the template org-wide from the start
439
+ --with-secrets With --from-here: also upload project env values as
440
+ template secrets
441
+ -y, --yes Skip confirmations (rm)
442
+ ```
443
+
444
+ A template is one project's environment. Keep a project as its source: accept the first
445
+ launch's offer, which creates the template and pins it in .pi-pod/config.json, or run
446
+ `create --from-here` and add `"template": "<name>"` to that file yourself. Then change it
447
+ with `pipod diff` and `pipod push` from the project.
448
+ A personal template sits above your user layer and an org-wide one below it
449
+ (`pipod help layers`); making one org-wide needs the org:manage permission.
450
+
451
+ ### pipod push
452
+
453
+ ```
454
+ Usage: pipod push [template [<name>] | user | org] [--dir <path>]
455
+ [--with-secrets] [--yes]
456
+
457
+ Replace a server config bundle with its local source, whole. The layer names
458
+ both sides; edit the local files with any editor, then push. A diff preview
459
+ precedes the confirmation.
460
+
461
+ Layers and their local source:
462
+ template [<name>] This project: .pi-pod/config.json, its init and bake
463
+ scripts, Pi files under .pi/, and the project env file
464
+ (secrets, with --with-secrets or a prompt). Without
465
+ <name> the project's pinned template is used.
466
+ user ~/.pi-pod/config.json and ~/.pi/agent/ (settings.json,
467
+ models.json, mcporter.json, subagents.json, agents/)
468
+ org ~/.pi-pod/org/: config.json, init.sh, bake.sh, pi/…, and
469
+ an optional env file whose values become org secrets
470
+
471
+ Inside a project the layer defaults to template; elsewhere it is required.
472
+ Provider credentials, hooks, mcpServers, and model credential values never
473
+ leave this machine.
474
+
475
+ Options:
476
+ --dir <path> org only: read the org source from <path> instead
477
+ --with-secrets Also upload the layer's env values as secrets
478
+ -y, --yes Apply the replacement without the confirmation prompt
479
+ ```
480
+
481
+ Whatever the local source lacks is removed from the server layer, so start from
482
+ `pipod pull` when the server may have changes this machine does not. With no terminal to
483
+ confirm on, push declines unless `--yes` is given.
484
+
485
+ ### pipod pull
486
+
487
+ ```
488
+ Usage: pipod pull [template [<name>] | user | org] [--dir <path>] [--yes]
489
+
490
+ Write a server config bundle into its local source files (see
491
+ `pipod push --help` for the layer → directory table). A diff preview
492
+ precedes the confirmation; nothing is written when the two already match.
493
+
494
+ What pull keeps from the local files:
495
+ config.json client-only keys: $schema, template, secretResolver,
496
+ pi.chords, pi.sessionNaming
497
+ settings.json hooks and mcpServers (and packages when hostConfig.packages
498
+ is off)
499
+ models.json credential values the push had dropped
500
+ agents/ files the bundle no longer contains are removed
501
+
502
+ Secrets stay on the server; their names are listed. The user layer has no
503
+ local script files, so user bundle scripts are shown but not written.
504
+
505
+ Options:
506
+ --dir <path> org only: write the org source to <path> instead
507
+ -y, --yes Apply the local changes without the confirmation prompt
508
+ ```
509
+
510
+ ### pipod diff
511
+
512
+ ```
513
+ Usage: pipod diff [template [<name>] | user | org] [--dir <path>]
514
+
515
+ Compare a config layer's local source with its server bundle (see
516
+ `pipod push --help` for the layer → directory table). Secrets compare by
517
+ name only. Exits 1 when they differ, 0 when they match.
518
+
519
+ Options:
520
+ --dir <path> org only: read the org source from <path> instead
521
+ ```
522
+
523
+ ### pipod secrets
524
+
525
+ ```
526
+ Usage: pipod secrets [action]
527
+
528
+ Manage the secret layers pods see. Requires account or pod-token auth. Server
529
+ scopes are org, user, and template/<name>; project is this project's dotenv
530
+ file, the highest-precedence layer for launches from the project.
531
+
532
+ Actions:
533
+ list Every secret a pod launched here would see,
534
+ which layer wins, and who set it (default)
535
+ set <scope> <NAME> Store a secret, its value read from a hidden
536
+ prompt or stdin (never the command line)
537
+ rm <scope> <NAME> Remove a secret (aliases: remove, unset)
538
+ sync <scope> Upload a dotenv file to a server scope
539
+
540
+ sync options (scope must be org, user, or template/<name>):
541
+ --file <path> Dotenv file to upload (default: ~/.pi-pod/secrets/<scope>.env)
542
+ --prune Also delete server secrets that are not in the file
543
+ --dry-run Show what would change without writing
544
+
545
+ Values may be op:// references; they resolve just-in-time (at upload for
546
+ server scopes, at launch for the project file) and the references themselves
547
+ are never stored on the server.
548
+ ```
549
+
550
+ Precedence, lowest first: org, user, template, project. A pod receives its secrets as
551
+ environment variables, and anything running in it can read them all. Stored values cannot be
552
+ read back, only replaced.
553
+
554
+ Keep values out of command lines and chats: a person types them at `set`'s hidden prompt,
555
+ or `sync` reads a dotenv file kept at mode 600. op:// references resolve through the
556
+ 1Password CLI (`op`) on this machine. Model-provider keys belong in `pipod credentials`.
557
+
558
+ ### pipod settings
559
+
560
+ ```
561
+ Usage: pipod settings <user|org> [show | edit | set <key> <value> | unset <key>]
562
+
563
+ Show or edit a persistent settings bundle on the server: your own user bundle,
564
+ or the org-wide defaults (org scope needs the org:manage permission). Edits
565
+ change only the config; scripts and Pi files stay as they are — replace the
566
+ whole bundle from local files with `pipod push user` or `pipod push org`.
567
+ Edits use compare-and-swap on the bundle version, so concurrent changes fail
568
+ cleanly instead of overwriting each other.
569
+
570
+ Actions:
571
+ show Print the settings bundle as JSON (default)
572
+ edit Edit the config in $VISUAL/$EDITOR, then save
573
+ set <key> <value> Set one dotted key to a JSON value, or to the text as
574
+ a string: pipod settings user set pi.model provider/model
575
+ unset <key> Remove one dotted key, so the layers below decide it
576
+ ```
577
+
578
+ Keys are those of pipod-config(5). `set` changes the server only: a later `pipod push` of the
579
+ same layer replaces it with the local source, so after a `set`, run `pipod pull` before
580
+ editing that source.
581
+
582
+ ### pipod jobs
583
+
584
+ ```
585
+ Usage: pipod jobs [action] [args] [--quiet] [--yes] [--project] [--org]
586
+
587
+ Manage scheduled jobs the pi pod server runs for you: at each trigger it
588
+ launches a pod from the job's template and sends the job's prompt. Local job
589
+ files in .pi-pod/jobs/ (project) or ~/.pi-pod/jobs/ (user) are the reviewable
590
+ source; `jobs push` promotes them to the server. <job> is an id, short ref
591
+ (j-…), or name.
592
+
593
+ Actions:
594
+ list List server jobs (default)
595
+ show <job> Show a job's schedule, template, model, and prompt
596
+ runs <job> List a job's recent runs
597
+ run <job> Run an active job once, now; its schedule is unchanged
598
+ activate <job> Activate a job
599
+ pause <job> Pause a job's schedule
600
+ resume <job> Resume a paused job
601
+ rm <job> Remove a job; its schedule stops firing
602
+ push [job…] Create or update server jobs from local job files
603
+ pull <job> Write a server job to a local job file
604
+ diff [job…] Show local vs server drift; exits 1 when drifted
605
+
606
+ Options:
607
+ --org push: create org-scoped jobs or promote matching user jobs
608
+ (promotion is one-way)
609
+ --project pull: write into this project's .pi-pod/jobs/ instead of
610
+ ~/.pi-pod/jobs/
611
+ -q, --quiet list: print job ids only, one per line
612
+ -y, --yes Skip confirmations; pull: overwrite an existing local file
613
+ ```
614
+
615
+ A job file is `<name>.json` (comments allowed), and its file name is the job's name:
616
+
617
+ ```
618
+ {
619
+ "description": "Triage new issues every morning",
620
+ "trigger": { "type": "cron", "cron": "0 6 * * *" },
621
+ "template": "my-service",
622
+ "model": "anthropic/claude-opus-4-7",
623
+ "prompt": "Review yesterday's new issues and post a triage summary."
624
+ }
625
+ ```
626
+
627
+ `trigger` is a cron expression, evaluated in UTC, or `{ "type": "at", "times": [...] }` with
628
+ up to 100 ISO 8601 timestamps that each name their timezone. Runs must be at least 5
629
+ minutes apart, since each run is a pod. `model` (provider/model-id) is required.
630
+ `promptFile` names a file beside the job file instead of `prompt`; prompts are at most 64 KiB
631
+ and must say everything the run needs, since it starts in a fresh pod. A job runs on its own
632
+ until paused, so agree its schedule with the person before `pipod jobs push`.
633
+
634
+ ### pipod list
635
+
636
+ ```
637
+ Usage: pipod list [pod] [--all] [--archived] [--template <name|id>] [--quiet]
638
+
639
+ Alias: ls
640
+
641
+ List pods on the signed-in server with stable short refs (p-…). The project is
642
+ the directory's git repository (or the directory, or its .pi-pod/ config): a
643
+ listing shows that project's pods when it has any — its pinned template's when
644
+ it pins one — and every pod otherwise. Co-located pods are grouped under the pod
645
+ whose machine they share, with an ON column naming it.
646
+ With a pod argument, show just that machine's group: the pod and everything
647
+ co-located on it.
648
+
649
+ Status says where a pod's files are: a stopped pod keeps them on disk and restarts on
650
+ attach; an archived workspace is restored on next use, which takes longer the bigger it is.
651
+ Pods you archive stay hidden unless --archived is passed.
652
+
653
+ Options:
654
+ -a, --all Every pod; ignore the current project and its template pin
655
+ --archived Include logically archived pods
656
+ --template <name|id> Only pods launched from that template (whole account)
657
+ -q, --quiet Print pod ids only, one per line
658
+ ```
659
+
660
+ ### pipod attach
661
+
662
+ ```
663
+ Usage: pipod attach [pod] [--yes] [-- <prompt…> [--tui-mode <mode>]]
664
+
665
+ Alias: a
666
+
667
+ Reconnect to a pod session through the server gateway. Name the pod by id,
668
+ short ref (p-…), or name; omit it when this project has exactly one pod.
669
+ Quitting detaches: the pod keeps running until the server's idle policy reaps
670
+ it or `pipod stop` stops it. Raw pod shells are not available.
671
+ Attaching to an archived pod offers to restore it first.
672
+
673
+ After --:
674
+ <prompt…> Words are sent to the session as a startup prompt
675
+ --tui-mode <mode> Local TUI layout for this attach: regular or fullscreen
676
+
677
+ Options:
678
+ -y, --yes Restore an archived pod without asking
679
+ ```
680
+
681
+ ### pipod stop
682
+
683
+ ```
684
+ Usage: pipod stop [pod…]
685
+
686
+ Stop pods now by id, short ref (p-…), or name; omit the argument when this
687
+ project has exactly one pod. Stopped pods keep their files and `pipod attach`
688
+ restarts them. Stopping a pod that hosts co-located pods stops those too.
689
+ ```
690
+
691
+ ### pipod fork
692
+
693
+ ```
694
+ Usage: pipod fork <pod> [--session <path>] [launch options] [-- <pi args…>]
695
+
696
+ Launch a new pod whose session starts as a fork of <pod>'s current session.
697
+ <pod> is an id, short ref (p-…), or name. The workspace is not copied —
698
+ commit and push first if the new pod needs those changes. --on is not
699
+ supported: a fork launches a new sandbox, not a co-located pod.
700
+
701
+ Options:
702
+ --session <path> Fork a specific session file instead of the newest
703
+ --template <name|id> Launch the new pod from an account template
704
+ --dry-run Resolve and print the launch plan; create nothing
705
+ -y, --yes Skip supported confirmations
706
+ ```
707
+
708
+ ### pipod rename
709
+
710
+ ```
711
+ Usage: pipod rename <pod> <name>
712
+
713
+ Rename a server-managed pod. <pod> is an id, short ref (p-…), or the current
714
+ name.
715
+ ```
716
+
717
+ ### pipod send
718
+
719
+ ```
720
+ Usage: pipod send [pod] <path> [--yes]
721
+
722
+ Copy a host file or directory into a pod through the server. Omit the pod when
723
+ this project has exactly one. Sending to an archived pod offers to restore it
724
+ first.
725
+
726
+ Options:
727
+ -y, --yes Restore an archived pod without asking
728
+ ```
729
+
730
+ ### pipod receive
731
+
732
+ ```
733
+ Usage: pipod receive [pod] <path> [--yes]
734
+
735
+ Copy a file or directory from a pod into the current local directory. <path>
736
+ may be a workdir-relative path or an absolute path inside that workdir, such
737
+ as foo or /workspace/foo. The destination must not already exist. Omit the
738
+ pod when this project has exactly one. Receiving from an archived pod offers
739
+ to restore it first.
740
+
741
+ Options:
742
+ -y, --yes Restore an archived pod without asking
743
+ ```
744
+
745
+ ### pipod archive
746
+
747
+ ```
748
+ Usage: pipod archive [pod…] [--all] [--template <name|id>] [--idle <duration>] [--dry-run] [--yes]
749
+
750
+ Archive pods by id, short ref (p-…), or name. Archiving hides pods from
751
+ `pipod list` (`pipod list --archived` shows them); it never deletes work, and
752
+ `pipod restore` brings them back. Archiving a pod that hosts co-located pods
753
+ archives those too.
754
+
755
+ Options:
756
+ -a, --all Archive every pod (cannot be combined with pod refs)
757
+ --template <name|id> Only pods launched from that template (whole account)
758
+ --idle <duration> Only pods whose last activity is older than this (4h, 2d, 30m)
759
+ --dry-run Print the matching pods; archive nothing
760
+ -y, --yes Skip the bulk confirmation
761
+ ```
762
+
763
+ ### pipod restore
764
+
765
+ ```
766
+ Usage: pipod restore [pod…] [--all] [--yes]
767
+
768
+ Bring archived pods back by id, short ref (p-…), or name. Restoring a host
769
+ restores the co-located pods archived with it. `pipod attach` then starts the
770
+ pod; a workspace in cold storage takes longer the bigger it is.
771
+
772
+ Options:
773
+ -a, --all Restore every archived pod (cannot be combined with pod refs)
774
+ -y, --yes Skip the --all confirmation
775
+ ```
776
+
777
+ ### pipod gc
778
+
779
+ ```
780
+ Usage: pipod gc [--delete] [--yes]
781
+
782
+ List the archived and failed pods that can be deleted for good; --delete deletes
783
+ them. (The server stops idle pods and moves stopped workspaces to cold storage on
784
+ its own schedule; that never deletes anything.)
785
+
786
+ Options:
787
+ --delete Permanently delete the reclaimable pods
788
+ -y, --yes Delete without a confirmation prompt
789
+ ```
790
+
791
+ ### pipod doctor
792
+
793
+ ```
794
+ Usage: pipod doctor [--template <name|id>]
795
+
796
+ Check each layer a launch depends on: account auth, server reachability and
797
+ version, organization membership and roles, secret references, and the
798
+ server-resolved settings bundle chain for this directory. Works while signed
799
+ out to diagnose auth problems. Exits non-zero when a layer fails.
800
+
801
+ Options:
802
+ --template <name|id> Plan the checked launch with this template
803
+ ```
804
+
805
+ ### pipod update
806
+
807
+ ```
808
+ Usage: pipod update [--dry-run]
809
+
810
+ Upgrade pi pod itself: a registry install updates to the latest published
811
+ version; a git checkout pulls its upstream and rebuilds.
812
+
813
+ Options:
814
+ --dry-run Report what an update would do without changing anything
815
+ ```
816
+
817
+ ## FILES
818
+
819
+ ```
820
+ ~/.pi-pod/auth.json this machine's sign-in (pipod login)
821
+ ~/.pi-pod/config.json this machine's preferences, and the config of your
822
+ user layer (pipod-config(5))
823
+ ~/.pi/agent/ your Pi files, the rest of your user layer:
824
+ settings.json, models.json, mcporter.json,
825
+ subagents.json, agents/
826
+ ~/.pi-pod/org/ the organization layer's source: config.json,
827
+ init.sh, bake.sh, pi/, env
828
+ ~/.pi-pod/secrets/ dotenv files for pipod secrets sync
829
+ ~/.pi-pod/jobs/ your job files
830
+ .pi-pod/config.json a project's config and its template pin
831
+ .pi-pod/init.sh runs in each of the project's new pods
832
+ .pi-pod/bake.sh built into the project's pod image
833
+ .pi-pod/env the project's secret values; never committed
834
+ .pi-pod/env.example the names of the project's secrets; committed
835
+ .pi-pod/jobs/ the project's job files
836
+ .pi/ the project's Pi files, as in ~/.pi/agent/
837
+ ```
838
+
839
+ ## ENVIRONMENT
840
+
841
+ ```
842
+ PI_POD_ACCOUNT_URL the server pipod login uses with no --server and no
843
+ previous session
844
+ PI_POD_ISSUER the OIDC issuer pipod login uses, for a server too old
845
+ to publish its own
846
+ PI_POD_SERVER_URL set in every pod: pipod there signs in with the pod's
847
+ PI_POD_SERVER_TOKEN own token, which reaches only the pods it launched and
848
+ launches only from the pod's own template
849
+ VISUAL, EDITOR the editor for pipod settings edit
850
+ NO_COLOR plain output without color
851
+ ```
852
+
853
+ ## SEE ALSO
854
+
855
+ pipod-config(5), https://github.com/pi-pod/pipod, and docs/self-host.md there for running
856
+ a server.