@msdavid/pi-distro 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,7 +28,59 @@ Never silently skip, silently overwrite, silently substitute, or silently choose
28
28
  If a decision is ambiguous or the user is unsure, explain the tradeoffs and let
29
29
  them choose. **The agent proposes; the user disposes.** Every other rule in this
30
30
  skill (merge-don't-clobber, package-redundancy, version-aware deploy, the GitHub
31
- trust gate) is a specific instance of this principle.
31
+ trust gate, the scope rule) is a specific instance of this principle.
32
+
33
+ ## Scope model: local vs global
34
+
35
+ pi supports two install scopes, and pi-distro lets the user choose per component:
36
+
37
+ - **Project-local** (default) — writes to `./.pi/` (packages via `pi install -l` →
38
+ `./.pi/settings.json`; extensions/skills/prompts/themes into `./.pi/<type>/`; settings into
39
+ `./.pi/settings.json`; AGENTS.md at `./AGENTS.md`). Scoped to this project only. This is the
40
+ default philosophy — different projects get different harnesses.
41
+ - **Global** — writes to `~/.pi/agent/` (packages via `pi install` →
42
+ `~/.pi/agent/settings.json`; extensions/skills/prompts/themes into `~/.pi/agent/<type>/`;
43
+ settings into `~/.pi/agent/settings.json`; AGENTS.md at `~/.pi/agent/AGENTS.md`). Shared
44
+ across **every project and session on this machine**. Opt-in, never the default.
45
+
46
+ pi merges global and project-local (project-local shadows global on conflict).
47
+
48
+ ### Per-type default scopes
49
+
50
+ | Component type | Default scope | Global allowed? |
51
+ |---|---|---|
52
+ | Packages | local | ✅ |
53
+ | Extensions | local | ✅ |
54
+ | Skills | local | ✅ |
55
+ | Prompts | local | ✅ |
56
+ | Themes | **global** | ✅ |
57
+ | settings.json merge | local | ⚠️ guarded (explicit confirm) |
58
+ | SYSTEM.md / APPEND_SYSTEM.md | local | ⚠️ double-confirm |
59
+ | AGENTS.md | local | ⚠️ guarded (explicit confirm) |
60
+
61
+ ### Deployment-plan procedure
62
+
63
+ At the start of a `deploy` (and for the selected items in a `pick`), the kickoff includes a
64
+ **scope rule** with this procedure. Follow it exactly:
65
+
66
+ 1. **Build a deployment plan** grouping every installable component by type, each with its
67
+ default scope (per the table above, or the author's `(global)` hint if the directives
68
+ mark one). Render it as markdown so the user sees the whole picture.
69
+ 2. **Offer three presets** via `ctx.ui.select`:
70
+ - **(a) Accept defaults** — keep every component at its default scope. Recommended.
71
+ - **(b) All-global (where safe)** — flip every global-allowed component to global;
72
+ dangerous types (settings, SYSTEM.md, AGENTS.md) stay local with a surfaced warning.
73
+ - **(c) Customize** — walk items one at a time, offering `local` / `global` / `skip`
74
+ each (`ctx.ui.select` is single-select). Cancel on an item = skip that item.
75
+ 3. **Scope-safety guard** — when a dangerous type's final scope is global, surface the blast
76
+ radius ("affects every project/session on this machine") and require explicit confirm.
77
+ For SYSTEM.md/APPEND_SYSTEM.md global, require a second confirm.
78
+ 4. **Install/place at the chosen scope** — `pi install -l` (local) or `pi install` (global)
79
+ for packages; write files to `./.pi/...` (local) or `~/.pi/agent/...` (global).
80
+ 5. **Provenance does not record scope.** At `undeploy`/`status` time, the extension detects
81
+ placement by checking both locations (`./.pi/...` and `~/.pi/agent/...`, plus `pi list`).
82
+ So note in your final report which components went global, so the user knows where to find
83
+ and remove them.
32
84
 
33
85
  ## `/pi-distro deploy` — Distro Deployment
34
86
 
@@ -47,7 +99,8 @@ cloned the repo, displayed a security warning + preview, and obtained the user's
47
99
  explicit confirmation before sending the kickoff — so you can proceed normally.
48
100
  The provenance `sourceCatalogue` will be `github:owner/repo[/subpath]`.
49
101
  Bundled files for GitHub distros are located in a temp directory (`/tmp/`) — copy
50
- them from there as usual.
102
+ them from there as usual, then **remove the temporary clone** (the kickoff names the
103
+ exact `rm -rf` target) so repeated GitHub deploys don't accumulate clones in `/tmp`.
51
104
 
52
105
  ### Deployment steps
53
106
 
@@ -79,17 +132,20 @@ them from there as usual.
79
132
 
80
133
  If the section already exists (re-deploy), replace only that delimited section.
81
134
 
82
- 3. **Install pi packages — with redundancy/conflict detection.** If the directives list pi packages to
83
- install, run `pi install -l <package>` for each one the `-l` flag installs
84
- **project-locally** (writes to `./.pi/settings.json`, not global) but **only after
135
+ 3. **Install pi packages — scope + redundancy/conflict detection.** If the directives
136
+ list pi packages to install, first run the **scope** flow (deployment-plan + preset from
137
+ the Scope model above) to decide local vs global per package, then run the
138
+ **redundancy/conflict** check, then install at the chosen scope — `pi install -l <package>`
139
+ for **project-local** or `pi install <package>` for **global** — but **only after
85
140
  confirming with the user** AND after evaluating tool redundancy/conflicts:
86
141
 
87
- **Do NOT pre-add packages to `./.pi/settings.json` by hand.** `pi install -l` is the single
88
- mechanism that registers a package: it installs the package AND appends the source to
89
- `./.pi/settings.json` on success. If an install fails, nothing is added to settings — so
90
- settings never contains a package that isn't actually installed. (This is why the bundled
91
- `settings.json` does not list packages they are registered by `pi install -l`, not by
92
- merging a `packages` array.)
142
+ **Do NOT pre-add packages to `settings.json` by hand.** `pi install -l` (local) and
143
+ `pi install` (global) are the single mechanisms that register a package: each installs the
144
+ package AND appends the source to the corresponding settings file (`./.pi/settings.json` or
145
+ `~/.pi/agent/settings.json`) on success. If an install fails, nothing is added to settings
146
+ so settings never contains a package that isn't actually installed. (This is why the
147
+ bundled `settings.json` does not list packages — they are registered by `pi install`, not
148
+ by merging a `packages` array.)
93
149
 
94
150
  **Redundancy/conflict evaluation (do this BEFORE installing each package):** Some packages
95
151
  may provide tools that overlap with already-active tools. This can be:
@@ -101,8 +157,9 @@ them from there as usual.
101
157
  leaving the user with duplicate capability and a confusing tool set.
102
158
  You (the agent) must **evaluate** this — it requires judgment, not just string matching.
103
159
  Before installing each package:
104
- 1. Read the **already-active tools** and **project packages** from the kickoff's
105
- "Current project state" section, and run `pi list` to see globally-installed packages.
160
+ 1. Read the **already-active tools**, **project packages**, and **global packages** from
161
+ the kickoff's "Current project state" section, and run `pi list` for a fresh view of
162
+ both local and global packages.
106
163
  2. For each to-be-installed package, compare its stated purpose (from the directives)
107
164
  against the already-active tools. Ask: *does this package do something an existing tool
108
165
  already does?* Consider both exact name matches and semantic overlap.
@@ -110,17 +167,20 @@ them from there as usual.
110
167
  a choice and explain the overlap:
111
168
  - **(a) Skip** — the capability already exists; don't install the package. Note this
112
169
  in the provenance/deployment report.
113
- - **(b) Replace** — `pi remove -l <overlapping-package>` (or remove it globally with
114
- `pi remove <pkg>` if that's where it lives), then `pi install -l <new-package>`.
170
+ - **(b) Replace** — remove the overlapping package from wherever it lives
171
+ (`pi remove -l <overlapping-package>` if project-local, `pi remove <pkg>` if global),
172
+ then install the new one at the chosen scope (`pi install -l <new-package>` for local
173
+ or `pi install <new-package>` for global).
115
174
  - **(c) Keep both** — install it anyway. Use this when the user prefers the new tool,
116
175
  or when the two tools serve subtly different purposes despite surface similarity.
117
176
  - **(d) Cancel** — don't install anything.
118
177
  4. Only proceed with the user's chosen option.
119
178
 
120
- 4. **Create hooks / extensions / prompts / skills.** If the directives instruct creating
121
- files under `./.pi/extensions/`, `./.pi/prompts/`, or `./.pi/skills/`, create them
122
- using the bundled source files or the directives' instructions. Apply the same
123
- merge-don't-clobber rule for any that already exist.
179
+ 4. **Create hooks / extensions / prompts / skills / themes.** If the directives instruct creating
180
+ these, place them at the **chosen scope**: `./.pi/<type>/` (local) or `~/.pi/agent/<type>/`
181
+ (global) — themes default to global. Create them using the bundled source files or the
182
+ directives' instructions. Apply the same merge-don't-clobber rule (at whichever target
183
+ path) for any that already exist.
124
184
 
125
185
  5. **Write/update provenance.** When the deployment is complete, write (or update)
126
186
  `./.pi/harness.md` in the project directory. The provenance file is itself a valid
@@ -201,21 +261,27 @@ your reference. Follow the selection procedure in the kickoff exactly:
201
261
 
202
262
  1. **Walk the user through each category, one at a time.** Use `ctx.ui.select`/`ctx.ui.confirm`
203
263
  to let them pick which items to apply. Present each item with its one-line purpose (from
204
- the directives). Let them select any subset including none (skip the category).
264
+ the directives) and its author scope hint (`[local]`/`[global]`). Let them select any
265
+ subset — including none (skip the category).
205
266
  2. **Surface dependencies.** As the user selects, evaluate cross-component dependencies and
206
267
  warn about them before applying. Example: if they pick an extension that references a
207
268
  theme provided by a package they skipped, point that out and ask whether to also install
208
269
  the package or skip the extension. Reason about the dependencies from the directives
209
270
  prose — this is a judgment task. Never silently install a dependency the user didn't pick.
210
- 3. **Apply only the selected components** with the same rules as a full deploy:
211
- merge-don't-clobber, package-redundancy check, `pi install -l` for packages (after
212
- confirming), copy/merge for files (overwrite / keep theirs / merge).
213
- 4. **Do NOT write standard provenance.** A partial deploy is a custom config, not "this
271
+ 3. **Choose scope (local vs global).** For the selected components, run the deployment-plan
272
+ + preset flow from the Scope model above (accept-defaults / all-global-where-safe /
273
+ customize). The plan is built from only the selected components. Apply the scope-safety
274
+ guard for dangerous types.
275
+ 4. **Apply only the selected components** at the chosen scope with the same rules as a full
276
+ deploy: merge-don't-clobber (at whichever target path), package-redundancy check,
277
+ `pi install -l` (local) or `pi install` (global) for packages (after confirming),
278
+ copy/merge for files (overwrite / keep theirs / merge).
279
+ 5. **Do NOT write standard provenance.** A partial deploy is a custom config, not "this
214
280
  distro was applied." Do not write `appliedHarness`/`appliedVersion` provenance. Instead,
215
281
  after applying, suggest the next step: "This is a custom configuration. Run
216
282
  `/pi-distro save` to snapshot it as your own reusable distro" (which writes clean
217
283
  provenance for the saved distro).
218
- 5. **Recommend a restart** if any packages or extensions were installed.
284
+ 6. **Recommend a restart** if any packages or extensions were installed.
219
285
 
220
286
  The natural loop is: `/pi-distro pick <distro-A>` → `/pi-distro pick <distro-B>` →
221
287
  `/pi-distro save` (snapshot the combined result as a new distro). This is how users build
@@ -236,19 +302,29 @@ directives against the *current* project state and let the user decide what to r
236
302
 
237
303
  Follow the removal procedure in the kickoff exactly:
238
304
 
239
- 1. **Walk the user through each removal category, one at a time:**
240
- - **(a) Packages** for each distro package still installed, offer `pi remove -l <pkg>`.
241
- Ask per package the user may want to keep some. Warn if removing a package that other
242
- components depend on.
243
- - **(b) Bundled files** — for each file the distro placed, check if it exists. If it
244
- does, **show the user the file (or a summary) before removing** they may have
245
- customized it. Offer: remove / keep. Never silently delete. For `settings.json`, offer
246
- to remove specific keys the distro merged, not the whole file.
247
- - **(c) AGENTS.md delimited section** if the `<!-- pi-distro: <name> -->` ...
248
- `<!-- /pi-distro: <name> -->` block exists, offer to remove it. Leave any non-distro
249
- content.
250
- - **(d) Extensions / skills / prompts / themes** — if described in the directives and
251
- present, offer to remove each (show before delete).
305
+ 1. **Walk the user through each removal category, one at a time.** A distro may have
306
+ placed components at EITHER scope the kickoff reports each package's placement
307
+ (`[local]`, `[global]`, `[both]`) by checking both `./.pi/...` and `~/.pi/agent/...`, plus
308
+ `pi list`. Remove from wherever it actually lives:
309
+ - **(a) Packages** — for each distro package still installed, remove it from where it
310
+ lives: `pi remove -l <pkg>` for `[local]`, `pi remove <pkg>` for `[global]` (warn: global
311
+ removal affects EVERY project on this machine get explicit confirm), and BOTH
312
+ commands for `[both]`. Ask per package — the user may want to keep some. Warn if
313
+ removing a package that other components depend on.
314
+ - **(b) Bundled files** — for each file the distro placed, check for it at BOTH
315
+ `./<path>` (local) and `~/.pi/agent/<equivalent>` (global). If it exists, **show the
316
+ user the file (or a summary) before removing** — they may have customized it. Offer:
317
+ remove / keep, per location. Never silently delete. For `settings.json` (local at
318
+ `./.pi/settings.json`, global at `~/.pi/agent/settings.json`), offer to remove specific
319
+ keys the distro merged, not the whole file. Warn that global settings removal affects
320
+ every project.
321
+ - **(c) AGENTS.md delimited section** — the `<!-- pi-distro: <name> -->` ...
322
+ `<!-- /pi-distro: <name> -->` block may exist at `./AGENTS.md` (local) and/or
323
+ `~/.pi/agent/AGENTS.md` (global). Offer to remove it from each location it was found.
324
+ Warn that removing the global one affects every session. Leave any non-distro content.
325
+ - **(d) Extensions / skills / prompts / themes** — if described in the directives, check
326
+ for them in BOTH `./.pi/<type>/` (local) and `~/.pi/agent/<type>/` (global). Offer to
327
+ remove each (show before delete), per location.
252
328
  2. **Remove provenance last** — only after the user confirms the component removals, remove
253
329
  `./.pi/harness.md`. Confirm before deleting.
254
330
  3. **Report and recommend a restart** — summarise what was removed vs. kept. Tell the user to
@@ -264,16 +340,18 @@ skip, delete, or strip. The user decides; you execute their choices.
264
340
 
265
341
  When you receive a draft request from the `save` command, it contains a live-config
266
342
  snapshot of the current project: the system prompt options (tools, skills, context
267
- files, guidelines), and the raw contents of **every project-local config file** found
343
+ files, guidelines), the raw contents of **every project-local config file** found
268
344
  under `./` (root `AGENTS.md`/`CLAUDE.md` variants), `./.pi/` (recursively — `settings.json`,
269
345
  `SYSTEM.md`, `APPEND_SYSTEM.md`, `extensions/`, `skills/`, `prompts/`, `themes/`, and any
270
346
  per-extension/skill config files like `.pi/<name>.json`), `./.crew/{agents,teams,workflows}/`
271
347
  (pi-crew project-local authored definitions — NOT the runtime state subdirs), and
272
- `./.agents/skills/` (project root only). Data/runtime dirs (`npm/`, `git/`, `sessions/`,
273
- `state/`, `tmp/`, the non-config subdirs of `.crew/`, `node_modules/`) and the provenance file
274
- `./.pi/harness.md` are excluded. Ancestor (parent-dir) `AGENTS.md` / `.agents/skills/`
275
- appear only in the context-files list as informational they are out of scope and must NOT
276
- be bundled.
348
+ `./.agents/skills/` (project root only). **It also captures global (user-level) config**
349
+ from `~/.pi/agent/` (`settings.json`, `AGENTS.md`, `extensions/`, `themes/`, `skills/`,
350
+ `prompts/`) and globally-installed packages — these are marked `(global)` in the snapshot so
351
+ you can reproduce them at the global scope in the saved distro. Data/runtime dirs and the
352
+ provenance file `./.pi/harness.md` are excluded. Ancestor (parent-dir) `AGENTS.md` /
353
+ `.agents/skills/` appear only in the context-files list as informational — they are out of
354
+ scope and must NOT be bundled.
277
355
 
278
356
  ### Authoring steps
279
357
 
@@ -288,6 +366,19 @@ be bundled.
288
366
  `version` (semver). Optionally `author` and `tags`.
289
367
  - **Directives body**: include sections for bundled files, pi packages to install,
290
368
  hooks/extensions, context, and skills/prompts — mirroring the live config.
369
+ - **Scope (local vs global)**: the snapshot separates **project-local** from **global**
370
+ (marked `(global)`, captured from `~/.pi/agent/`). Reproduce each component at the scope
371
+ it was captured at:
372
+ - A **global package** → list it in `## pi packages to install` with the `(global)`
373
+ marker suffix. A **project-local package** → no marker (default local).
374
+ - A **global bundled file** → copy into `files/` as usual, AND add a `## Global
375
+ deployment notes` section listing which file targets should be placed globally
376
+ (e.g. `.pi/extensions/foo.ts` → deploy globally to `~/.pi/agent/extensions/foo.ts`).
377
+ - Global `settings.json` / `SYSTEM.md` / `AGENTS.md` → note in `## Global deployment
378
+ notes` that they target `~/.pi/agent/...`, so the deploy-time scope-safety guard
379
+ surfaces the blast radius.
380
+ The user's deploy-time preset still governs the final scope — these markers/notes are
381
+ the author-suggested defaults.
291
382
 
292
383
  3. **Propose & confirm.** Present the proposed `name`, `title`, `description`, and the full
293
384
  draft to the user. Ask for confirmation or edits. Do not proceed until the user