@sienklogic/plan-build-run 2.56.0 → 2.56.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@ All notable changes to Plan-Build-Run will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.56.1](https://github.com/SienkLogic/plan-build-run/compare/plan-build-run-v2.56.0...plan-build-run-v2.56.1) (2026-03-03)
9
+
10
+
11
+ ### Documentation
12
+
13
+ * **quick-020:** comprehensively update documentation for v2.56.0 ([82f9177](https://github.com/SienkLogic/plan-build-run/commit/82f917792dd573192c4ce69df8633f13b1050b0a))
14
+
8
15
  ## [2.56.0](https://github.com/SienkLogic/plan-build-run/compare/plan-build-run-v2.55.0...plan-build-run-v2.56.0) (2026-03-02)
9
16
 
10
17
 
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  </p>
4
4
 
5
5
  <p align="center">
6
- <strong>Context-engineered development workflow for Claude Code, Cursor, and GitHub Copilot CLI.</strong>
6
+ <strong>Context-engineered development workflow for Claude Code, Cursor, GitHub Copilot CLI, OpenAI Codex, and Google Jules.</strong>
7
7
  <br />
8
8
  Build ambitious multi-phase software without quality degradation.
9
9
  <br />
@@ -27,7 +27,7 @@
27
27
  <img src="https://img.shields.io/badge/Node.js-18%2B-339933?style=for-the-badge&logo=node.js&logoColor=white" alt="Node.js 18+" />
28
28
  <a href="LICENSE"><img src="https://img.shields.io/github/license/SienkLogic/plan-build-run?style=for-the-badge" alt="License" /></a>
29
29
  <a href="https://www.npmjs.com/package/@sienklogic/plan-build-run"><img src="https://img.shields.io/npm/v/@sienklogic/plan-build-run?style=for-the-badge&logo=npm&logoColor=white" alt="npm" /></a>
30
- <img src="https://img.shields.io/badge/Tests-2153_passing-brightgreen?style=for-the-badge" alt="2153 Tests" />
30
+ <img src="https://img.shields.io/badge/Tests-9283_passing-brightgreen?style=for-the-badge" alt="9283 Tests" />
31
31
  </p>
32
32
 
33
33
  ---
@@ -132,6 +132,48 @@ All three plugins share the same `.planning/` directory — start in any tool, c
132
132
 
133
133
  </details>
134
134
 
135
+ <details>
136
+ <summary><strong>Install for OpenAI Codex CLI</strong></summary>
137
+
138
+ Plan-Build-Run also works in OpenAI Codex CLI. Skills and agents are available via the `plugins/codex-pbr/` plugin. No hooks (Codex CLI does not support lifecycle hooks).
139
+
140
+ **macOS / Linux:**
141
+ ```bash
142
+ cd /path/to/your/project
143
+ bash /path/to/plan-build-run/plugins/codex-pbr/setup.sh
144
+ ```
145
+
146
+ **Windows (PowerShell):**
147
+ ```powershell
148
+ cd C:\path\to\your\project
149
+ powershell -ExecutionPolicy Bypass -File C:\path\to\plan-build-run\plugins\codex-pbr\setup.ps1
150
+ ```
151
+
152
+ All five plugins share the same `.planning/` directory. See [`plugins/codex-pbr/README.md`](plugins/codex-pbr/README.md) for full details.
153
+
154
+ </details>
155
+
156
+ <details>
157
+ <summary><strong>Install for Google Jules</strong></summary>
158
+
159
+ Plan-Build-Run also works in Google Jules. Skills and agents are available via the `plugins/jules-pbr/` plugin. No hooks (Jules does not support lifecycle hooks).
160
+
161
+ **macOS / Linux:**
162
+ ```bash
163
+ cd /path/to/your/project
164
+ bash /path/to/plan-build-run/plugins/jules-pbr/setup.sh
165
+ ```
166
+
167
+ **Windows (PowerShell):**
168
+ ```powershell
169
+ cd C:\path\to\your\project
170
+ powershell -ExecutionPolicy Bypass -File C:\path\to\plan-build-run\plugins\jules-pbr\setup.ps1
171
+ ```
172
+
173
+ All five plugins share the same `.planning/` directory. See [`plugins/jules-pbr/README.md`](plugins/jules-pbr/README.md) for full details.
174
+
175
+ </details>
176
+
135
177
  <details>
136
178
  <summary><strong>Dashboard (Optional)</strong></summary>
137
179
 
@@ -219,7 +261,7 @@ Set `depth: quick` in `/pbr:config` to reduce agent spawns across all workflows.
219
261
  | `/pbr:build <N>` | Build a phase: parallel execution in waves, atomic commits | 2-4 (quick: 1-2) |
220
262
  | `/pbr:review <N>` | Verify a phase: automated 3-layer checks + conversational UAT | 1 |
221
263
 
222
- See **[Commands](https://github.com/SienkLogic/plan-build-run/wiki/Commands)** for all 26 commands with flags, cost-by-depth tables, and detailed descriptions.
264
+ See **[Commands](https://github.com/SienkLogic/plan-build-run/wiki/Commands)** for all 27 commands with flags, cost-by-depth tables, and detailed descriptions.
223
265
 
224
266
  ---
225
267
 
@@ -292,8 +334,8 @@ Requires a GPU with 6+ GB VRAM for best performance. CPU-only works but adds lat
292
334
  | Topic | Description |
293
335
  |-------|-------------|
294
336
  | **[Agents](https://github.com/SienkLogic/plan-build-run/wiki/Agents)** | 12 specialized agents with configurable model profiles and file-based communication |
295
- | **[Configuration](https://github.com/SienkLogic/plan-build-run/wiki/Configuration)** | 13 config keys, depth/model profiles, 16+ feature toggles, local LLM settings |
296
- | **[Hooks](https://github.com/SienkLogic/plan-build-run/wiki/Hooks)** | 38 hook scripts that enforce discipline at zero token cost |
337
+ | **[Configuration](https://github.com/SienkLogic/plan-build-run/wiki/Configuration)** | 12 config keys, depth/model profiles, 14+ feature toggles, local LLM settings |
338
+ | **[Hooks](https://github.com/SienkLogic/plan-build-run/wiki/Hooks)** | 41 hook scripts that enforce discipline at zero token cost |
297
339
  | **[Local LLM](https://github.com/SienkLogic/plan-build-run/wiki/Configuration#local_llm)** | Offload hook-level inference to Ollama for token savings with automatic fallback |
298
340
  | **[Project Structure](https://github.com/SienkLogic/plan-build-run/wiki/Project-Structure)** | The `.planning/` directory layout, key files, and file ownership |
299
341
  | **[Dashboard](https://github.com/SienkLogic/plan-build-run/wiki/Dashboard)** | Web UI with live updates for browsing project state |
@@ -306,28 +348,29 @@ Requires a GPU with 6+ GB VRAM for best performance. CPU-only works but adds lat
306
348
 
307
349
  ## Platform Compatibility
308
350
 
309
- Plan-Build-Run works across three platforms with varying levels of hook support. Hooks are the mechanism that fires validation scripts on every tool call — they power local LLM offloading, commit format enforcement, context budget tracking, and workflow gates.
310
-
311
- | Feature | Claude Code | Copilot CLI | Cursor IDE |
312
- |---------|:-----------:|:-----------:|:----------:|
313
- | Skills (slash commands) | All 26 | All 26 | All 26 |
314
- | Agents (subagent delegation) | All 12 | All 12 | All 12 |
315
- | `.planning/` state management | Full | Full | Full |
316
- | **Hook support** | **Full (14 events)** | **Partial (4 events)** | **Unverified** |
317
- | Commit format enforcement | Hook-enforced | Hook-enforced | Manual |
318
- | PLAN/SUMMARY quality classification | Hook + skill fallback | Hook + skill fallback | Skill fallback only |
319
- | Test failure triage | Automatic (hook) | Automatic (hook) | Not available |
320
- | Context budget tracking | Automatic (hook) | Not available | Not available |
321
- | Auto-continue between skills | Automatic (hook) | Not available | Not available |
322
- | Subagent lifecycle logging | Automatic (hook) | Not available | Not available |
323
- | **Local LLM offloading** | **Full (8 operations)** | **Mostly (6-7 operations)** | **CLI only** |
324
- | `pbr-tools.js llm` CLI commands | Full | Full | Full |
351
+ Plan-Build-Run works across five platforms with varying levels of hook support. Hooks are the mechanism that fires validation scripts on every tool call — they power local LLM offloading, commit format enforcement, context budget tracking, and workflow gates.
352
+
353
+ | Feature | Claude Code | Copilot CLI | Cursor IDE | Codex CLI | Jules |
354
+ |---------|:-----------:|:-----------:|:----------:|:---------:|:-----:|
355
+ | Skills (slash commands) | All 27 | All 27 | All 27 | All 27 | All 27 |
356
+ | Agents (subagent delegation) | All 12 | All 12 | All 12 | All 12 | All 12 |
357
+ | `.planning/` state management | Full | Full | Full | Full | Full |
358
+ | **Hook support** | **Full (14 events)** | **Partial (4 events)** | **Unverified** | **None** | **None** |
359
+ | Commit format enforcement | Hook-enforced | Hook-enforced | Manual | Manual | Manual |
360
+ | PLAN/SUMMARY quality classification | Hook + skill fallback | Hook + skill fallback | Skill fallback only | Skill fallback only | Skill fallback only |
361
+ | Test failure triage | Automatic (hook) | Automatic (hook) | Not available | Not available | Not available |
362
+ | Context budget tracking | Automatic (hook) | Not available | Not available | Not available | Not available |
363
+ | Auto-continue between skills | Automatic (hook) | Not available | Not available | Not available | Not available |
364
+ | Subagent lifecycle logging | Automatic (hook) | Not available | Not available | Not available | Not available |
365
+ | **Local LLM offloading** | **Full (8 operations)** | **Mostly (6-7 operations)** | **CLI only** | **CLI only** | **CLI only** |
366
+ | `pbr-tools.js llm` CLI commands | Full | Full | Full | Full | Full |
325
367
 
326
368
  **Key differences:**
327
369
 
328
370
  - **Claude Code** has full hook support — all local LLM operations fire automatically on every tool call
329
371
  - **Copilot CLI** supports `sessionStart`, `preToolUse`, `postToolUse`, and `sessionEnd` — covers most validation hooks but misses lifecycle events (`SubagentStop`, `PreCompact`, `Stop`)
330
372
  - **Cursor IDE** hook support is unverified — hooks.json is configured but whether Cursor actually fires them is unknown. Skills include `pbr-tools.js llm` fallback calls for key operations (plan quality, verification quality) so local LLM classification is available even without hooks
373
+ - **OpenAI Codex CLI** and **Google Jules** do not support hooks. All skills and agents are available via `plugins/codex-pbr/` and `plugins/jules-pbr/` respectively. Agent definitions use AGENTS.md format.
331
374
 
332
375
  All platforms share the same scripts via relative paths — no code duplication. See the [Copilot CLI](plugins/copilot-pbr/README.md) and [Cursor IDE](plugins/cursor-pbr/README.md) READMEs for platform-specific details.
333
376
 
@@ -341,7 +384,7 @@ git clone https://github.com/SienkLogic/plan-build-run.git
341
384
  cd plan-build-run
342
385
  npm install
343
386
 
344
- # Run tests (2153 tests, 73 suites)
387
+ # Run tests (9283 tests, 281 suites)
345
388
  npm test
346
389
 
347
390
  # Lint
@@ -362,14 +405,19 @@ CI runs on Node 18/20/22 across Windows, macOS, and Linux. See [CONTRIBUTING.md]
362
405
 
363
406
  | Metric | Count |
364
407
  |--------|-------|
365
- | Skills (slash commands) | 26 |
408
+ | Skills (slash commands) | 27 |
366
409
  | Specialized agents | 12 |
367
- | Hook scripts | 38 |
410
+ | Hook scripts | 41 |
368
411
  | Local LLM operations | 8 |
369
- | Supported platforms | 3 (Claude Code, Cursor, Copilot CLI) |
370
- | Tests | 2153 |
371
- | Test suites | 73 |
372
- | Config keys | 13 top-level (62+ properties) |
412
+ | Supported platforms | 5 (Claude Code, Cursor, Copilot CLI, Codex, Jules) |
413
+ | Tests | 9283 |
414
+ | Test suites | 281 |
415
+ | Config keys | 12 top-level (62+ properties) |
416
+ | Feature toggles | 14 |
417
+ | Lib modules | 19 |
418
+ | Shared fragments | 12 |
419
+ | Templates | 10 |
420
+ | References | 19 |
373
421
 
374
422
  ---
375
423
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sienklogic/plan-build-run",
3
- "version": "2.56.0",
3
+ "version": "2.56.1",
4
4
  "description": "Plan it, Build it, Run it — structured development workflow for Claude Code",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -361,7 +361,7 @@ All phases with status and completion data.
361
361
  node ${CLAUDE_PLUGIN_ROOT}/scripts/pbr-tools.js init progress
362
362
  ```
363
363
 
364
- **Output:** `current_phase`, `total_phases`, `status`, `phases` array, `total_plans`, `completed_plans`, `percentage`.
364
+ **Output:** `current_phase`, `phase_count`, `status`, `phases` array, `total_plans`, `completed_plans`, `percentage`.
365
365
 
366
366
  ---
367
367
 
@@ -375,7 +375,7 @@ Multi-field atomic STATE.md update. Updates all fields in a single pass.
375
375
  node ${CLAUDE_PLUGIN_ROOT}/scripts/pbr-tools.js state patch '{"status":"executing","last_activity":"now"}'
376
376
  ```
377
377
 
378
- **Valid fields:** `current_phase`, `status`, `plans_complete`, `last_activity`, `progress_percent`, `phase_slug`, `total_phases`, `last_command`, `blockers`
378
+ **Valid fields:** `current_phase`, `status`, `plans_complete`, `last_activity`, `progress_percent`, `phase_slug`, `last_command`, `blockers`
379
379
 
380
380
  **Output:** `{ "success": true, "updated": ["status", "last_activity"] }`
381
381
 
@@ -172,7 +172,7 @@ After running all 10 checks and collecting results, if any of the following auto
172
172
 
173
173
  | Pattern | Detection | Fix Action |
174
174
  |---------|-----------|------------|
175
- | Missing STATE.md frontmatter | Check 5 finds STATE.md without `---` block | Regenerate frontmatter from ROADMAP.md phase data (current_phase, total_phases, status) |
175
+ | Missing STATE.md frontmatter | Check 5 finds STATE.md without `---` block | Regenerate frontmatter from ROADMAP.md phase data (current_phase, phase_slug, status) |
176
176
  | STATE.md phase_slug mismatch | Check 5/7 finds phase_slug doesn't match current phase directory name | Correct phase_slug to match the actual directory name in `.planning/phases/` |
177
177
  | Missing config.json | Check 1/2 finds no `.planning/config.json` | Create with default config template (same as `$pbr-setup` defaults) |
178
178
  | Orphaned .active-skill file | Check 10 or general scan finds `.planning/.active-skill` older than 1 hour | Delete the stale `.active-skill` file |
@@ -53,7 +53,7 @@ Progress: [{progress_bar}] {percent}%
53
53
  Phase 3 of 10 = 20% → [████░░░░░░░░░░░░░░░░] 20%
54
54
  Phase 7 of 10 = 70% → [██████████████░░░░░░] 70%
55
55
  ```
56
- Calculation: `filled = Math.round((completed_phases / total_phases) * 20)`
56
+ Calculation: `filled = Math.round((completed_phases / phase_count) * 20)` where `phase_count` is derived from ROADMAP.md (available via `stateLoad` as `phase_count`)
57
57
 
58
58
  ### 3. Accumulated Context (lines 16-25)
59
59
  ```
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pbr",
3
3
  "displayName": "Plan-Build-Run",
4
- "version": "2.56.0",
4
+ "version": "2.56.1",
5
5
  "description": "Plan-Build-Run — Structured development workflow for GitHub Copilot CLI. Solves context rot through disciplined agent delegation, structured planning, atomic execution, and goal-backward verification.",
6
6
  "author": {
7
7
  "name": "SienkLogic",
@@ -361,7 +361,7 @@ All phases with status and completion data.
361
361
  node ${CLAUDE_PLUGIN_ROOT}/scripts/pbr-tools.js init progress
362
362
  ```
363
363
 
364
- **Output:** `current_phase`, `total_phases`, `status`, `phases` array, `total_plans`, `completed_plans`, `percentage`.
364
+ **Output:** `current_phase`, `phase_count`, `status`, `phases` array, `total_plans`, `completed_plans`, `percentage`.
365
365
 
366
366
  ---
367
367
 
@@ -375,7 +375,7 @@ Multi-field atomic STATE.md update. Updates all fields in a single pass.
375
375
  node ${CLAUDE_PLUGIN_ROOT}/scripts/pbr-tools.js state patch '{"status":"executing","last_activity":"now"}'
376
376
  ```
377
377
 
378
- **Valid fields:** `current_phase`, `status`, `plans_complete`, `last_activity`, `progress_percent`, `phase_slug`, `total_phases`, `last_command`, `blockers`
378
+ **Valid fields:** `current_phase`, `status`, `plans_complete`, `last_activity`, `progress_percent`, `phase_slug`, `last_command`, `blockers`
379
379
 
380
380
  **Output:** `{ "success": true, "updated": ["status", "last_activity"] }`
381
381
 
@@ -2,7 +2,6 @@
2
2
  ---
3
3
  version: 2
4
4
  current_phase: 1
5
- total_phases: {total}
6
5
  phase_slug: "{phase_1_slug}"
7
6
  phase_name: "{Phase 1 name}"
8
7
  status: "ready_to_plan"
@@ -172,7 +172,7 @@ After running all 10 checks and collecting results, if any of the following auto
172
172
 
173
173
  | Pattern | Detection | Fix Action |
174
174
  |---------|-----------|------------|
175
- | Missing STATE.md frontmatter | Check 5 finds STATE.md without `---` block | Regenerate frontmatter from ROADMAP.md phase data (current_phase, total_phases, status) |
175
+ | Missing STATE.md frontmatter | Check 5 finds STATE.md without `---` block | Regenerate frontmatter from ROADMAP.md phase data (current_phase, phase_slug, status) |
176
176
  | STATE.md phase_slug mismatch | Check 5/7 finds phase_slug doesn't match current phase directory name | Correct phase_slug to match the actual directory name in `.planning/phases/` |
177
177
  | Missing config.json | Check 1/2 finds no `.planning/config.json` | Create with default config template (same as `/pbr:setup` defaults) |
178
178
  | Orphaned .active-skill file | Check 10 or general scan finds `.planning/.active-skill` older than 1 hour | Delete the stale `.active-skill` file |
@@ -53,7 +53,7 @@ Progress: [{progress_bar}] {percent}%
53
53
  Phase 3 of 10 = 20% → [████░░░░░░░░░░░░░░░░] 20%
54
54
  Phase 7 of 10 = 70% → [██████████████░░░░░░] 70%
55
55
  ```
56
- Calculation: `filled = Math.round((completed_phases / total_phases) * 20)`
56
+ Calculation: `filled = Math.round((completed_phases / phase_count) * 20)` where `phase_count` is derived from ROADMAP.md (available via `stateLoad` as `phase_count`)
57
57
 
58
58
  ### 3. Accumulated Context (lines 16-25)
59
59
  ```
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pbr",
3
3
  "displayName": "Plan-Build-Run",
4
- "version": "2.56.0",
4
+ "version": "2.56.1",
5
5
  "description": "Plan-Build-Run — Structured development workflow for Cursor. Solves context rot through disciplined subagent delegation, structured planning, atomic execution, and goal-backward verification.",
6
6
  "author": {
7
7
  "name": "SienkLogic",
@@ -361,7 +361,7 @@ All phases with status and completion data.
361
361
  node ${CLAUDE_PLUGIN_ROOT}/scripts/pbr-tools.js init progress
362
362
  ```
363
363
 
364
- **Output:** `current_phase`, `total_phases`, `status`, `phases` array, `total_plans`, `completed_plans`, `percentage`.
364
+ **Output:** `current_phase`, `phase_count`, `status`, `phases` array, `total_plans`, `completed_plans`, `percentage`.
365
365
 
366
366
  ---
367
367
 
@@ -375,7 +375,7 @@ Multi-field atomic STATE.md update. Updates all fields in a single pass.
375
375
  node ${CLAUDE_PLUGIN_ROOT}/scripts/pbr-tools.js state patch '{"status":"executing","last_activity":"now"}'
376
376
  ```
377
377
 
378
- **Valid fields:** `current_phase`, `status`, `plans_complete`, `last_activity`, `progress_percent`, `phase_slug`, `total_phases`, `last_command`, `blockers`
378
+ **Valid fields:** `current_phase`, `status`, `plans_complete`, `last_activity`, `progress_percent`, `phase_slug`, `last_command`, `blockers`
379
379
 
380
380
  **Output:** `{ "success": true, "updated": ["status", "last_activity"] }`
381
381
 
@@ -2,7 +2,6 @@
2
2
  ---
3
3
  version: 2
4
4
  current_phase: 1
5
- total_phases: {total}
6
5
  phase_slug: "{phase_1_slug}"
7
6
  phase_name: "{Phase 1 name}"
8
7
  status: "ready_to_plan"
@@ -173,7 +173,7 @@ After running all 10 checks and collecting results, if any of the following auto
173
173
 
174
174
  | Pattern | Detection | Fix Action |
175
175
  |---------|-----------|------------|
176
- | Missing STATE.md frontmatter | Check 5 finds STATE.md without `---` block | Regenerate frontmatter from ROADMAP.md phase data (current_phase, total_phases, status) |
176
+ | Missing STATE.md frontmatter | Check 5 finds STATE.md without `---` block | Regenerate frontmatter from ROADMAP.md phase data (current_phase, phase_slug, status) |
177
177
  | STATE.md phase_slug mismatch | Check 5/7 finds phase_slug doesn't match current phase directory name | Correct phase_slug to match the actual directory name in `.planning/phases/` |
178
178
  | Missing config.json | Check 1/2 finds no `.planning/config.json` | Create with default config template (same as `/pbr:setup` defaults) |
179
179
  | Orphaned .active-skill file | Check 10 or general scan finds `.planning/.active-skill` older than 1 hour | Delete the stale `.active-skill` file |
@@ -53,7 +53,7 @@ Progress: [{progress_bar}] {percent}%
53
53
  Phase 3 of 10 = 20% → [████░░░░░░░░░░░░░░░░] 20%
54
54
  Phase 7 of 10 = 70% → [██████████████░░░░░░] 70%
55
55
  ```
56
- Calculation: `filled = Math.round((completed_phases / total_phases) * 20)`
56
+ Calculation: `filled = Math.round((completed_phases / phase_count) * 20)` where `phase_count` is derived from ROADMAP.md (available via `stateLoad` as `phase_count`)
57
57
 
58
58
  ### 3. Accumulated Context (lines 16-25)
59
59
  ```
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pbr",
3
- "version": "2.56.0",
3
+ "version": "2.56.1",
4
4
  "description": "Plan-Build-Run — Structured development workflow for Claude Code. Solves context rot through disciplined subagent delegation, structured planning, atomic execution, and goal-backward verification.",
5
5
  "author": {
6
6
  "name": "SienkLogic",
@@ -361,7 +361,7 @@ All phases with status and completion data.
361
361
  node ${CLAUDE_PLUGIN_ROOT}/scripts/pbr-tools.js init progress
362
362
  ```
363
363
 
364
- **Output:** `current_phase`, `total_phases`, `status`, `phases` array, `total_plans`, `completed_plans`, `percentage`.
364
+ **Output:** `current_phase`, `phase_count`, `status`, `phases` array, `total_plans`, `completed_plans`, `percentage`.
365
365
 
366
366
  ---
367
367
 
@@ -375,7 +375,7 @@ Multi-field atomic STATE.md update. Updates all fields in a single pass.
375
375
  node ${CLAUDE_PLUGIN_ROOT}/scripts/pbr-tools.js state patch '{"status":"executing","last_activity":"now"}'
376
376
  ```
377
377
 
378
- **Valid fields:** `current_phase`, `status`, `plans_complete`, `last_activity`, `progress_percent`, `phase_slug`, `total_phases`, `last_command`, `blockers`
378
+ **Valid fields:** `current_phase`, `status`, `plans_complete`, `last_activity`, `progress_percent`, `phase_slug`, `last_command`, `blockers`
379
379
 
380
380
  **Output:** `{ "success": true, "updated": ["status", "last_activity"] }`
381
381
 
@@ -347,7 +347,7 @@ function validateState(content, _filePath) {
347
347
  warnings.push('Unclosed YAML frontmatter');
348
348
  } else {
349
349
  const frontmatter = content.substring(3, frontmatterEnd);
350
- const requiredFields = ['version', 'current_phase', 'total_phases', 'phase_slug', 'status'];
350
+ const requiredFields = ['version', 'current_phase', 'phase_slug', 'status'];
351
351
  for (const field of requiredFields) {
352
352
  if (!frontmatter.includes(`${field}:`)) {
353
353
  warnings.push(`Frontmatter missing "${field}" field`);
@@ -440,14 +440,12 @@ function syncStateBody(content, filePath) {
440
440
 
441
441
  const fm = content.substring(3, fmEnd);
442
442
  const phaseMatch = fm.match(/^current_phase:\s*(\d+)/m);
443
- const totalMatch = fm.match(/^total_phases:\s*(\d+)/m);
444
443
  const slugMatch = fm.match(/^phase_name:\s*"?([^"\r\n]+)"?/m);
445
444
  const statusMatch = fm.match(/^status:\s*"?([^"\r\n]+)"?/m);
446
445
 
447
446
  if (!phaseMatch) return null;
448
447
 
449
448
  const fmPhase = phaseMatch[1];
450
- const fmTotal = totalMatch ? totalMatch[1] : null;
451
449
  const fmName = slugMatch ? slugMatch[1] : null;
452
450
  const fmStatus = statusMatch ? statusMatch[1] : null;
453
451
 
@@ -459,9 +457,10 @@ function syncStateBody(content, filePath) {
459
457
 
460
458
  // Fix phase line drift
461
459
  if (bodyPhaseMatch && bodyPhaseMatch[1] !== fmPhase) {
462
- const newPhaseLine = fmTotal
463
- ? (fmName ? `Phase: ${fmPhase} of ${fmTotal} (${fmName})` : `Phase: ${fmPhase} of ${fmTotal}`)
464
- : `Phase: ${fmPhase} of ${bodyPhaseMatch[2]}`;
460
+ const bodyTotal = bodyPhaseMatch ? bodyPhaseMatch[2] : null;
461
+ const newPhaseLine = bodyTotal
462
+ ? (fmName ? `Phase: ${fmPhase} of ${bodyTotal} (${fmName})` : `Phase: ${fmPhase} of ${bodyTotal}`)
463
+ : `Phase: ${fmPhase}`;
465
464
  updated = updated.replace(/^Phase:\s*\d+\s*of\s*\d+.*/m, newPhaseLine);
466
465
  needsFix = true;
467
466
  }
@@ -210,9 +210,6 @@ function updateStatePosition(content, updates) {
210
210
  if (updates.fmCurrentPhase !== undefined) {
211
211
  fm = fm.replace(/^(current_phase:\s*).*/m, (_, p) => `${p}${updates.fmCurrentPhase}`);
212
212
  }
213
- if (updates.fmTotalPhases !== undefined) {
214
- fm = fm.replace(/^(total_phases:\s*).*/m, (_, p) => `${p}${updates.fmTotalPhases}`);
215
- }
216
213
  if (updates.fmPhaseSlug !== undefined) {
217
214
  fm = fm.replace(/^(phase_slug:\s*).*/m, (_, p) => `${p}"${updates.fmPhaseSlug}"`);
218
215
  }
@@ -420,7 +417,6 @@ function checkStateSync(data) {
420
417
  if (currentPhase !== null && currentPhase !== phaseNumInt) {
421
418
  stateUpdates.phaseLine = `${phaseNumInt} of ${totalPhases} (${phaseName})`;
422
419
  stateUpdates.fmCurrentPhase = phaseNumInt;
423
- stateUpdates.fmTotalPhases = totalPhases;
424
420
  stateUpdates.fmPhaseSlug = phaseSlug;
425
421
  stateUpdates.fmPhaseName = phaseName;
426
422
  messages.push(`STATE.md: Phase ${currentPhase} → ${phaseNumInt}`);
@@ -503,7 +499,6 @@ function checkStateSync(data) {
503
499
  if (currentPhase !== null && currentPhase !== phaseNumInt) {
504
500
  stateUpdates.phaseLine = `${phaseNumInt} of ${totalPhases} (${phaseName})`;
505
501
  stateUpdates.fmCurrentPhase = phaseNumInt;
506
- stateUpdates.fmTotalPhases = totalPhases;
507
502
  stateUpdates.fmPhaseSlug = phaseSlug;
508
503
  stateUpdates.fmPhaseName = phaseName;
509
504
  messages.push(`STATE.md: Phase ${currentPhase} → ${phaseNumInt}`);
@@ -31,7 +31,6 @@ function parseStateMd(content) {
31
31
  if (frontmatter.version === 2 || frontmatter.current_phase !== undefined) {
32
32
  result.format = 'frontmatter';
33
33
  result.current_phase = frontmatter.current_phase || null;
34
- result.total_phases = frontmatter.total_phases || null;
35
34
  result.phase_name = frontmatter.phase_slug || frontmatter.phase_name || null;
36
35
  result.status = frontmatter.status || null;
37
36
  result.progress = frontmatter.progress_percent !== undefined ? frontmatter.progress_percent : null;
@@ -301,7 +300,6 @@ function stateUpdate(field, value, planningDir) {
301
300
  'last_activity',
302
301
  'progress_percent',
303
302
  'phase_slug',
304
- 'total_phases',
305
303
  'last_command',
306
304
  'blockers'
307
305
  ];
@@ -340,7 +338,7 @@ function statePatch(jsonStr, planningDir) {
340
338
  if (!fs.existsSync(statePath)) return { success: false, error: "STATE.md not found" };
341
339
  let fields;
342
340
  try { fields = JSON.parse(jsonStr); } catch (_e) { return { success: false, error: "Invalid JSON" }; }
343
- const validFields = ["current_phase", "status", "plans_complete", "last_activity", "progress_percent", "phase_slug", "total_phases", "last_command", "blockers"];
341
+ const validFields = ["current_phase", "status", "plans_complete", "last_activity", "progress_percent", "phase_slug", "last_command", "blockers"];
344
342
  const updates = [], errors = [];
345
343
  for (const [field, value] of Object.entries(fields)) {
346
344
  if (!validFields.includes(field)) { errors.push("Unknown field: " + field); continue; }
@@ -539,7 +539,7 @@ async function main() {
539
539
  const field = args[2];
540
540
  const value = args[3];
541
541
  if (!field || value === undefined) {
542
- error('Usage: pbr-tools.js state update <field> <value>\nFields: current_phase, status, plans_complete, last_activity, progress_percent, phase_slug, total_phases, last_command, blockers');
542
+ error('Usage: pbr-tools.js state update <field> <value>\nFields: current_phase, status, plans_complete, last_activity, progress_percent, phase_slug, last_command, blockers');
543
543
  }
544
544
  output(stateUpdate(field, value));
545
545
  } else if (command === 'config' && subcommand === 'validate') {
@@ -242,12 +242,11 @@ function buildStatusLine(content, ctxPercent, cfg, stdinData, planningDir) {
242
242
  // Phase section (always includes brand text)
243
243
  if (sections.includes('phase')) {
244
244
  const fmPhase = fm && fm.current_phase;
245
- const fmTotal = fm && fm.total_phases;
246
245
  const fmName = fm && fm.phase_name;
247
246
  const phaseMatch = content.match(/Phase:\s*(\d+)\s*of\s*(\d+)\s*(?:\(([^)]+)\))?/);
248
247
 
249
248
  const phaseNum = fmPhase || (phaseMatch && phaseMatch[1]);
250
- const phaseTotal = fmTotal || (phaseMatch && phaseMatch[2]);
249
+ const phaseTotal = phaseMatch && phaseMatch[2];
251
250
  const phaseName = fmName || (phaseMatch && phaseMatch[3]);
252
251
 
253
252
  if (phaseNum && phaseTotal) {
@@ -263,11 +262,11 @@ function buildStatusLine(content, ctxPercent, cfg, stdinData, planningDir) {
263
262
  // Plan section
264
263
  if (sections.includes('plan')) {
265
264
  const fmComplete = fm && fm.plans_complete;
266
- const fmTotal = fm && fm.plans_total;
265
+ const fmPlansTotal = fm && fm.plans_total;
267
266
  const planMatch = content.match(/Plan:\s*(\d+)\s*of\s*(\d+)/);
268
267
 
269
268
  const done = fmComplete != null ? parseInt(fmComplete, 10) : (planMatch ? parseInt(planMatch[1], 10) : null);
270
- const total = fmTotal != null ? parseInt(fmTotal, 10) : (planMatch ? parseInt(planMatch[2], 10) : null);
269
+ const total = fmPlansTotal != null ? parseInt(fmPlansTotal, 10) : (planMatch ? parseInt(planMatch[2], 10) : null);
271
270
 
272
271
  if (done != null && total != null && total > 0) {
273
272
  const planColor = done === total ? c.green : c.white;
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  version: 2
3
3
  current_phase: 1
4
- total_phases: {total}
5
4
  phase_slug: "{phase_1_slug}"
6
5
  phase_name: "{Phase 1 name}"
7
6
  status: "ready_to_plan"
@@ -174,7 +174,7 @@ After running all 10 checks and collecting results, if any of the following auto
174
174
 
175
175
  | Pattern | Detection | Fix Action |
176
176
  |---------|-----------|------------|
177
- | Missing STATE.md frontmatter | Check 5 finds STATE.md without `---` block | Regenerate frontmatter from ROADMAP.md phase data (current_phase, total_phases, status) |
177
+ | Missing STATE.md frontmatter | Check 5 finds STATE.md without `---` block | Regenerate frontmatter from ROADMAP.md phase data (current_phase, phase_slug, status) |
178
178
  | STATE.md phase_slug mismatch | Check 5/7 finds phase_slug doesn't match current phase directory name | Correct phase_slug to match the actual directory name in `.planning/phases/` |
179
179
  | Missing config.json | Check 1/2 finds no `.planning/config.json` | Create with default config template (same as `/pbr:setup` defaults) |
180
180
  | Orphaned .active-skill file | Check 10 or general scan finds `.planning/.active-skill` older than 1 hour | Delete the stale `.active-skill` file |
@@ -53,7 +53,7 @@ Progress: [{progress_bar}] {percent}%
53
53
  Phase 3 of 10 = 20% → [████░░░░░░░░░░░░░░░░] 20%
54
54
  Phase 7 of 10 = 70% → [██████████████░░░░░░] 70%
55
55
  ```
56
- Calculation: `filled = Math.round((completed_phases / total_phases) * 20)`
56
+ Calculation: `filled = Math.round((completed_phases / phase_count) * 20)` where `phase_count` is derived from ROADMAP.md (available via `stateLoad` as `phase_count`)
57
57
 
58
58
  ### 3. Accumulated Context (lines 16-25)
59
59
  ```