pi-plan-task 1.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.
@@ -0,0 +1,287 @@
1
+ # Planning and Task Breakdown
2
+
3
+ ## Overview
4
+
5
+ Decompose work into small, verifiable tasks with explicit acceptance criteria. Good task breakdown is the difference between an agent that completes work reliably and one that produces a tangled mess. Every task should be small enough to implement, test, and verify in a single focused session.
6
+
7
+ ## When to Use
8
+
9
+ - You have a spec and need to break it into implementable units
10
+ - A task feels too large or vague to start
11
+ - Work needs to be parallelized across multiple agents or sessions
12
+ - You need to communicate scope to a human
13
+ - The implementation order isn't obvious
14
+
15
+ **When NOT to use:** Single-file changes with obvious scope, or when the spec already contains well-defined tasks.
16
+
17
+ ## The Planning Process
18
+
19
+ ### Step 1: Enter Plan Mode
20
+
21
+ Before writing any code, operate in read-only mode:
22
+
23
+ - Read the spec and relevant codebase sections
24
+ - Identify existing patterns and conventions
25
+ - Map dependencies between components
26
+ - Note risks and unknowns
27
+
28
+ **Do NOT write code during planning.** The output is a plan document saved to `.plan_task/plan.md` and a task list saved to `.plan_task/task.md`, not implementation.
29
+
30
+ ### Step 2: Identify the Dependency Graph
31
+
32
+ Map what depends on what:
33
+
34
+ ```
35
+ Database schema
36
+
37
+ ├── API models/types
38
+ │ │
39
+ │ ├── API endpoints
40
+ │ │ │
41
+ │ │ └── Frontend API client
42
+ │ │ │
43
+ │ │ └── UI components
44
+ │ │
45
+ │ └── Validation logic
46
+
47
+ └── Seed data / migrations
48
+ ```
49
+
50
+ Implementation order follows the dependency graph bottom-up: build foundations first.
51
+
52
+ ### Step 3: Slice Vertically
53
+
54
+ Instead of building all the database, then all the API, then all the UI — build one complete feature path at a time:
55
+
56
+ **Bad (horizontal slicing):**
57
+ ```
58
+ Task 1: Build entire database schema
59
+ Task 2: Build all API endpoints
60
+ Task 3: Build all UI components
61
+ Task 4: Connect everything
62
+ ```
63
+
64
+ **Good (vertical slicing):**
65
+ ```
66
+ Task 1: User can create an account (schema + API + UI for registration)
67
+ Task 2: User can log in (auth schema + API + UI for login)
68
+ Task 3: User can create a task (task schema + API + UI for creation)
69
+ Task 4: User can view task list (query + API + UI for list view)
70
+ ```
71
+
72
+ Each vertical slice delivers working, testable functionality.
73
+
74
+ ### Step 4: Write Tasks
75
+
76
+ Each task follows this structure:
77
+
78
+ ```markdown
79
+ ## Task [N]: [Short descriptive title]
80
+
81
+ **Description:** One paragraph explaining what this task accomplishes.
82
+
83
+ **Acceptance criteria:**
84
+ - [ ] [Specific, testable condition]
85
+ - [ ] [Specific, testable condition]
86
+
87
+ **Verification:**
88
+ - [ ] Tests pass: [the repository's focused-test command]
89
+ - [ ] Build succeeds: [the repository's build command]
90
+ - [ ] Manual check: [description of what to verify]
91
+
92
+ **Dependencies:** [Task numbers this depends on, or "None"]
93
+
94
+ **Files likely touched:**
95
+ - `src/path/to/file.ts`
96
+ - `tests/path/to/test.ts`
97
+
98
+ **Estimated scope:** [Small: 1-2 files | Medium: 3-5 files | Large: 5+ files]
99
+ ```
100
+
101
+ ### Step 5: Order and Checkpoint
102
+
103
+ Arrange tasks so that:
104
+
105
+ 1. Dependencies are satisfied (build foundation first)
106
+ 2. Each task leaves the system in a working state
107
+ 3. Verification checkpoints occur after every 2-3 tasks
108
+ 4. High-risk tasks are early (fail fast)
109
+
110
+ Add explicit checkpoints to the task list:
111
+
112
+ ```markdown
113
+ ## Checkpoint: After Tasks 1-3
114
+ - [ ] All tests pass
115
+ - [ ] Application builds without errors
116
+ - [ ] Core user flow works end-to-end
117
+ - [ ] Review with human before proceeding
118
+ ```
119
+
120
+ ## Task Sizing Guidelines
121
+
122
+ | Size | Files | Scope | Example |
123
+ |------|-------|-------|---------|
124
+ | **XS** | 1 | Single function or config change | Add a validation rule |
125
+ | **S** | 1-2 | One component or endpoint | Add a new API endpoint |
126
+ | **M** | 3-5 | One feature slice | User registration flow |
127
+ | **L** | 5-8 | Multi-component feature | Search with filtering and pagination |
128
+ | **XL** | 8+ | **Too large — break it down further** | — |
129
+
130
+ If a task is L or larger, it should be broken into smaller tasks. An agent performs best on S and M tasks.
131
+
132
+ **When to break a task down further:**
133
+ - It would take more than one focused session (roughly 2+ hours of agent work)
134
+ - You cannot describe the acceptance criteria in 3 or fewer bullet points
135
+ - It touches two or more independent subsystems (e.g., auth and billing)
136
+ - You find yourself writing "and" in the task title (a sign it is two tasks)
137
+
138
+ ## Output Files
139
+
140
+ - **Plan document:** Save the implementation plan to `.plan_task/plan.md`. This is always a markdown file — design decisions, risks, and open questions don't map cleanly onto individual tracker issues.
141
+ - **Task list:** Record each task in `.plan_task/task.md`.
142
+
143
+ Create the `.plan_task/` directory if it does not exist.
144
+
145
+ The checklist at the top of `.plan_task/task.md` is the source of truth for `/build`. Keep items in the form `- [ ] N. Title` so later sessions can resume.
146
+
147
+ After the checklist, write one `## Task [N]:` section per item using the Step 4 structure. Put `## Checkpoint:` sections after the tasks they cover, not in the top checklist.
148
+
149
+ Example `.plan_task/task.md`:
150
+
151
+ ```markdown
152
+ - [ ] 1. User can create an account
153
+ - [ ] 2. User can log in
154
+
155
+ ## Task 1: User can create an account
156
+
157
+ **Description:** Registration schema, API, and UI as one vertical slice.
158
+
159
+ **Acceptance criteria:**
160
+ - [ ] A new user can register with email and password
161
+ - [ ] Duplicate emails are rejected
162
+
163
+ **Verification:**
164
+ - [ ] Tests pass: [the repository's focused-test command]
165
+ - [ ] Build succeeds: [the repository's build command]
166
+ - [ ] Manual check: submit the registration form
167
+
168
+ **Dependencies:** None
169
+
170
+ **Files likely touched:**
171
+ - `src/auth/register.ts`
172
+ - `tests/auth/register.test.ts`
173
+
174
+ **Estimated scope:** Medium: 3-5 files
175
+
176
+ ## Task 2: User can log in
177
+
178
+ **Description:** Auth session API and login UI.
179
+
180
+ **Acceptance criteria:**
181
+ - [ ] Valid credentials create a session
182
+ - [ ] Invalid credentials are rejected
183
+
184
+ **Verification:**
185
+ - [ ] Tests pass: [the repository's focused-test command]
186
+ - [ ] Manual check: log in with the account from Task 1
187
+
188
+ **Dependencies:** 1
189
+
190
+ **Files likely touched:**
191
+ - `src/auth/login.ts`
192
+ - `tests/auth/login.test.ts`
193
+
194
+ **Estimated scope:** Small: 1-2 files
195
+
196
+ ## Checkpoint: After Tasks 1-2
197
+ - [ ] Registration and login work end-to-end
198
+ - [ ] Review with human before proceeding
199
+ ```
200
+
201
+ ## Plan Document Template
202
+
203
+ ```markdown
204
+ # Implementation Plan: [Feature/Project Name]
205
+
206
+ ## Overview
207
+ [One paragraph summary of what we're building]
208
+
209
+ ## Architecture Decisions
210
+ - [Key decision 1 and rationale]
211
+ - [Key decision 2 and rationale]
212
+
213
+ ## Task List
214
+
215
+ ### Phase 1: Foundation
216
+ - [ ] 1. ...
217
+ - [ ] 2. ...
218
+
219
+ ### Checkpoint: Foundation
220
+ - [ ] Tests pass, builds clean
221
+
222
+ ### Phase 2: Core Features
223
+ - [ ] 3. ...
224
+ - [ ] 4. ...
225
+
226
+ ### Checkpoint: Core Features
227
+ - [ ] End-to-end flow works
228
+
229
+ ### Phase 3: Polish
230
+ - [ ] 5. ...
231
+ - [ ] 6. ...
232
+
233
+ ### Checkpoint: Complete
234
+ - [ ] All acceptance criteria met
235
+ - [ ] Ready for review
236
+
237
+ ## Risks and Mitigations
238
+ | Risk | Impact | Mitigation |
239
+ |------|--------|------------|
240
+ | [Risk] | [High/Med/Low] | [Strategy] |
241
+
242
+ ## Open Questions
243
+ - [Question needing human input]
244
+ ```
245
+
246
+ ## Parallelization Opportunities
247
+
248
+ When multiple agents or sessions are available:
249
+
250
+ - **Safe to parallelize:** Independent feature slices, tests for already-implemented features, documentation
251
+ - **Must be sequential:** Database migrations, shared state changes, dependency chains
252
+ - **Needs coordination:** Features that share an API contract (define the contract first, then parallelize)
253
+
254
+ ## Common Rationalizations
255
+
256
+ | Rationalization | Reality |
257
+ |---|---|
258
+ | "I'll figure it out as I go" | That's how you end up with a tangled mess and rework. 10 minutes of planning saves hours. |
259
+ | "The tasks are obvious" | Write them down anyway. Explicit tasks surface hidden dependencies and forgotten edge cases. |
260
+ | "Planning is overhead" | Planning is the task. Implementation without a plan is just typing. |
261
+ | "I can hold it all in my head" | Context windows are finite. Written plans survive session boundaries and compaction. |
262
+
263
+ ## Red Flags
264
+
265
+ - Starting implementation without a written task list
266
+ - Writing tasks somewhere other than `.plan_task/task.md`
267
+ - Tasks that say "implement the feature" without acceptance criteria
268
+ - No verification steps in the plan
269
+ - All tasks are XL-sized
270
+ - No checkpoints between tasks
271
+ - Dependency order isn't considered
272
+
273
+ ## Verification
274
+
275
+ Before starting implementation, confirm:
276
+
277
+ - [ ] Every task has acceptance criteria
278
+ - [ ] Every task has a verification step
279
+ - [ ] Task dependencies are identified and ordered correctly
280
+ - [ ] Tasks are recorded in `.plan_task/task.md`
281
+ - [ ] No task touches more than ~5 files
282
+ - [ ] Checkpoints exist between major phases
283
+ - [ ] The human has reviewed and approved the plan
284
+
285
+ ## See Also
286
+
287
+ Acceptance criteria are per-task and answer "did we build the right thing?". They sit on top of any project-wide Definition of Done, the standing bar every task clears before it counts as done.
@@ -0,0 +1,20 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+ import { loadPlanningMethod, PLANNING_METHOD_HEADINGS } from "./planning-method.ts";
4
+
5
+ describe("loadPlanningMethod", () => {
6
+ it("keeps the same section headings as planning-and-task-breakdown.md", () => {
7
+ const method = loadPlanningMethod();
8
+ let cursor = 0;
9
+ for (const heading of PLANNING_METHOD_HEADINGS) {
10
+ const index = method.indexOf(heading, cursor);
11
+ assert.notEqual(index, -1, `missing heading: ${heading}`);
12
+ cursor = index + heading.length;
13
+ }
14
+ assert.doesNotMatch(method, /^---/);
15
+ assert.doesNotMatch(method, /This skill/);
16
+ assert.doesNotMatch(method, /tasks\/todo\.md/);
17
+ assert.match(method, /\.plan_task\/plan\.md/);
18
+ assert.match(method, /\.plan_task\/task\.md/);
19
+ });
20
+ });
@@ -0,0 +1,38 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ /**
6
+ * /plan methodology file.
7
+ *
8
+ * Section headings match `planning-and-task-breakdown.md` at the workspace
9
+ * root so later updates can be copied section-by-section from that file.
10
+ *
11
+ * Plan-task-only adaptations (do not copy these from the source blindly):
12
+ * - Output paths are `.plan_task/plan.md` and `.plan_task/task.md`
13
+ * - Checklist items must be `- [ ] N. Title`
14
+ * - No external tracker, no skill frontmatter, no definition-of-done.md link
15
+ */
16
+ export const PLANNING_METHOD_FILE = resolve(
17
+ dirname(fileURLToPath(import.meta.url)),
18
+ "planning-and-task-breakdown.md",
19
+ );
20
+
21
+ export const PLANNING_METHOD_HEADINGS = [
22
+ "# Planning and Task Breakdown",
23
+ "## Overview",
24
+ "## When to Use",
25
+ "## The Planning Process",
26
+ "## Task Sizing Guidelines",
27
+ "## Output Files",
28
+ "## Plan Document Template",
29
+ "## Parallelization Opportunities",
30
+ "## Common Rationalizations",
31
+ "## Red Flags",
32
+ "## Verification",
33
+ "## See Also",
34
+ ] as const;
35
+
36
+ export function loadPlanningMethod(): string {
37
+ return readFileSync(PLANNING_METHOD_FILE, "utf8").trim();
38
+ }
@@ -0,0 +1,70 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+ import { PLANNING_METHOD_HEADINGS } from "./planning-method.ts";
4
+ import { buildPrompt, buildRequest, buildStatus, buildStatusKey, planPrompt, planRequest } from "./prompts.ts";
5
+
6
+ describe("planPrompt", () => {
7
+ it("injects the request, runtime rules, and planning method headings", () => {
8
+ const source = { kind: "prompt" as const, prompt: "Add login" };
9
+ const prompt = planPrompt(source);
10
+ assert.equal(planRequest(source), "Add login");
11
+ assert.match(prompt, /Request:\nAdd login/);
12
+ assert.match(prompt, /Runtime rules:/);
13
+ assert.match(prompt, /\.plan_task\/plan\.md/);
14
+ assert.match(prompt, /\.plan_task\/task\.md/);
15
+ assert.match(prompt, /- \[ \] N\. Title/);
16
+ for (const heading of PLANNING_METHOD_HEADINGS) {
17
+ assert.match(prompt, new RegExp(heading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")));
18
+ }
19
+ assert.doesNotMatch(prompt, /Planning skill/);
20
+ assert.doesNotMatch(prompt, /tasks\/todo\.md/);
21
+ assert.match(prompt, /ask_user_question/);
22
+ });
23
+
24
+ it("inlines a spec file and extra notes", () => {
25
+ const prompt = planPrompt({
26
+ kind: "file",
27
+ displayPath: "docs/spec.md",
28
+ resolvedPath: "/tmp/docs/spec.md",
29
+ notes: "focus on OAuth",
30
+ content: "# Auth\nAdd login.",
31
+ });
32
+ assert.match(prompt, /Request:\nWrite a plan from docs\/spec\.md\.\n\nfocus on OAuth/);
33
+ assert.match(prompt, /Spec file \(docs\/spec\.md\):/);
34
+ assert.match(prompt, /# Auth\nAdd login\./);
35
+ assert.match(prompt, /treat it as the primary requirements/);
36
+ });
37
+ });
38
+
39
+ describe("buildPrompt", () => {
40
+ it("scopes work to one task and requires acceptance criteria", () => {
41
+ const task = {
42
+ id: 2,
43
+ title: "Add login UI",
44
+ done: false,
45
+ body: "## Task 2: Add login UI\n\n**Acceptance criteria:**\n- [ ] Form submits",
46
+ };
47
+ const prompt = buildPrompt(task, 3, false);
48
+ assert.equal(buildRequest(task), "Execute planned task 2. Add login UI");
49
+ assert.match(prompt, /Current task: 2\. Add login UI/);
50
+ assert.match(prompt, /Remaining tasks after this one: 2/);
51
+ assert.match(prompt, /Form submits/);
52
+ assert.match(prompt, /acceptance criteria/);
53
+ assert.match(prompt, /ask_user_question/);
54
+ assert.match(prompt, /Do not start the next task/);
55
+ });
56
+ });
57
+
58
+ describe("buildStatus", () => {
59
+ it("summarizes checklist progress for later turns", () => {
60
+ const tasks = [
61
+ { id: 1, title: "API", done: true, body: "" },
62
+ { id: 2, title: "UI", done: false, body: "" },
63
+ ];
64
+ const status = buildStatus(tasks, 2);
65
+ assert.match(status, /Progress 1\/2/);
66
+ assert.match(status, /\[x\] 1\. API/);
67
+ assert.match(status, /\[ \] 2\. UI {2}<- current/);
68
+ assert.equal(buildStatusKey(tasks, 2), "2:1:1,2:0");
69
+ });
70
+ });
@@ -0,0 +1,87 @@
1
+ import { loadPlanningMethod } from "./planning-method.ts";
2
+ import type { PlanSource } from "./plan-input.ts";
3
+ import type { TaskItem } from "./types.ts";
4
+
5
+ export const DEFAULT_PLAN_REQUEST = "Write a plan from the current conversation and repository.";
6
+
7
+ export function planRequest(source: PlanSource): string {
8
+ if (source.kind === "empty") return DEFAULT_PLAN_REQUEST;
9
+ if (source.kind === "prompt") return source.prompt.trim() || DEFAULT_PLAN_REQUEST;
10
+ const notes = source.notes.trim();
11
+ const head = `Write a plan from ${source.displayPath}.`;
12
+ return notes ? `${head}\n\n${notes}` : head;
13
+ }
14
+
15
+ function specSection(source: PlanSource): string {
16
+ if (source.kind !== "file") return "";
17
+ if (source.content !== undefined) {
18
+ return `\nSpec file (${source.displayPath}):\n\`\`\`\n${source.content}\n\`\`\`\n`;
19
+ }
20
+ return `\nSpec file: ${source.displayPath}\nThe file is too large to inline. Read \`${source.resolvedPath}\` with the read tool before writing the plan.\n`;
21
+ }
22
+
23
+ /** Delivered once when plan mode starts. Not a system-prompt patch. */
24
+ export function planPrompt(source: PlanSource): string {
25
+ const request = planRequest(source);
26
+ return `You are in plan mode. Explore the repository and write a plan. Do not implement product code.
27
+
28
+ Request:
29
+ ${request}
30
+ ${specSection(source)}
31
+ Runtime rules:
32
+ - Do not modify project files.
33
+ - The only files you may create or edit are \`.plan_task/plan.md\` and \`.plan_task/task.md\`.
34
+ - Use write/edit for those two files. Do not implement the work itself.
35
+ - Follow the planning method below for process, task sizing, templates, and verification.
36
+ - The checklist lines in \`.plan_task/task.md\` must stay in the exact form \`- [ ] N. Title\` so later sessions can resume.
37
+ - If a spec file is provided, treat it as the primary requirements.
38
+ - If a consequential, user-answerable decision remains, call \`ask_user_question\` with 2-4 options, a recommended default, and an Other path. Do not leave blocking decisions as open questions in the plan.
39
+ - When both files are written, stop and wait for /build.
40
+
41
+ ${loadPlanningMethod()}`;
42
+ }
43
+
44
+ export function buildRequest(task: TaskItem): string {
45
+ return `Execute planned task ${task.id}. ${task.title}`;
46
+ }
47
+
48
+ /** Delivered once when a build task starts. Not a system-prompt patch. */
49
+ export function buildPrompt(task: TaskItem, remaining: number, continueAll: boolean): string {
50
+ const stopRule = continueAll
51
+ ? "After this task is complete, mark it done. Remaining tasks will be assigned automatically. Do not stop to ask about sessions."
52
+ : "After this task is complete, mark it done and stop. Do not start the next task.";
53
+ const body = task.body.trim() || `## Task ${task.id}: ${task.title}`;
54
+ return `Execute exactly one planned task. Do not start any other task.
55
+
56
+ Current task: ${task.id}. ${task.title}
57
+ Remaining tasks after this one: ${Math.max(0, remaining - 1)}
58
+
59
+ ${body}
60
+
61
+ Rules:
62
+ - Implement only this task.
63
+ - Follow existing project conventions.
64
+ - Leave the system in a working state when the task ends.
65
+ - Verify against this task's acceptance criteria and verification steps before marking it done.
66
+ - Do not mark the task complete if acceptance criteria are unmet or verification failed.
67
+ - If a consequential decision is still ambiguous, call \`ask_user_question\` instead of guessing.
68
+ - When the task is done, call the plan_task tool with action "complete" and this task id, and keep the matching checklist box checked in \`.plan_task/task.md\`.
69
+ - ${stopRule}`;
70
+ }
71
+
72
+ export function buildStatus(tasks: TaskItem[], currentId: number): string {
73
+ const done = tasks.filter((task) => task.done).length;
74
+ const lines = tasks.map((task) => {
75
+ const mark = task.done ? "[x]" : "[ ]";
76
+ const current = task.id === currentId ? " <- current" : "";
77
+ return `- ${mark} ${task.id}. ${task.title}${current}`;
78
+ });
79
+ return `[BUILD STATUS]
80
+ Progress ${done}/${tasks.length}
81
+
82
+ ${lines.join("\n")}`;
83
+ }
84
+
85
+ export function buildStatusKey(tasks: TaskItem[], currentId: number): string {
86
+ return `${currentId}:${tasks.map((task) => `${task.id}:${task.done ? "1" : "0"}`).join(",")}`;
87
+ }
@@ -0,0 +1,26 @@
1
+ export interface PlanTaskConfig {
2
+ planTools: string[];
3
+ }
4
+
5
+ export interface TaskItem {
6
+ id: number;
7
+ title: string;
8
+ done: boolean;
9
+ body: string;
10
+ }
11
+
12
+ export interface TaskFile {
13
+ raw: string;
14
+ tasks: TaskItem[];
15
+ }
16
+
17
+ export const DEFAULT_PLAN_TOOLS = ["read", "bash", "grep", "find", "ls", "pwsh", "rg"] as const;
18
+
19
+ export const DEFAULT_CONFIG: PlanTaskConfig = {
20
+ planTools: [...DEFAULT_PLAN_TOOLS],
21
+ };
22
+
23
+ export const PLAN_DIR_NAME = ".plan_task";
24
+ export const PLAN_FILE_NAME = "plan.md";
25
+ export const TASK_FILE_NAME = "task.md";
26
+ export const CONFIG_FILE_NAME = "plan_task.json";
package/package.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "pi-plan-task",
3
+ "version": "1.0.0",
4
+ "license": "MIT",
5
+ "description": "Pi package: /plan, /build, /goal, /tasks.",
6
+ "keywords": ["pi-package"],
7
+ "files": ["extensions", "README.md"],
8
+ "type": "module",
9
+ "pi": {
10
+ "extensions": ["./extensions/index.ts"]
11
+ },
12
+ "peerDependencies": {
13
+ "@earendil-works/pi-ai": "*",
14
+ "@earendil-works/pi-coding-agent": "*",
15
+ "@earendil-works/pi-tui": "*",
16
+ "typebox": "*"
17
+ }
18
+ }