@pipod/cli 0.1.10 → 0.1.12

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.
@@ -115,15 +115,17 @@ ignored, except `--dry-run`/`--on`-with-fork which are usage errors.
115
115
  `--from-here`), `edit` (`--name/--description/--config/--init-script/--bake-script`;
116
116
  `--org` rejected — org-wide goes through `share`; whole-snapshot replace goes through `push`), `share` (one-way),
117
117
  `rm|delete [-y]`. A global `--yes` is honored (no false scope warning).
118
- - `push [template [<name>]|user|org]`: whole-bundle replace from the layer's
119
- local source (project `.pi-pod/`+`.pi/`, user `~/.pi-pod`+`~/.pi/agent`, org
120
- `~/.pi-pod/org/` or `--dir`), after a diff preview. `--with-secrets` uploads
121
- env values (else a prompt per bundle); `-y` applies without confirming.
122
- - `pull [layer]`: reverse of push (same sources; `--dir` for org; `-y`).
118
+ - `push [template [<name>]|user|org|policy]`: whole-bundle replace from the
119
+ layer's local source (project `.pi-pod/`+`.pi/`, user `~/.pi-pod`+`~/.pi/agent`,
120
+ org `~/.pi-pod/org/` or `--dir`, policy `policy.json` in that org directory),
121
+ after a diff preview. The policy is config only and validated by the server.
122
+ `--with-secrets` uploads env values (else a prompt per bundle); `-y` applies
123
+ without confirming.
124
+ - `pull [layer]`: reverse of push (same sources; `--dir` for org and policy; `-y`).
123
125
  Client-only keys, host-coupled settings, and model credential values survive;
124
126
  server scripts with no local file warn instead of writing.
125
127
  - `diff [layer]`: same sources, secrets by name only; exit 1 on drift (`--dir`
126
- for org; no `-y` — it never writes).
128
+ for org and policy; no `-y` — it never writes).
127
129
  - `settings <user|org> [show|edit|set <key> <json-value>]`: config-only
128
130
  compare-and-swap edits (scripts/Pi files untouched — that is `push`).
129
131
  `show` prints JSON; `edit` uses `$VISUAL`/`$EDITOR`; `set` takes a dotted key
@@ -23,20 +23,23 @@ from a subdirectory seeds the whole repository and prints the subdirectory so it
23
23
 
24
24
  ## Clone or archive
25
25
 
26
- A clone is chosen only when it reproduces the host checkout exactly. Every check below fails
27
- closed into an archive with a human-readable reason (`pipod --dry-run` prints it):
26
+ A clone is preferred when the pod can fetch the host's exact **committed HEAD**. Local
27
+ staged, unstaged, and untracked changes do not prevent cloning and are **not copied** by a
28
+ successful clone. The local checkout is left untouched. Every check below fails closed into
29
+ an archive with a human-readable reason (`pipod --dry-run` prints it):
28
30
 
29
31
  1. inside a git work tree
30
32
  2. `origin` exists and rewrites to an `https://` URL (`git@host:x/y.git` and `ssh://` are rewritten; local paths cannot be cloned by a pod)
31
33
  3. HEAD is on a branch
32
- 4. no modified, staged, or untracked non-ignored files
33
- 5. the branch has an upstream with no unpushed commits
34
- 6. no initialized submodules, no Git LFS attributes
35
- 7. the pod's egress policy admits the remote host
36
- 8. a live `git ls-remote` shows the remote branch at exactly the local HEAD commit
34
+ 4. the branch has an upstream with no unpushed commits
35
+ 5. no initialized submodules, no Git LFS attributes
36
+ 6. the pod's egress policy admits the remote host
37
+ 7. a live `git ls-remote` shows the remote branch at exactly the local HEAD commit
37
38
 
38
39
  The server clones that exact commit into the empty workdir. If the clone fails for any
39
- reason, the launch automatically falls back to an archive of the local tree.
40
+ reason, the launch automatically falls back to an archive of the local working tree,
41
+ **including uncommitted changes**. The committed-only behavior applies to successful clones,
42
+ not archive or configured-project copy transports.
40
43
 
41
44
  An **archive** is a gzip-compressed POSIX tar stream written to a temporary file and streamed
42
45
  to `PUT /v1/pods/:id/workspace/archive`. It contains tracked and untracked non-ignored files,
@@ -91,10 +94,12 @@ on the sandbox backend:
91
94
  the forwarding prompt; approve; `!git remote -v` inside the pod shows the https URL with no
92
95
  token, and `!cat .git/config` holds no token.
93
96
  3. **Declined forwarding** — answer `n`; expect an archive, and the pod still holds the tree.
94
- 4. **Dirty repository archive** — edit a file, launch; expect `will be archived … (uncommitted
95
- changes would be lost by a clone)` and `!git status` in the pod shows the same edit.
97
+ 4. **Dirty repository clone** — in a pushed, cloneable repository, stage a change, edit it
98
+ again, and add an untracked file. Launch; expect `will clone … (local uncommitted changes
99
+ are not copied)`. Inside the pod, `!git status` is clean, tracked content matches HEAD,
100
+ and the untracked file is absent. The host's staged, unstaged and untracked changes remain.
96
101
  5. **Non-git archive** — a plain directory of files; expect the files without a `.git`.
97
- 6. **100+ MiB streaming archive** — a repository with a large untracked binary; watch the
102
+ 6. **100+ MiB streaming archive** — a repository without `origin`, with a large untracked binary; watch the
98
103
  `upload 25% …` lines; verify the file's checksum in the pod.
99
104
  7. **Interrupted upload** — Ctrl-C during upload; expect the pod deleted and no
100
105
  `pi-pod-seed-*.tar.gz` left in the temp directory.
@@ -1,4 +1,4 @@
1
- .TH "PIPOD\-CONFIG" "5" "October 2026" "0.1.10"
1
+ .TH "PIPOD\-CONFIG" "5" "October 2026" "0.1.12"
2
2
  .SH "NAME"
3
3
  \fBpipod-config\fR \- pi pod configuration files
4
4
  .SH SYNOPSIS
package/man/pipod.1 CHANGED
@@ -1,4 +1,4 @@
1
- .TH "PIPOD" "1" "October 2026" "0.1.10"
1
+ .TH "PIPOD" "1" "October 2026" "0.1.12"
2
2
  .SH "NAME"
3
3
  \fBpipod\fR \- run pi coding\-agent sessions in server\-managed pods
4
4
  .SH SYNOPSIS
@@ -90,9 +90,9 @@ bake script that is built into the pod image once, and Pi files\. Secrets are st
90
90
  the layers and reach pods as environment variables\. \fBpipod help layers\fP explains how they
91
91
  combine\.
92
92
  .P
93
- Every server layer has a local source of truth: a directory you edit with any editor, then
94
- upload with \fBpipod push\fP\|\. \fBpipod pull\fP writes the server's copy back, and \fBpipod diff\fP
95
- compares the two\.
93
+ Every server layer, organization policy included, has a local source of truth: files you edit
94
+ with any editor, then upload with \fBpipod push\fP\|\. \fBpipod pull\fP writes the server's copy back, and
95
+ \fBpipod diff\fP compares the two\.
96
96
  .SH SETUP
97
97
  .P
98
98
  Setting pi pod up for yourself or an organization, in order\. A person has to do the steps
@@ -137,8 +137,20 @@ pipod push org
137
137
  .RE
138
138
  .P
139
139
  Values for secrets the whole organization shares: \fBpipod secrets set org <NAME>\fP (person)\.
140
- Organization policy (limits rather than defaults) is set in the web dashboard,
141
- \fB<server>/dashboard/\fP\|\.
140
+ .P
141
+ Organization policy (limits rather than defaults) needs the policy:write permission\. Its source
142
+ is policy\.json beside the organization layer's files:
143
+ .RS 2
144
+ .nf
145
+ pipod pull policy # writes ~/\.pi\-pod/org/policy\.json
146
+ # edit it
147
+ pipod diff policy
148
+ pipod push policy
149
+ .fi
150
+ .RE
151
+ .P
152
+ To keep the organization's source in a repository instead, give each of these commands
153
+ \fB\-\-dir <path>\fP\|\.
142
154
  .SS 5\. Your own defaults
143
155
  .P
144
156
  Your model and thinking level, your Pi settings, personal setup such as a git identity:
@@ -217,8 +229,8 @@ and the server refuses a literal key\.
217
229
  .P
218
230
  Organization policy holds limits rather than defaults: maximum idle and archive times,
219
231
  allowed providers, a required template, network rules, concurrency\. It clamps the merged
220
- result, and \fBpipod doctor\fP and \fBpipod \-\-dry\-run\fP report every clamp\. It is set in the web
221
- dashboard by someone with the policy:write permission\.
232
+ result, and \fBpipod doctor\fP and \fBpipod \-\-dry\-run\fP report every clamp\. Someone with the
233
+ policy:write permission changes it with \fBpipod push policy\fP or in the web dashboard\.
222
234
  .P
223
235
  Where each layer's source lives, and the commands that change it:
224
236
  .RS 2
@@ -229,6 +241,8 @@ user ~/\.pi\-pod/config\.json and ~/\.pi/agent/
229
241
  pipod pull|diff|push user; pipod settings user set
230
242
  template a project: \.pi\-pod/config\.json, init\.sh, bake\.sh, env, and \.pi/
231
243
  pipod pull|diff|push [template [<name>]]; pipod templates
244
+ policy ~/\.pi\-pod/org/policy\.json
245
+ pipod pull|diff|push policy (policy:write)
232
246
  .fi
233
247
  .RE
234
248
  .P
@@ -251,10 +265,13 @@ The launch uses the template named by \fB\-\-template\fP, or else the one pinned
251
265
  first launch offers to create a template from the project and pin it\.
252
266
  .P
253
267
  Workspace seeding: launching from a directory with no \.pi\-pod/config\.json seeds the new pod
254
- from that directory (its git repository root when inside one)\. A clean, pushed checkout whose
255
- remote tip matches HEAD is cloned at that exact commit; anything else (dirty trees, unpushed
256
- commits, private remotes without usable credentials, plain directories) is streamed in as a
257
- tar archive, without git\-ignored paths, node_modules, or \.pi\-pod/env\. Private\-remote
268
+ from that directory (its git repository root when inside one)\. A pushed checkout whose
269
+ remote tip matches HEAD is cloned at that exact committed HEAD, even with local uncommitted
270
+ changes\. A successful clone does not copy staged, unstaged, or untracked changes and leaves
271
+ the local checkout untouched\. When cloning is unavailable or fails (unpushed commits, private
272
+ remotes without usable credentials, plain directories), the local working tree, including
273
+ uncommitted changes, is streamed in as a tar archive, without git\-ignored paths, node_modules,
274
+ or \.pi\-pod/env\. Private\-remote
258
275
  credentials are forwarded only after a prompt (\fB\-\-yes\fP approves it) and are never stored\.
259
276
  \fB\-\-dry\-run\fP prints the decision without prompting or creating a pod\. Forks, reused pods,
260
277
  \fB\-\-on\fP co\-location, and \fB\-\-no\-seed\fP never seed\. A project with a \.pi\-pod/config\.json gets its
@@ -459,7 +476,7 @@ A personal template sits above your user layer and an org\-wide one below it
459
476
  .SS pipod push
460
477
  .RS 2
461
478
  .nf
462
- Usage: pipod push [template [<name>] | user | org] [\-\-dir <path>]
479
+ Usage: pipod push [template [<name>] | user | org | policy] [\-\-dir <path>]
463
480
  [\-\-with\-secrets] [\-\-yes]
464
481
 
465
482
  Replace a server config bundle with its local source, whole\. The layer names
@@ -475,13 +492,16 @@ Layers and their local source:
475
492
  models\.json, mcporter\.json, subagents\.json, agents/)
476
493
  org ~/\.pi\-pod/org/: config\.json, init\.sh, bake\.sh, pi/…, and
477
494
  an optional env file whose values become org secrets
495
+ policy ~/\.pi\-pod/org/policy\.json: the organization policy, one
496
+ JSON object of limits, checked by the server
478
497
 
479
498
  Inside a project the layer defaults to template; elsewhere it is required\.
480
499
  Provider credentials, hooks, mcpServers, and model credential values never
481
500
  leave this machine\.
482
501
 
483
502
  Options:
484
- \-\-dir <path> org only: read the org source from <path> instead
503
+ \-\-dir <path> org and policy: read the org source directory from <path>
504
+ instead
485
505
  \-\-with\-secrets Also upload the layer's env values as secrets
486
506
  \-y, \-\-yes Apply the replacement without the confirmation prompt
487
507
  .fi
@@ -493,7 +513,8 @@ confirm on, push declines unless \fB\-\-yes\fP is given\.
493
513
  .SS pipod pull
494
514
  .RS 2
495
515
  .nf
496
- Usage: pipod pull [template [<name>] | user | org] [\-\-dir <path>] [\-\-yes]
516
+ Usage: pipod pull [template [<name>] | user | org | policy] [\-\-dir <path>]
517
+ [\-\-yes]
497
518
 
498
519
  Write a server config bundle into its local source files (see
499
520
  `pipod push \-\-help` for the layer → directory table)\. A diff preview
@@ -511,21 +532,23 @@ Secrets stay on the server; their names are listed\. The user layer has no
511
532
  local script files, so user bundle scripts are shown but not written\.
512
533
 
513
534
  Options:
514
- \-\-dir <path> org only: write the org source to <path> instead
535
+ \-\-dir <path> org and policy: write the org source directory at <path>
536
+ instead
515
537
  \-y, \-\-yes Apply the local changes without the confirmation prompt
516
538
  .fi
517
539
  .RE
518
540
  .SS pipod diff
519
541
  .RS 2
520
542
  .nf
521
- Usage: pipod diff [template [<name>] | user | org] [\-\-dir <path>]
543
+ Usage: pipod diff [template [<name>] | user | org | policy] [\-\-dir <path>]
522
544
 
523
545
  Compare a config layer's local source with its server bundle (see
524
546
  `pipod push \-\-help` for the layer → directory table)\. Secrets compare by
525
547
  name only\. Exits 1 when they differ, 0 when they match\.
526
548
 
527
549
  Options:
528
- \-\-dir <path> org only: read the org source from <path> instead
550
+ \-\-dir <path> org and policy: read the org source directory from <path>
551
+ instead
529
552
  .fi
530
553
  .RE
531
554
  .SS pipod secrets
package/man/pipod.1.md CHANGED
@@ -89,9 +89,9 @@ bake script that is built into the pod image once, and Pi files. Secrets are sto
89
89
  the layers and reach pods as environment variables. `pipod help layers` explains how they
90
90
  combine.
91
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.
92
+ Every server layer, organization policy included, has a local source of truth: files you edit
93
+ with any editor, then upload with `pipod push`. `pipod pull` writes the server's copy back, and
94
+ `pipod diff` compares the two.
95
95
 
96
96
  ## SETUP
97
97
 
@@ -139,8 +139,19 @@ pipod push org
139
139
  ```
140
140
 
141
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/`.
142
+
143
+ Organization policy (limits rather than defaults) needs the policy:write permission. Its source
144
+ is policy.json beside the organization layer's files:
145
+
146
+ ```
147
+ pipod pull policy # writes ~/.pi-pod/org/policy.json
148
+ # edit it
149
+ pipod diff policy
150
+ pipod push policy
151
+ ```
152
+
153
+ To keep the organization's source in a repository instead, give each of these commands
154
+ `--dir <path>`.
144
155
 
145
156
  ### 5. Your own defaults
146
157
 
@@ -207,8 +218,8 @@ project's .pi-pod/config.json. Within the layers:
207
218
 
208
219
  Organization policy holds limits rather than defaults: maximum idle and archive times,
209
220
  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.
221
+ result, and `pipod doctor` and `pipod --dry-run` report every clamp. Someone with the
222
+ policy:write permission changes it with `pipod push policy` or in the web dashboard.
212
223
 
213
224
  Where each layer's source lives, and the commands that change it:
214
225
 
@@ -219,6 +230,8 @@ user ~/.pi-pod/config.json and ~/.pi/agent/
219
230
  pipod pull|diff|push user; pipod settings user set
220
231
  template a project: .pi-pod/config.json, init.sh, bake.sh, env, and .pi/
221
232
  pipod pull|diff|push [template [<name>]]; pipod templates
233
+ policy ~/.pi-pod/org/policy.json
234
+ pipod pull|diff|push policy (policy:write)
222
235
  ```
223
236
 
224
237
  What belongs where: the organization layer holds what everyone needs (pod size, network
@@ -241,10 +254,13 @@ The launch uses the template named by `--template`, or else the one pinned in th
241
254
  first launch offers to create a template from the project and pin it.
242
255
 
243
256
  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
257
+ from that directory (its git repository root when inside one). A pushed checkout whose
258
+ remote tip matches HEAD is cloned at that exact committed HEAD, even with local uncommitted
259
+ changes. A successful clone does not copy staged, unstaged, or untracked changes and leaves
260
+ the local checkout untouched. When cloning is unavailable or fails (unpushed commits, private
261
+ remotes without usable credentials, plain directories), the local working tree, including
262
+ uncommitted changes, is streamed in as a tar archive, without git-ignored paths, node_modules,
263
+ or .pi-pod/env. Private-remote
248
264
  credentials are forwarded only after a prompt (`--yes` approves it) and are never stored.
249
265
  `--dry-run` prints the decision without prompting or creating a pod. Forks, reused pods,
250
266
  `--on` co-location, and `--no-seed` never seed. A project with a .pi-pod/config.json gets its
@@ -451,7 +467,7 @@ A personal template sits above your user layer and an org-wide one below it
451
467
  ### pipod push
452
468
 
453
469
  ```
454
- Usage: pipod push [template [<name>] | user | org] [--dir <path>]
470
+ Usage: pipod push [template [<name>] | user | org | policy] [--dir <path>]
455
471
  [--with-secrets] [--yes]
456
472
 
457
473
  Replace a server config bundle with its local source, whole. The layer names
@@ -467,13 +483,16 @@ Layers and their local source:
467
483
  models.json, mcporter.json, subagents.json, agents/)
468
484
  org ~/.pi-pod/org/: config.json, init.sh, bake.sh, pi/…, and
469
485
  an optional env file whose values become org secrets
486
+ policy ~/.pi-pod/org/policy.json: the organization policy, one
487
+ JSON object of limits, checked by the server
470
488
 
471
489
  Inside a project the layer defaults to template; elsewhere it is required.
472
490
  Provider credentials, hooks, mcpServers, and model credential values never
473
491
  leave this machine.
474
492
 
475
493
  Options:
476
- --dir <path> org only: read the org source from <path> instead
494
+ --dir <path> org and policy: read the org source directory from <path>
495
+ instead
477
496
  --with-secrets Also upload the layer's env values as secrets
478
497
  -y, --yes Apply the replacement without the confirmation prompt
479
498
  ```
@@ -485,7 +504,8 @@ confirm on, push declines unless `--yes` is given.
485
504
  ### pipod pull
486
505
 
487
506
  ```
488
- Usage: pipod pull [template [<name>] | user | org] [--dir <path>] [--yes]
507
+ Usage: pipod pull [template [<name>] | user | org | policy] [--dir <path>]
508
+ [--yes]
489
509
 
490
510
  Write a server config bundle into its local source files (see
491
511
  `pipod push --help` for the layer → directory table). A diff preview
@@ -503,21 +523,23 @@ Secrets stay on the server; their names are listed. The user layer has no
503
523
  local script files, so user bundle scripts are shown but not written.
504
524
 
505
525
  Options:
506
- --dir <path> org only: write the org source to <path> instead
526
+ --dir <path> org and policy: write the org source directory at <path>
527
+ instead
507
528
  -y, --yes Apply the local changes without the confirmation prompt
508
529
  ```
509
530
 
510
531
  ### pipod diff
511
532
 
512
533
  ```
513
- Usage: pipod diff [template [<name>] | user | org] [--dir <path>]
534
+ Usage: pipod diff [template [<name>] | user | org | policy] [--dir <path>]
514
535
 
515
536
  Compare a config layer's local source with its server bundle (see
516
537
  `pipod push --help` for the layer → directory table). Secrets compare by
517
538
  name only. Exits 1 when they differ, 0 when they match.
518
539
 
519
540
  Options:
520
- --dir <path> org only: read the org source from <path> instead
541
+ --dir <path> org and policy: read the org source directory from <path>
542
+ instead
521
543
  ```
522
544
 
523
545
  ### pipod secrets
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipod/cli",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "Run pi coding-agent sessions in server-managed pods",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",