@pipod/cli 0.1.12 → 0.1.13

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.
@@ -35,7 +35,7 @@ drops everything a bundle payload must not contain: the rejected keys
35
35
  `envFile`/`initScript`/`bakeScript`; `pi.hostConfig.skills`/`extensions`) plus
36
36
  client-only metadata (`$schema`, `secretResolver`, `pi.chords`/`pi.sessionNaming`/`pi.podExtensions`).
37
37
  Covered paths: project/user/org-dir compilation, the launch bootstrap preview,
38
- `templates create/edit --config`, and `settings user|org edit|set` — the settings
38
+ `templates create/edit --config`, and `settings user|org|template edit|set` — the settings
39
39
  verbs validate the edited config locally first (types and retired keys fail
40
40
  before any write request) and throw on non-bundle keys with the fix, so an
41
41
  explicit `set reuse true` fails visibly rather than vanishing.
@@ -126,11 +126,11 @@ ignored, except `--dry-run`/`--on`-with-fork which are usage errors.
126
126
  server scripts with no local file warn instead of writing.
127
127
  - `diff [layer]`: same sources, secrets by name only; exit 1 on drift (`--dir`
128
128
  for org and policy; no `-y` — it never writes).
129
- - `settings <user|org> [show|edit|set <key> <json-value>]`: config-only
130
- compare-and-swap edits (scripts/Pi files untouched — that is `push`).
131
- `show` prints JSON; `edit` uses `$VISUAL`/`$EDITOR`; `set` takes a dotted key
132
- plus a JSON value. Templates are not a settings scope (hint points at
133
- `templates`).
129
+ - `settings [user|org|policy|template [<name>]] [show|edit|set <key> <json-value>|unset <key>]`:
130
+ config-only compare-and-swap edits of the layers `push` replaces whole
131
+ (scripts/Pi files untouched — that is `push`). `show` prints JSON; `edit` uses
132
+ `$VISUAL`/`$EDITOR`; `set` takes a dotted key plus a JSON value. `template`
133
+ without a name is the project's pin. The policy is checked by the server only.
134
134
  - `login`: Zitadel PKCE in the browser; where none can open (SSH, headless), the
135
135
  device flow with a code finished on another device. `--server`, `--issuer`
136
136
  (self-hosted), `--org` (domain pin), `--device` (force the code), `--token`
@@ -1,4 +1,4 @@
1
- .TH "PIPOD\-CONFIG" "5" "October 2026" "0.1.12"
1
+ .TH "PIPOD\-CONFIG" "5" "October 2026" "0.1.13"
2
2
  .SH "NAME"
3
3
  \fBpipod-config\fR \- pi pod configuration files
4
4
  .SH SYNOPSIS
@@ -7,6 +7,7 @@
7
7
  \|\.pi\-pod/config\.json a project: the source of its template
8
8
  ~/\.pi\-pod/config\.json this machine's preferences, and your user layer
9
9
  ~/\.pi\-pod/org/config\.json the organization layer
10
+ ~/\.pi\-pod/org/policy\.json the organization policy (POLICY KEYS)
10
11
  .fi
11
12
  .RE
12
13
  .SH DESCRIPTION
@@ -14,8 +15,8 @@
14
15
  Each file is one settings layer's config, written as JSON with comments allowed\. The server
15
16
  merges the layers for each launch (\fBpipod help layers\fP), so a file names only what its layer
16
17
  must decide; anything left out comes from the layers below it\. The keys are the same in every
17
- file\. \fBpipod push\fP uploads a file and \fBpipod settings <user|org> set <key> <value>\fP changes
18
- one key on the server\.
18
+ file but policy\.json, which holds limits on the merged result instead\. \fBpipod push\fP uploads a
19
+ file and \fBpipod settings <layer> set <key> <value>\fP changes one key on the server\.
19
20
  .P
20
21
  A key of the wrong type fails the command that reads it, naming the key\. An unknown key is
21
22
  ignored with a warning\.
@@ -101,6 +102,36 @@ pi\.podExtensions a pod's Pi extensions run on this machine, as you, to
101
102
  $schema ignored
102
103
  .fi
103
104
  .RE
105
+ .SH POLICY KEYS
106
+ .P
107
+ policy\.json holds the organization's policy: limits the server applies after every other
108
+ layer, whatever a person's settings, template, or launch ask for\. Every key is optional, and
109
+ one left out sets no limit\. The server checks every change to it and names any key or value it
110
+ refuses\.
111
+ .RS 2
112
+ .nf
113
+ maxIdleTimeoutMinutes the longest idleTimeoutMinutes a pod gets; a longer one,
114
+ or 0, becomes this
115
+ maxArchiveAfterMinutes the same for archiveAfterMinutes
116
+ maxConcurrentPods pods the whole organization may have awake at once; the
117
+ server's own limit per person still applies
118
+ allowedProviders the providers a launch may use; others are refused
119
+ requireTemplate true: every launch must use a template
120
+ requireEgressMode "allowlist": a pod set to "open" gets "allowlist" instead
121
+ forbiddenEgressHosts hosts removed from every egress\.allow
122
+ nestedPods\.enabled false: pods may not launch pods or schedule jobs
123
+ (default true)
124
+ nestedPods\.maxDepth how deep pods may launch pods, 0 to 8 (default 2)
125
+ nestedPods\.maxChildrenPerPod awake child pods per pod, 0 to 100 (default 5)
126
+ nestedPods\.maxPodsPerLineage awake pods in one family of pods, 1 to 500 (default 10)
127
+ nestedPods\.allowFileSend false: pods may not send files to other pods (default true)
128
+ nestedPods\.allowFileReceive false: pods may not copy files out of other pods
129
+ (default true)
130
+ notifications\.redacted true: push notifications leave out pod names and summaries
131
+ .fi
132
+ .RE
133
+ .P
134
+ Each clamp a launch gets is reported by \fBpipod doctor\fP and \fBpipod \-\-dry\-run\fP\|\.
104
135
  .SH SCRIPTS
105
136
  .P
106
137
  A layer's two scripts sit beside its config: \.pi\-pod/init\.sh and \.pi\-pod/bake\.sh in a
@@ -143,6 +174,14 @@ pipod settings org set resources\.memoryGB 8
143
174
  pipod settings org set idleTimeoutMinutes 30
144
175
  .fi
145
176
  .RE
177
+ .P
178
+ An organization policy that caps idle time and keeps pods from launching pods:
179
+ .RS 2
180
+ .nf
181
+ pipod settings policy set maxIdleTimeoutMinutes 60
182
+ pipod settings policy set nestedPods\.enabled false
183
+ .fi
184
+ .RE
146
185
  .SH RETIRED KEYS
147
186
  .P
148
187
  \fBenvFile\fP, \fBinitScript\fP, \fBbakeScript\fP, and \fBreuse\fP fail with a message saying what replaced
@@ -6,6 +6,7 @@
6
6
  .pi-pod/config.json a project: the source of its template
7
7
  ~/.pi-pod/config.json this machine's preferences, and your user layer
8
8
  ~/.pi-pod/org/config.json the organization layer
9
+ ~/.pi-pod/org/policy.json the organization policy (POLICY KEYS)
9
10
  ```
10
11
 
11
12
  ## DESCRIPTION
@@ -13,8 +14,8 @@
13
14
  Each file is one settings layer's config, written as JSON with comments allowed. The server
14
15
  merges the layers for each launch (`pipod help layers`), so a file names only what its layer
15
16
  must decide; anything left out comes from the layers below it. The keys are the same in every
16
- file. `pipod push` uploads a file and `pipod settings <user|org> set <key> <value>` changes
17
- one key on the server.
17
+ file but policy.json, which holds limits on the merged result instead. `pipod push` uploads a
18
+ file and `pipod settings <layer> set <key> <value>` changes one key on the server.
18
19
 
19
20
  A key of the wrong type fails the command that reads it, naming the key. An unknown key is
20
21
  ignored with a warning.
@@ -98,6 +99,36 @@ pi.podExtensions a pod's Pi extensions run on this machine, as you, to r
98
99
  $schema ignored
99
100
  ```
100
101
 
102
+ ## POLICY KEYS
103
+
104
+ policy.json holds the organization's policy: limits the server applies after every other
105
+ layer, whatever a person's settings, template, or launch ask for. Every key is optional, and
106
+ one left out sets no limit. The server checks every change to it and names any key or value it
107
+ refuses.
108
+
109
+ ```
110
+ maxIdleTimeoutMinutes the longest idleTimeoutMinutes a pod gets; a longer one,
111
+ or 0, becomes this
112
+ maxArchiveAfterMinutes the same for archiveAfterMinutes
113
+ maxConcurrentPods pods the whole organization may have awake at once; the
114
+ server's own limit per person still applies
115
+ allowedProviders the providers a launch may use; others are refused
116
+ requireTemplate true: every launch must use a template
117
+ requireEgressMode "allowlist": a pod set to "open" gets "allowlist" instead
118
+ forbiddenEgressHosts hosts removed from every egress.allow
119
+ nestedPods.enabled false: pods may not launch pods or schedule jobs
120
+ (default true)
121
+ nestedPods.maxDepth how deep pods may launch pods, 0 to 8 (default 2)
122
+ nestedPods.maxChildrenPerPod awake child pods per pod, 0 to 100 (default 5)
123
+ nestedPods.maxPodsPerLineage awake pods in one family of pods, 1 to 500 (default 10)
124
+ nestedPods.allowFileSend false: pods may not send files to other pods (default true)
125
+ nestedPods.allowFileReceive false: pods may not copy files out of other pods
126
+ (default true)
127
+ notifications.redacted true: push notifications leave out pod names and summaries
128
+ ```
129
+
130
+ Each clamp a launch gets is reported by `pipod doctor` and `pipod --dry-run`.
131
+
101
132
  ## SCRIPTS
102
133
 
103
134
  A layer's two scripts sit beside its config: .pi-pod/init.sh and .pi-pod/bake.sh in a
@@ -140,6 +171,13 @@ pipod settings org set resources.memoryGB 8
140
171
  pipod settings org set idleTimeoutMinutes 30
141
172
  ```
142
173
 
174
+ An organization policy that caps idle time and keeps pods from launching pods:
175
+
176
+ ```
177
+ pipod settings policy set maxIdleTimeoutMinutes 60
178
+ pipod settings policy set nestedPods.enabled false
179
+ ```
180
+
143
181
  ## RETIRED KEYS
144
182
 
145
183
  `envFile`, `initScript`, `bakeScript`, and `reuse` fail with a message saying what replaced
package/man/pipod.1 CHANGED
@@ -1,4 +1,4 @@
1
- .TH "PIPOD" "1" "October 2026" "0.1.12"
1
+ .TH "PIPOD" "1" "October 2026" "0.1.13"
2
2
  .SH "NAME"
3
3
  \fBpipod\fR \- run pi coding\-agent sessions in server\-managed pods
4
4
  .SH SYNOPSIS
@@ -138,8 +138,9 @@ pipod push org
138
138
  .P
139
139
  Values for secrets the whole organization shares: \fBpipod secrets set org <NAME>\fP (person)\.
140
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:
141
+ Organization policy (limits rather than defaults) needs the policy:write permission\. Change
142
+ one limit with \fBpipod settings policy set <key> <value>\fP (its keys are in pipod\-config(5)), or
143
+ the whole policy from its source, policy\.json beside the organization layer's files:
143
144
  .RS 2
144
145
  .nf
145
146
  pipod pull policy # writes ~/\.pi\-pod/org/policy\.json
@@ -240,9 +241,10 @@ org ~/\.pi\-pod/org/: config\.json, init\.sh, bake\.sh, pi/, env
240
241
  user ~/\.pi\-pod/config\.json and ~/\.pi/agent/
241
242
  pipod pull|diff|push user; pipod settings user set
242
243
  template a project: \.pi\-pod/config\.json, init\.sh, bake\.sh, env, and \.pi/
243
- pipod pull|diff|push [template [<name>]]; pipod templates
244
+ pipod pull|diff|push [template [<name>]]; pipod settings template set;
245
+ pipod templates
244
246
  policy ~/\.pi\-pod/org/policy\.json
245
- pipod pull|diff|push policy (policy:write)
247
+ pipod pull|diff|push policy; pipod settings policy set (policy:write)
246
248
  .fi
247
249
  .RE
248
250
  .P
@@ -589,17 +591,23 @@ or \fBsync\fP reads a dotenv file kept at mode 600\. op:// references resolve th
589
591
  .SS pipod settings
590
592
  .RS 2
591
593
  .nf
592
- Usage: pipod settings <user|org> [show | edit | set <key> <value> | unset <key>]
594
+ Usage: pipod settings [user | org | policy | template [<name>]]
595
+ [show | edit | set <key> <value> | unset <key>]
593
596
 
594
- Show or edit a persistent settings bundle on the server: your own user bundle,
595
- or the org\-wide defaults (org scope needs the org:manage permission)\. Edits
596
- change only the config; scripts and Pi files stay as they are — replace the
597
- whole bundle from local files with `pipod push user` or `pipod push org`\.
598
- Edits use compare\-and\-swap on the bundle version, so concurrent changes fail
599
- cleanly instead of overwriting each other\.
597
+ Show or edit one server layer's config directly, the same layers `pipod push`
598
+ replaces whole:
599
+ user Your own settings (the default)
600
+ org The organization's defaults (needs org:manage)
601
+ policy The organization's policy (needs policy:write)
602
+ template [<name>] A template; without <name>, the one this project pins
603
+
604
+ Edits change only the config; scripts and Pi files stay as they are — replace
605
+ a whole layer from local files with `pipod push`\. Edits use compare\-and\-swap
606
+ on the layer's version, so concurrent changes fail cleanly instead of
607
+ overwriting each other\.
600
608
 
601
609
  Actions:
602
- show Print the settings bundle as JSON (default)
610
+ show Print the layer as JSON (default)
603
611
  edit Edit the config in $VISUAL/$EDITOR, then save
604
612
  set <key> <value> Set one dotted key to a JSON value, or to the text as
605
613
  a string: pipod settings user set pi\.model provider/model
@@ -607,9 +615,11 @@ Actions:
607
615
  .fi
608
616
  .RE
609
617
  .P
610
- Keys are those of pipod\-config(5)\. \fBset\fP changes the server only: a later \fBpipod push\fP of the
611
- same layer replaces it with the local source, so after a \fBset\fP, run \fBpipod pull\fP before
612
- editing that source\.
618
+ Keys are those of pipod\-config(5): its pod keys for user, org, and template, and its policy
619
+ keys for policy, which the server checks\. \fBset\fP changes the server only: a later \fBpipod push\fP
620
+ of the same layer replaces it with the local source, so after a \fBset\fP, run \fBpipod pull\fP before
621
+ editing that source\. A template named like an action (show, edit, set, unset) is named by its
622
+ id instead\.
613
623
  .SS pipod jobs
614
624
  .RS 2
615
625
  .nf
package/man/pipod.1.md CHANGED
@@ -140,8 +140,9 @@ pipod push org
140
140
 
141
141
  Values for secrets the whole organization shares: `pipod secrets set org <NAME>` (person).
142
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:
143
+ Organization policy (limits rather than defaults) needs the policy:write permission. Change
144
+ one limit with `pipod settings policy set <key> <value>` (its keys are in pipod-config(5)), or
145
+ the whole policy from its source, policy.json beside the organization layer's files:
145
146
 
146
147
  ```
147
148
  pipod pull policy # writes ~/.pi-pod/org/policy.json
@@ -229,9 +230,10 @@ org ~/.pi-pod/org/: config.json, init.sh, bake.sh, pi/, env
229
230
  user ~/.pi-pod/config.json and ~/.pi/agent/
230
231
  pipod pull|diff|push user; pipod settings user set
231
232
  template a project: .pi-pod/config.json, init.sh, bake.sh, env, and .pi/
232
- pipod pull|diff|push [template [<name>]]; pipod templates
233
+ pipod pull|diff|push [template [<name>]]; pipod settings template set;
234
+ pipod templates
233
235
  policy ~/.pi-pod/org/policy.json
234
- pipod pull|diff|push policy (policy:write)
236
+ pipod pull|diff|push policy; pipod settings policy set (policy:write)
235
237
  ```
236
238
 
237
239
  What belongs where: the organization layer holds what everyone needs (pod size, network
@@ -580,26 +582,34 @@ or `sync` reads a dotenv file kept at mode 600. op:// references resolve through
580
582
  ### pipod settings
581
583
 
582
584
  ```
583
- Usage: pipod settings <user|org> [show | edit | set <key> <value> | unset <key>]
585
+ Usage: pipod settings [user | org | policy | template [<name>]]
586
+ [show | edit | set <key> <value> | unset <key>]
584
587
 
585
- Show or edit a persistent settings bundle on the server: your own user bundle,
586
- or the org-wide defaults (org scope needs the org:manage permission). Edits
587
- change only the config; scripts and Pi files stay as they are — replace the
588
- whole bundle from local files with `pipod push user` or `pipod push org`.
589
- Edits use compare-and-swap on the bundle version, so concurrent changes fail
590
- cleanly instead of overwriting each other.
588
+ Show or edit one server layer's config directly, the same layers `pipod push`
589
+ replaces whole:
590
+ user Your own settings (the default)
591
+ org The organization's defaults (needs org:manage)
592
+ policy The organization's policy (needs policy:write)
593
+ template [<name>] A template; without <name>, the one this project pins
594
+
595
+ Edits change only the config; scripts and Pi files stay as they are — replace
596
+ a whole layer from local files with `pipod push`. Edits use compare-and-swap
597
+ on the layer's version, so concurrent changes fail cleanly instead of
598
+ overwriting each other.
591
599
 
592
600
  Actions:
593
- show Print the settings bundle as JSON (default)
601
+ show Print the layer as JSON (default)
594
602
  edit Edit the config in $VISUAL/$EDITOR, then save
595
603
  set <key> <value> Set one dotted key to a JSON value, or to the text as
596
604
  a string: pipod settings user set pi.model provider/model
597
605
  unset <key> Remove one dotted key, so the layers below decide it
598
606
  ```
599
607
 
600
- Keys are those of pipod-config(5). `set` changes the server only: a later `pipod push` of the
601
- same layer replaces it with the local source, so after a `set`, run `pipod pull` before
602
- editing that source.
608
+ Keys are those of pipod-config(5): its pod keys for user, org, and template, and its policy
609
+ keys for policy, which the server checks. `set` changes the server only: a later `pipod push`
610
+ of the same layer replaces it with the local source, so after a `set`, run `pipod pull` before
611
+ editing that source. A template named like an action (show, edit, set, unset) is named by its
612
+ id instead.
603
613
 
604
614
  ### pipod jobs
605
615
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipod/cli",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "Run pi coding-agent sessions in server-managed pods",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-only",