@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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.documentation/INDEX.md +224 -0
- package/.documentation/README.md +90 -0
- package/.documentation/REGISTRY.md +80 -0
- package/.documentation/agents/INDEX.md +43 -0
- package/.documentation/agents/REGISTRY.md +38 -0
- package/.documentation/api/INDEX.md +43 -0
- package/.documentation/api/REGISTRY.md +38 -0
- package/.documentation/architecture/INDEX.md +50 -0
- package/.documentation/architecture/REGISTRY.md +57 -0
- package/{docs/reference.md → .documentation/architecture/context-engineering-principles.md} +20 -1
- package/{docs → .documentation/architecture}/lg-mode.md +33 -8
- package/.documentation/architecture/lg-plan-artifact-lifecycle.md +104 -0
- package/.documentation/architecture/skill-linking-and-reclaim.md +84 -0
- package/.documentation/archive/README.md +46 -0
- package/.documentation/backups/INDEX.md +43 -0
- package/.documentation/backups/REGISTRY.md +38 -0
- package/.documentation/database/INDEX.md +43 -0
- package/.documentation/database/REGISTRY.md +38 -0
- package/.documentation/devops/INDEX.md +43 -0
- package/.documentation/devops/REGISTRY.md +38 -0
- package/.documentation/drafts/.gitkeep +1 -0
- package/.documentation/features/INDEX.md +43 -0
- package/.documentation/features/REGISTRY.md +38 -0
- package/.documentation/plans/INDEX.md +43 -0
- package/.documentation/plans/REGISTRY.md +38 -0
- package/.documentation/procedures/INDEX.md +43 -0
- package/.documentation/procedures/REGISTRY.md +53 -0
- package/.documentation/procedures/plan-completion-and-archive.md +185 -0
- package/.documentation/procedures/plugin-update-delivery.md +99 -0
- package/.documentation/quickstart/INDEX.md +42 -0
- package/.documentation/quickstart/REGISTRY.md +51 -0
- package/{docs → .documentation/quickstart}/examples.md +20 -0
- package/.documentation/reference/INDEX.md +49 -0
- package/.documentation/reference/REGISTRY.md +55 -0
- package/.documentation/reference/mandatory-frontmatter.md +71 -0
- package/.documentation/reference/skill-version-marker.md +70 -0
- package/{docs → .documentation/reference}/workspace-json.md +11 -5
- package/.documentation/security/INDEX.md +43 -0
- package/.documentation/security/REGISTRY.md +38 -0
- package/.documentation/standards/INDEX.md +43 -0
- package/.documentation/standards/REGISTRY.md +53 -0
- package/{docs → .documentation/standards}/atom-granularity.md +12 -5
- package/.documentation/standards/mandatory-closing-phases.md +145 -0
- package/.documentation/testing/INDEX.md +42 -0
- package/.documentation/testing/REGISTRY.md +51 -0
- package/.documentation/testing/test-suite.md +126 -0
- package/.documentation/troubleshooting/INDEX.md +43 -0
- package/.documentation/troubleshooting/REGISTRY.md +53 -0
- package/.documentation/troubleshooting/plan-never-reads-complete.md +109 -0
- package/.documentation/troubleshooting/stale-skill-dir-drift.md +115 -0
- package/.documentation/workflows/INDEX.md +43 -0
- package/.documentation/workflows/REGISTRY.md +38 -0
- package/CHANGELOG.md +198 -0
- package/README.md +67 -7
- package/bin/persistent-planning.js +56 -6
- package/commands/archive-plan.md +66 -0
- package/commands/plan-status.md +62 -0
- package/commands/start-atom.md +3 -3
- package/commands/start-planning.md +2 -2
- package/commands/start-task.md +2 -2
- package/hooks/session-start.js +191 -8
- package/package.json +6 -3
- package/scripts/archive-plan.sh +143 -0
- package/scripts/init-atom.sh +7 -0
- package/scripts/init-phase.sh +58 -6
- package/scripts/init-planning.sh +39 -4
- package/scripts/init-task.sh +7 -0
- package/scripts/lib/planning.sh +122 -0
- package/scripts/lib/skill-link.js +177 -0
- package/scripts/link-skills.js +38 -0
- package/scripts/plan-status.sh +196 -0
- package/skills/persistent-planning/SKILL.md +37 -9
- package/templates/lg/phase.md +22 -3
- 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
|
[](https://opensource.org/licenses/MIT)
|
|
8
8
|
[](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
|
-
├──
|
|
177
|
-
|
|
178
|
-
│ └──
|
|
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
|
-
|
|
188
|
-
|
|
244
|
+
/archive-plan [task-name]
|
|
245
|
+
```
|
|
189
246
|
|
|
190
|
-
|
|
191
|
-
|
|
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
|
|
17
|
-
const script =
|
|
18
|
-
if (!
|
|
19
|
-
|
|
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
|
package/commands/start-atom.md
CHANGED
|
@@ -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
|
|
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
|
-
-
|
|
93
|
-
-
|
|
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
|
-
-
|
|
115
|
-
-
|
|
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)
|
package/commands/start-task.md
CHANGED
|
@@ -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
|
-
-
|
|
83
|
-
-
|
|
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
|