pi-plan-task 1.1.0 → 4.0.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 (38) hide show
  1. package/README.md +535 -68
  2. package/extensions/build-session.test.ts +25 -27
  3. package/extensions/build-session.ts +26 -11
  4. package/extensions/command-surface.test.ts +15 -0
  5. package/extensions/config.ts +12 -40
  6. package/extensions/files.test.ts +21 -1
  7. package/extensions/files.ts +11 -27
  8. package/extensions/framing.test.ts +1 -0
  9. package/extensions/framing.ts +5 -2
  10. package/extensions/history.test.ts +24 -0
  11. package/extensions/history.ts +42 -0
  12. package/extensions/index.ts +523 -245
  13. package/extensions/integration.test.ts +231 -0
  14. package/extensions/migration.test.ts +34 -0
  15. package/extensions/parse.ts +80 -4
  16. package/extensions/paths.ts +26 -32
  17. package/extensions/planning-and-task-breakdown.md +10 -8
  18. package/extensions/planning-method.test.ts +15 -2
  19. package/extensions/planning-method.ts +4 -2
  20. package/extensions/policy.test.ts +11 -0
  21. package/extensions/prompts.test.ts +54 -9
  22. package/extensions/prompts.ts +100 -32
  23. package/extensions/recovery.test.ts +15 -0
  24. package/extensions/review.test.ts +19 -0
  25. package/extensions/review.ts +53 -0
  26. package/extensions/state.test.ts +25 -0
  27. package/extensions/state.ts +198 -0
  28. package/extensions/task-ui.ts +59 -0
  29. package/extensions/tool-policy.ts +4 -0
  30. package/extensions/tools.test.ts +10 -0
  31. package/extensions/tools.ts +16 -0
  32. package/extensions/types.ts +53 -5
  33. package/extensions/validation.test.ts +38 -0
  34. package/extensions/workflow-policy.test.ts +76 -0
  35. package/extensions/workflow-policy.ts +117 -0
  36. package/extensions/workflow-store.test.ts +48 -0
  37. package/extensions/workflow-store.ts +165 -0
  38. package/package.json +29 -5
package/README.md CHANGED
@@ -1,136 +1,603 @@
1
1
  # pi-plan-task
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/pi-plan-task.svg)](https://www.npmjs.com/package/pi-plan-task)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
3
+ A safe, file-backed planning and execution workflow for [Pi](https://github.com/badlogic/pi-mono):
5
4
 
6
- One Pi package: `/plan`, `/build`, `/goal`, and `/tasks`. Progress lives on disk, so a new session or a Pi restart can continue from the next unfinished task.
5
+ ```text
6
+ Plan → Review → Approve → Execute → Verify → Continue / Stop
7
+ ```
7
8
 
8
- Structured questions use [`@juicesharp/rpiv-ask-user-question`](https://pi.dev/packages/@juicesharp/rpiv-ask-user-question). This package does not register `ask_user_question`.
9
+ `pi-plan-task` separates planning from implementation, binds approval to the exact submitted plan structure, executes one focused task at a time, and persists enough state to resume after reloads or session changes.
9
10
 
10
- ## Install
11
+ [![npm version](https://img.shields.io/npm/v/pi-plan-task.svg)](https://www.npmjs.com/package/pi-plan-task)
12
+ [![License](https://img.shields.io/badge/license-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
13
+
14
+
15
+ ## Contents
16
+
17
+ - [Highlights](#highlights)
18
+ - [Requirements](#requirements)
19
+ - [Installation](#installation)
20
+ - [Quick start](#quick-start)
21
+ - [Commands](#commands)
22
+ - [`/plan`](#plan--planning-and-approval)
23
+ - [`/build`](#build--execution)
24
+ - [`/tasks`](#tasks--inspection-and-rework)
25
+ - [LLM tool: `plan_task`](#llm-tool-plan_task)
26
+ - [Task file contract](#task-file-contract)
27
+ - [Durable files](#durable-files)
28
+ - [Lifecycle](#lifecycle)
29
+ - [State](#state)
30
+ - [Resume and recovery](#resume-and-recovery)
31
+ - [Configuration](#configuration)
32
+ - [Events](#events)
33
+ - [Optional Plannotator integration](#optional-plannotator-integration)
34
+ - [Troubleshooting](#troubleshooting)
35
+ - [Development](#development)
36
+ - [Safety notes](#safety-notes)
37
+ ## Highlights
38
+
39
+ - Only three user-facing commands: `/plan`, `/build`, and `/tasks`.
40
+ - Planning writes to an isolated `.plan_task/draft/` area.
41
+ - Explicit approval is required before implementation.
42
+ - Approval is revoked if submitted plan or task structure changes.
43
+ - Task implementation and verification are separate states.
44
+ - `task.md` is the single source of truth for execution progress.
45
+ - One task can run here, in a new session, or in a clean session.
46
+ - All remaining tasks can run here or one-per-session.
47
+ - State updates are validated and serialized; multi-file changes use transactional replacement with rollback.
48
+ - Optional Plannotator integration provides browser-based plan review.
49
+
50
+ ## Requirements
51
+
52
+ - Pi with extension/package support.
53
+ - `ask_user_question` is required at runtime when planning or execution reaches a consequential user decision.
54
+ - Plannotator is optional. After a plan is submitted, choose `review` if the CLI is installed.
55
+
56
+ ## Installation
11
57
 
12
58
  ```bash
13
59
  pi install npm:@juicesharp/rpiv-ask-user-question
14
60
  pi install npm:pi-plan-task
15
61
  ```
16
62
 
17
- Restart Pi or run `/reload`. If juicesharp is missing, this package warns on session start.
63
+ Restart Pi or run `/reload` after installation.
18
64
 
19
- Local checkout (development):
65
+ For local development:
20
66
 
21
67
  ```bash
22
68
  pi install /absolute/path/to/pi-plan-task
23
69
  ```
24
70
 
25
- Or add the source to `packages` in `~/.pi/agent/settings.json`.
71
+ Alternatively, add the package path to `packages` in `~/.pi/agent/settings.json`.
72
+
73
+ ## Quick start
74
+
75
+ ```text
76
+ /plan Add OAuth login
77
+ ```
78
+
79
+ When the draft is valid, choose one of:
80
+
81
+ ```text
82
+ approve lock the submitted plan (then choose here/new/fresh, or run /build later)
83
+ review open optional Plannotator review
84
+ reject reject and revise with feedback
85
+ later leave the submitted plan ready for later approval
86
+ ```
87
+
88
+ A typical flow is:
89
+
90
+ 1. Run `/plan <request>`.
91
+ 2. The agent writes `.plan_task/draft/plan.md` and `.plan_task/draft/task.md`.
92
+ 3. The extension validates both draft files.
93
+ 4. The valid draft is transactionally submitted as `.plan_task/plan.md` and `.plan_task/task.md`, with rollback on failure.
94
+ 5. Review or approve the submitted plan.
95
+ 6. Run one task with `/build`, or all remaining tasks with `/build all`.
96
+ 7. Each task follows `pending → implementation-complete → verified`.
97
+ 8. Only verification checks the task and permits progression.
98
+
99
+ Execution is approval-gated. A missing, changed, or unapproved plan cannot start implementation.
26
100
 
27
101
  ## Commands
28
102
 
29
- | Command | What it does |
103
+ The extension registers exactly three user-facing slash commands:
104
+
105
+ ```text
106
+ /plan create, approve, and reject plans
107
+ /build execute one or all tasks
108
+ /tasks inspect and manage tasks
109
+ ```
110
+
111
+ ### `/plan` — planning and approval
112
+
113
+ | Command | Description |
30
114
  | --- | --- |
31
- | `/plan [file or goal]` | Read-only planning. Writes `.plan_task/plan.md` and `.plan_task/task.md`. |
32
- | `/build` | Execute the next unfinished task in this session, then ask whether to continue here or in a new session. |
33
- | `/build new` | Same as `/build`, but start that task in a new session. |
34
- | `/goal` | Execute remaining tasks until `task.md` is complete. No session prompts. All in this session. |
35
- | `/goal new` | Same as `/goal`, but each remaining task starts in a new session. |
36
- | `/tasks` | Show the current task list and progress. |
115
+ | `/plan` | Plan from the current conversation and repository. |
116
+ | `/plan <request>` | Plan from a free-text request. |
117
+ | `/plan <file> [notes]` | Use a repository spec file with optional guidance. |
118
+ | `/plan request <text>` | Force text beginning with a reserved subcommand to be treated as a request. |
119
+ | `/plan approve` | Approve the submitted plan. Does not start execution. |
120
+ | `/plan reject [feedback]` | Reject the submitted plan and initialize a revision draft. |
121
+
122
+ The first argument to `/plan` is reserved when it is one of:
123
+
124
+ ```text
125
+ approve reject request
126
+ ```
37
127
 
38
- Restarting Pi does not auto-start work. Run `/build` or `/goal` again.
128
+ If the actual request starts with a reserved word, use `/plan request ...`:
39
129
 
40
- Session prompts only happen after a `/build` task finishes. `/goal` and `/goal new` never ask. Those prompts use this package's `select` dialog, not `ask_user_question`.
130
+ ```text
131
+ /plan request review the login page accessibility
132
+ ```
133
+
134
+ `/plan approve` only locks the submitted structure. In a UI session it then asks where the next task should run (`here`, `new`, or `fresh`). In non-UI mode it stops after approval; run `/build` or `/build all` to execute. `/plan reject` works from `ready`, `approved`, `blocked`, or `completed`.
135
+
136
+ #### Draft behavior
137
+
138
+ - New work receives a new `workId` and does not inherit old blocked/task runtime state.
139
+ - Revision preserves the current submitted files until the new draft validates successfully.
140
+ - An unchanged draft is not resubmitted.
141
+ - Invalid or half-written drafts never replace current files.
142
+ - Only draft files are writable during Plan mode.
143
+
144
+ ### `/build` — execution
41
145
 
42
- ### `/plan` arguments
146
+ | Command | Description |
147
+ | --- | --- |
148
+ | `/build` | Execute one pending task in this session. |
149
+ | `/build all` | Execute all remaining tasks in this session. |
150
+
151
+ `--all` is accepted as an alias for `all`. Unknown and duplicate options are rejected.
152
+
153
+ After a single task is verified, a UI session asks:
43
154
 
155
+ ```text
156
+ Continue in this session
157
+ Continue in a new session
158
+ Stop
44
159
  ```
45
- /plan
46
- /plan Add login with OAuth
47
- /plan docs/auth-spec.md
48
- /plan docs/auth-spec.md focus on the callback flow
49
- /plan @docs/auth-spec.md
160
+
161
+ Choosing a new session persists `continueMode: "all-new"` and opens a replacement session that runs `/build` for the next task. `/build all` continues remaining tasks here without prompting. In non-UI modes, `/build` stops after the current task.
162
+
163
+ #### Session placement
164
+
165
+ Placement is chosen in UI prompts, not as `/build` flags:
166
+
167
+ - `here` continues in the current session.
168
+ - `new` records the current session as parent and opens a replacement session.
169
+ - `fresh` is offered after `/plan approve` and opens a clean session without the planning conversation as parent context.
170
+ - If session creation is cancelled, the plan remains approved and can be started again with `/build`.
171
+
172
+ ### `/tasks` — inspection and rework
173
+
174
+ | Command | Description |
175
+ | --- | --- |
176
+ | `/tasks` | Show lifecycle status, work identity, approved hash, current task, and the canonical checklist. |
177
+ | `/tasks rework <id>` | Reopen a verified task and every later task. |
178
+
179
+ Rework is intentionally strict:
180
+
181
+ - The target must exist and already be verified.
182
+ - The target and every later task return to `pending`.
183
+ - Their top-level checklist items are unchecked.
184
+ - Verification, completion, and block metadata are cleared.
185
+ - Approval is revoked.
186
+ - The plan returns to `ready` and must be approved again.
187
+
188
+
189
+ ## LLM tool: `plan_task`
190
+
191
+ `plan_task` is callable by the model; it is not a slash command.
192
+
193
+ ### Status
194
+
195
+ ```json
196
+ {"action":"status"}
50
197
  ```
51
198
 
52
- If the first argument is an existing file — or looks like a path such as `./spec.md`, `notes.txt`, or `@spec.md` — that file is the spec. Anything after it is extra planning guidance. Missing explicit paths are rejected instead of being treated as a prompt.
199
+ Returns the canonical checklist and progress.
53
200
 
54
- ### `/build` and `/goal`
201
+ ### Complete implementation
55
202
 
203
+ ```json
204
+ {"action":"complete","id":1}
56
205
  ```
57
- /build
58
- /build new
59
- /goal
60
- /goal new
206
+
207
+ Valid only when:
208
+
209
+ - the plan is `executing`;
210
+ - the ID is the current task;
211
+ - the task exists and is `pending`;
212
+ - the submitted structure still matches the approved hash.
213
+
214
+ `complete` changes task runtime state to `implementation-complete`. It does **not** check the task and does **not** advance execution.
215
+
216
+ ### Verify
217
+
218
+ ```json
219
+ {"action":"verify","id":1,"reason":"Focused tests and typecheck passed"}
61
220
  ```
62
221
 
63
- `new` and `--new` are equivalent.
222
+ Valid only for the current `implementation-complete` task and requires a non-empty verification result. A successful verification performs one serialized transaction that:
64
223
 
65
- - `/build` runs one task here. After it is marked complete, Pi asks whether to continue in this session or a new session.
66
- - `/build new` opens a new session for that one task, then asks the same question when it finishes.
67
- - `/goal` runs every remaining task in this session.
68
- - `/goal new` opens a new session for the next unfinished task, then another new session after each completed task, until the list is done.
224
+ 1. records `verified` state and evidence;
225
+ 2. checks the matching top-level item in `task.md`;
226
+ 3. persists state;
227
+ 4. emits `pi-plan-task:task-verified`;
228
+ 5. allows execution to continue.
69
229
 
70
- ## Planning method
230
+ ### Block
71
231
 
72
- `/plan` uses `extensions/planning-and-task-breakdown.md` as the planning prompt.
232
+ ```json
233
+ {"action":"block","id":1,"reason":"Waiting for API decision"}
234
+ ```
73
235
 
74
- That file keeps the same section headings as `planning-and-task-breakdown.md`, so later methodology edits can be copied section-by-section from that source. Plan-task only changes output paths and the checklist form `/build` and `/goal` need:
236
+ Valid only for the current `pending` or `implementation-complete` task and requires a non-empty reason. The pre-block state is retained so the task can return to the correct state later.
75
237
 
76
- - `.plan_task/plan.md` and `.plan_task/task.md`
77
- - checklist lines in the form `- [ ] N. Title`
238
+ ### Unblock
78
239
 
79
- This package does not install or load a skill. It also does not modify Pi's system prompt.
240
+ ```json
241
+ {"action":"unblock","id":1}
242
+ ```
80
243
 
81
- ## Prompt injection
244
+ Restores a blocked task to `pending` or `implementation-complete`. It does not automatically start execution. If the whole plan was blocked, unblocking restores it to an approved, buildable state.
82
245
 
83
- Phase instructions are conversation messages, not system-prompt patches:
246
+ Invalid tool actions fail without changing files, state, or emitting success events.
247
+
248
+ ## Task file contract
249
+
250
+ `.plan_task/task.md` is the canonical execution queue and completion source. It must begin with numbered top-level checklist items:
251
+
252
+ ```markdown
253
+ # Tasks
84
254
 
85
- - `/plan`, `/build`, and `/goal` send a short visible user message to start the turn.
86
- - The planning method or current-task instructions are injected once, as a hidden message, when that phase or task starts.
87
- - Later turns in the same phase inject nothing unless the checklist actually changed; then a small build-status message is appended.
88
- - `context` keeps only the newest framing for the current phase. Stale plan/build messages are dropped from the model context. While idle, every injected message is filtered out.
255
+ - [ ] 1. Add the login API
256
+ - [ ] 2. Add the login UI
89
257
 
90
- Session history still stores the injected messages. Filtering is non-destructive.
258
+ ## Task 1: Add the login API
91
259
 
92
- ## Ask user
260
+ **Description:** Create the endpoint.
93
261
 
94
- `/plan`, `/build`, and `/goal` keep juicesharp's `ask_user_question` available and tell the model to call it for consequential choices the repo cannot answer:
262
+ **Acceptance criteria:**
263
+ - [ ] Requests validate input.
264
+ - [ ] Valid requests return 200.
95
265
 
96
- - 1-4 questions per call, each with a short `header` and 2-4 described options
97
- - recommended option first, with `(Recommended)` on the label
98
- - do not author `Other` or `Type something.` — juicesharp appends a custom-answer row
266
+ **Verification:**
267
+ - [ ] Run the focused API tests.
268
+ - [ ] Run the typecheck.
99
269
 
100
- Do not also register another `ask_user_question` tool. The names collide and the schemas differ.
270
+ ## Task 2: Add the login UI
101
271
 
102
- ## Files
272
+ **Description:** Create the login form.
103
273
 
104
- Created in the current project:
274
+ **Acceptance criteria:**
275
+ - [ ] The form submits valid credentials.
105
276
 
277
+ **Verification:**
278
+ - [ ] Run the focused UI tests.
106
279
  ```
107
- .plan_task/plan.md
108
- .plan_task/task.md
280
+
281
+ Validation requires:
282
+
283
+ - exact top-level format `- [ ] N. Title` or `- [x] N. Title`;
284
+ - unique positive task IDs;
285
+ - one matching `## Task N: Title` section per checklist item;
286
+ - heading titles matching checklist titles;
287
+ - a description, acceptance criteria, and verification instructions for every task;
288
+ - no orphan or duplicate task headings.
289
+
290
+ Nested acceptance/verification checkboxes are not execution tasks.
291
+
292
+ Do not manually check top-level task items. Only a successful `plan_task verify` should do that.
293
+
294
+ ## Durable files
295
+
296
+ ```text
297
+ .plan_task/
298
+ ├── plan.md # submitted plan; immutable during execution
299
+ ├── task.md # canonical queue and completion truth
300
+ ├── state.json # validated workflow state and task runtime metadata
301
+ ├── draft/ # exists only while planning or revising
302
+ │ ├── plan.md
303
+ │ └── task.md
304
+ ├── history/ # immutable submitted-plan snapshots
305
+ └── .lock/ # short-lived cross-process workflow lock
109
306
  ```
110
307
 
111
- `task.md` must start with numbered checklist lines:
308
+ Writes use:
112
309
 
113
- ```markdown
114
- - [ ] 1. Add login API
115
- - [ ] 2. Add login UI
310
+ - an in-process serial queue;
311
+ - a project workflow lock;
312
+ - random temporary file names;
313
+ - atomic replacement with rollback for multi-file changes.
314
+
315
+ A stale lock older than ten minutes may be removed during recovery.
316
+
317
+ ### Approval hash
318
+
319
+ Approval stores a SHA-256 structure hash computed from:
320
+
321
+ - the exact `plan.md` content;
322
+ - the exact `task.md` content, except top-level `[ ]`/`[x]` progress markers are normalized.
323
+
324
+ As a result:
325
+
326
+ - normal verified-task progress does not invalidate approval;
327
+ - changing task titles, bodies, criteria, verification steps, or plan context revokes approval;
328
+ - `/build`, task mutation tools, task progression, and session recovery all enforce the approved hash;
329
+ - a mismatch fails closed and returns the plan to `ready`.
330
+
331
+ `plan.md` is not updated as tasks complete. Runtime progress exists only in `task.md` and `state.json`.
332
+
333
+ ## Lifecycle
334
+
335
+ ### Plan lifecycle
336
+
337
+ ```text
338
+ idle → planning → ready → approved → executing → completed
339
+ ↑ ↘ ↘
340
+ └─ rework blocked ──┘
116
341
  ```
117
342
 
118
- `/build` and `/goal` resume from the first unchecked item.
343
+ Important rules:
119
344
 
120
- ## Config
345
+ - `planning → ready` only happens after a valid changed draft is submitted.
346
+ - `ready → approved` recomputes and stores the approved structure hash.
347
+ - `approved → executing` occurs only after files, state, hash, and queue are validated.
348
+ - `executing → completed` requires every task to be checked **and** have `verified` runtime state.
349
+ - If every remaining unchecked task is blocked, the plan becomes `blocked`; it is never reported complete.
350
+ - Revision or rework clears approval.
121
351
 
122
- Allowed `/plan` tools:
352
+ ### Task lifecycle
353
+
354
+ ```text
355
+ pending → implementation-complete → verified
356
+ ↘ ↘
357
+ blocked
358
+ ```
123
359
 
124
- - Global: `~/.pi/agent/plan_task.json`
125
- - Project override: `.pi/plan_task.json`
360
+ `unblock` restores the task to whichever active state existed before blocking.
361
+
362
+ ## State
363
+
364
+ `state.json` is validated before use. Unknown versions, malformed statuses, invalid IDs, invalid hashes, invalid dates, verified tasks without evidence, and blocked tasks without reasons fail closed.
365
+
366
+ Example:
126
367
 
127
368
  ```json
128
369
  {
129
- "planTools": ["read", "bash", "grep", "find", "ls", "pwsh", "rg"]
370
+ "version": 2,
371
+ "status": "executing",
372
+ "workId": "f2f0c9b4e4c1a2d3",
373
+ "planningRequest": "Add OAuth login",
374
+ "currentTaskId": 2,
375
+ "continueMode": "all-new",
376
+ "executionMode": "automatic",
377
+ "draftStructureHash": "0000000000000000000000000000000000000000000000000000000000000000",
378
+ "approvedStructureHash": "1111111111111111111111111111111111111111111111111111111111111111",
379
+ "sessionFile": "...",
380
+ "updatedAt": "2026-01-01T00:00:00.000Z",
381
+ "tasks": {
382
+ "1": {
383
+ "status": "verified",
384
+ "verification": "Focused tests passed",
385
+ "verifiedAt": "2026-01-01T00:00:00.000Z"
386
+ },
387
+ "2": {
388
+ "status": "implementation-complete",
389
+ "completedAt": "2026-01-01T00:05:00.000Z"
390
+ },
391
+ "3": {
392
+ "status": "blocked",
393
+ "reason": "Needs API decision",
394
+ "blockedFrom": "pending"
395
+ }
396
+ }
130
397
  }
131
398
  ```
132
399
 
133
- During `/plan`, `write` and `edit` stay available but can only touch the two plan files. Bash is limited to read-only commands. `plan_task` and `ask_user_question` stay available in every mode.
400
+ Do not hand-edit `state.json` to bypass workflow checks.
401
+
402
+ ## Resume and recovery
403
+
404
+ The extension restores persisted behavior during startup, reload, resume, and fork:
405
+
406
+ | Persisted state | Restored behavior |
407
+ | --- | --- |
408
+ | `planning` | Restores Plan mode, draft write boundary, and planning request framing. |
409
+ | `ready` | Leaves the submitted plan ready for review/approval. |
410
+ | `approved` | Leaves the plan approved and ready to build after hash verification. |
411
+ | `executing` | Restores current task, build framing, and continuation policy. |
412
+ | `blocked` | Restores blocked state and reasons without reporting completion. |
413
+ | `completed` | Preserves completed history; verified work can be explicitly reopened. |
414
+
415
+ If approved files changed while Pi was not running, approval is revoked during recovery. If `state.json` is malformed, execution is disabled rather than guessing or overwriting the damaged state.
416
+
417
+ ## Configuration
418
+
419
+ Configuration is merged in this order:
420
+
421
+ 1. defaults;
422
+ 2. global `~/.pi/agent/plan_task.json`;
423
+ 3. project `.pi/plan_task.json`.
424
+
425
+ Example:
426
+
427
+ ```json
428
+ {
429
+ "planTools": ["read", "grep", "find", "ls", "rg"],
430
+ "executionMode": "automatic"
431
+ }
432
+ ```
433
+
434
+ ### `planTools`
435
+
436
+ Read-only tools that may be used during Plan mode. Values are filtered through the extension's safe allowlist:
437
+
438
+ ```text
439
+ read grep find ls rg plan_task ask_user_question
440
+ ```
441
+
442
+ `write` and `edit` are added specifically for the two draft files. Calls targeting other paths are blocked.
443
+
444
+ Shell tools, unknown tools, current submitted files, and implementation tools are blocked during Plan mode even if another extension exposes them.
445
+
446
+ ### `executionMode`
447
+
448
+ | Value | Behavior |
449
+ | --- | --- |
450
+ | `automatic` | The extension starts and coordinates local implementation sessions. |
451
+ | `external` | Approval emits `pi-plan-task:plan-approved`; local `/build` does not execute. |
452
+
453
+ New-session model and thinking behavior follow Pi defaults.
454
+
455
+ ## Events
456
+
457
+ Other extensions can subscribe through Pi's shared event bus:
458
+
459
+ ```text
460
+ pi-plan-task:plan-ready
461
+ pi-plan-task:plan-approved
462
+ pi-plan-task:plan-rejected
463
+ pi-plan-task:task-started
464
+ pi-plan-task:task-completed
465
+ pi-plan-task:task-verified
466
+ pi-plan-task:task-blocked
467
+ pi-plan-task:execution-finished
468
+ ```
469
+
470
+ Event payloads include workflow metadata such as:
471
+
472
+ ```text
473
+ cwd
474
+ planPath
475
+ taskPath
476
+ planHash
477
+ taskId
478
+ sessionFile
479
+ feedback
480
+ reason
481
+ ```
482
+
483
+ Event semantics:
484
+
485
+ | Event | Meaning |
486
+ | --- | --- |
487
+ | `plan-ready` | A valid draft was transactionally submitted. |
488
+ | `plan-approved` | Current structure was validated and approved. |
489
+ | `plan-rejected` | Review rejected the submitted plan and initialized a revision draft. |
490
+ | `task-started` | A current task was selected and persisted. |
491
+ | `task-completed` | Implementation reached `implementation-complete`; verification is still required. |
492
+ | `task-verified` | Verification evidence was persisted and the checklist item was checked. |
493
+ | `task-blocked` | The current task was blocked with a reason. |
494
+ | `execution-finished` | Every task is checked and verified. |
495
+
496
+ Events are emitted only after the corresponding state/file update succeeds.
497
+
498
+ ## Prompt and context behavior
499
+
500
+ Phase instructions are conversation messages rather than permanent system-prompt patches:
501
+
502
+ - Plan and build commands send visible user requests.
503
+ - Phase/task framing is injected once when a phase or task starts.
504
+ - Planning requests are persisted so reload can restore framing.
505
+ - Stale framing is filtered from model context without rewriting session history.
506
+ - Build framing includes `plan.md` as untrusted reference context.
507
+ - Current task instructions and safety rules take precedence over plan content.
508
+ - A clean session does not inherit the planning conversation as parent context.
509
+ - An `implementation-complete` task that is resumed for verification receives verification-only framing and must not call `complete` again.
510
+
511
+ ## Optional Plannotator integration
512
+
513
+ Plannotator is not a core dependency.
514
+
515
+ If the `plannotator` CLI is installed, choose `review` after a plan is submitted. That opens the submitted plan for browser review. Approved results are normalized to `/plan approve`; annotated or rejected results are normalized to `/plan reject <feedback>`.
516
+
517
+ If Plannotator is unavailable, use:
518
+
519
+ ```text
520
+ /tasks
521
+ /plan approve
522
+ /plan reject <feedback>
523
+ ```
524
+
525
+ ## Troubleshooting
526
+
527
+ ### “Plan files changed after approval”
528
+
529
+ The submitted structure no longer matches the approved hash. Inspect the files, then run:
530
+
531
+ ```text
532
+ /tasks
533
+ /plan approve
534
+ ```
535
+
536
+ ### “Implementation is complete but verification is pending”
537
+
538
+ The task has called `complete` but has not passed verification. Run the task's verification steps and let the model call:
539
+
540
+ ```json
541
+ {"action":"verify","id":1,"reason":"Describe the successful checks"}
542
+ ```
543
+
544
+ ### “Execution blocked”
545
+
546
+ Every remaining unchecked task is blocked. Resolve the reason, then ask the agent to call:
547
+
548
+ ```json
549
+ {"action":"unblock","id":1}
550
+ ```
551
+
552
+ Run `/build` again when ready.
553
+
554
+ ### Invalid `state.json`
555
+
556
+ The extension fails closed and will not execute. Inspect `.plan_task/history/` for snapshots. Restore a known-good state or start an explicitly new plan rather than weakening state validation.
557
+
558
+ ### Stale `.plan_task/.lock`
559
+
560
+ Normal operations remove the lock automatically. A lock older than ten minutes is considered stale and may be recovered automatically. Do not remove a recent lock while another Pi process is operating on the same project.
561
+
562
+ ### Plannotator is unavailable
563
+
564
+ Use the built-in text workflow:
565
+
566
+ ```text
567
+ /tasks
568
+ /plan approve
569
+ /plan reject <feedback>
570
+ ```
571
+
572
+ ## Development
573
+
574
+ ```bash
575
+ npm test
576
+ npm run typecheck
577
+ npm run bundle
578
+ npm pack --dry-run
579
+ ```
580
+
581
+ The test suite includes:
582
+
583
+ - parser and Markdown-boundary tests;
584
+ - strict plan validation tests;
585
+ - state schema tests;
586
+ - structure hash tests;
587
+ - concurrent workflow mutation tests;
588
+ - command-surface tests;
589
+ - ExtensionAPI mock integration tests for planning, approval, execution, verification, blocking, rework, recovery framing, session handoff, cancellation, and external mode.
590
+
591
+ ## Safety notes
592
+
593
+ - Treat `plan.md` as untrusted reference data, not executable instructions.
594
+ - Never edit history snapshots to make work appear complete.
595
+ - Do not manually check top-level execution tasks.
596
+ - Do not confuse nested acceptance checkboxes with execution completion.
597
+ - Do not bypass approval by hand-editing state.
598
+ - Unverified and blocked tasks are never silently skipped as completed.
599
+ - Use `/tasks rework <id>` for explicit, approval-gated retries.
600
+ - Browser review is optional; Markdown files and validated state are the durable core.
134
601
 
135
602
  ## License
136
603