@theglitchking/persistent-planning 3.0.1 → 3.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.
Files changed (76) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.documentation/INDEX.md +224 -0
  4. package/.documentation/README.md +90 -0
  5. package/.documentation/REGISTRY.md +80 -0
  6. package/.documentation/agents/INDEX.md +43 -0
  7. package/.documentation/agents/REGISTRY.md +38 -0
  8. package/.documentation/api/INDEX.md +43 -0
  9. package/.documentation/api/REGISTRY.md +38 -0
  10. package/.documentation/architecture/INDEX.md +50 -0
  11. package/.documentation/architecture/REGISTRY.md +57 -0
  12. package/{docs/reference.md → .documentation/architecture/context-engineering-principles.md} +20 -1
  13. package/{docs → .documentation/architecture}/lg-mode.md +33 -8
  14. package/.documentation/architecture/lg-plan-artifact-lifecycle.md +104 -0
  15. package/.documentation/architecture/skill-linking-and-reclaim.md +84 -0
  16. package/.documentation/archive/README.md +46 -0
  17. package/.documentation/backups/INDEX.md +43 -0
  18. package/.documentation/backups/REGISTRY.md +38 -0
  19. package/.documentation/database/INDEX.md +43 -0
  20. package/.documentation/database/REGISTRY.md +38 -0
  21. package/.documentation/devops/INDEX.md +43 -0
  22. package/.documentation/devops/REGISTRY.md +38 -0
  23. package/.documentation/drafts/.gitkeep +1 -0
  24. package/.documentation/features/INDEX.md +43 -0
  25. package/.documentation/features/REGISTRY.md +38 -0
  26. package/.documentation/plans/INDEX.md +43 -0
  27. package/.documentation/plans/REGISTRY.md +38 -0
  28. package/.documentation/procedures/INDEX.md +43 -0
  29. package/.documentation/procedures/REGISTRY.md +53 -0
  30. package/.documentation/procedures/plan-completion-and-archive.md +185 -0
  31. package/.documentation/procedures/plugin-update-delivery.md +99 -0
  32. package/.documentation/quickstart/INDEX.md +42 -0
  33. package/.documentation/quickstart/REGISTRY.md +51 -0
  34. package/{docs → .documentation/quickstart}/examples.md +20 -0
  35. package/.documentation/reference/INDEX.md +49 -0
  36. package/.documentation/reference/REGISTRY.md +55 -0
  37. package/.documentation/reference/mandatory-frontmatter.md +71 -0
  38. package/.documentation/reference/skill-version-marker.md +70 -0
  39. package/{docs → .documentation/reference}/workspace-json.md +11 -5
  40. package/.documentation/security/INDEX.md +43 -0
  41. package/.documentation/security/REGISTRY.md +38 -0
  42. package/.documentation/standards/INDEX.md +43 -0
  43. package/.documentation/standards/REGISTRY.md +53 -0
  44. package/{docs → .documentation/standards}/atom-granularity.md +12 -5
  45. package/.documentation/standards/mandatory-closing-phases.md +145 -0
  46. package/.documentation/testing/INDEX.md +42 -0
  47. package/.documentation/testing/REGISTRY.md +51 -0
  48. package/.documentation/testing/test-suite.md +126 -0
  49. package/.documentation/troubleshooting/INDEX.md +43 -0
  50. package/.documentation/troubleshooting/REGISTRY.md +53 -0
  51. package/.documentation/troubleshooting/plan-never-reads-complete.md +109 -0
  52. package/.documentation/troubleshooting/stale-skill-dir-drift.md +115 -0
  53. package/.documentation/workflows/INDEX.md +43 -0
  54. package/.documentation/workflows/REGISTRY.md +38 -0
  55. package/CHANGELOG.md +198 -0
  56. package/README.md +67 -7
  57. package/bin/persistent-planning.js +56 -6
  58. package/commands/archive-plan.md +66 -0
  59. package/commands/plan-status.md +62 -0
  60. package/commands/start-atom.md +3 -3
  61. package/commands/start-planning.md +2 -2
  62. package/commands/start-task.md +2 -2
  63. package/hooks/session-start.js +191 -8
  64. package/package.json +6 -3
  65. package/scripts/archive-plan.sh +143 -0
  66. package/scripts/init-atom.sh +7 -0
  67. package/scripts/init-phase.sh +58 -6
  68. package/scripts/init-planning.sh +39 -4
  69. package/scripts/init-task.sh +7 -0
  70. package/scripts/lib/planning.sh +122 -0
  71. package/scripts/lib/skill-link.js +177 -0
  72. package/scripts/link-skills.js +38 -0
  73. package/scripts/plan-status.sh +196 -0
  74. package/skills/persistent-planning/SKILL.md +37 -9
  75. package/templates/lg/phase.md +22 -3
  76. package/templates/lg/task.md +4 -3
package/CHANGELOG.md CHANGED
@@ -2,6 +2,204 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [3.4.0] - 2026-09-04
6
+
7
+ ### Changed — only completed plans are gitignored (#15)
8
+
9
+ Both init scripts blanket-ignored the entire `.planning/` tree, a v1.0.0 behavior
10
+ (`fb35f19`) that 3.1.0 implicitly reversed and never removed. `archive-plan.sh` had
11
+ already decided only completed plans are local history, and four shipped docs —
12
+ `SKILL.md`, `lg-mode.md` (twice), `README.md` — described `.planning/.archive/` as *the*
13
+ gitignored path. The code did the opposite.
14
+
15
+ In lg mode the contradiction was sharpest: that mode is selected because ≥2 git authors
16
+ exist, plans are what subagents read via the planning MCP, and the first thing
17
+ `init-phase.sh` did was guarantee no teammate would ever receive them. The blanket entry
18
+ also suppressed `archive-plan.sh`'s narrow one — its first guard returns early when the
19
+ whole tree is ignored — so the narrow entry could never appear in a repo where
20
+ `/start-planning` had run, which is every repo.
21
+
22
+ - **Active plans are tracked; only `.planning/.archive/` is ignored.** One rule, shared by
23
+ both lg init and `archive-plan.sh` via `planning_ensure_archive_gitignored`;
24
+ `init-planning.sh` keeps its own copy since it is deliberately self-contained.
25
+ - **An existing blanket `.planning/` line is never rewritten.** It is the user's file. The
26
+ tool says once how to narrow it and moves on — otherwise the plans someone is about to
27
+ create are invisible to their team and nothing tells them.
28
+ - **Init still never creates a `.gitignore`** where none exists. `archive-plan.sh` does,
29
+ because it has just moved files into `.archive/` and that path must be ignored for the
30
+ move to mean anything.
31
+
32
+ sm plan output remains byte-identical. Test suite grows to 119 assertions.
33
+
34
+ ## [3.3.1] - 2026-09-04
35
+
36
+ ### Fixed — a plan that documented markdown could not complete (#14)
37
+
38
+ `plan-status.sh` had one correct frontmatter reader and three that scanned whole files:
39
+ the checkbox counter, the mandatory gate, and blocked detection. A `notes.md` that merely
40
+ *documented* the contract — which is what notes.md is for — tripped all three:
41
+
42
+ - a fenced `- [ ]` example inflated the denominator, so the plan could never reach
43
+ COMPLETE. A quoted `- [x]` cancelled out; a quoted `- [ ]` did not.
44
+ - a fenced `mandatory: true` held the plan open with the box count showing a perfect
45
+ `1/1` — **no visible signal at all**, and the documented triage steps pointed at a
46
+ notes file that was pure prose. Regression from #13.
47
+ - a fenced `status: blocked` produced a false `blocked` verdict, masked whenever the plan
48
+ was otherwise COMPLETE, so it surfaced only intermittently.
49
+
50
+ `archive-plan.sh` inherited all three through its pre-flight and refused to archive,
51
+ advising `--force` — wrong advice for a miscount.
52
+
53
+ The fix splits in two, because these are not the same defect:
54
+
55
+ - **Checkboxes are body content**, so counting is now fence-aware — backtick and tilde
56
+ fences, tagged or not, indented, closing only on their own character. An unterminated
57
+ fence swallows the rest of the file: ambiguous content is not counted as outstanding.
58
+ - **`status:` and `mandatory:` are frontmatter fields**, so they are read from the leading
59
+ `---` block via the existing scoped reader, generalised as `frontmatter_field`. That is
60
+ strictly stronger than fence-stripping — it also rejects the field appearing in prose or
61
+ a table.
62
+
63
+ All consumers — `archive-plan.sh`, `/plan-status`, the SessionStart hook — shell out to
64
+ `plan-status.sh` and needed no change. Test suite grows to 109 assertions.
65
+
66
+ ## [3.3.0] - 2026-09-04
67
+
68
+ ### Fixed — lg task lists were maintained by hand, and the mandatory closers were unenforceable (#12)
69
+
70
+ `init-task.sh` never wrote to `phase.md` — it referenced the file only in an existence
71
+ check — and `init-atom.sh` never wrote the atom into its task. So **every lg task list was
72
+ maintained by hand**: create six task directories and the phase still reported
73
+ `(no tasks yet)`. The "closers must stay last" rule therefore governed a list no tool
74
+ produced, and the test that claimed to cover it only ever inspected a freshly rendered
75
+ template, which can never be wrong.
76
+
77
+ - **Creating a child writes it into its parent's list.** `planning_insert_list_item` in
78
+ `scripts/lib/planning.sh` inserts above the first `MANDATORY` entry — so the closers stay
79
+ last *by construction* — appends after the last item in sections with no MANDATORY
80
+ entries, drops the placeholder on first use, is idempotent under `PLANNING_FORCE=1`, and
81
+ is section-scoped. It anchors on the MANDATORY marker, never on line numbers, because the
82
+ list is a human-editable surface.
83
+ - **The closers are real task directories now.** `init-phase.sh` scaffolds
84
+ `validate-success-through-comprehensive-testing/` and
85
+ `documentation-pass-create-update-deprecate-docs/` with `task.md` (`mandatory: true`,
86
+ `parallelizable: false`), `notes.md`, `atoms/`, and seeded atoms. Previously the two most
87
+ important tasks in every plan were the only ones with no artifact a subagent could read.
88
+ - **Placeholders stopped counting as work.** `(no tasks yet …)` and `(no atoms yet …)`
89
+ shipped as real checkboxes, and `plan-status.sh` counts every box under a plan — a fresh
90
+ phase with two tasks reported `0/5`, a plan could reach 100% by ticking lines asserting
91
+ nothing existed, and a finished phase stayed open until someone ticked "no tasks yet".
92
+ They are italic text now; `plan-status.sh` needed no change.
93
+ - **The completion gate is real.** `plan-status.sh` refuses `COMPLETE` while any
94
+ `mandatory: true` task's own `status:` is not `done`. Ticking its checkbox is not enough.
95
+ `archive-plan.sh` inherits this through its existing pre-flight rather than duplicating
96
+ the rule. Strictly additive: plans with no `mandatory:` frontmatter behave exactly as
97
+ before.
98
+
99
+ Test suite grows to 99 assertions, every new one mutating the plan before asserting.
100
+ sm mode verified byte-identical against the pre-change render. New docs:
101
+ `.documentation/architecture/lg-plan-artifact-lifecycle.md`,
102
+ `.documentation/reference/mandatory-frontmatter.md`,
103
+ `.documentation/troubleshooting/plan-never-reads-complete.md`.
104
+
105
+ ## [3.2.0] - 2026-09-04
106
+
107
+ ### Fixed — Stale skill directories run frozen code (#10)
108
+
109
+ A consumer repo could run a **pre-3.1.0 copy** of the skill indefinitely while the update
110
+ check reported the current version — no nudge, no warning, exit 0 everywhere. Plans
111
+ generated that way silently omitted the mandatory validate and documentation phases and
112
+ the entire `## On Completion` archive block: precisely the guarantees 3.1.0 was released
113
+ to make.
114
+
115
+ **Cause.** v1's `persistent-planning install` (removed in 2.0.0) *copied*
116
+ `skills/persistent-planning/` into `.claude/skills/`. The v2+ linker only symlinks, and
117
+ when it finds a real directory at the destination it warns and skips — permanently. So
118
+ `installedVersion()` reported the plugin's version while `/start-planning` executed the
119
+ skill dir's frozen copy. Two artifacts, nothing reconciling them. (The linker was never
120
+ copying, as first reported; it was refusing to reclaim what v1 left behind.)
121
+
122
+ - **Reclaim instead of skip** — `scripts/lib/skill-link.js` renames a real directory to
123
+ `<name>.bak-<ISO8601>` before the runtime's linker runs, leaving a clean destination it
124
+ then symlinks normally. Nothing is ever deleted; a failed rename falls through to the
125
+ old skip but says so loudly and names the fix. Idempotent — a healthy symlink is left
126
+ alone, so a second run makes no second backup. Opt out with
127
+ `PERSISTENT_PLANNING_NO_RECLAIM=1`.
128
+ - **The drift is detectable now.** The primary signal is structural: a real directory at
129
+ `.claude/skills/<name>` is *always* drift, because nothing in the current system creates
130
+ one. A `.version` marker beside `SKILL.md` is the secondary signal — how far behind a
131
+ drifted copy is, and the only signal available where symlinks are impossible. Only
132
+ healthy symlinks are stamped; stamping a stale copy would mark it current.
133
+ - **SessionStart reports it**, naming the path, the running vs installed version, the
134
+ user-visible consequence, and `npx persistent-planning relink`. Merged into the existing
135
+ single JSON response; fails open; silent under `updatePolicy: off`.
136
+ - **SessionStart repairs it under `updatePolicy: auto`**, once per plugin version. This is
137
+ the part that reaches the installs that are actually broken: a marketplace install has
138
+ no `node_modules` in the plugin cache and **never runs npm postinstall**, so a fix
139
+ shipped only through postinstall would reach nobody affected. The hook is the one thing
140
+ that runs every session in that shape. `nudge` warns without touching the filesystem;
141
+ `off` does nothing at all.
142
+ - **No more clean exits for no-ops.** `update` with no managed install exits 1 and lists
143
+ every path probed, instead of printing `(not installed)` twice and exiting 0. `relink`
144
+ gained `CLAUDE_PLUGIN_ROOT/scripts/` and self-package probes — it previously could not
145
+ run at all in a marketplace-only install, the shape that needs it most — and no longer
146
+ swallows the linker's exit code.
147
+
148
+ Test suite grows to 74 assertions, including a marketplace-shaped fixture with no
149
+ `node_modules`. New docs: `.documentation/troubleshooting/stale-skill-dir-drift.md`,
150
+ `.documentation/architecture/skill-linking-and-reclaim.md`,
151
+ `.documentation/reference/skill-version-marker.md`,
152
+ `.documentation/procedures/plugin-update-delivery.md`.
153
+
154
+ ## [3.1.0] - 2026-08-31
155
+
156
+ ### Added — Status tracking and completion archive (#4)
157
+
158
+ Plans now report their own completion, and completed plans get retired out of the active tree.
159
+
160
+ **Completion is derived, not declared.** A plan is COMPLETE when every checkbox under it is checked, or when its top-level artifact (`phase.md` / `task_plan.md` / `task.md`) declares `status: done`. Nothing has to be remembered or kept in sync — checking the last box *is* the signal. Combined with the mandatory closing phases above, a plan cannot read COMPLETE until its work has been tested and documented.
161
+
162
+ - `scripts/plan-status.sh` — the single implementation of the scan. Default output is a table (`in progress` / `blocked` / `COMPLETE` / `empty` / `archived` with a checked/total count); `--complete` prints one complete slug per line; `--nudge` prints a one-line notice or nothing.
163
+ - `scripts/archive-plan.sh` — moves `.planning/<slug>/` to `.planning/.archive/<slug>/`, ensures that path is gitignored, and stamps the top-level artifact `status: archived` + `archived_on` (or a dated footer for sm plans without frontmatter). Prefers `git mv` when the plan is tracked. Refuses incomplete plans unless `--force`; also supports `--all-complete` and `--dry-run`. Nothing is ever deleted.
164
+ - `hooks/session-start.js` — now surfaces complete-but-unarchived plans in the session's context. It merges the notice into the runtime's single `SessionStart` response by intercepting that one stdout write, since the runtime exposes no append hook and a second response line would be invalid; it fails open, so the update check is unaffected if the payload isn't the expected shape.
165
+ - `/plan-status` and `/archive-plan` slash commands.
166
+ - Both plan templates gained an `## On Completion` section stating the rule and the archive command, so an agent reading only the plan still learns the protocol.
167
+
168
+ `.planning/.archive/` is gitignored on purpose: a completed plan is local history. Anything worth sharing gets promoted into a real doc by the mandatory documentation phase.
169
+
170
+ Test suite grows to 42 assertions. New doc: `.documentation/procedures/plan-completion-and-archive.md`.
171
+
172
+ ### Added — Mandatory closing phases (#5)
173
+
174
+ Every plan now ends with the same two units of work, seeded by the templates so an agent never has to remember them:
175
+
176
+ 1. **Validate success through comprehensive testing**
177
+ 2. **Documentation pass — create/update/deprecate docs**
178
+
179
+ - **sm mode**: `task_plan.md` seeds 6 phases instead of 4; phases 5 and 6 are the mandatory pair, marked `MANDATORY`.
180
+ - **lg mode**: `templates/lg/phase.md` seeds the pair as the last two task checkboxes. A phase cannot be marked `done` until both are `done`, and neither may be `parallelizable`.
181
+ - Both templates carry the ordering rule inline: new work is inserted **above** the pair, never after it.
182
+
183
+ ### Added — Test suite
184
+
185
+ `tests/run.sh` — plain bash asserts (no framework), wired to `npm test`. 21 assertions covering sm/lg init, the closing-phase ordering, slug conversion, template placeholder substitution, atom sequence auto-increment, idempotent re-runs, and the lg-mode guard on `init-phase.sh`.
186
+
187
+ ### Changed — Documentation moved to hit-em-with-the-docs
188
+
189
+ `docs/` is gone; documentation now lives in a hewtd-managed `.documentation/` tree, split by domain:
190
+
191
+ | Was | Now |
192
+ |---|---|
193
+ | `docs/lg-mode.md` | `.documentation/architecture/lg-mode.md` |
194
+ | `docs/reference.md` | `.documentation/architecture/context-engineering-principles.md` |
195
+ | `docs/atom-granularity.md` | `.documentation/standards/atom-granularity.md` |
196
+ | `docs/workspace-json.md` | `.documentation/reference/workspace-json.md` |
197
+ | `docs/examples.md` | `.documentation/quickstart/examples.md` |
198
+
199
+ New docs: `.documentation/standards/mandatory-closing-phases.md` and `.documentation/testing/test-suite.md`. A custom `reference` domain is registered in `.claude/hit-em-with-the-docs.json`. The npm `files` array now ships `.documentation/` in place of `docs/`.
200
+
201
+ Links in older CHANGELOG entries still point at the old `docs/` paths; they are left as written, since they describe the layout as it was at those releases.
202
+
5
203
  ## [3.0.1] - 2026-05-08
6
204
 
7
205
  ### Fixed
package/README.md CHANGED
@@ -7,6 +7,13 @@ A Claude Code plugin that uses on-disk markdown files as "working memory" for pl
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
8
  [![Plugin](https://img.shields.io/badge/Claude%20Code-Plugin-blue)](https://github.com/TheGlitchKing/persistent-planning)
9
9
 
10
+ > [!NOTE]
11
+ > **New in 3.0.0 — sm/lg modes + layered planning.** Solo work and quick spikes still get the original single-task flow (now called **sm mode**). Multi-week projects with multiple contributors get a new **lg mode** with layered phase / task / atom / notes artifacts that subagents can pick up via [semantic-memory](https://github.com/TheGlitchKing/semantic-sidekick)'s MCP. Mode is auto-detected from 90-day git author count; sm preserved bit-for-bit from v2. See [`.documentation/architecture/lg-mode.md`](./.documentation/architecture/lg-mode.md) for the layered model + [`.documentation/standards/atom-granularity.md`](./.documentation/standards/atom-granularity.md) for the inline-checkbox-vs-standalone-atom decision rule.
12
+ >
13
+ > Two new slash commands ship in 3.0: `/start-task "Name" --parent <phase>` and `/start-atom "Name" --parent <task>` (lg-mode only). `/start-planning` now dispatches to either flow based on detected mode (with `--mode sm|lg` override).
14
+ >
15
+ > All lg-mode artifacts carry [HEWTD](https://github.com/TheGlitchKing/hit-em-with-the-docs) 2.2.0+ frontmatter (`tier: "plan"`).
16
+
10
17
  ---
11
18
 
12
19
  ## Why This Plugin?
@@ -161,6 +168,8 @@ persistent-planning/
161
168
  │ └── persistent-planning.js # CLI (update/policy/status/relink)
162
169
  ├── commands/
163
170
  │ ├── start-planning.md # /start-planning slash command
171
+ │ ├── plan-status.md # /plan-status
172
+ │ ├── archive-plan.md # /archive-plan
164
173
  │ ├── update.md # /persistent-planning:update
165
174
  │ ├── policy.md # /persistent-planning:policy
166
175
  │ ├── status.md # /persistent-planning:status
@@ -169,26 +178,77 @@ persistent-planning/
169
178
  │ ├── hooks.json # SessionStart hook manifest
170
179
  │ └── session-start.js # Runtime-delegated hook
171
180
  ├── scripts/
181
+ │ ├── init-*.sh # planning artifact creation (sm + lg)
182
+ │ ├── plan-status.sh # completion scan (single implementation)
183
+ │ ├── archive-plan.sh # retire a completed plan
172
184
  │ └── link-skills.js # Postinstall (runtime-delegated)
173
185
  ├── skills/
174
186
  │ └── persistent-planning/
175
187
  │ └── SKILL.md # Core skill definition
176
- ├── docs/
177
- │ ├── reference.md # Manus context engineering principles
178
- │ └── examples.md # Worked examples
188
+ ├── templates/lg/ # phase / task / atom / notes templates (lg mode)
189
+ ├── tests/
190
+ │ └── run.sh # bash smoke tests (npm test)
191
+ ├── .documentation/ # hewtd-managed docs — start at INDEX.md
192
+ │ ├── architecture/ # lg-mode layer model, context-engineering rationale
193
+ │ ├── standards/ # mandatory closing phases, atom granularity
194
+ │ ├── reference/ # workspace.json schema
195
+ │ ├── testing/ # test suite guide
196
+ │ └── quickstart/ # worked examples
179
197
  ├── README.md
180
198
  ├── LICENSE
181
199
  └── CHANGELOG.md
182
200
  ```
183
201
 
202
+ ## Status tracking and archive
203
+
204
+ A plan is **complete** when every checkbox in it is checked (or its top-level artifact says `status: done`). Completion is derived from the artifacts, so it cannot drift from what the plan actually says — checking the last box *is* the signal.
205
+
206
+ ```
207
+ /plan-status # what's in progress, blocked, or complete
208
+ /archive-plan <slug> # retire a completed plan
209
+ /archive-plan --all-complete # retire all of them
210
+ ```
211
+
212
+ Archiving moves `.planning/<slug>/` to the gitignored `.planning/.archive/<slug>/` and stamps it `status: archived` + `archived_on`. Nothing is deleted — restore by moving the directory back out.
213
+
214
+ The SessionStart hook mentions complete-but-unarchived plans at the top of the next session, so a finished plan gets retired instead of rediscovered. Full protocol: [Plan Completion and Archive](./.documentation/procedures/plan-completion-and-archive.md).
215
+
216
+ ## Documentation
217
+
218
+ Docs are managed by [hit-em-with-the-docs](https://github.com/TheGlitchKing/hit-em-with-the-docs) and live in `.documentation/`, split by domain. Start at [`.documentation/INDEX.md`](./.documentation/INDEX.md).
219
+
220
+ | Doc | What it covers |
221
+ |---|---|
222
+ | [Lg-Mode Layered Planning Guide](./.documentation/architecture/lg-mode.md) | phase / task / atom / notes layer model, scheduling, subagent contract |
223
+ | [Manus Context Engineering Principles](./.documentation/architecture/context-engineering-principles.md) | the rationale the whole plugin is built on |
224
+ | [Mandatory Closing Phases](./.documentation/standards/mandatory-closing-phases.md) | the two phases every plan must end with, and why |
225
+ | [Atom Granularity](./.documentation/standards/atom-granularity.md) | inline checkbox vs. standalone atom file |
226
+ | [workspace.json Reference](./.documentation/reference/workspace-json.md) | mode tracker schema |
227
+ | [Plan Completion and Archive](./.documentation/procedures/plan-completion-and-archive.md) | how completion is detected and how plans are retired |
228
+ | [Test Suite](./.documentation/testing/test-suite.md) | what `npm test` covers, how to add a case |
229
+ | [Worked Examples](./.documentation/quickstart/examples.md) | end-to-end planning walkthroughs |
230
+
231
+ `INDEX.md` and `REGISTRY.md` are generated — change the documents, then run `npx hewtd maintain --quick`.
232
+
233
+ ## Testing
234
+
235
+ ```bash
236
+ npm test # bash smoke tests over the init scripts (tests/run.sh)
237
+ ```
238
+
184
239
  ## Cleanup
185
240
 
241
+ Prefer archiving — it keeps the record of what was done:
242
+
186
243
  ```bash
187
- # Remove a single task's planning files
188
- rm -rf .planning/[task-name]/
244
+ /archive-plan [task-name]
245
+ ```
189
246
 
190
- # Remove all planning files
191
- rm -rf .planning/
247
+ Hard deletion still works, but throws that record away:
248
+
249
+ ```bash
250
+ rm -rf .planning/[task-name]/ # one plan
251
+ rm -rf .planning/ # everything, archive included
192
252
  ```
193
253
 
194
254
  ## Acknowledgments
@@ -5,25 +5,49 @@ import { registerUpdateCommands } from "@theglitchking/claude-plugin-runtime";
5
5
  import { createRequire } from "node:module";
6
6
  import { spawnSync } from "node:child_process";
7
7
  import { existsSync } from "node:fs";
8
- import { join, resolve } from "node:path";
8
+ import { dirname, join, resolve } from "node:path";
9
+ import { fileURLToPath } from "node:url";
9
10
 
10
11
  const require_ = createRequire(import.meta.url);
11
12
  const { version } = require_("../package.json");
12
13
 
13
14
  const PKG = "@theglitchking/persistent-planning";
14
15
 
16
+ // Where the linker can live, most specific first. The third probe matters: in a
17
+ // marketplace-only install there is no node_modules and cwd is the consumer repo,
18
+ // so the first two both miss and relink -- the one command that repairs a stale
19
+ // skill dir -- could not run at all in exactly the shape that needs it.
20
+ function linkerCandidates(cwd) {
21
+ const out = [
22
+ join(cwd, "node_modules", "@theglitchking", "persistent-planning", "scripts", "link-skills.js"),
23
+ resolve(process.cwd(), "scripts", "link-skills.js"),
24
+ ];
25
+ if (process.env.CLAUDE_PLUGIN_ROOT) {
26
+ out.push(join(process.env.CLAUDE_PLUGIN_ROOT, "scripts", "link-skills.js"));
27
+ }
28
+ // The package this CLI is itself running from — correct for `npx <pkg> relink`.
29
+ out.push(resolve(dirname(fileURLToPath(import.meta.url)), "..", "scripts", "link-skills.js"));
30
+ return out;
31
+ }
32
+
15
33
  function runRelink(cwd) {
16
- const linker = join(cwd, "node_modules", "@theglitchking", "persistent-planning", "scripts", "link-skills.js");
17
- const script = existsSync(linker) ? linker : resolve(process.cwd(), "scripts", "link-skills.js");
18
- if (!existsSync(script)) {
19
- console.error("link-skills.js not found — is the package installed?");
34
+ const candidates = linkerCandidates(cwd);
35
+ const script = candidates.find((p) => existsSync(p));
36
+ if (!script) {
37
+ // ponytail: never exit 0 after doing nothing — a clean success for a no-op is
38
+ // how the stale-skill-dir bug stayed invisible for five months (issue #10).
39
+ console.error("relink failed: link-skills.js not found. Looked in:");
40
+ for (const p of candidates) console.error(` ${p}`);
41
+ console.error("\nIs @theglitchking/persistent-planning installed, or CLAUDE_PLUGIN_ROOT set?");
42
+ process.exitCode = 1;
20
43
  return;
21
44
  }
22
- spawnSync(process.execPath, [script], {
45
+ const r = spawnSync(process.execPath, [script], {
23
46
  cwd,
24
47
  env: { ...process.env, INIT_CWD: cwd },
25
48
  stdio: "inherit",
26
49
  });
50
+ if (r.status !== 0) process.exitCode = r.status ?? 1;
27
51
  }
28
52
 
29
53
  program
@@ -31,6 +55,32 @@ program
31
55
  .description("Persistent markdown-based planning for Claude Code.")
32
56
  .version(version);
33
57
 
58
+ // The runtime's `update` resolves the installed version, finds none in a
59
+ // marketplace-only install, prints "Current: (not installed) / Now: (not installed)"
60
+ // and exits 0 -- a clean success for a no-op. Fail before it gets that far, and say
61
+ // where we looked. Same defect as runRelink's missing third probe (issue #10, fix #4).
62
+ // Deliberately NOT including the package this CLI runs from: under
63
+ // `npx --no @theglitchking/persistent-planning update` that copy always exists, which
64
+ // is what let the original bug report see a clean exit 0 for a no-op. Only a *managed*
65
+ // install -- a project dependency or a marketplace plugin root -- is updatable.
66
+ function installCandidates(cwd) {
67
+ const out = [join(cwd, "node_modules", "@theglitchking", "persistent-planning", "package.json")];
68
+ if (process.env.CLAUDE_PLUGIN_ROOT) out.push(join(process.env.CLAUDE_PLUGIN_ROOT, "package.json"));
69
+ return out;
70
+ }
71
+
72
+ program.hook("preAction", (_thisCmd, actionCmd) => {
73
+ if (actionCmd.name() !== "update") return;
74
+ const candidates = installCandidates(process.cwd());
75
+ if (candidates.some((p) => existsSync(p))) return;
76
+ console.error("update failed: no managed install of @theglitchking/persistent-planning found.");
77
+ console.error("Looked in:");
78
+ for (const p of candidates) console.error(` ${p}`);
79
+ console.error("\nInstall it with `npm i -D @theglitchking/persistent-planning`,");
80
+ console.error("or update the marketplace plugin with `/plugin` inside Claude Code.");
81
+ process.exit(1);
82
+ });
83
+
34
84
  registerUpdateCommands(program, {
35
85
  packageName: PKG,
36
86
  pluginName: "persistent-planning",
@@ -0,0 +1,66 @@
1
+ ---
2
+ name: archive-plan
3
+ description: "Retire a completed plan into the gitignored .planning/.archive/ directory. Refuses to archive a plan that still has unchecked boxes unless --force is passed. Works in both sm and lg mode."
4
+ ---
5
+
6
+ # /archive-plan
7
+
8
+ Move a finished plan out of the active tree so `.planning/` only ever shows work
9
+ that is still live. Nothing is deleted — archiving is a move plus a status stamp,
10
+ and is reversed by moving the directory back.
11
+
12
+ ---
13
+
14
+ ## Usage
15
+
16
+ ```
17
+ /archive-plan <plan-slug>
18
+ /archive-plan --all-complete
19
+ /archive-plan <plan-slug> --force # archive a plan that is not finished
20
+ /archive-plan <plan-slug> --dry-run
21
+ ```
22
+
23
+ ## What To Do
24
+
25
+ When the user runs `/archive-plan`:
26
+
27
+ 1. Run the script:
28
+
29
+ ```bash
30
+ SCRIPT_DIR="$(dirname "$(readlink -f "$0")")/../scripts"
31
+ bash "${SCRIPT_DIR}/archive-plan.sh" "<plan-slug>"
32
+ ```
33
+
34
+ If the script isn't found at that path, try in order:
35
+
36
+ ```bash
37
+ bash scripts/archive-plan.sh "<plan-slug>"
38
+ bash ~/.claude/skills/persistent-planning/scripts/archive-plan.sh "<plan-slug>"
39
+ ```
40
+
41
+ 2. If the script refuses because the plan is incomplete, **do not reach for
42
+ `--force` on your own.** Run `/plan-status`, tell the user what is still
43
+ unchecked, and let them decide.
44
+
45
+ ## What it does
46
+
47
+ 1. Verifies the plan is complete (every checkbox checked, or `status: done`).
48
+ 2. Ensures `.planning/.archive/` exists and is listed in `.gitignore` — completed
49
+ plans are local history, not something every clone carries.
50
+ 3. Moves `.planning/<slug>/` to `.planning/.archive/<slug>/`, using `git mv` when
51
+ the plan is tracked so history follows it.
52
+ 4. Stamps the plan's top-level artifact: `status: archived` plus `archived_on`
53
+ (frontmatter), or a dated footer for sm plans that have no frontmatter.
54
+
55
+ ## Restoring
56
+
57
+ ```bash
58
+ mv .planning/.archive/<slug> .planning/<slug>
59
+ ```
60
+
61
+ Then set `status:` back to `active` and drop the `archived_on` stamp.
62
+
63
+ ## See also
64
+
65
+ - `/plan-status` — see which plans are complete
66
+ - `.documentation/procedures/plan-completion-and-archive.md` — the full completion protocol
@@ -0,0 +1,62 @@
1
+ ---
2
+ name: plan-status
3
+ description: "Show completion status for every plan under .planning/ — which are in progress, blocked, or complete and ready to archive. Works in both sm and lg mode."
4
+ ---
5
+
6
+ # /plan-status
7
+
8
+ Report where every plan stands. Completion is derived from the plan artifacts
9
+ themselves (checkbox state + frontmatter `status:`), so it cannot drift away from
10
+ what the plan actually says.
11
+
12
+ ---
13
+
14
+ ## Usage
15
+
16
+ ```
17
+ /plan-status
18
+ ```
19
+
20
+ ## What To Do
21
+
22
+ Run the status script:
23
+
24
+ ```bash
25
+ SCRIPT_DIR="$(dirname "$(readlink -f "$0")")/../scripts"
26
+ bash "${SCRIPT_DIR}/plan-status.sh"
27
+ ```
28
+
29
+ If the script isn't found at that path, try in order:
30
+
31
+ ```bash
32
+ bash scripts/plan-status.sh
33
+ bash ~/.claude/skills/persistent-planning/scripts/plan-status.sh
34
+ ```
35
+
36
+ Then read the table back to the user. If any plan is listed `COMPLETE`, offer to
37
+ archive it with `/archive-plan <slug>`.
38
+
39
+ ## Verdicts
40
+
41
+ | Verdict | Meaning |
42
+ |---|---|
43
+ | `in progress` | Unchecked boxes remain |
44
+ | `blocked` | An atom in the plan carries `status: blocked` |
45
+ | `COMPLETE` | Every box checked, or the top-level artifact says `status: done` — ready to archive |
46
+ | `empty` | Plan artifact exists but has no checkboxes yet |
47
+ | `archived` | Already retired (only visible if left in the active tree) |
48
+
49
+ ## Machine-readable forms
50
+
51
+ ```bash
52
+ bash scripts/plan-status.sh --complete # one complete plan slug per line
53
+ bash scripts/plan-status.sh --nudge # one-line notice, or silence
54
+ ```
55
+
56
+ `--nudge` is what the SessionStart hook uses, so a finished plan gets mentioned
57
+ at the top of the next session rather than being rediscovered later.
58
+
59
+ ## See also
60
+
61
+ - `/archive-plan` — retire a completed plan into `.planning/.archive/`
62
+ - `.documentation/procedures/plan-completion-and-archive.md` — the full completion protocol
@@ -69,7 +69,7 @@ Not every step needs a standalone atom file. The rule of thumb:
69
69
  - **Inline checkbox in `task.md`**: simple, self-contained step that doesn't need its own context file. The user (or the active agent) handles it directly.
70
70
  - **Standalone atom file via `/start-atom`**: a step that will be **handed off to a subagent**. Atoms get their own files because subagents need explicit inputs / outputs / acceptance criteria they can read structured rather than parse from prose.
71
71
 
72
- See `docs/atom-granularity.md` for full anti-pattern guidance with examples.
72
+ See `.documentation/standards/atom-granularity.md` for full anti-pattern guidance with examples.
73
73
 
74
74
  ## Sequence semantics
75
75
 
@@ -89,5 +89,5 @@ This command refuses to run if the project is in sm mode. To switch:
89
89
 
90
90
  - `/start-planning` — initialize the planning structure (phase in lg)
91
91
  - `/start-task` — add a task under a phase
92
- - `docs/lg-mode.md` — full lg-mode layer model
93
- - `docs/atom-granularity.md` — when to spawn an atom file vs. inline checkbox
92
+ - `.documentation/architecture/lg-mode.md` — full lg-mode layer model
93
+ - `.documentation/standards/atom-granularity.md` — when to spawn an atom file vs. inline checkbox
@@ -111,5 +111,5 @@ Names are converted to URL-friendly slugs:
111
111
 
112
112
  - `/start-task` — add a task under a phase (lg mode only)
113
113
  - `/start-atom` — add an atom (subagent hand-off unit) under a task (lg mode only)
114
- - `docs/workspace-json.md` — workspace.json schema reference
115
- - `docs/lg-mode.md` — full lg-mode guide (phase / task / atom / notes layer model)
114
+ - `.documentation/reference/workspace-json.md` — workspace.json schema reference
115
+ - `.documentation/architecture/lg-mode.md` — full lg-mode guide (phase / task / atom / notes layer model)
@@ -79,5 +79,5 @@ That writes `.planning/.meta/workspace.json` with `mode: "lg"` and creates the f
79
79
 
80
80
  - `/start-planning` — initialize the planning structure (phase in lg, task in sm)
81
81
  - `/start-atom` — add an atom under a task
82
- - `docs/lg-mode.md` — full lg-mode layer model
83
- - `docs/atom-granularity.md` — when to spawn an atom file vs. add an inline checkbox
82
+ - `.documentation/architecture/lg-mode.md` — full lg-mode layer model
83
+ - `.documentation/standards/atom-granularity.md` — when to spawn an atom file vs. add an inline checkbox