@pareto4/pp-core 1.7.1 → 1.8.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.
Files changed (48) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/bin/install.js +116 -0
  3. package/commands/pp-build-handoff.md +8 -2
  4. package/commands/pp-discovery-to-build.md +40 -0
  5. package/gemini-extension.json +1 -1
  6. package/package.json +2 -1
  7. package/pareto-skills/_shared/create-project-board.sh +195 -0
  8. package/pareto-skills/_shared/pp-claude-md-protocol.md +306 -0
  9. package/pareto-skills/_shared/sync-phase-status.sh +139 -0
  10. package/pareto-skills/pp-brand/SKILL.md +644 -0
  11. package/pareto-skills/pp-brand/assets/crew/ParetoAgent.inline.html +120 -0
  12. package/pareto-skills/pp-brand/assets/crew/ParetoAgent.tsx +239 -0
  13. package/pareto-skills/pp-brand/assets/crew/build.svg +11 -0
  14. package/pareto-skills/pp-brand/assets/crew/deploy.svg +11 -0
  15. package/pareto-skills/pp-brand/assets/crew/discovery.svg +11 -0
  16. package/pareto-skills/pp-brand/assets/crew/plan.svg +11 -0
  17. package/pareto-skills/pp-brand/assets/crew/run.svg +11 -0
  18. package/pareto-skills/pp-brand/assets/crew/validate.svg +11 -0
  19. package/pareto-skills/pp-brand/assets/pareto-brand-preview.html +547 -0
  20. package/pareto-skills/pp-obsidian-notes/SKILL.md +127 -0
  21. package/pareto-skills/pp-obsidian-notes/templates/CLAUDE.md +29 -0
  22. package/pareto-skills/pp-obsidian-notes/templates/client-context.md +116 -0
  23. package/pareto-skills/pp-obsidian-notes/templates/meeting-note.md +66 -0
  24. package/pareto-skills/pp-obsidian-notes/templates/pareto-context.md +102 -0
  25. package/pareto-skills/pp-obsidian-notes/templates/proposal.md +117 -0
  26. package/pareto-skills/pp-project-setup/SKILL.md +1364 -0
  27. package/pp-core/bin/lib/intel.cjs +1 -1
  28. package/pp-core/bin/lib/io.cjs +120 -0
  29. package/pp-core/bin/lib/profile-pipeline-command-router.cjs +1 -1
  30. package/pp-core/bin/lib/roadmap-parser.cjs +1 -1
  31. package/pp-core/bin/lib/runtime-artifact-conversion.cjs +2 -2
  32. package/pp-core/bin/lib/surface.cjs +1 -1
  33. package/pp-core/bin/lib/worktree-safety.cjs +2 -2
  34. package/pp-core/bin/pp-tools.cjs +23 -0
  35. package/pp-core/references/ui-brand.md +73 -11
  36. package/pp-core/templates/codebase/structure.md +5 -5
  37. package/pp-core/templates/spec.md +7 -7
  38. package/pp-core/workflows/add-backlog.md +1 -1
  39. package/pp-core/workflows/autonomous.md +4 -4
  40. package/pp-core/workflows/debug.md +1 -1
  41. package/pp-core/workflows/{build-handoff.md → discovery-to-build.md} +2 -2
  42. package/pp-core/workflows/execute-phase.md +9 -1
  43. package/pp-core/workflows/plan-phase.md +14 -12
  44. package/pp-core/workflows/pr-branch.md +5 -4
  45. package/pp-core/workflows/reapply-patches.md +1 -1
  46. package/pp-core/workflows/ship.md +1 -1
  47. package/pp-core/workflows/thread.md +1 -1
  48. package/pp-core/workflows/verify-work.md +6 -5
@@ -240,7 +240,7 @@ function intelUpdate(planningDir) {
240
240
  return disabledResponse();
241
241
  return {
242
242
  action: 'spawn_agent',
243
- message: 'Run pp-tools intel update or spawn gsd-intel-updater agent for full refresh',
243
+ message: 'Run pp-tools intel update or spawn pp-intel-updater agent for full refresh',
244
244
  };
245
245
  }
246
246
  /**
@@ -210,6 +210,119 @@ function error(message, reason = ERROR_REASON.UNKNOWN) {
210
210
  }
211
211
  process.exit(1);
212
212
  }
213
+ // ─── Pareto visual brand: banner engine (Phase 17 / UIBR-01, UIBR-02) ─────────
214
+ //
215
+ // A hand-rolled ANSI banner emitter (no color library — CLAUDE.md constraint).
216
+ // The pure/impure split (formatBanner vs banner) lets the whole degrade ladder
217
+ // be asserted by injecting `level`, with no PTY. Branding is routed to fd 2
218
+ // (stderr) ONLY; output() (fd 1) is left byte-for-byte unchanged, so machine-
219
+ // readable payloads physically cannot carry branding bytes (UIBR-02, D-03).
220
+ /**
221
+ * Pareto Blue — the single signal color for the banner rule (D-01). Every
222
+ * banner rule renders in this hue at every color tier; only the per-phase Crew
223
+ * glyph carries the phase accent. #2251FF.
224
+ */
225
+ const PARETO_BLUE = [34, 81, 255];
226
+ /**
227
+ * Frozen phase→Crew-identity map (mirrors the ERROR_REASON frozen-object idiom
228
+ * at ~163). Keyed by the six Crew phases; each entry carries the locked glyph
229
+ * (D-01) and its accent at three color tiers. Accent hexes are verbatim from
230
+ * pareto-skills/pp-brand/SKILL.md Crew Accent Palette (D-02).
231
+ */
232
+ const CREW = Object.freeze({
233
+ discovery: { glyph: '◎', ascii: '(o)', rgb: [246, 180, 55], c256: 221, c16: '33' }, // Amber #F6B437
234
+ plan: { glyph: '◆', ascii: '<>', rgb: [20, 111, 244], c256: 33, c16: '34' }, // Steel #146FF4
235
+ build: { glyph: '⬢', ascii: '#', rgb: [34, 81, 255], c256: 27, c16: '34' }, // Pareto Blue #2251FF
236
+ validate: { glyph: '◈', ascii: '<*>', rgb: [62, 207, 142], c256: 42, c16: '32' }, // Mint #3ECF8E
237
+ deploy: { glyph: '▲', ascii: '^', rgb: [255, 107, 74], c256: 209, c16: '31' }, // Coral #FF6B4A
238
+ run: { glyph: '▶', ascii: '>', rgb: [168, 132, 255], c256: 141, c16: '35' }, // Violet #A884FF
239
+ });
240
+ /**
241
+ * Wrap `text` in the SGR foreground escape for the given color `level`, always
242
+ * reset-terminated. level>=3 → 24-bit truecolor; 2 → 256-color; 1 → 16-color;
243
+ * 0 → plain text, no escapes at all (D-04 ladder bottom).
244
+ */
245
+ function paint(text, rgb, level, c256, c16) {
246
+ const [r, g, b] = rgb;
247
+ if (level >= 3)
248
+ return `\x1b[38;2;${r};${g};${b}m${text}\x1b[0m`;
249
+ if (level === 2)
250
+ return `\x1b[38;5;${c256}m${text}\x1b[0m`;
251
+ if (level === 1)
252
+ return `\x1b[${c16}m${text}\x1b[0m`;
253
+ return text;
254
+ }
255
+ /**
256
+ * Detect the terminal color capability of `stream` (default: process.stderr,
257
+ * since banners target fd 2). Returns 0 = none, 1 = 16-color, 2 = 256-color,
258
+ * 3 = truecolor. Gates on COLOR CAPABILITY only — never on the runtime — so the
259
+ * brand renders on any color-capable TTY and degrades cleanly on no-color /
260
+ * non-TTY environments (D-04). Honors NO_COLOR (no-color.org) and FORCE_COLOR.
261
+ */
262
+ function colorLevel(stream = process.stderr) {
263
+ const env = process.env;
264
+ // 1. NO_COLOR present-and-nonempty disables color (no-color.org).
265
+ if (env.NO_COLOR != null && env.NO_COLOR !== '')
266
+ return 0;
267
+ // 2. FORCE_COLOR override (force a specific tier, e.g. on a pipe in tests).
268
+ const fc = env.FORCE_COLOR;
269
+ if (fc === '0' || fc === 'false')
270
+ return 0;
271
+ if (fc === '1' || fc === 'true')
272
+ return 1;
273
+ if (fc === '2')
274
+ return 2;
275
+ if (fc === '3')
276
+ return 3;
277
+ // 3. Not a TTY → plain (piped, redirected, tool-harness capture).
278
+ if (!stream || !stream.isTTY)
279
+ return 0;
280
+ // 4. Truecolor advertised.
281
+ if (env.COLORTERM === 'truecolor' || env.COLORTERM === '24bit')
282
+ return 3;
283
+ // 5. 256-color terminals.
284
+ const term = env.TERM || '';
285
+ if (/-256(color)?$/.test(term))
286
+ return 2;
287
+ if (term === 'dumb')
288
+ return 0;
289
+ // 6. Known ANSI terminal families → 16-color floor; unknown TTY → safe 16.
290
+ if (/xterm|screen|vt100|vt220|rxvt|color|ansi|cygwin|linux|tmux/i.test(term))
291
+ return 1;
292
+ return 1;
293
+ }
294
+ /**
295
+ * PURE: build the three-line brand banner for `phaseKey` at color `level`. No
296
+ * I/O and no env reads — `level` is injected so every ladder tier is unit-
297
+ * testable without a PTY. The rule always renders in Pareto Blue (the D-01
298
+ * signal color); only the glyph carries the phase accent. At level 0 the rule
299
+ * is plain ASCII and the glyph is kept as a plain char — zero escapes (D-04).
300
+ *
301
+ * `stageText` is treated as an opaque literal: it is interpolated verbatim and
302
+ * never parsed, so embedded \x1b sequences are never re-interpreted into new
303
+ * SGR state (V5 / T-17-01 ANSI-injection mitigation).
304
+ */
305
+ function formatBanner(phaseKey, stageText, level) {
306
+ const RULE = '━'.repeat(51);
307
+ const crew = CREW[phaseKey] ?? CREW.build;
308
+ if (level === 0) {
309
+ return `${RULE}\n ${crew.glyph} pp-core ► ${stageText}\n${RULE}\n`;
310
+ }
311
+ const rule = paint(RULE, PARETO_BLUE, level, 27, '34');
312
+ const glyph = paint(crew.glyph, crew.rgb, level, crew.c256, crew.c16);
313
+ return `${rule}\n ${glyph} pp-core ► ${stageText}\n${rule}\n`;
314
+ }
315
+ /**
316
+ * IMPURE: render the banner for `phaseKey`/`stageText` and write it to fd 2
317
+ * (stderr) via the back-pressure-safe writeAllSync. The color level is detected
318
+ * from opts.stream (default process.stderr) unless opts.forceLevel is given.
319
+ * NEVER touches output()/stdout — fd separation is the structural UIBR-02
320
+ * guarantee (D-03, T-17-02).
321
+ */
322
+ function banner(phaseKey, stageText, opts = {}) {
323
+ const level = opts.forceLevel ?? colorLevel(opts.stream ?? process.stderr);
324
+ writeAllSync(2, formatBanner(phaseKey, stageText, level));
325
+ }
213
326
  module.exports = {
214
327
  GSD_TEMP_DIR,
215
328
  ensureGsdTempDir,
@@ -219,4 +332,11 @@ module.exports = {
219
332
  setJsonErrorMode,
220
333
  getJsonErrorMode,
221
334
  error,
335
+ // Pareto visual brand banner engine (Phase 17 / UIBR-01, UIBR-02)
336
+ PARETO_BLUE,
337
+ CREW,
338
+ paint,
339
+ colorLevel,
340
+ formatBanner,
341
+ banner,
222
342
  };
@@ -44,7 +44,7 @@ function routeExtractMessages({ args, cwd, raw, error, _pipeline }) {
44
44
  // args[0] = 'extract-messages' (family name), args[1] = project positional
45
45
  const projectArg = args[1];
46
46
  if (!projectArg || projectArg.startsWith('--')) {
47
- error('Usage: gsd-tools extract-messages <project> [--session <id>] [--limit N] [--path <dir>]\nRun scan-sessions first to see available projects.', ERROR_REASON.USAGE);
47
+ error('Usage: pp-tools extract-messages <project> [--session <id>] [--limit N] [--path <dir>]\nRun scan-sessions first to see available projects.', ERROR_REASON.USAGE);
48
48
  return;
49
49
  }
50
50
  // cmdExtractMessages is async — do NOT return the Promise.
@@ -344,7 +344,7 @@ function getMilestonePhaseFilter(cwd, versionOverride, phaseIdConvention) {
344
344
  const hasVersionedMilestonesGlobal = /^#{1,3}\s+.*v\d+\.\d+/mi.test(roadmapContent);
345
345
  const hasPhaseHeadings = /#{2,4}\s*(?:\[[^\]]+\]\s*)?Phase\s+[\w]/i.test(roadmapContent);
346
346
  if (!hasVersionedMilestonesGlobal && hasPhaseHeadings && phaseIdConvention === 'milestone-prefixed') {
347
- console.warn('[gsd] Deprecated: free-form ROADMAP.md detected (no versioned milestone headings). ' +
347
+ console.warn('[pp-core] Deprecated: free-form ROADMAP.md detected (no versioned milestone headings). ' +
348
348
  'The project has phase_id_convention set to "milestone-prefixed" in config.json but the ' +
349
349
  'ROADMAP does not use versioned milestone headings. Run `pp-tools roadmap upgrade --convention milestone-prefixed` to migrate (dry-run by default).');
350
350
  }
@@ -427,8 +427,8 @@ function convertClaudeCommandToKimiSkill(content, skillName, _runtime = null, cm
427
427
  const kimiSkillName = normalizeKimiSkillName(skillName);
428
428
  const names = cmdNames || readGsdCommandNames();
429
429
  const description = frontmatter
430
- ? extractFrontmatterField(frontmatter, 'description') || `Run GSD workflow ${kimiSkillName}.`
431
- : `Run GSD workflow ${kimiSkillName}.`;
430
+ ? extractFrontmatterField(frontmatter, 'description') || `Run pp-core workflow ${kimiSkillName}.`
431
+ : `Run pp-core workflow ${kimiSkillName}.`;
432
432
  const normalizedBody = convertGsdCommandReferencesToKimiSkillInvocations(frontmatter ? body : content, names);
433
433
  return `---\nname: ${kimiSkillName}\ndescription: ${yamlQuote(toSingleLine(description))}\n---\nInvoke this pp-core skill with \`/skill:${kimiSkillName}\`.\n\n${normalizedBody}`;
434
434
  }
@@ -348,7 +348,7 @@ function pruneSkillDirs(skillsDir, retainedNames, prefix, manifest) {
348
348
  // The dir must also be in the manifest to be considered GSD-owned.
349
349
  // A user-created gsd-* dir that isn't in the manifest is preserved with a warning.
350
350
  if (!canonicalStems.has(entry.slice(prefix.length))) {
351
- process.stderr.write(`[gsd] Warning: ${entry} matches GSD prefix '${prefix}' but is not in the manifest — preserving (user-owned or unknown)\n`);
351
+ process.stderr.write(`[pp-core] Warning: ${entry} matches GSD prefix '${prefix}' but is not in the manifest — preserving (user-owned or unknown)\n`);
352
352
  continue;
353
353
  }
354
354
  isGsdOwned = true;
@@ -920,13 +920,13 @@ function cmdWorktreeReapOrphans(cwd) {
920
920
  }
921
921
  catch (err) {
922
922
  // Surface failure as a one-line warning; keep exit-zero so workflows don't break.
923
- process.stderr.write(`[gsd] worktree.reap-orphans failed: ${err && err.message ? err.message : String(err)}\n`);
923
+ process.stderr.write(`[pp-core] worktree.reap-orphans failed: ${err && err.message ? err.message : String(err)}\n`);
924
924
  result = [];
925
925
  }
926
926
  const skippedCount = result.filter((r) => r.status === 'skipped').length;
927
927
  if (skippedCount > 0) {
928
928
  // Surface skipped entries so operators are aware of unresolved orphans.
929
- process.stderr.write(`[gsd] worktree.reap-orphans: ${skippedCount} orphan(s) skipped (run with DEBUG=1 for details)\n`);
929
+ process.stderr.write(`[pp-core] worktree.reap-orphans: ${skippedCount} orphan(s) skipped (run with DEBUG=1 for details)\n`);
930
930
  }
931
931
  process.stdout.write(`${JSON.stringify({ ok: true, reaped: result.filter((r) => r.status === 'reaped').length, entries: result }, null, 2)}\n`);
932
932
  }
@@ -709,6 +709,29 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand
709
709
  break;
710
710
  }
711
711
 
712
+ case 'banner': {
713
+ // Pareto brand banner (Phase 17 / UIBR-02). Workflows shell out via
714
+ // `pp_run banner <phaseKey> "<STAGE TEXT>"`. The banner reaches the
715
+ // terminal ONLY via io.banner → fd 2 (stderr); output()/stdout is never
716
+ // touched, so machine-readable payloads physically cannot carry branding
717
+ // bytes (D-03, T-17-02). The `--raw` flag is already stripped upstream and
718
+ // is irrelevant here — stdout stays clean regardless.
719
+ const phaseKey = args[1];
720
+ const stageText = args[2] ?? '';
721
+ if (!phaseKey || !Object.prototype.hasOwnProperty.call(io.CREW, phaseKey)) {
722
+ // Unknown key → fail loud, never render a partial/garbage banner
723
+ // (T-17-03, ASVS V5). io.error writes to fd 2 and exits non-zero.
724
+ error(
725
+ `banner: unknown phase key "${phaseKey ?? ''}" — expected one of: ${Object.keys(io.CREW).join(', ')}`,
726
+ ERROR_REASON.SDK_MISSING_ARG,
727
+ );
728
+ }
729
+ // stageText is passed as an opaque literal — no re-interpretation of
730
+ // embedded escapes (V5 / T-17-01 ANSI-injection mitigation).
731
+ io.banner(phaseKey, stageText);
732
+ break;
733
+ }
734
+
712
735
  case 'generate-client-context': {
713
736
  // generate-client-context --from-json <path> [--output <path>] [--force]
714
737
  // generate-client-context --read [--output <path>]
@@ -4,24 +4,86 @@ Visual patterns for user-facing pp-core output. Orchestrators @-reference this f
4
4
 
5
5
  ## Stage Banners
6
6
 
7
- Use for major workflow transitions.
7
+ Use for major workflow transitions. The banner is a three-line block: a rule, a
8
+ title line ` {glyph} pp-core ► {STAGE NAME}`, and a closing rule.
8
9
 
9
10
  ```
10
11
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
11
- pp-core ► {STAGE NAME}
12
+ {glyph} pp-core ► {STAGE NAME}
12
13
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
13
14
  ```
14
15
 
16
+ **Color rule (D-01):** the two rules are **ALWAYS Pareto Blue `#2251FF`** — the
17
+ single signal color. Only the **glyph** carries the phase accent (the per-phase
18
+ Crew color below). The rule hue never changes with the phase; this keeps the
19
+ brand's one signal color constant while the glyph communicates which Crew phase
20
+ is active.
21
+
22
+ ### Phase → glyph → accent-hex mapping (D-02)
23
+
24
+ Each major transition belongs to one of the six Pareto Crew phases. The glyph and
25
+ its accent color are fixed per phase (all glyphs are BMP for wide font coverage):
26
+
27
+ | Crew phase | phaseKey | Glyph | Codepoint | Accent | Hex | RGB | ASCII fallback | Stage banners |
28
+ |-----------|----------|:-----:|-----------|--------|-----|-----|:--------------:|---------------|
29
+ | Discovery | `discovery` | ◎ | U+25CE BULLSEYE | Amber | `#F6B437` | 246,180,55 | `(o)` | QUESTIONING · RESEARCHING · DEFINING REQUIREMENTS · CREATING ROADMAP |
30
+ | Plan | `plan` | ◆ | U+25C6 BLACK DIAMOND | Steel | `#146FF4` | 20,111,244 | `<>` | PLANNING PHASE {N} · PATTERN MAPPING |
31
+ | Build | `build` | ⬢ | U+2B22 BLACK HEXAGON | Pareto Blue | `#2251FF` | 34,81,255 | `#` | EXECUTING WAVE {N} |
32
+ | Validate | `validate` | ◈ | U+25C8 WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND | Mint | `#3ECF8E` | 62,207,142 | `<*>` | VERIFYING · PHASE {N} COMPLETE ✓ |
33
+ | Deploy | `deploy` | ▲ | U+25B2 BLACK UP-POINTING TRIANGLE | Coral | `#FF6B4A` | 255,107,74 | `^` | ship · PR BRANCH · MILESTONE COMPLETE 🎉 |
34
+ | Run | `run` | ▶ | U+25B6 BLACK RIGHT-POINTING TRIANGLE | Violet | `#A884FF` | 168,132,255 | `>` | autonomous · progress · resume |
35
+
36
+ Build's accent equals Pareto Blue by design, so at the Build transition the glyph
37
+ and rule share a hue.
38
+
15
39
  **Stage names (uppercase):**
16
- - `QUESTIONING`
17
- - `RESEARCHING`
18
- - `DEFINING REQUIREMENTS`
19
- - `CREATING ROADMAP`
20
- - `PLANNING PHASE {N}`
21
- - `EXECUTING WAVE {N}`
22
- - `VERIFYING`
23
- - `PHASE {N} COMPLETE ✓`
24
- - `MILESTONE COMPLETE 🎉`
40
+ - `QUESTIONING` (Discovery ◎)
41
+ - `RESEARCHING` (Discovery ◎)
42
+ - `DEFINING REQUIREMENTS` (Discovery ◎)
43
+ - `CREATING ROADMAP` (Discovery ◎)
44
+ - `PLANNING PHASE {N}` (Plan ◆)
45
+ - `PATTERN MAPPING PHASE {N}` (Plan ◆)
46
+ - `EXECUTING WAVE {N}` (Build ⬢)
47
+ - `VERIFYING` (Validate ◈)
48
+ - `PHASE {N} COMPLETE ✓` (Validate ◈)
49
+ - `PR BRANCH` (Deploy ▲)
50
+ - `MILESTONE COMPLETE 🎉` (Deploy ▲)
51
+
52
+ ### How banners are emitted (the shell-out call)
53
+
54
+ Banners are **not** printed as LLM prose. Workflows emit them via the CLI, which
55
+ writes the rendered banner to **stderr (fd 2)** and auto-degrades on non-TTY:
56
+
57
+ ```bash
58
+ pp_run banner <phaseKey> "<STAGE TEXT>"
59
+ ```
60
+
61
+ For example, at the research transition a workflow runs
62
+ `pp_run banner discovery "RESEARCHING PHASE {X}"`; at wave start it runs
63
+ `pp_run banner build "EXECUTING WAVE {N}"`. The `<phaseKey>` is the Crew key from
64
+ the table above; the stage text is passed as an opaque literal.
65
+
66
+ **Degrade ladder (D-04):** the emitter gates on **color capability, not runtime**.
67
+ It detects the terminal level from fd 2 and steps down cleanly:
68
+
69
+ - **truecolor (level 3):** 24-bit `\x1b[38;2;R;G;Bm` — full accent hex.
70
+ - **256-color (level 2):** nearest xterm-256 index for rule and glyph.
71
+ - **16-color (level 1):** basic ANSI SGR for rule and glyph.
72
+ - **none (level 0):** plain ASCII — no escapes at all; the glyph is kept as a
73
+ plain character (or its ASCII fallback where a terminal can't render it).
74
+
75
+ Because level 0 is exactly the non-TTY / piped / no-color case, branding
76
+ auto-degrades in precisely the environments where ANSI wouldn't render anyway,
77
+ and `NO_COLOR` / `FORCE_COLOR` are honored.
78
+
79
+ **Double-print rule (Pitfall 4):** the inline ASCII block shown above is the
80
+ **documented visual spec only**. A workflow that adopts the `pp_run banner` call
81
+ MUST drop its own inline `━━━ / pp-core ► {STAGE} / ━━━` block at that transition —
82
+ otherwise the banner prints twice. Keep the inline block here in `ui-brand.md`;
83
+ remove it from the adopting workflow.
84
+
85
+ The `✓` / `🎉` status symbols below remain additive to the stage text (e.g.
86
+ `PHASE {N} COMPLETE ✓`).
25
87
 
26
88
  ---
27
89
 
@@ -145,10 +145,10 @@ pp-core/
145
145
  - Key files: install.js - handles npx installation
146
146
  - Subdirectories: None
147
147
 
148
- **commands/gsd/**
149
- - Purpose: Slash command definitions for Claude Code
150
- - Contains: *.md files (one per command)
151
- - Key files: new-project.md, plan-phase.md, execute-plan.md
148
+ **commands/**
149
+ - Purpose: Slash command definitions for Claude Code (pp-* flat-hyphen layout)
150
+ - Contains: pp-*.md files (one per command)
151
+ - Key files: pp-new-project.md, pp-plan-phase.md, pp-execute-phase.md
152
152
  - Subdirectories: None (flat structure)
153
153
 
154
154
  **pp-core/references/**
@@ -206,7 +206,7 @@ pp-core/
206
206
  ## Where to Add New Code
207
207
 
208
208
  **New Slash Command:**
209
- - Primary code: `commands/gsd/{command-name}.md`
209
+ - Primary code: `commands/pp-{command-name}.md`
210
210
  - Tests: `tests/commands/{command-name}.test.js` (if testing implemented)
211
211
  - Documentation: Update `README.md` with new command
212
212
 
@@ -232,7 +232,7 @@ The database has a `posts` table and `follows` table. No feed query or feed UI e
232
232
 
233
233
  ## Goal
234
234
 
235
- A `gsd backup` CLI command creates a reproducible database snapshot that can be restored by `gsd restore` (a separate phase).
235
+ A `myapp backup` CLI command creates a reproducible database snapshot that can be restored by `myapp restore` (a separate phase).
236
236
 
237
237
  ## Background
238
238
 
@@ -242,8 +242,8 @@ No backup tooling exists. The project uses PostgreSQL. Developers currently use
242
242
 
243
243
  1. **Backup creation**: CLI command executes a full database backup.
244
244
  - Current: No `backup` subcommand exists in the CLI
245
- - Target: `gsd backup` connects to the database (via `DATABASE_URL` env or `--db` flag), runs pg_dump, writes output to `./backups/YYYY-MM-DD_HH-MM-SS.dump`
246
- - Acceptance: Running `gsd backup` on a test database creates a `.dump` file; running `pg_restore` on that file recreates the database without error
245
+ - Target: `myapp backup` connects to the database (via `DATABASE_URL` env or `--db` flag), runs pg_dump, writes output to `./backups/YYYY-MM-DD_HH-MM-SS.dump`
246
+ - Acceptance: Running `myapp backup` on a test database creates a `.dump` file; running `pg_restore` on that file recreates the database without error
247
247
 
248
248
  2. **Network retry**: Transient network failures are retried automatically.
249
249
  - Current: pg_dump fails immediately on network error
@@ -258,13 +258,13 @@ No backup tooling exists. The project uses PostgreSQL. Developers currently use
258
258
  ## Boundaries
259
259
 
260
260
  **In scope:**
261
- - `gsd backup` subcommand (full dump only)
261
+ - `myapp backup` subcommand (full dump only)
262
262
  - Output to `./backups/` directory (created if missing)
263
263
  - Network retry (3 attempts)
264
264
  - Partial file cleanup on failure
265
265
 
266
266
  **Out of scope:**
267
- - `gsd restore` — that is Phase 3
267
+ - `myapp restore` — that is Phase 3
268
268
  - Incremental backups — separate backlog item (full dump only for now)
269
269
  - S3 or remote storage — separate backlog item
270
270
  - Encryption — separate backlog item
@@ -277,8 +277,8 @@ No backup tooling exists. The project uses PostgreSQL. Developers currently use
277
277
 
278
278
  ## Acceptance Criteria
279
279
 
280
- - [ ] `gsd backup` creates a `.dump` file in `./backups/YYYY-MM-DD_HH-MM-SS.dump` format
281
- - [ ] `gsd backup` uses `DATABASE_URL` env var or `--db` flag for connection
280
+ - [ ] `myapp backup` creates a `.dump` file in `./backups/YYYY-MM-DD_HH-MM-SS.dump` format
281
+ - [ ] `myapp backup` uses `DATABASE_URL` env var or `--db` flag for connection
282
282
  - [ ] 3 retries on network failure, then exit code 1 with stderr message
283
283
  - [ ] `--no-retry` flag skips retries and fails immediately on first error
284
284
  - [ ] No partial `.dump` file left after a failed backup
@@ -1,6 +1,6 @@
1
1
  # Add Backlog Item Workflow
2
2
 
3
- Invoked by `/pp:capture --backlog` (`commands/gsd/capture.md`).
3
+ Invoked by `/pp:capture --backlog` (`commands/pp-capture.md`).
4
4
 
5
5
  Adds an idea to the ROADMAP.md backlog parking lot using 999.x numbering. Backlog items
6
6
  are unsequenced ideas that aren't ready for active planning — they live outside the normal
@@ -342,10 +342,10 @@ Read `frontend` and `hasUiSpec` from `GATE` (in-context).
342
342
  **Otherwise (frontend phase + no UI-SPEC):** For each active step hook (the `kind == "step"` set from above, in array order):
343
343
 
344
344
  ```
345
- Skill(skill="gsd-${ref.skill}", args="${PHASE_NUM}")
345
+ Skill(skill="pp-${ref.skill}", args="${PHASE_NUM}")
346
346
  ```
347
347
 
348
- (Prepend `gsd-` to `ref.skill` — so `ui-phase` → `pp-ui-phase`. Bare `${PHASE_NUM}` args — autonomous style, same pattern as the verify:post dispatch.) Entries where `kind == "gate"` are silently ignored — autonomous is always pipeline mode, there is no blocking gate here.
348
+ (Prepend `pp-` to `ref.skill` — so `ui-phase` → `pp-ui-phase`. Bare `${PHASE_NUM}` args — autonomous style, same pattern as the verify:post dispatch.) Entries where `kind == "gate"` are silently ignored — autonomous is always pipeline mode, there is no blocking gate here.
349
349
 
350
350
  After all step hooks return, re-read:
351
351
 
@@ -465,7 +465,7 @@ If no active code-review step hook exists: display "Code review skipped (code-re
465
465
  For each active code-review step hook, dispatch the skill using the registry-provided stem:
466
466
 
467
467
  ```
468
- Skill(skill="gsd-${ref.skill}", args="${PHASE_NUM}")
468
+ Skill(skill="pp-${ref.skill}", args="${PHASE_NUM}")
469
469
  ```
470
470
 
471
471
  Parse status from REVIEW.md frontmatter. If "clean" or "skipped": proceed to 3d. If findings found after the capability-dispatched review, auto-invoke the consolidated fix entry point:
@@ -590,7 +590,7 @@ For each entry in `activeHooks` in array order where `kind == "step"` and `ref.s
590
590
  - Invoke:
591
591
 
592
592
  ```
593
- Skill(skill="gsd-${ref.skill}", args="${PHASE_NUM}")
593
+ Skill(skill="pp-${ref.skill}", args="${PHASE_NUM}")
594
594
  ```
595
595
 
596
596
  (i.e. prepend `pp-` to `ref.skill` — so `ui-review` → `pp-ui-review`.)
@@ -1,6 +1,6 @@
1
1
  # Debug Workflow
2
2
 
3
- Invoked by `/pp:debug` (`commands/gsd/debug.md`).
3
+ Invoked by `/pp:debug` (`commands/pp-debug.md`).
4
4
 
5
5
  Systematic debugging using the scientific method with subagent isolation.
6
6
  Orchestrates symptom gathering, session creation, and delegation to `pp-debug-session-manager`.
@@ -95,7 +95,7 @@ AskUserQuestion([
95
95
  **If "Complete discovery first":** Exit with guidance:
96
96
  ```
97
97
  Run /pp-discovery to see progress and continue with the next session.
98
- When all sessions are complete, run /pp-build-handoff again.
98
+ When all sessions are complete, run /pp-discovery-to-build again.
99
99
  ```
100
100
 
101
101
  **If "Proceed anyway":** Continue to Step 3, noting which sessions are incomplete.
@@ -326,7 +326,7 @@ AskUserQuestion([
326
326
  ```
327
327
 
328
328
  **If "Review first":** Wait for the user to review, then remind them to say "continue" or
329
- re-run `/pp-build-handoff` when ready.
329
+ re-run `/pp-discovery-to-build` when ready.
330
330
 
331
331
  **If "Regenerate":** Ask what's wrong, adjust, and regenerate Step 3.
332
332
 
@@ -539,6 +539,14 @@ increases monotonically across waves. `{status}` is `complete` (success),
539
539
  [checkpoint] phase {PHASE_NUMBER} wave {N}/{M} starting, {wave_plan_count} plan(s), {P}/{Q} plans done
540
540
  ```
541
541
 
542
+ **Emit the branded Build stage banner (the marquee wave-start transition).**
543
+ Run this Bash command — it renders on stderr and auto-degrades on non-TTY; do
544
+ NOT print an inline ASCII banner alongside it:
545
+
546
+ ```bash
547
+ pp_run banner build "EXECUTING WAVE {N}"
548
+ ```
549
+
542
550
  Then read each plan's `<objective>`. Extract what's being built and why.
543
551
 
544
552
  ```
@@ -1184,7 +1192,7 @@ If no active code-review step hook exists: display "Code review skipped (code-re
1184
1192
 
1185
1193
  **Invoke review:**
1186
1194
  ```
1187
- Skill(skill="gsd-${ref.skill}", args="${PHASE_NUMBER}")
1195
+ Skill(skill="pp-${ref.skill}", args="${PHASE_NUMBER}")
1188
1196
  ```
1189
1197
 
1190
1198
  **Check results using deterministic path (not glob):**
@@ -488,12 +488,13 @@ If user selects "Skip research": skip to step 6.
488
488
 
489
489
  **If `--auto` and `research_enabled` is false:** Skip research silently (preserves automated behavior).
490
490
 
491
- Display banner:
491
+ Run this Bash command to emit the branded Discovery stage banner (renders on stderr, auto-degrades on non-TTY — do NOT print an inline ASCII banner, that would double-print):
492
+ ```bash
493
+ pp_run banner discovery "RESEARCHING PHASE {X}"
492
494
  ```
493
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
494
- pp-core ► RESEARCHING PHASE {X}
495
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
496
495
 
496
+ Then announce the spawn:
497
+ ```
497
498
  ◆ Spawning researcher... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
498
499
  ```
499
500
 
@@ -501,7 +502,7 @@ Display banner:
501
502
 
502
503
  ```bash
503
504
  if pp_run query teams-status --active >/dev/null 2>&1; then
504
- echo "⚠️ CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS detected. pp-core's multi-agent orchestration is not validated under claude-code agent-teams and may stall (a subagent's completion can fail to route to the orchestrator). Recommend disabling agent-teams for GSD workflows. See https://github.com/open-gsd/pp-core/issues/1355" >&2
505
+ echo "⚠️ CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS detected. pp-core's multi-agent orchestration is not validated under claude-code agent-teams and may stall (a subagent's completion can fail to route to the orchestrator). Recommend disabling agent-teams for pp-core workflows. See https://github.com/open-gsd/pp-core/issues/1355" >&2
505
506
  fi
506
507
  ```
507
508
 
@@ -634,12 +635,12 @@ Read the `activeHooks` array directly from `PLAN_PRE_HOOKS_JSON` / `HOOKS_JSON`
634
635
  **Branch 1 — all plan:pre hooks inactive (`activeHooks` is empty or absent):** Skip to step 6.
635
636
 
636
637
  **Generic step hook dispatch contract:** For each active entry where `kind == "step"`:
637
- - If `ref.skill` is set, dispatch with `Skill(skill="gsd-${ref.skill}", args="${PHASE} --auto ${GSD_WS}")` when pipeline mode allows auto-chaining. Prepend `gsd-` to `ref.skill` — `ui-phase` → `pp-ui-phase`.
638
+ - If `ref.skill` is set, dispatch with `Skill(skill="pp-${ref.skill}", args="${PHASE} --auto ${GSD_WS}")` when pipeline mode allows auto-chaining. Prepend `pp-` to `ref.skill` — `ui-phase` → `pp-ui-phase`.
638
639
  - If `ref.agent` is set, dispatch with `Agent(prompt=filled_hook_fragment, subagent_type=ref.agent, model="{researcher_model}")`. Use the hook's `fragment.inline` as the prompt body and fill phase fields before spawning.
639
640
  - The `research` hook is handled by §5.1's research decision. The `pattern-mapper` hook is handled by §7.8 after `RESEARCH_PATH` is known. Future plan:pre agent hooks use the same `ref.agent` fragment contract.
640
641
 
641
642
  **AI integration capability:** If the active `ai-integration` step hook is present, `AI_SPEC_PATH` is empty, and the phase goal contains AI keywords (`agent`, `llm`, `rag`, `chatbot`, `embedding`, `langchain`, `llamaindex`, `crewai`, `langgraph`, `openai`, `anthropic`, `vector`, `eval`, `ai system`), then:
642
- - In pipeline / `--auto` mode, invoke the hook's `ref.skill` via `Skill(skill="gsd-${ref.skill}", args="${PHASE} --auto ${GSD_WS}")`.
643
+ - In pipeline / `--auto` mode, invoke the hook's `ref.skill` via `Skill(skill="pp-${ref.skill}", args="${PHASE} --auto ${GSD_WS}")`.
643
644
  - In manual mode, display the existing non-blocking `/pp:ai-integration-phase {N}` recommendation and let the user continue planning without AI-SPEC or stop to run the capability workflow first.
644
645
 
645
646
  Run the UI deterministic gate whenever **any** `plan:pre` UI hook is active — including the step-only case (`workflow.ui_safety_gate` off). (`check.query` = `"ui.plan-gate"`; router normalizes dots→hyphens.)
@@ -674,7 +675,7 @@ AUTO_CHAIN=$(pp_run query check auto-mode --pick auto_chain_active 2>/dev/null |
674
675
  **Branch 5 — `AUTO_CHAIN` is `true` (pipeline / `--auto`):** Fire each active UI **step** hook — runs independently of whether a gate is active (covers `{ui_phase:true,ui_safety_gate:false}`). For each entry in `activeHooks` (in array order) where `kind == "step"` and `ref.skill` is set:
675
676
 
676
677
  ```
677
- Skill(skill="gsd-${ref.skill}", args="${PHASE} --auto ${GSD_WS}")
678
+ Skill(skill="pp-${ref.skill}", args="${PHASE} --auto ${GSD_WS}")
678
679
  ```
679
680
 
680
681
  After all UI step hooks return, re-read:
@@ -827,12 +828,13 @@ Continue to step 8.
827
828
 
828
829
  ## 8. Spawn pp-planner Agent
829
830
 
830
- Display banner:
831
+ Run this Bash command to emit the branded Plan stage banner (renders on stderr, auto-degrades on non-TTY — do NOT print an inline ASCII banner, that would double-print):
832
+ ```bash
833
+ pp_run banner plan "PLANNING PHASE {X}"
831
834
  ```
832
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
833
- pp-core ► PLANNING PHASE {X}
834
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
835
835
 
836
+ Then announce the spawn:
837
+ ```
836
838
  ◆ Spawning planner... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
837
839
  ```
838
840
 
@@ -31,12 +31,13 @@ if [ "$AHEAD" = "0" ]; then
31
31
  fi
32
32
  ```
33
33
 
34
- Display:
34
+ Run this Bash command to emit the branded Deploy stage banner (renders on stderr, auto-degrades on non-TTY — do NOT print an inline ASCII banner, that would double-print):
35
+ ```bash
36
+ pp_run banner deploy "PR BRANCH"
35
37
  ```
36
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
37
- pp-core ► PR BRANCH
38
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
39
38
 
39
+ Then display the branch summary:
40
+ ```
40
41
  Branch: {CURRENT_BRANCH}
41
42
  Target: {TARGET}
42
43
  Commits: {AHEAD} ahead
@@ -1,6 +1,6 @@
1
1
  # Reapply Local Patches Workflow
2
2
 
3
- Invoked by `/pp:update --reapply` (`commands/gsd/update.md`).
3
+ Invoked by `/pp:update --reapply` (`commands/pp-update.md`).
4
4
 
5
5
  After a pp-core update wipes and reinstalls files, this workflow merges user's previously saved local modifications back into the new version. Uses three-way comparison (pristine baseline, user-modified backup, newly installed version) to reliably distinguish user customizations from version drift.
6
6
 
@@ -442,7 +442,7 @@ Read the `activeHooks` array directly from `SHIP_POST_HOOKS_JSON` in-context (do
442
442
  ```
443
443
 
444
444
  `Agent(subagent_type=ref.agent, prompt="Ship-time capability hook for phase ${PHASE_NUMBER}. Phase dir: ${PHASE_DIR}. Consume: ${consumed_files}. Follow your agent instructions.", model="{balanced_model}")`
445
- - If `ref.skill` is set, apply **prefix-aware resolution**: if `ref.skill` already begins with a runtime-resolvable stem (e.g. `pareto-`), dispatch it verbatim with no phase/workspace args — `Skill(skill=ref.skill)` — because the skill handles its own invocation (e.g. `pareto-sync-board` triggers bare). Otherwise, fall back to the existing stem behavior: `Skill(skill="gsd-${ref.skill}", args="${PHASE_NUMBER} --auto ${GSD_WS}")`. This prevents a `pareto-` skill from being incorrectly prefixed to a non-existent `gsd-pareto-*` name.
445
+ - If `ref.skill` is set, apply **prefix-aware resolution**: if `ref.skill` already begins with a runtime-resolvable stem (e.g. `pareto-`), dispatch it verbatim with no phase/workspace args — `Skill(skill=ref.skill)` — because the skill handles its own invocation (e.g. `pareto-sync-board` triggers bare). Otherwise, fall back to the existing stem behavior: `Skill(skill="pp-${ref.skill}", args="${PHASE_NUMBER} --auto ${GSD_WS}")`. This prevents a `pareto-` skill from being incorrectly prefixed to a non-existent `pp-pareto-*` name.
446
446
 
447
447
  Each dispatch is best-effort: if it errors, record a warning and continue — never re-raise (`onError: skip`).
448
448
  </step>
@@ -1,6 +1,6 @@
1
1
  # Thread Workflow
2
2
 
3
- Invoked by `/pp:thread` (`commands/gsd/thread.md`).
3
+ Invoked by `/pp:thread` (`commands/pp-thread.md`).
4
4
 
5
5
  Create, list, close, or resume persistent context threads for cross-session work.
6
6
 
@@ -467,7 +467,7 @@ Resolve active step hooks from `VERIFY_POST_HOOKS_JSON` where `kind == "step"` a
467
467
  If an active secure-phase step hook exists AND `SECURITY_FILE` is empty, dispatch the registry-provided skill stem:
468
468
 
469
469
  ```
470
- Skill(skill="gsd-${ref.skill}", args="{phase}")
470
+ Skill(skill="pp-${ref.skill}", args="{phase}")
471
471
  ```
472
472
 
473
473
  After the skill returns, refresh `SECURITY_FILE`:
@@ -619,12 +619,13 @@ On return:
619
619
  <step name="verify_gap_plans">
620
620
  **Verify fix plans with checker:**
621
621
 
622
- Display:
622
+ Run this Bash command to emit the branded Validate stage banner (renders on stderr, auto-degrades on non-TTY — do NOT print an inline ASCII banner, that would double-print):
623
+ ```bash
624
+ pp_run banner validate "VERIFYING"
623
625
  ```
624
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
625
- pp-core ► VERIFYING FIX PLANS
626
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
627
626
 
627
+ Then announce the spawn:
628
+ ```
628
629
  ◆ Spawning plan checker... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
629
630
  ```
630
631