@engineereddev/fractal-planner 0.1.1
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 +22 -0
- package/.claude-plugin/plugin.json +19 -0
- package/LICENSE +21 -0
- package/README.md +257 -0
- package/agents/fp-analyst.md +96 -0
- package/agents/fp-context-builder.md +87 -0
- package/agents/fp-critic.md +140 -0
- package/agents/fp-decomposer.md +261 -0
- package/agents/fp-interviewer.md +263 -0
- package/agents/fp-linear-sync.md +128 -0
- package/agents/fp-researcher.md +82 -0
- package/agents/fp-task-tracker.md +134 -0
- package/dist/cli/classify-intent.js +118 -0
- package/dist/cli/compute-signals.js +495 -0
- package/dist/cli/generate-plan.js +14209 -0
- package/dist/cli/load-config.js +13661 -0
- package/dist/cli/validate-tasks.js +467 -0
- package/dist/index.js +24598 -0
- package/dist/src/cli/classify-intent.d.ts +3 -0
- package/dist/src/cli/compute-signals.d.ts +14 -0
- package/dist/src/cli/generate-plan.d.ts +3 -0
- package/dist/src/cli/load-config.d.ts +3 -0
- package/dist/src/cli/validate-tasks.d.ts +3 -0
- package/dist/src/config.d.ts +182 -0
- package/dist/src/index.d.ts +12 -0
- package/dist/src/phases/clearance.d.ts +12 -0
- package/dist/src/phases/decomposition.d.ts +41 -0
- package/dist/src/phases/interview.d.ts +17 -0
- package/dist/src/phases/planning.d.ts +21 -0
- package/dist/src/phases/research.d.ts +9 -0
- package/dist/src/types/index.d.ts +116 -0
- package/dist/src/utils/draft.d.ts +21 -0
- package/dist/src/utils/question-strategies.d.ts +24 -0
- package/dist/src/utils/task-parser.d.ts +3 -0
- package/hooks/hooks.json +27 -0
- package/hooks/nudge-teammate.sh +216 -0
- package/hooks/run-comment-checker.sh +91 -0
- package/package.json +65 -0
- package/skills/commit/SKILL.md +157 -0
- package/skills/fp/SKILL.md +857 -0
- package/skills/fp/scripts/resolve-env.sh +66 -0
- package/skills/handoff/SKILL.md +195 -0
- package/skills/implement/SKILL.md +783 -0
- package/skills/implement/reference.md +935 -0
- package/skills/retry/SKILL.md +333 -0
- package/skills/status/SKILL.md +182 -0
|
@@ -0,0 +1,935 @@
|
|
|
1
|
+
# fp:implement Reference
|
|
2
|
+
|
|
3
|
+
## Task Interface
|
|
4
|
+
|
|
5
|
+
Each task in the task tree has this structure:
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
interface Task {
|
|
9
|
+
id: string; // e.g. "1.2.1"
|
|
10
|
+
description: string; // what to implement
|
|
11
|
+
acceptanceCriteria: string[]; // measurable criteria for verification
|
|
12
|
+
estimatedComplexity: number; // 1-10 scale
|
|
13
|
+
dependencies: string[]; // task IDs that must complete first
|
|
14
|
+
subtasks?: Task[]; // if present, this is NOT a leaf task
|
|
15
|
+
status?: 'pending' | 'in-progress' | 'completed' | 'failed';
|
|
16
|
+
metadata?: {
|
|
17
|
+
filesToModify?: string[]; // files the builder should focus on
|
|
18
|
+
testsRequired?: boolean; // whether tests must be written
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Only **leaf tasks** (those without `subtasks`) are executed.
|
|
24
|
+
|
|
25
|
+
## VerificationReport Format
|
|
26
|
+
|
|
27
|
+
The verification subagent produces structured verification reports:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
interface VerificationReport {
|
|
31
|
+
verified: boolean; // true if ALL criteria passed
|
|
32
|
+
passedCriteria: number[]; // indices of passed acceptance criteria (0-based)
|
|
33
|
+
failedCriteria: number[]; // indices of failed acceptance criteria (0-based)
|
|
34
|
+
feedback: string; // human-readable summary
|
|
35
|
+
suggestions?: string[]; // optional improvement suggestions
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Plan File Formats
|
|
40
|
+
|
|
41
|
+
### `.fractal-planner/plans/{planId}/tasks.md`
|
|
42
|
+
|
|
43
|
+
The task tree file uses this markdown structure:
|
|
44
|
+
|
|
45
|
+
```markdown
|
|
46
|
+
# Task Decomposition
|
|
47
|
+
|
|
48
|
+
## Root Task
|
|
49
|
+
- [ID: root] Main goal description (Complexity: 8)
|
|
50
|
+
|
|
51
|
+
### Subtasks
|
|
52
|
+
- [ID: 1] First major component (Complexity: 6)
|
|
53
|
+
- [ID: 1.1] Sub-component A (Complexity: 3)
|
|
54
|
+
- Acceptance: Code compiles, tests pass, follows patterns
|
|
55
|
+
- Dependencies: none
|
|
56
|
+
- Files: src/foo.ts
|
|
57
|
+
- Tests Required: yes
|
|
58
|
+
- [ID: 1.2] Sub-component B (Complexity: 4)
|
|
59
|
+
- Acceptance: Integration works, error handling present
|
|
60
|
+
- Dependencies: 1.1
|
|
61
|
+
- Files: src/bar.ts, src/baz.ts
|
|
62
|
+
- Tests Required: yes
|
|
63
|
+
- [ID: 2] Second major component (Complexity: 5)
|
|
64
|
+
- [ID: 2.1] Setup config (Complexity: 2)
|
|
65
|
+
- Acceptance: Config file created, validated by schema
|
|
66
|
+
- Dependencies: none
|
|
67
|
+
- Files: config/setup.json
|
|
68
|
+
- Tests Required: no
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### `.fractal-planner/plans/{planId}/plan.md`
|
|
72
|
+
|
|
73
|
+
The execution plan file uses this markdown structure:
|
|
74
|
+
|
|
75
|
+
```markdown
|
|
76
|
+
# Implementation Plan
|
|
77
|
+
|
|
78
|
+
## Execution Order
|
|
79
|
+
1. [Task 1.1]: Sub-component A
|
|
80
|
+
- Dependencies: none
|
|
81
|
+
- Acceptance:
|
|
82
|
+
1. Code compiles without errors
|
|
83
|
+
2. Tests pass
|
|
84
|
+
3. Follows existing patterns
|
|
85
|
+
2. [Task 2.1]: Setup config
|
|
86
|
+
- Dependencies: none
|
|
87
|
+
- Acceptance:
|
|
88
|
+
1. Config file created
|
|
89
|
+
2. Validated by schema
|
|
90
|
+
3. [Task 1.2]: Sub-component B
|
|
91
|
+
- Dependencies: 1.1
|
|
92
|
+
- Acceptance:
|
|
93
|
+
1. Integration works
|
|
94
|
+
2. Error handling present
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Valid/Invalid Input Examples
|
|
98
|
+
|
|
99
|
+
### Valid
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
/fp:implement abc123
|
|
103
|
+
/fp:implement abc123 --max-iterations 5
|
|
104
|
+
/fp:implement my-session-id-here
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Invalid
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
/fp:implement # missing planId
|
|
111
|
+
/fp:implement --max-iterations 3 # missing planId (flag is not a planId)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Codebase Context File
|
|
115
|
+
|
|
116
|
+
### Format
|
|
117
|
+
|
|
118
|
+
`.fractal-planner/plans/{planId}/context.md`:
|
|
119
|
+
|
|
120
|
+
```markdown
|
|
121
|
+
# Codebase Context
|
|
122
|
+
|
|
123
|
+
## Project Overview
|
|
124
|
+
[1-2 sentence description of what this project is]
|
|
125
|
+
|
|
126
|
+
## Tech Stack
|
|
127
|
+
- Language: [e.g. TypeScript]
|
|
128
|
+
- Runtime: [e.g. Bun]
|
|
129
|
+
- Build: [e.g. bun build + tsc]
|
|
130
|
+
- Test: [e.g. bun test / vitest]
|
|
131
|
+
- Package manager: [e.g. bun]
|
|
132
|
+
|
|
133
|
+
## Project Structure
|
|
134
|
+
[Key directories and their purpose, 5-10 lines max]
|
|
135
|
+
|
|
136
|
+
## Key Files
|
|
137
|
+
[Entry points, configs, shared types — the files you'd read first]
|
|
138
|
+
|
|
139
|
+
## Patterns & Conventions
|
|
140
|
+
[Naming, module structure, error handling, export style — what a new contributor needs to know]
|
|
141
|
+
|
|
142
|
+
## Build & Test Commands
|
|
143
|
+
[Exact commands to build, test, lint]
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Three-Tier Fallback
|
|
147
|
+
|
|
148
|
+
The implementation lead loads codebase context using this fallback chain:
|
|
149
|
+
|
|
150
|
+
1. **Tier 1 — Plan-time context file**: `fp:plan` Phase 1 produces `.fractal-planner/plans/{planId}/context.md` as a byproduct of research. If this file exists, use it directly.
|
|
151
|
+
2. **Tier 2 — Lead-generated context**: If the file doesn't exist (older plan or plan created before this feature), the lead generates it by reading `package.json`, scanning project structure, and identifying patterns. The result is written to `.fractal-planner/plans/{planId}/context.md` for reuse.
|
|
152
|
+
3. **Tier 3 — Self-discovery**: If both fail, `codebaseContext` is set to empty string and builder explores the codebase itself (no injection).
|
|
153
|
+
|
|
154
|
+
The context is injected into:
|
|
155
|
+
- Builder spawn instructions (so it knows the tech stack, patterns, and conventions)
|
|
156
|
+
- Verification subagent prompt (so it knows what patterns to check against)
|
|
157
|
+
|
|
158
|
+
## Native Task Format
|
|
159
|
+
|
|
160
|
+
### TaskCreate Fields
|
|
161
|
+
|
|
162
|
+
| Field | Value |
|
|
163
|
+
|-------|-------|
|
|
164
|
+
| `subject` | `[{planTaskId}] {description truncated to 80 chars}` |
|
|
165
|
+
| `description` | Full static builder payload (see template below) |
|
|
166
|
+
| `activeForm` | `Implementing [{planTaskId}]` |
|
|
167
|
+
| `addBlockedBy` | Array of native task IDs for plan-level dependencies (only those already in `taskMap`) |
|
|
168
|
+
|
|
169
|
+
The `owner` field is set by the builder itself during the claim step (TaskUpdate), using its own name (e.g., `builder-1`). This naming convention enables P3 tooling that reads `owner` from task JSON files.
|
|
170
|
+
|
|
171
|
+
### Structured Delegation Format
|
|
172
|
+
|
|
173
|
+
The `description` field of each native task holds a rigid 6-section builder payload. This format constrains builder behavior by making guardrails explicit and always present.
|
|
174
|
+
|
|
175
|
+
```markdown
|
|
176
|
+
## TASK
|
|
177
|
+
{one-sentence atomic goal from task.description}
|
|
178
|
+
|
|
179
|
+
## EXPECTED OUTCOME
|
|
180
|
+
1. {criterion from task.acceptanceCriteria}
|
|
181
|
+
2. {criterion from task.acceptanceCriteria}
|
|
182
|
+
|
|
183
|
+
## MUST DO
|
|
184
|
+
- {hint from task.metadata.hints}
|
|
185
|
+
- {reference from task.metadata.references, if any}
|
|
186
|
+
|
|
187
|
+
## MUST NOT DO
|
|
188
|
+
- Do NOT modify files outside: {task.metadata.filesToModify list}
|
|
189
|
+
- Do NOT add new dependencies
|
|
190
|
+
- Do NOT refactor existing code beyond the task scope
|
|
191
|
+
- {additional guardrail from task.metadata.guardrails}
|
|
192
|
+
|
|
193
|
+
## CONTEXT
|
|
194
|
+
- Files: {task.metadata.filesToModify}
|
|
195
|
+
- Tests Required: {task.metadata.testsRequired — yes/no}
|
|
196
|
+
- References: {task.metadata.references, or omit line if none}
|
|
197
|
+
|
|
198
|
+
## VERIFICATION
|
|
199
|
+
- Test Commands: {task.metadata.testCommands, or "none"}
|
|
200
|
+
- Evidence: .fractal-planner/plans/{planId}/evidence/task-{id}-verification.md
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### Section Construction Rules
|
|
204
|
+
|
|
205
|
+
| Section | Source Fields | Notes |
|
|
206
|
+
|---------|-------------|-------|
|
|
207
|
+
| TASK | `task.description` | One sentence only |
|
|
208
|
+
| EXPECTED OUTCOME | `task.acceptanceCriteria` | Numbered list |
|
|
209
|
+
| MUST DO | `task.metadata.hints` + `task.metadata.references` | References formatted as "Read {file}:{line} — {explanation}" |
|
|
210
|
+
| MUST NOT DO | Baseline guardrails + `task.metadata.guardrails` | 3 baseline items always present (see below), then task-specific |
|
|
211
|
+
| CONTEXT | `task.metadata.filesToModify`, `task.metadata.testsRequired`, `task.metadata.references` | Static context only |
|
|
212
|
+
| VERIFICATION | `task.metadata.testCommands`, `task.metadata.testsRequired` | Evidence file path included |
|
|
213
|
+
|
|
214
|
+
**Baseline guardrails** (always in MUST NOT DO, regardless of task metadata):
|
|
215
|
+
1. `Do NOT modify files outside: {filesToModify list}`
|
|
216
|
+
2. `Do NOT add new dependencies`
|
|
217
|
+
3. `Do NOT refactor existing code beyond the task scope`
|
|
218
|
+
|
|
219
|
+
Task-specific guardrails from `task.metadata.guardrails` are appended after these three.
|
|
220
|
+
|
|
221
|
+
**Note**: Dependencies are NOT included in the payload — they are handled by native `addBlockedBy` on TaskCreate.
|
|
222
|
+
|
|
223
|
+
Do NOT include dynamic content (notepad entries, codebase context) in the native task description. Codebase context is injected at builder spawn time; notepad entries are read by the builder per-task from `notepad.md`.
|
|
224
|
+
|
|
225
|
+
### TaskUpdate Status Patterns
|
|
226
|
+
|
|
227
|
+
| Scenario | `status` | `metadata` |
|
|
228
|
+
|----------|----------|------------|
|
|
229
|
+
| Task claimed by builder | `in_progress` | `{ owner: "builder-N" }` |
|
|
230
|
+
| Verification passed + committed | `completed` | `{ fpStatus: "COMPLETED", iterations: "n/max", commit: "hash", summary: "text" }` |
|
|
231
|
+
| Max iterations reached | `completed` | `{ fpStatus: "FAILED", iterations: "max/max", reason: "text" }` |
|
|
232
|
+
| Builder finished implementation | `in_progress` | `{ fpStatus: "AWAITING_VERIFICATION" }` |
|
|
233
|
+
| Verification failed, retry cycle | `in_progress` | `{ fpStatus: "IMPLEMENTING" }` |
|
|
234
|
+
| Blocked by failed dependency | `deleted` | `{ fpStatus: "SKIPPED", reason: "Blocked by {planTaskId}" }` |
|
|
235
|
+
|
|
236
|
+
**Why `completed` for FAILED?** Native statuses are `pending`, `in_progress`, `completed`, `deleted`. Marking a failed task `completed` causes the native system to auto-clear `blockedBy` on its dependents. The lead then immediately marks those dependents `deleted` (SKIPPED) before the next `TaskList()` call. `metadata.fpStatus` is the authoritative status for FAILED vs COMPLETED tasks.
|
|
237
|
+
|
|
238
|
+
**Why `deleted` for SKIPPED?** `deleted` tasks are invisible to `TaskList()`, preventing them from appearing as ready in future computations.
|
|
239
|
+
|
|
240
|
+
## Self-Claiming Protocol
|
|
241
|
+
|
|
242
|
+
### Overview
|
|
243
|
+
|
|
244
|
+
Builders are persistent teammates that run a self-claiming work loop. Instead of the lead computing waves and assigning tasks, builders call `TaskList()` themselves, claim available tasks via `TaskUpdate(owner)`, and read task payloads via `TaskGet()`. The lead shrinks to: spawn builders, handle verification, serialize commits, manage failures.
|
|
245
|
+
|
|
246
|
+
### Builder Naming Convention
|
|
247
|
+
|
|
248
|
+
Builders are named `builder-1` through `builder-N` (where N = `maxParallelTasks`). The builder name matches the `owner` value set in native task JSON — this is critical for the nudge mechanism (P3) where the TeammateIdle hook reads `owner` from task files.
|
|
249
|
+
|
|
250
|
+
### Claiming Rules
|
|
251
|
+
|
|
252
|
+
- **One task at a time**: A builder must complete (or be told to move on from) its current task before claiming the next.
|
|
253
|
+
- **Lowest ID first**: When multiple tasks are available, pick the one with the lowest native task ID.
|
|
254
|
+
- **Race handling**: If two builders claim the same task (last-write-wins on `TaskUpdate`), the lead detects duplicate `TASK_CLAIMED` messages and tells the second builder `TASK_ALREADY_CLAIMED`.
|
|
255
|
+
|
|
256
|
+
### Builder → Lead Messages
|
|
257
|
+
|
|
258
|
+
| Message | When | Payload |
|
|
259
|
+
|---------|------|---------|
|
|
260
|
+
| `TASK_CLAIMED: {planTaskId}` | After claiming via TaskUpdate | `Builder: {builderName}`, `NativeId: {nativeTaskId}` |
|
|
261
|
+
| `IMPLEMENTATION COMPLETE: {planTaskId}` | After finishing implementation | `FILES_MODIFIED:` list, optional `NOTEPAD_ENTRY:` |
|
|
262
|
+
| `CLARIFICATION NEEDED: {planTaskId}` | Iteration 1, before IMPLEMENTATION COMPLETE | `QUESTION:`, `OPTIONS:`, `HEADER:`, `MULTI_SELECT:` |
|
|
263
|
+
| `NO_MORE_TASKS: {builderName}` | When TaskList returns no claimable tasks | None |
|
|
264
|
+
|
|
265
|
+
### Lead → Builder Messages
|
|
266
|
+
|
|
267
|
+
| Message | When | Effect on Builder |
|
|
268
|
+
|---------|------|-------------------|
|
|
269
|
+
| `VERIFICATION PASSED: {planTaskId}` | After verifier passes | Builder loops to claim next task |
|
|
270
|
+
| `VERIFICATION FAILED: {planTaskId}` | After verifier fails, iterations remain | Builder fixes issues and re-sends IMPLEMENTATION COMPLETE |
|
|
271
|
+
| `MAX_ITERATIONS_REACHED: {planTaskId}` | After verifier fails, no iterations remain | Builder loops to claim next task |
|
|
272
|
+
| `CLARIFICATION ANSWER: {planTaskId}` | After user answers clarification | Builder continues implementation |
|
|
273
|
+
| `TASKS_AVAILABLE` | After commit unblocks new tasks | Idle builder resumes self-claiming loop |
|
|
274
|
+
| `TASK_ALREADY_CLAIMED: {planTaskId}` | Duplicate claim detected | Builder loops to claim a different task |
|
|
275
|
+
|
|
276
|
+
### TASK_CLAIMED Message Format
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
TASK_CLAIMED: {planTaskId}
|
|
280
|
+
Builder: {builderName}
|
|
281
|
+
NativeId: {nativeTaskId}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Execution State File
|
|
285
|
+
|
|
286
|
+
### Location
|
|
287
|
+
|
|
288
|
+
`.fractal-planner/plans/{planId}/execution-state.json`
|
|
289
|
+
|
|
290
|
+
### Format
|
|
291
|
+
|
|
292
|
+
```json
|
|
293
|
+
{
|
|
294
|
+
"planId": "20260219-153000",
|
|
295
|
+
"team": "fp-impl-20260219-153000",
|
|
296
|
+
"taskMap": {
|
|
297
|
+
"T1.1": "1",
|
|
298
|
+
"T1.2": "2",
|
|
299
|
+
"T2.1": "3"
|
|
300
|
+
},
|
|
301
|
+
"maxIterations": 3,
|
|
302
|
+
"noCommit": false,
|
|
303
|
+
"createdAt": "2026-02-19T15:30:00Z",
|
|
304
|
+
"skippedTasks": {
|
|
305
|
+
"T2.1": "Blocked by T1.1"
|
|
306
|
+
},
|
|
307
|
+
"failureReasons": {
|
|
308
|
+
"T1.1": "Criterion 2 failed: catch block never triggered"
|
|
309
|
+
},
|
|
310
|
+
"iterationMap": {
|
|
311
|
+
"T1.1": 3,
|
|
312
|
+
"T1.2": 1
|
|
313
|
+
},
|
|
314
|
+
"clarificationsUsed": {
|
|
315
|
+
"T1.1": true
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Field Descriptions
|
|
321
|
+
|
|
322
|
+
| Field | Description |
|
|
323
|
+
|-------|-------------|
|
|
324
|
+
| `planId` | Plan session ID |
|
|
325
|
+
| `team` | Native team name (`fp-impl-{planId}`) |
|
|
326
|
+
| `taskMap` | Maps plan task IDs to native task IDs returned by `TaskCreate` |
|
|
327
|
+
| `maxIterations` | Max builder iterations per task |
|
|
328
|
+
| `noCommit` | Whether `--no-commit` was passed |
|
|
329
|
+
| `createdAt` | ISO timestamp when the file was first written |
|
|
330
|
+
| `skippedTasks` | Map of plan task ID → skip reason (updated incrementally) |
|
|
331
|
+
| `failureReasons` | Map of plan task ID → failure reason (updated incrementally) |
|
|
332
|
+
| `iterationMap` | Map of plan task ID → current iteration number (updated incrementally) |
|
|
333
|
+
| `clarificationsUsed` | Map of plan task ID → boolean, tracks whether clarification was used (updated incrementally) |
|
|
334
|
+
|
|
335
|
+
### When Written vs. Updated
|
|
336
|
+
|
|
337
|
+
- **Written once**: After all `TaskCreate` calls complete on a fresh run (Step 4.0)
|
|
338
|
+
- **Updated incrementally**:
|
|
339
|
+
- `skippedTasks` and `failureReasons` are updated in-place during Step 5.8 as tasks fail and their dependents are cascade-skipped
|
|
340
|
+
- `iterationMap` is updated when a task is first claimed (Step 5.3) and after each failed verification iteration (Step 5.4)
|
|
341
|
+
- `clarificationsUsed` is updated when a builder uses its clarification for a task (Step 5.5)
|
|
342
|
+
|
|
343
|
+
The file is the sole resume artifact. On resume, the lead reads `taskMap` to map plan task IDs to native task IDs, then calls `TaskList()` to get current statuses.
|
|
344
|
+
|
|
345
|
+
## Communication Protocol Summary
|
|
346
|
+
|
|
347
|
+
### Standard Flow (self-claiming with verification subagent)
|
|
348
|
+
|
|
349
|
+
```
|
|
350
|
+
Team-Lead creates team fp-impl-{planId}
|
|
351
|
+
Team-Lead calls TaskCreate for each leaf task (fresh run only) → writes execution-state.json
|
|
352
|
+
Team-Lead spawns Tracker
|
|
353
|
+
Team-Lead ──INIT──> Tracker (LINEAR_MAPPING only)
|
|
354
|
+
Tracker parses linearMapping into memory
|
|
355
|
+
Tracker ──TRACKER READY──> Team-Lead
|
|
356
|
+
|
|
357
|
+
Team-Lead spawns builder-1..builder-N (persistent)
|
|
358
|
+
Builder: TaskList() → finds pending task with empty blockedBy
|
|
359
|
+
Builder: TaskUpdate(taskId, in_progress, owner: "builder-N") → claims task
|
|
360
|
+
Builder: TaskGet(taskId) → reads full task spec
|
|
361
|
+
Builder ──TASK_CLAIMED: {id}──> Team-Lead
|
|
362
|
+
Team-Lead ──TASK_STARTED: {id}──> Tracker
|
|
363
|
+
Tracker ──ACK_STARTED: {id}──> Team-Lead
|
|
364
|
+
Builder implements → IMPLEMENTATION COMPLETE: {id} with FILES_MODIFIED
|
|
365
|
+
(Parallel mode: builder may SendMessage peer notifications to other builders — max 2 per task)
|
|
366
|
+
Team-Lead spawns Verifier subagent (Task tool):
|
|
367
|
+
Reads modified files, runs tests, checks criteria
|
|
368
|
+
Returns VERIFICATION PASSED or VERIFICATION FAILED
|
|
369
|
+
If PASSED:
|
|
370
|
+
Team-Lead ──VERIFICATION PASSED: {id}──> Builder (loops to claim next)
|
|
371
|
+
Team-Lead adds to commitQueue → processes commit
|
|
372
|
+
Team-Lead ──task──> Committer → COMMIT COMPLETED
|
|
373
|
+
TaskUpdate(nativeId, completed, fpStatus: "COMPLETED", commit: hash)
|
|
374
|
+
Team-Lead ──TASK_COMPLETED: {id}──> Tracker
|
|
375
|
+
Tracker ──ACK_COMPLETED: {id}──> Team-Lead
|
|
376
|
+
If FAILED (iterations remain):
|
|
377
|
+
Team-Lead ──VERIFICATION FAILED: {id}──> Builder (retries in-place)
|
|
378
|
+
No tasks available:
|
|
379
|
+
Builder ──NO_MORE_TASKS──> Team-Lead
|
|
380
|
+
Later: commit unblocks tasks → Team-Lead ──TASKS_AVAILABLE──> idle Builder
|
|
381
|
+
All done → Step 6 (shutdown builders, tracker, delete team)
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Failure Flow
|
|
385
|
+
|
|
386
|
+
```
|
|
387
|
+
Builder retries exhaust all iterations without passing verification
|
|
388
|
+
Team-Lead ──ask──> User: "Task {id} failed. Continue or stop?"
|
|
389
|
+
TaskUpdate(nativeId, status: "completed", fpStatus: "FAILED") ← auto-unblocks dependents
|
|
390
|
+
Update execution-state.json failureReasons
|
|
391
|
+
Team-Lead ──TASK_FAILED: {id}──> Tracker (+ Linear failed)
|
|
392
|
+
Tracker ──ACK_FAILED: {id}──> Team-Lead
|
|
393
|
+
Team-Lead computes blocked dependents from plan-level dependency graph
|
|
394
|
+
For each blocked dependent:
|
|
395
|
+
TaskUpdate(depNativeId, status: "deleted", fpStatus: "SKIPPED")
|
|
396
|
+
Update execution-state.json skippedTasks
|
|
397
|
+
Team-Lead ──TASK_SKIPPED: {blocked_id}\nReason: Blocked by {id}──> Tracker
|
|
398
|
+
Tracker ──ACK_SKIPPED: {blocked_id}──> Team-Lead
|
|
399
|
+
Team-Lead ──MAX_ITERATIONS_REACHED: {id}──> Builder (loops to next task)
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### FILES_MODIFIED Message Format
|
|
403
|
+
|
|
404
|
+
Builder completion message (sent to team-lead when implementation is done):
|
|
405
|
+
```
|
|
406
|
+
IMPLEMENTATION COMPLETE: {id}
|
|
407
|
+
|
|
408
|
+
FILES_MODIFIED:
|
|
409
|
+
- /absolute/path/to/file1.ts
|
|
410
|
+
- /absolute/path/to/file2.test.ts
|
|
411
|
+
- /absolute/path/to/component.tsx
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
Verifier pass report (returned by verification subagent to lead):
|
|
415
|
+
```
|
|
416
|
+
VERIFICATION PASSED
|
|
417
|
+
All {N} criteria met.
|
|
418
|
+
[1-2 sentence summary of what was verified]
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
Verifier failure report (returned by verification subagent to lead):
|
|
422
|
+
```
|
|
423
|
+
VERIFICATION FAILED
|
|
424
|
+
Failed:
|
|
425
|
+
- Criterion {N}: {text} — {specific failure reason and fix instruction}
|
|
426
|
+
Passed:
|
|
427
|
+
- Criterion {N}: {text}
|
|
428
|
+
Tests: {PASS/FAIL with relevant output}
|
|
429
|
+
Typecheck: {PASS/FAIL with errors if any}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Linear Integration
|
|
433
|
+
|
|
434
|
+
### Overview
|
|
435
|
+
|
|
436
|
+
When `linear.enabled` is `true` in `.fractal-planner/config.json`, the planning phase creates Linear issues mirroring the task tree, and the implementation phase updates issue statuses as work progresses.
|
|
437
|
+
|
|
438
|
+
### Mapping File Format
|
|
439
|
+
|
|
440
|
+
`.fractal-planner/plans/{planId}/linear-mapping.json`:
|
|
441
|
+
|
|
442
|
+
```json
|
|
443
|
+
{
|
|
444
|
+
"planId": "session-id",
|
|
445
|
+
"teamId": "team-uuid",
|
|
446
|
+
"projectId": "project-uuid-or-null",
|
|
447
|
+
"resolvedStatuses": {
|
|
448
|
+
"pending": "status-uuid-1",
|
|
449
|
+
"in-progress": "status-uuid-2",
|
|
450
|
+
"completed": "status-uuid-3",
|
|
451
|
+
"failed": "status-uuid-4",
|
|
452
|
+
"review": "status-uuid-5"
|
|
453
|
+
},
|
|
454
|
+
"tasks": {
|
|
455
|
+
"root": { "linearIssueId": "issue-uuid", "linearIdentifier": "TEAM-42" },
|
|
456
|
+
"1": { "linearIssueId": "issue-uuid", "linearIdentifier": "TEAM-43" },
|
|
457
|
+
"1.1": { "linearIssueId": "issue-uuid", "linearIdentifier": "TEAM-44" }
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
This file is created during `fp:plan` Phase 2.5 and consumed during `fp:implement`. It is gitignored (under `.fractal-planner/`).
|
|
463
|
+
|
|
464
|
+
### Status Update Points
|
|
465
|
+
|
|
466
|
+
During implementation, the **tracker teammate** (not the team-lead or builder) updates Linear issues at these points:
|
|
467
|
+
|
|
468
|
+
| Event | Linear Status Update |
|
|
469
|
+
|-------|---------------------|
|
|
470
|
+
| Task claimed by builder | `in-progress` |
|
|
471
|
+
| Verification passed | `review` |
|
|
472
|
+
| Task failed (max iterations) | `failed` |
|
|
473
|
+
| Task skipped (blocked dep) | (no change) |
|
|
474
|
+
|
|
475
|
+
After all leaf tasks are processed, parent issue statuses are rolled up bottom-to-top:
|
|
476
|
+
- All children completed → parent marked `completed`
|
|
477
|
+
- Any child in-progress → parent marked `in-progress`
|
|
478
|
+
- All children failed → parent marked `failed`
|
|
479
|
+
|
|
480
|
+
### Status Resolution Strategy
|
|
481
|
+
|
|
482
|
+
Statuses are resolved once during planning (Phase 2.5) and stored in the mapping file.
|
|
483
|
+
|
|
484
|
+
**When `statusMap` is configured**: Each name (e.g. `"Todo"`, `"In Progress"`) is matched against the team's available statuses by name. If a name doesn't match, it falls back to auto-detect for that status with a warning.
|
|
485
|
+
|
|
486
|
+
**When `statusMap` is NOT configured** (default): Auto-detect by Linear status **type**:
|
|
487
|
+
- `pending` → first status of type `backlog` (or `unstarted` if no backlog type exists)
|
|
488
|
+
- `in-progress` → first status of type `started`
|
|
489
|
+
- `completed` → first status of type `completed`
|
|
490
|
+
- `failed` → first status of type `canceled`
|
|
491
|
+
- `review` → first status with name matching "In Review" (case-insensitive); falls back to resolved `completed` UUID
|
|
492
|
+
|
|
493
|
+
### Graceful Degradation
|
|
494
|
+
|
|
495
|
+
- If `linear.enabled` is `false` (default), zero Linear calls are made
|
|
496
|
+
- If Linear MCP server is unavailable, planning logs a warning and skips Linear sync — the plan still completes normally
|
|
497
|
+
- If `linearMapping` is `null` during implementation (no mapping file), all Linear updates are silently skipped
|
|
498
|
+
|
|
499
|
+
## Progress Snapshot
|
|
500
|
+
|
|
501
|
+
`.fractal-planner/plans/{planId}/progress.md` is generated **once at the end of implementation** (Step 6) as a human-readable audit artifact. It is NOT a runtime artifact and is NOT read by any skill for execution state.
|
|
502
|
+
|
|
503
|
+
All runtime state lives in:
|
|
504
|
+
- The native task system (`~/.claude/tasks/fp-impl-{planId}/`)
|
|
505
|
+
- `execution-state.json` (resume artifact)
|
|
506
|
+
|
|
507
|
+
## Tracker Communication Protocol
|
|
508
|
+
|
|
509
|
+
The `fp-task-tracker` teammate handles Linear sync. The team lead communicates with it via structured text messages.
|
|
510
|
+
|
|
511
|
+
### Lead → Tracker
|
|
512
|
+
|
|
513
|
+
| Command | When | Payload |
|
|
514
|
+
|---------|------|---------|
|
|
515
|
+
| `INIT` | At spawn | `LINEAR_MAPPING:` section with JSON or `"null"` |
|
|
516
|
+
| `TASK_STARTED: {id}` | After builder claims task | None |
|
|
517
|
+
| `TASK_COMPLETED: {id}` | After verification + commit | `Iterations: n/max`, `Commit: hash`, `Summary: text` |
|
|
518
|
+
| `TASK_FAILED: {id}` | After max iterations | `Iterations: n/max`, `Reason: text` |
|
|
519
|
+
| `TASK_SKIPPED: {id}` | Dep failed/skipped | `Reason: text` |
|
|
520
|
+
| `ROLLUP_PARENTS` | After all tasks | None |
|
|
521
|
+
|
|
522
|
+
### Tracker → Lead
|
|
523
|
+
|
|
524
|
+
| Response | Meaning |
|
|
525
|
+
|----------|---------|
|
|
526
|
+
| `TRACKER READY` | Init complete, includes `Linear: enabled/disabled` |
|
|
527
|
+
| `ACK_STARTED: {id}` | Linear updated to in-progress |
|
|
528
|
+
| `ACK_COMPLETED: {id}` | Linear updated to review/completed |
|
|
529
|
+
| `ACK_FAILED: {id}` | Linear updated to failed |
|
|
530
|
+
| `ACK_SKIPPED: {id}` | Acknowledged (no Linear update for skips) |
|
|
531
|
+
| `ROLLUP_COMPLETE` | Parent statuses rolled up in Linear |
|
|
532
|
+
|
|
533
|
+
### INIT Message Format
|
|
534
|
+
|
|
535
|
+
```
|
|
536
|
+
INIT
|
|
537
|
+
LINEAR_MAPPING:
|
|
538
|
+
{raw JSON content of linear-mapping.json, or the literal string "null"}
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
### Message Examples
|
|
542
|
+
|
|
543
|
+
**Lead reports completion:**
|
|
544
|
+
```
|
|
545
|
+
TASK_COMPLETED: 1.1
|
|
546
|
+
Iterations: 1/3
|
|
547
|
+
Commit: abc1234
|
|
548
|
+
Summary: JWT utility with sign/verify and full test coverage
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
**Tracker acknowledges:**
|
|
552
|
+
```
|
|
553
|
+
ACK_COMPLETED: 1.1
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
**Lead reports failure:**
|
|
557
|
+
```
|
|
558
|
+
TASK_FAILED: 1.3
|
|
559
|
+
Iterations: 3/3
|
|
560
|
+
Reason: Criterion 2 (error handling) consistently fails — catch block not triggered
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
**Tracker acknowledges:**
|
|
564
|
+
```
|
|
565
|
+
ACK_FAILED: 1.3
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
## Self-Claiming Execution Protocol
|
|
569
|
+
|
|
570
|
+
Builders self-organize via the native task list. The lead's role is verification, commits, failure handling, and tracker communication.
|
|
571
|
+
|
|
572
|
+
### Sequential Mode (maxParallelTasks = 1)
|
|
573
|
+
|
|
574
|
+
A single `builder-1` runs the self-claiming loop. Behavior is equivalent to the previous wave-of-1: tasks execute one at a time in dependency order. No race conditions possible.
|
|
575
|
+
|
|
576
|
+
### Parallel Mode (maxParallelTasks > 1)
|
|
577
|
+
|
|
578
|
+
N builders (`builder-1` through `builder-N`) claim tasks independently. The native `blockedBy` system ensures dependency ordering — builders can only see tasks whose dependencies are all completed. Multiple builders may work on independent tasks simultaneously. Builders may also send up to 2 peer notifications per task to coordinate shared interfaces and flag conflicts (see Peer Communication Protocol).
|
|
579
|
+
|
|
580
|
+
### Race Condition Handling
|
|
581
|
+
|
|
582
|
+
If two builders call `TaskUpdate(taskId, in_progress, owner)` on the same task, last-write-wins — both builders think they claimed it. The lead detects the race when it receives two `TASK_CLAIMED` messages for the same `planTaskId`:
|
|
583
|
+
1. First `TASK_CLAIMED` is accepted normally (recorded in `builderTaskMap`).
|
|
584
|
+
2. Second `TASK_CLAIMED` for the same `planTaskId` triggers: lead sends `TASK_ALREADY_CLAIMED: {planTaskId}` to the second builder.
|
|
585
|
+
3. The second builder loops back to `TaskList()` and claims a different task.
|
|
586
|
+
|
|
587
|
+
### Task Unblocking
|
|
588
|
+
|
|
589
|
+
After each commit in Step 5.7, the lead calls `TaskList()` to check for newly available tasks (status: "pending", blockedBy: []). If new tasks appear and idle builders exist:
|
|
590
|
+
- Lead picks an idle builder, moves it from `idleBuilders` to `activeBuilders`.
|
|
591
|
+
- Lead sends `TASKS_AVAILABLE` to wake the builder, which resumes its self-claiming loop.
|
|
592
|
+
|
|
593
|
+
### Commit Serialization
|
|
594
|
+
|
|
595
|
+
Unchanged from previous protocol — the `commitQueue` is processed one entry at a time in dependency order. Git index cannot handle parallel commits.
|
|
596
|
+
|
|
597
|
+
### Failure Handling
|
|
598
|
+
|
|
599
|
+
- Builder retries in-place when verification fails (no re-spawn).
|
|
600
|
+
- When max iterations reached: lead asks user Continue/Stop.
|
|
601
|
+
- If Continue: mark failed (TaskUpdate completed+FAILED), compute blocked dependents, mark deleted+SKIPPED for each. Send `MAX_ITERATIONS_REACHED` to builder — builder loops to next task.
|
|
602
|
+
- Other builders are unaffected and continue their self-claiming loops during failure handling.
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
## Cross-Task Notepad
|
|
607
|
+
|
|
608
|
+
File: `.fractal-planner/plans/{planId}/notepad.md`
|
|
609
|
+
|
|
610
|
+
Builders can contribute discoveries via an optional `NOTEPAD_ENTRY` section in their `IMPLEMENTATION COMPLETE` message.
|
|
611
|
+
|
|
612
|
+
### Builder Message Format (with notepad entry)
|
|
613
|
+
|
|
614
|
+
```
|
|
615
|
+
IMPLEMENTATION COMPLETE: {id}
|
|
616
|
+
|
|
617
|
+
FILES_MODIFIED:
|
|
618
|
+
- /abs/path/to/file.ts
|
|
619
|
+
|
|
620
|
+
NOTEPAD_ENTRY:
|
|
621
|
+
- PATTERN: SecureHash from src/utils/crypto.ts — use instead of raw Buffer
|
|
622
|
+
- GOTCHA: jsonwebtoken v9 requires explicit algorithm in verify() or throws
|
|
623
|
+
- UTIL: src/utils/validate.ts:45 — input validation helper already exists
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
`NOTEPAD_ENTRY` is optional. Builders should include it only when they discover something genuinely useful to future tasks.
|
|
627
|
+
|
|
628
|
+
### Entry Types
|
|
629
|
+
|
|
630
|
+
- `PATTERN`: A useful code pattern or utility found in the codebase
|
|
631
|
+
- `GOTCHA`: A non-obvious constraint or library behavior that caused issues
|
|
632
|
+
- `UTIL`: An existing utility or helper that future builders should reuse
|
|
633
|
+
- `WARN`: A risky area or fragile code that future builders should be careful around
|
|
634
|
+
|
|
635
|
+
### Notepad.md Format
|
|
636
|
+
|
|
637
|
+
```markdown
|
|
638
|
+
# Implementation Notepad
|
|
639
|
+
|
|
640
|
+
Plan: {planId}
|
|
641
|
+
Started: {ISO timestamp}
|
|
642
|
+
|
|
643
|
+
## Entries (most recent last)
|
|
644
|
+
- [Task 1.1] PATTERN: SecureHash from src/utils/crypto.ts — use instead of raw Buffer
|
|
645
|
+
- [Task 1.1] GOTCHA: jsonwebtoken v9 requires explicit algorithm in verify() or throws
|
|
646
|
+
- [Task 1.2] UTIL: src/utils/validate.ts:45 — input validation helper already exists
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
### Injection Rules
|
|
650
|
+
|
|
651
|
+
Builders read `notepad.md` themselves as part of the self-claiming loop (Step 4.4, loop step 6). The relevance filter:
|
|
652
|
+
- Include an entry if: it's in the **last 10 entries** overall, OR the task that wrote it had overlapping `filesToModify` with the current task
|
|
653
|
+
- Cap at 10 entries per task to limit context growth
|
|
654
|
+
|
|
655
|
+
---
|
|
656
|
+
|
|
657
|
+
## Peer Communication Protocol
|
|
658
|
+
|
|
659
|
+
### Overview
|
|
660
|
+
|
|
661
|
+
When `maxParallelTasks > 1`, builders can send direct messages to peer builders via `SendMessage`. This enables real-time coordination during parallel work — sharing new interfaces, flagging conflicts, and propagating discoveries without waiting for the notepad cycle (which only propagates after commit).
|
|
662
|
+
|
|
663
|
+
Peer messages are **informational and one-way**. Builders do not wait for responses. The lead sees peer DM summaries in idle notifications automatically (built into agent teams framework).
|
|
664
|
+
|
|
665
|
+
In sequential mode (`maxParallelTasks = 1`), peer communication is disabled (`peerBuilderNames = "none"`).
|
|
666
|
+
|
|
667
|
+
### Message Format
|
|
668
|
+
|
|
669
|
+
```
|
|
670
|
+
PEER_NOTIFICATION
|
|
671
|
+
TYPE: {notification_type}
|
|
672
|
+
DETAILS:
|
|
673
|
+
{1-3 lines describing what happened and what the peer should do}
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
Sent via: `SendMessage(type: "message", recipient: "{peer-builder-name}", content: "...", summary: "...")`
|
|
677
|
+
|
|
678
|
+
### Notification Types
|
|
679
|
+
|
|
680
|
+
| Type | When to Send | Example |
|
|
681
|
+
|------|-------------|---------|
|
|
682
|
+
| `INTERFACE_CREATED` | Created a new export/type/utility that a peer's task could consume | `Created validateInput(s: string): boolean at src/utils/validate.ts:10. Use this instead of inline validation.` |
|
|
683
|
+
| `PATTERN_FOUND` | Discovered a codebase convention or library quirk affecting a peer's work area | `This codebase uses zod v4 parse() not safeParse(). Your task touches the same validation layer.` |
|
|
684
|
+
| `CONFLICT_WARNING` | Detected overlapping file modifications or incompatible interface assumptions | `I'm modifying src/config.ts exports — your task also imports from it. I renamed loadConfig to loadConfigAsync.` |
|
|
685
|
+
| `FILE_MOVED` | Moved or renamed a file that a peer's task references | `Moved src/utils/helpers.ts to src/utils/string-helpers.ts. Your task references the old path.` |
|
|
686
|
+
|
|
687
|
+
### Budget Rules
|
|
688
|
+
|
|
689
|
+
- **2 messages max per task** — counter resets when claiming a new task
|
|
690
|
+
- Send to the **specific peer(s) affected**, not broadcast to all peers
|
|
691
|
+
- If unsure whether a peer is affected, don't send — false positives waste turns
|
|
692
|
+
- Each message consumes one tool call (one builder turn), so budget is self-limiting
|
|
693
|
+
|
|
694
|
+
### Receiving Protocol
|
|
695
|
+
|
|
696
|
+
Builders may receive `PEER_NOTIFICATION` messages at any point during their work:
|
|
697
|
+
1. Read the message content
|
|
698
|
+
2. If relevant to current task: adapt approach (e.g., reuse a newly created utility, adjust for a renamed import)
|
|
699
|
+
3. If not relevant: ignore and continue
|
|
700
|
+
4. **Never reply** to peer messages — they are one-way
|
|
701
|
+
5. **Never block** waiting for peer input
|
|
702
|
+
|
|
703
|
+
### Interaction with Notepad
|
|
704
|
+
|
|
705
|
+
Peer messages and notepad entries serve different timescales:
|
|
706
|
+
- **Peer messages**: real-time, within the current wave (reaches concurrent builders immediately)
|
|
707
|
+
- **Notepad entries**: post-commit, for future waves (reaches builders who claim tasks later)
|
|
708
|
+
|
|
709
|
+
If a discovery is useful for both current peers AND future tasks, do both:
|
|
710
|
+
1. Send a `PEER_NOTIFICATION` to affected concurrent peers
|
|
711
|
+
2. Include it as a `NOTEPAD_ENTRY` in your `IMPLEMENTATION COMPLETE` message
|
|
712
|
+
|
|
713
|
+
### When NOT to Send
|
|
714
|
+
|
|
715
|
+
- Discovery only matters for future tasks → use `NOTEPAD_ENTRY` only
|
|
716
|
+
- Not sure if peer is affected → skip (avoid false positives)
|
|
717
|
+
- Budget exhausted (2 messages sent for current task) → save it for `NOTEPAD_ENTRY`
|
|
718
|
+
- Sequential mode (`peerBuilderNames` is "none") → protocol is disabled
|
|
719
|
+
- Trivial changes that don't affect peers → skip
|
|
720
|
+
|
|
721
|
+
---
|
|
722
|
+
|
|
723
|
+
## Evidence File Format
|
|
724
|
+
|
|
725
|
+
File: `.fractal-planner/plans/{planId}/evidence/task-{id}-verification.md`
|
|
726
|
+
|
|
727
|
+
Written by the verifier subagent after each verification pass. Used by the lead to extract PASS/FAIL (more robust than parsing agent messages), and by `fp:status` for reporting.
|
|
728
|
+
|
|
729
|
+
### Format
|
|
730
|
+
|
|
731
|
+
```markdown
|
|
732
|
+
# Verification Evidence: Task {id}
|
|
733
|
+
|
|
734
|
+
Result: PASS | FAIL
|
|
735
|
+
Timestamp: {ISO timestamp}
|
|
736
|
+
Task: {description}
|
|
737
|
+
|
|
738
|
+
## Criteria Results
|
|
739
|
+
| # | Criterion | Result | Evidence |
|
|
740
|
+
|---|-----------|--------|---------|
|
|
741
|
+
| 1 | {text} | PASS/FAIL | {code snippet, "met", or specific failure reason} |
|
|
742
|
+
| 2 | {text} | PASS/FAIL | {code snippet, "met", or specific failure reason} |
|
|
743
|
+
|
|
744
|
+
## Test Output
|
|
745
|
+
```
|
|
746
|
+
{test command output or "Tests not required"}
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
## Typecheck Output
|
|
750
|
+
```
|
|
751
|
+
{typecheck output or "No tsconfig.json found"}
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
## Files Reviewed
|
|
755
|
+
- /absolute/path/to/reviewed/file.ts
|
|
756
|
+
|
|
757
|
+
## Summary
|
|
758
|
+
{1-2 sentence summary of the verification result}
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
### Lead Behavior with Evidence Files
|
|
762
|
+
|
|
763
|
+
- Lead reads the evidence file (not just the agent message) to extract `Result: PASS | FAIL`
|
|
764
|
+
- On resume: evidence files from the previous session provide failure context for builders retrying tasks
|
|
765
|
+
- In `fp:status` output: evidence files are linked for FAILED tasks
|
|
766
|
+
|
|
767
|
+
---
|
|
768
|
+
|
|
769
|
+
## Handoff File Format
|
|
770
|
+
|
|
771
|
+
File: `.fractal-planner/plans/{planId}/handoff.md`
|
|
772
|
+
|
|
773
|
+
Generated by `/fp:handoff` to provide a dense context summary for session continuation. When a large plan exhausts the context window mid-implementation, the handoff file captures volatile state (discoveries, iteration counts, failure details) so the next `/fp:implement` session resumes with full context.
|
|
774
|
+
|
|
775
|
+
### When Generated
|
|
776
|
+
|
|
777
|
+
Run `/fp:handoff {planId}` after an implementation session ends (or is interrupted). Can be run multiple times — each run overwrites the previous handoff.
|
|
778
|
+
|
|
779
|
+
### How Consumed
|
|
780
|
+
|
|
781
|
+
During `/fp:implement` resume (Step 4.1):
|
|
782
|
+
1. Lead checks for `handoff.md` in the plan directory
|
|
783
|
+
2. If found, extracts "Key Discoveries" section → injected into builder spawn context (Step 5.1)
|
|
784
|
+
3. "Resume Notes" section → displayed to user
|
|
785
|
+
4. Structural resume still uses `execution-state.json` + `TaskList()` — handoff.md adds curated context only
|
|
786
|
+
|
|
787
|
+
### Format
|
|
788
|
+
|
|
789
|
+
```markdown
|
|
790
|
+
# Handoff: {planId}
|
|
791
|
+
Generated: {ISO timestamp}
|
|
792
|
+
|
|
793
|
+
## Progress
|
|
794
|
+
Completed: N/{total} | Failed: M | Skipped: S | Remaining: R
|
|
795
|
+
|
|
796
|
+
## Completed Tasks
|
|
797
|
+
- {planTaskId}: {description} | Iterations: n/max | Commit: {hash}
|
|
798
|
+
|
|
799
|
+
## Failed Tasks
|
|
800
|
+
- {planTaskId}: {description} | Iterations: max/max | Reason: {reason}
|
|
801
|
+
|
|
802
|
+
## Skipped Tasks
|
|
803
|
+
- {planTaskId}: {description} | Reason: Blocked by {depId}
|
|
804
|
+
|
|
805
|
+
## In Progress (Interrupted)
|
|
806
|
+
- {planTaskId}: {description} | Iteration: n/max | Owner: {builder}
|
|
807
|
+
|
|
808
|
+
## Pending Tasks
|
|
809
|
+
- {planTaskId}: {description} | Blocked by: {deps or "none (ready)"}
|
|
810
|
+
|
|
811
|
+
## Key Discoveries
|
|
812
|
+
{verbatim entries from notepad.md ## Entries section}
|
|
813
|
+
|
|
814
|
+
## Resume Notes
|
|
815
|
+
- Iteration counts and clarification state preserved in execution-state.json
|
|
816
|
+
- {task-specific warnings based on failure patterns, if any}
|
|
817
|
+
- {note if all tasks completed: "All tasks complete. No resume needed."}
|
|
818
|
+
|
|
819
|
+
## Resume Command
|
|
820
|
+
/fp:implement {planId}
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
### Section Rules
|
|
824
|
+
|
|
825
|
+
- Omit "Failed Tasks", "Skipped Tasks", "In Progress" sections when their count is zero
|
|
826
|
+
- Use description from `plan.md` lookup, not truncated subject from native task
|
|
827
|
+
- For IN_PROGRESS: include owner from task JSON metadata, iteration count from `iterationMap` in execution-state.json
|
|
828
|
+
- For FAILED: prefer evidence file reason, fall back to `failureReasons` in execution-state.json
|
|
829
|
+
|
|
830
|
+
### Relationship to Other Artifacts
|
|
831
|
+
|
|
832
|
+
| Artifact | Purpose | Handoff Interaction |
|
|
833
|
+
|----------|---------|---------------------|
|
|
834
|
+
| `execution-state.json` | Structural resume (taskMap, statuses, iterations) | Handoff reads; implement resumes from it |
|
|
835
|
+
| `progress.md` | Human-readable snapshot (written at end of implement) | Handoff is independent — may exist before progress.md |
|
|
836
|
+
| `notepad.md` | Builder discoveries during implementation | Handoff copies Key Discoveries from notepad entries |
|
|
837
|
+
| Native task files | Runtime task state | Handoff reads for classification; implement resumes via TaskList() |
|
|
838
|
+
|
|
839
|
+
---
|
|
840
|
+
|
|
841
|
+
## Builder Clarification Protocol
|
|
842
|
+
|
|
843
|
+
Builders may request one clarification per task, on iteration 1 only. This allows builders to surface genuine ambiguities without wasting a full iteration on a wrong assumption.
|
|
844
|
+
|
|
845
|
+
### CLARIFICATION NEEDED Format
|
|
846
|
+
|
|
847
|
+
```
|
|
848
|
+
CLARIFICATION NEEDED: {id}
|
|
849
|
+
|
|
850
|
+
QUESTION:
|
|
851
|
+
{clear, specific question about the task — one question only}
|
|
852
|
+
|
|
853
|
+
OPTIONS:
|
|
854
|
+
- {option 1 label} | {option 1 description}
|
|
855
|
+
- {option 2 label} | {option 2 description}
|
|
856
|
+
- {option 3 label} | {option 3 description}
|
|
857
|
+
|
|
858
|
+
HEADER: {12 chars max}
|
|
859
|
+
MULTI_SELECT: false
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
### Lead Response Protocol
|
|
863
|
+
|
|
864
|
+
1. Intercept `CLARIFICATION NEEDED` message from builder
|
|
865
|
+
2. Verify this is iteration 1 (tracked in `clarificationsUsed` map). If `clarificationsUsed[taskId]` is already true OR iteration > 1:
|
|
866
|
+
- Reject: `SendMessage(recipient: builder, "Clarification only allowed on iteration 1. Proceed with task spec only.")`
|
|
867
|
+
3. If valid: parse the message, call `AskUserQuestion` with the question
|
|
868
|
+
4. Mark `clarificationsUsed[taskId] = true`
|
|
869
|
+
5. Forward answer to builder:
|
|
870
|
+
```
|
|
871
|
+
CLARIFICATION ANSWER: {id}
|
|
872
|
+
User selected: "{option}"
|
|
873
|
+
Context: {additional text if any}
|
|
874
|
+
```
|
|
875
|
+
6. Builder continues implementation with the answer
|
|
876
|
+
|
|
877
|
+
### Budget Enforcement
|
|
878
|
+
|
|
879
|
+
- 1 clarification maximum per task, iteration 1 only
|
|
880
|
+
- Subsequent iterations: lead rejects with "Proceed with failure report and task spec only"
|
|
881
|
+
- In parallel mode: clarification requests are processed one at a time (AskUserQuestion is sequential)
|
|
882
|
+
|
|
883
|
+
---
|
|
884
|
+
|
|
885
|
+
## Nudge Mechanism (P3)
|
|
886
|
+
|
|
887
|
+
### Overview
|
|
888
|
+
|
|
889
|
+
A `TeammateIdle` hook that detects stalled builders and re-injects continuation prompts.
|
|
890
|
+
Prevents builders from going permanently idle while still owning in-progress tasks.
|
|
891
|
+
|
|
892
|
+
### Hook Behavior
|
|
893
|
+
|
|
894
|
+
| Teammate | Hook behavior |
|
|
895
|
+
|----------|---------------|
|
|
896
|
+
| `builder-*` on `fp-impl-*` | Active -- scans tasks, may re-inject |
|
|
897
|
+
| `tracker` | Filtered out |
|
|
898
|
+
| `committer-*` | Filtered out |
|
|
899
|
+
| Non-fp-impl teams | Filtered out |
|
|
900
|
+
|
|
901
|
+
### State File
|
|
902
|
+
|
|
903
|
+
Location: `~/.claude/teams/{team_name}/nudge-{teammate_name}.json`
|
|
904
|
+
|
|
905
|
+
```json
|
|
906
|
+
{ "retries": 1, "lastRetryAt": "2026-02-20T12:00:00Z", "taskId": "5" }
|
|
907
|
+
```
|
|
908
|
+
|
|
909
|
+
Lifecycle:
|
|
910
|
+
- Created on first stall detection for a task
|
|
911
|
+
- Retries increment on subsequent stalls for the same task
|
|
912
|
+
- **Reset** when builder moves to a different task (taskId mismatch)
|
|
913
|
+
- **Deleted** when builder has no in_progress tasks (legitimate idle)
|
|
914
|
+
- **Deleted** when retries >= maxRetries (give up)
|
|
915
|
+
|
|
916
|
+
### Configuration
|
|
917
|
+
|
|
918
|
+
```json
|
|
919
|
+
{ "nudge": { "enabled": true, "maxRetries": 3 } }
|
|
920
|
+
```
|
|
921
|
+
|
|
922
|
+
### Verification Guard
|
|
923
|
+
|
|
924
|
+
The nudge hook reads `fpStatus` from task metadata to distinguish "stuck implementing" from "waiting for verification":
|
|
925
|
+
|
|
926
|
+
- **`fpStatus: "AWAITING_VERIFICATION"`** — Builder has sent `IMPLEMENTATION COMPLETE` and is waiting for the lead's verification response. The hook exits 0 (no nudge).
|
|
927
|
+
- **`fpStatus: "IMPLEMENTING"`** (or absent) — Builder is actively implementing. If idle, this is a genuine stall and the hook fires the continuation prompt.
|
|
928
|
+
|
|
929
|
+
Lifecycle:
|
|
930
|
+
1. Builder finishes implementation → sets `fpStatus: "AWAITING_VERIFICATION"` (TaskUpdate, step 9)
|
|
931
|
+
2. Builder sends `IMPLEMENTATION COMPLETE` (SendMessage, step 10)
|
|
932
|
+
3. Lead spawns verifier, gets result
|
|
933
|
+
4. If **VERIFICATION PASSED**: lead proceeds to commit (fpStatus becomes "COMPLETED" in Step 5.7)
|
|
934
|
+
5. If **VERIFICATION FAILED**: lead resets `fpStatus: "IMPLEMENTING"` (Step 5.4), then sends failure details to builder. This re-enables nudging if the builder stalls during the retry.
|
|
935
|
+
|