planrails 0.2.1 → 0.3.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/CHANGELOG.md +29 -0
- package/PLANNER.md +42 -7
- package/README.md +23 -16
- package/bin/planrails.mjs +11 -9
- package/package.json +1 -1
- package/tools/check-plans.mjs +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0 — 2026-09-12
|
|
4
|
+
|
|
5
|
+
Two changes, both asked for by a user planning a long, multi-session feature:
|
|
6
|
+
carry learnings forward so a mistake is not re-paid in the next chat, and tidy the
|
|
7
|
+
installed files into one folder.
|
|
8
|
+
|
|
9
|
+
- **Learnings are now a first-class, reloaded part of a plan.** `PLAN.md` gains a
|
|
10
|
+
`## Learnings` section: each line is the trap and the rule it taught. It reloads
|
|
11
|
+
with the plan at the start of every session — and after every compaction —
|
|
12
|
+
through the same reload line, so the next session reads the lesson before it
|
|
13
|
+
repeats the struggle. A learning is distinct from a `Rule` (a constraint known
|
|
14
|
+
up front) and a `Decision` (a choice and why). `PLANNER.md` makes capturing a
|
|
15
|
+
learning a step of the execute loop, written the moment a task fights back; tells
|
|
16
|
+
a resuming session to read the Learnings first; and graduates a learning that
|
|
17
|
+
outlives the plan to the always-loaded file. Until now the only place for a
|
|
18
|
+
lesson was a `LOG.md` line, and the log is neither reloaded nor re-read — which
|
|
19
|
+
is exactly why the same struggle returned in each new session.
|
|
20
|
+
- **The two installed files move into `.project-management/planrails/`.** `init`
|
|
21
|
+
now writes `.project-management/planrails/PLANNER.md` and
|
|
22
|
+
`.project-management/planrails/check-plans.mjs`, leaving `.project-management/`
|
|
23
|
+
holding just two folders: `planrails/` (the tool) and `plans/` (your plans). The
|
|
24
|
+
reload line is unchanged — `@.project-management/plans/<id>/PLAN.md`. If you ran
|
|
25
|
+
an older `init`, point your check command at the new path
|
|
26
|
+
(`node .project-management/planrails/check-plans.mjs`) and remove the two loose
|
|
27
|
+
files left at the `.project-management/` root.
|
|
28
|
+
- The checker's behaviour is unchanged: learnings are prose, enforced by the
|
|
29
|
+
method, not the gate, and a plan with no `Learnings` section still validates. A
|
|
30
|
+
test pins that a `Learnings` section does not confuse the parser. 34 tests.
|
|
31
|
+
|
|
3
32
|
## 0.2.1 — 2026-09-12
|
|
4
33
|
|
|
5
34
|
A careful post-release review, including an end-to-end test of the published
|
package/PLANNER.md
CHANGED
|
@@ -36,6 +36,13 @@ Three rules make the plan trustworthy. They are the whole point of this system:
|
|
|
36
36
|
code and last line are pasted into the plan. An empty evidence cell is not
|
|
37
37
|
done, whatever the status column says.
|
|
38
38
|
|
|
39
|
+
The plan is also the project's memory. Besides the tasks, PLAN.md carries the
|
|
40
|
+
**Rules** you must not break, the **Decisions** you made and why, and the
|
|
41
|
+
**Learnings** — a mistake or dead end, written as the rule that avoids it next
|
|
42
|
+
time. The reload line brings all of it back at the start of every session, so a
|
|
43
|
+
lesson learned in one chat is read by the next one *before* it repeats the
|
|
44
|
+
struggle. That is how you stop paying for the same mistake twice.
|
|
45
|
+
|
|
39
46
|
---
|
|
40
47
|
|
|
41
48
|
## §1 Get ready
|
|
@@ -110,16 +117,21 @@ Pick a short kebab-case `<id>` (`weekly-digest`). Then:
|
|
|
110
117
|
back on its own. (For a tool that does not do `@`-imports, put the plan's path
|
|
111
118
|
in `AGENTS.md` and open it by hand at the start of each session.)
|
|
112
119
|
- **Wire the checker, if the project runs Node and has a check command.**
|
|
113
|
-
`npx planrails init` already put it at `.project-management/check-plans.mjs`;
|
|
114
|
-
you did not run init, copy this repo's `tools/check-plans.mjs` there. Add
|
|
115
|
-
`node .project-management/check-plans.mjs` to the check command. Now the
|
|
116
|
-
fails if a task is marked done with no evidence. If the project is not Node,
|
|
120
|
+
`npx planrails init` already put it at `.project-management/planrails/check-plans.mjs`;
|
|
121
|
+
if you did not run init, copy this repo's `tools/check-plans.mjs` there. Add
|
|
122
|
+
`node .project-management/planrails/check-plans.mjs` to the check command. Now the
|
|
123
|
+
build fails if a task is marked done with no evidence. If the project is not Node,
|
|
117
124
|
skip this; the plan still works, and you enforce the gate yourself.
|
|
118
125
|
|
|
119
126
|
---
|
|
120
127
|
|
|
121
128
|
## §4 Execute — one task at a time
|
|
122
129
|
|
|
130
|
+
**At the start of every session, read the plan back first.** The reload line has
|
|
131
|
+
already loaded PLAN.md. Read **NOW**, then the **Rules** and the **Learnings**,
|
|
132
|
+
before you touch anything. The Learnings are mistakes a past session already paid
|
|
133
|
+
for — read them and you skip the struggle instead of repeating it.
|
|
134
|
+
|
|
123
135
|
The loop for each task:
|
|
124
136
|
|
|
125
137
|
1. **Set it doing.** Change the status cell to `doing`. Update **NOW**.
|
|
@@ -131,6 +143,10 @@ The loop for each task:
|
|
|
131
143
|
5. **Set it done.** Only now. Update **NOW** to point at the next task.
|
|
132
144
|
6. **Append one line to LOG.md** — what landed, what is next, anything learned,
|
|
133
145
|
any decision made.
|
|
146
|
+
7. **If the task fought back, record the learning.** An error, a wrong turn, an
|
|
147
|
+
hour lost before you found the cause — add it to PLAN.md under **Learnings** as
|
|
148
|
+
"trap → rule", with the real case. LOG.md holds what happened; Learnings holds
|
|
149
|
+
the rule, because Learnings reloads every session and the log does not.
|
|
134
150
|
|
|
135
151
|
**Update NOW before you end any turn.** NOW is the first thing a fresh session
|
|
136
152
|
reads. If it is stale, the next session repeats your work or starts in the wrong
|
|
@@ -158,6 +174,9 @@ the task `blocked` with the reason, and stop. Do not hand-fix state to look done
|
|
|
158
174
|
3. **Retire the plan.** Move its reload line out of "Active plans" into a
|
|
159
175
|
"Finished" list (or delete the line). The plan files stay on disk; they are the
|
|
160
176
|
record.
|
|
177
|
+
4. **Graduate any lasting learning.** A learning that is true beyond this feature
|
|
178
|
+
moves to the always-loaded file (`CLAUDE.md` / `AGENTS.md`), so it outlives the
|
|
179
|
+
plan you are retiring. One that was only about this work retires with it.
|
|
161
180
|
|
|
162
181
|
---
|
|
163
182
|
|
|
@@ -172,6 +191,11 @@ Each line here was paid for by a real failure in earlier planning systems:
|
|
|
172
191
|
A named command that must be run and pasted can.
|
|
173
192
|
- **Evidence at close** is the one machine-checkable rail worth keeping. The
|
|
174
193
|
checker enforces exactly this and nothing else.
|
|
194
|
+
- **Learnings live in the plan, not only the log.** The log is history a fresh
|
|
195
|
+
session does not re-read; the plan is reloaded every session. A mistake written
|
|
196
|
+
as a rule, where the next session will see it, is the only kind that stops being
|
|
197
|
+
repeated. The same struggle coming back in a new chat is the exact failure this
|
|
198
|
+
fixes.
|
|
175
199
|
- **Sub-agent findings are leads** because four spot-checked findings were each
|
|
176
200
|
right in direction and wrong in number, and a wrong number becomes a wrong plan.
|
|
177
201
|
- **Repo-relative paths** because absolute paths break on the next machine, and a
|
|
@@ -181,8 +205,10 @@ Each line here was paid for by a real failure in earlier planning systems:
|
|
|
181
205
|
package, and that is what broke on the projects that were not npm — Python,
|
|
182
206
|
pnpm, bun, monorepos, Windows. A prompt and a copied script work everywhere.
|
|
183
207
|
|
|
184
|
-
Keep it this simple.
|
|
185
|
-
|
|
208
|
+
Keep it this simple. The three rails — reload, proof, evidence — are the whole
|
|
209
|
+
machine-checked core. If you are tempted to add a config file, a second script, or
|
|
210
|
+
a fourth rail, you are rebuilding the thing this replaced. (Rules, Decisions and
|
|
211
|
+
Learnings are plain sections of the plan, not new machinery.)
|
|
186
212
|
|
|
187
213
|
---
|
|
188
214
|
|
|
@@ -232,6 +258,14 @@ updated: <YYYY-MM-DD HH:MM>
|
|
|
232
258
|
|------|----------|-----|
|
|
233
259
|
| <YYYY-MM-DD> | <what was chosen> | <the reason and what it rules out> |
|
|
234
260
|
|
|
261
|
+
## Learnings
|
|
262
|
+
<!-- Mistakes already paid for, so no later session repeats them. Each line: the
|
|
263
|
+
trap, then the rule it taught, with the real case. Not a Rule (a constraint
|
|
264
|
+
known up front) and not a Decision (a choice between options) — a learning is
|
|
265
|
+
what a failure taught you. Add one the moment a task fights back. This section
|
|
266
|
+
reloads with the plan every session; that is what makes the lesson stick. -->
|
|
267
|
+
- <the trap you hit> → <the rule that avoids it> (<the real case, one line>)
|
|
268
|
+
|
|
235
269
|
## Context (read during planning — do not re-read)
|
|
236
270
|
- <path> — <one line of what it holds>
|
|
237
271
|
````
|
|
@@ -251,5 +285,6 @@ Append-only. One entry per landed piece of work, newest at the bottom.
|
|
|
251
285
|
- files: <repo-relative paths touched>
|
|
252
286
|
- proof: <the command and its result — e.g. `npx vitest run tests/digest.test.ts` → exit 0, "6 passed">
|
|
253
287
|
- next: <what comes next; where you stopped if you paused>
|
|
254
|
-
- learned / decided: <anything a second reader needs; omit if nothing
|
|
288
|
+
- learned / decided: <anything a second reader needs; omit if nothing. A durable
|
|
289
|
+
trap also goes to PLAN.md § Learnings, which reloads every session>
|
|
255
290
|
````
|
package/README.md
CHANGED
|
@@ -28,15 +28,16 @@ From the root of your project:
|
|
|
28
28
|
npx planrails init
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
That copies two files into `.project-management/` and makes the
|
|
32
|
-
It writes **nothing else** — no `package.json`, no `npm install`,
|
|
33
|
-
edits to your `CLAUDE.md`. Run it again any time; it skips files that
|
|
34
|
-
exist. What lands:
|
|
31
|
+
That copies two files into `.project-management/planrails/` and makes the
|
|
32
|
+
`plans/` folder. It writes **nothing else** — no `package.json`, no `npm install`,
|
|
33
|
+
no hooks, no edits to your `CLAUDE.md`. Run it again any time; it skips files that
|
|
34
|
+
already exist. What lands:
|
|
35
35
|
|
|
36
36
|
```
|
|
37
37
|
.project-management/
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
planrails/
|
|
39
|
+
PLANNER.md the prompt your agent follows to plan and execute
|
|
40
|
+
check-plans.mjs the checker (the one machine-enforced rail)
|
|
40
41
|
plans/ your plans will live here, one folder each
|
|
41
42
|
```
|
|
42
43
|
|
|
@@ -44,8 +45,8 @@ Then, two steps:
|
|
|
44
45
|
|
|
45
46
|
1. **Tell your agent to plan with you.** In any coding agent:
|
|
46
47
|
|
|
47
|
-
> Follow `.project-management/PLANNER.md` and tell me when you are
|
|
48
|
-
> plan the next feature with me.
|
|
48
|
+
> Follow `.project-management/planrails/PLANNER.md` and tell me when you are
|
|
49
|
+
> ready to plan the next feature with me.
|
|
49
50
|
|
|
50
51
|
It reads your repo, reports what it found in eight lines, and waits. Then you
|
|
51
52
|
plan together, and it writes the plan and wires the reload line.
|
|
@@ -54,7 +55,7 @@ Then, two steps:
|
|
|
54
55
|
every commit (your `check` / `lint` / CI script):
|
|
55
56
|
|
|
56
57
|
```bash
|
|
57
|
-
node .project-management/check-plans.mjs
|
|
58
|
+
node .project-management/planrails/check-plans.mjs
|
|
58
59
|
```
|
|
59
60
|
|
|
60
61
|
Now the build fails if any task is marked done without pasted evidence.
|
|
@@ -76,9 +77,9 @@ The command is the same; the difference is what your agent sees.
|
|
|
76
77
|
### Without npm, or a non-Node project
|
|
77
78
|
|
|
78
79
|
No npm? Copy the two files by hand from this repo:
|
|
79
|
-
[`PLANNER.md`](PLANNER.md) → `.project-management/PLANNER.md`, and
|
|
80
|
+
[`PLANNER.md`](PLANNER.md) → `.project-management/planrails/PLANNER.md`, and
|
|
80
81
|
[`tools/check-plans.mjs`](tools/check-plans.mjs) →
|
|
81
|
-
`.project-management/check-plans.mjs`. Make a `.project-management/plans/`
|
|
82
|
+
`.project-management/planrails/check-plans.mjs`. Make a `.project-management/plans/`
|
|
82
83
|
folder. Done.
|
|
83
84
|
|
|
84
85
|
The checker needs Node to run. If your project has no Node at all, skip it — the
|
|
@@ -93,7 +94,11 @@ beside it in the same folder. Then `/plan` starts the same flow in any project.
|
|
|
93
94
|
## How a plan works
|
|
94
95
|
|
|
95
96
|
Each plan is two files: `PLAN.md` (the map and tracker) and `LOG.md` (append-only
|
|
96
|
-
history).
|
|
97
|
+
history). `PLAN.md` also carries the plan's memory — the rules to keep, the
|
|
98
|
+
decisions made, and the **learnings** (a mistake, written as the rule that avoids
|
|
99
|
+
it). Because the reload line brings `PLAN.md` back at the start of every session, a
|
|
100
|
+
lesson from one chat is read by the next one before it repeats the struggle. The
|
|
101
|
+
top of `PLAN.md` is what a fresh session reads first:
|
|
97
102
|
|
|
98
103
|
```
|
|
99
104
|
## NOW
|
|
@@ -115,9 +120,9 @@ is in [`examples/weekly-digest/`](examples/weekly-digest).
|
|
|
115
120
|
## The checker
|
|
116
121
|
|
|
117
122
|
```bash
|
|
118
|
-
node .project-management/check-plans.mjs
|
|
119
|
-
node .project-management/check-plans.mjs --verify
|
|
120
|
-
npx planrails check
|
|
123
|
+
node .project-management/planrails/check-plans.mjs # done tasks must name a proof and carry evidence
|
|
124
|
+
node .project-management/planrails/check-plans.mjs --verify # also re-run each done task's proof, expect exit 0
|
|
125
|
+
npx planrails check # the same, using the latest published checker
|
|
121
126
|
```
|
|
122
127
|
|
|
123
128
|
No dependencies. Node 20+, any OS (Windows included). The default is a fast
|
|
@@ -147,6 +152,8 @@ review found ten data-loss and silent-failure paths in that surface, and the
|
|
|
147
152
|
"works with any project" promise broke on pnpm, bun, non-Node projects,
|
|
148
153
|
monorepos and Windows. 0.2.0 keeps the idea and drops the weight: the same three
|
|
149
154
|
rails, as a prompt plus one checker, with a two-command CLI that only copies
|
|
150
|
-
files.
|
|
155
|
+
files. 0.3.0 makes learnings a reloaded part of every plan and groups the two
|
|
156
|
+
installed files under `.project-management/planrails/`. See
|
|
157
|
+
[`CHANGELOG.md`](CHANGELOG.md).
|
|
151
158
|
|
|
152
159
|
MIT.
|
package/bin/planrails.mjs
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
* planrails — a planner prompt and one checker. Two commands, both safe:
|
|
4
4
|
*
|
|
5
5
|
* npx planrails init [--dir DIR] [--force]
|
|
6
|
-
* Copies PLANNER.md and the checker into <project>/.project-management/
|
|
7
|
-
* makes the plans/ folder. It writes nothing else — no package.json, no npm
|
|
6
|
+
* Copies PLANNER.md and the checker into <project>/.project-management/planrails/
|
|
7
|
+
* and makes the plans/ folder. It writes nothing else — no package.json, no npm
|
|
8
8
|
* install, no hooks, no edits to your CLAUDE.md. Idempotent: it skips files
|
|
9
9
|
* that already exist unless you pass --force.
|
|
10
10
|
*
|
|
11
11
|
* npx planrails check [--dir DIR] [--verify]
|
|
12
12
|
* Runs the checker over the project's plans. --verify re-runs each done
|
|
13
|
-
* task's proof. Same as running the copied .project-management/check-plans.mjs.
|
|
13
|
+
* task's proof. Same as running the copied .project-management/planrails/check-plans.mjs.
|
|
14
14
|
*
|
|
15
15
|
* planrails --version | --help
|
|
16
16
|
*/
|
|
@@ -28,8 +28,8 @@ const HELP = `planrails ${version()} — a planner prompt and one checker.
|
|
|
28
28
|
npx planrails check [--dir DIR] [--verify] check the project's plans
|
|
29
29
|
planrails --version | --help
|
|
30
30
|
|
|
31
|
-
After init, tell your agent: Follow .project-management/PLANNER.md and plan <the feature> with me.
|
|
32
|
-
Add to the command you run before every commit: node .project-management/check-plans.mjs
|
|
31
|
+
After init, tell your agent: Follow .project-management/planrails/PLANNER.md and plan <the feature> with me.
|
|
32
|
+
Add to the command you run before every commit: node .project-management/planrails/check-plans.mjs
|
|
33
33
|
Full guide: https://github.com/vivmagarwal/planrails#readme`;
|
|
34
34
|
|
|
35
35
|
function flag(args, name) {
|
|
@@ -43,7 +43,9 @@ function init(args) {
|
|
|
43
43
|
const target = resolve(flag(args, "--dir") || ".");
|
|
44
44
|
const force = args.includes("--force");
|
|
45
45
|
const pm = join(target, ".project-management");
|
|
46
|
+
const sys = join(pm, "planrails");
|
|
46
47
|
const plans = join(pm, "plans");
|
|
48
|
+
mkdirSync(sys, { recursive: true });
|
|
47
49
|
mkdirSync(plans, { recursive: true });
|
|
48
50
|
|
|
49
51
|
const copy = (from, to, label) => {
|
|
@@ -52,18 +54,18 @@ function init(args) {
|
|
|
52
54
|
console.log(` + ${label}`);
|
|
53
55
|
};
|
|
54
56
|
console.log(`planrails ${version()} → ${target}`);
|
|
55
|
-
copy(join(ROOT, "PLANNER.md"), join(
|
|
56
|
-
copy(join(ROOT, "tools", "check-plans.mjs"), join(
|
|
57
|
+
copy(join(ROOT, "PLANNER.md"), join(sys, "PLANNER.md"), ".project-management/planrails/PLANNER.md");
|
|
58
|
+
copy(join(ROOT, "tools", "check-plans.mjs"), join(sys, "check-plans.mjs"), ".project-management/planrails/check-plans.mjs");
|
|
57
59
|
const keep = join(plans, ".gitkeep");
|
|
58
60
|
if (!existsSync(keep)) { writeFileSync(keep, ""); console.log(" + .project-management/plans/"); }
|
|
59
61
|
else console.log(" · .project-management/plans/ already present");
|
|
60
62
|
|
|
61
63
|
console.log(`
|
|
62
64
|
Next:
|
|
63
|
-
1. Tell your agent: Follow .project-management/PLANNER.md and plan <the feature> with me.
|
|
65
|
+
1. Tell your agent: Follow .project-management/planrails/PLANNER.md and plan <the feature> with me.
|
|
64
66
|
(Or, in Claude Code, use /plan if you installed the skill.)
|
|
65
67
|
2. Add to the command you run before every commit:
|
|
66
|
-
node .project-management/check-plans.mjs
|
|
68
|
+
node .project-management/planrails/check-plans.mjs
|
|
67
69
|
3. When the agent writes a plan, it adds one line to your CLAUDE.md so the plan
|
|
68
70
|
reloads after every compaction: @.project-management/plans/<id>/PLAN.md`);
|
|
69
71
|
return 0;
|
package/package.json
CHANGED
package/tools/check-plans.mjs
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
* (todo, doing, blocked, …). So no spelling of "done" — done, completed, ✅,
|
|
12
12
|
* shipped, a typo — can slip through unchecked.
|
|
13
13
|
*
|
|
14
|
-
* `npx planrails init` copies this file into a project's .project-management/;
|
|
15
|
-
* add `node .project-management/check-plans.mjs` to the command you run before
|
|
14
|
+
* `npx planrails init` copies this file into a project's .project-management/planrails/;
|
|
15
|
+
* add `node .project-management/planrails/check-plans.mjs` to the command you run before
|
|
16
16
|
* every commit. No dependencies. Runs on Node 20+ on any OS.
|
|
17
17
|
*
|
|
18
18
|
* node check-plans.mjs # structural: completion claims need proof + evidence
|