taskplane 0.1.11 → 0.1.12
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/README.md +180 -2
- package/bin/taskplane.mjs +288 -32
- package/package.json +1 -1
- package/templates/agents/task-merger.md +35 -76
- package/templates/config/task-orchestrator.yaml +3 -3
- package/templates/config/task-runner.yaml +2 -2
- package/templates/tasks/EXAMPLE-001-hello-world/PROMPT.md +15 -6
- package/templates/tasks/EXAMPLE-001-hello-world/STATUS.md +2 -2
- package/templates/tasks/EXAMPLE-002-parallel-smoke/PROMPT.md +98 -0
- package/templates/tasks/EXAMPLE-002-parallel-smoke/STATUS.md +73 -0
package/README.md
CHANGED
|
@@ -1,2 +1,180 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# Taskplane
|
|
2
|
+
|
|
3
|
+
Multi-agent AI orchestration for [pi](https://github.com/badlogic/pi-mono) — parallel task execution with checkpoint discipline, fresh-context worker loops, cross-model reviews, and automated merges.
|
|
4
|
+
|
|
5
|
+
> **Status:** Experimental / Early — APIs and config formats may change between releases.
|
|
6
|
+
|
|
7
|
+
## What It Does
|
|
8
|
+
|
|
9
|
+
Taskplane turns your coding project into an AI-managed task board. You define tasks as structured markdown files. Taskplane's agents execute them autonomously — one at a time with `/task`, or many in parallel with `/orch`.
|
|
10
|
+
|
|
11
|
+
### Key Features
|
|
12
|
+
|
|
13
|
+
- **Task Runner** (`/task`) — Autonomous single-task execution. Workers run in fresh-context loops with STATUS.md as persistent memory. Every checkbox gets a git checkpoint. Cross-model reviewers catch what the worker missed.
|
|
14
|
+
- **Task Orchestrator** (`/orch`) — Parallel multi-task execution using git worktrees for full filesystem isolation. Dependency-aware wave scheduling. Automated merges with conflict resolution.
|
|
15
|
+
- **Web Dashboard** — Live browser-based monitoring via `taskplane dashboard`. SSE streaming, lane/task progress, wave visualization, batch history.
|
|
16
|
+
- **Structured Tasks** — PROMPT.md defines the mission, steps, and constraints. STATUS.md tracks progress. Agents follow the plan, not vibes.
|
|
17
|
+
- **Checkpoint Discipline** — Every completed checkbox item triggers a git commit. Work is never lost, even if a worker crashes mid-task.
|
|
18
|
+
- **Cross-Model Review** — Reviewer agent uses a different model than the worker. Independent quality gate before merge.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
Taskplane is a [pi package](https://github.com/badlogic/pi-mono). You need [Node.js](https://nodejs.org/) ≥ 20 and [pi](https://github.com/badlogic/pi-mono) installed first.
|
|
23
|
+
|
|
24
|
+
### Option A: Global Install (all projects)
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pi install npm:taskplane
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Option B: Project-Local Install (recommended for teams)
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
cd my-project
|
|
34
|
+
pi install -l npm:taskplane
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Then scaffold your project:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
taskplane init
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Verify the installation:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
taskplane doctor
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Quickstart
|
|
50
|
+
|
|
51
|
+
### 1. Initialize a project
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
cd my-project
|
|
55
|
+
taskplane init --preset full
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
This creates config files in `.pi/`, agent prompts, and two example tasks.
|
|
59
|
+
|
|
60
|
+
### 2. Launch the dashboard (recommended)
|
|
61
|
+
|
|
62
|
+
In a separate terminal:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
taskplane dashboard
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Opens a live web dashboard at `http://localhost:8099` with real-time batch monitoring.
|
|
69
|
+
|
|
70
|
+
### 3. Run your first orchestration
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pi
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Inside the pi session:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
/orch-plan all # Preview waves, lanes, and dependencies
|
|
80
|
+
/orch all # Execute all pending tasks in parallel
|
|
81
|
+
/orch-status # Monitor batch progress
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The default scaffold includes two independent example tasks, so `/orch all` gives you an immediate orchestrator + dashboard experience.
|
|
85
|
+
|
|
86
|
+
### 4. Optional: run one task directly
|
|
87
|
+
|
|
88
|
+
`/task` is still useful for single-task execution and focused debugging:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
/task taskplane-tasks/EXAMPLE-001-hello-world/PROMPT.md
|
|
92
|
+
/task-status
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Important distinction:
|
|
96
|
+
|
|
97
|
+
- `/task` runs in your **current branch/worktree**.
|
|
98
|
+
- `/orch` runs tasks in **isolated worktrees** and merges back.
|
|
99
|
+
|
|
100
|
+
Because workers checkpoint with git commits, `/task` can capture unrelated local edits if you're changing files in parallel. For safer isolation (even with one task), prefer:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
/orch taskplane-tasks/EXAMPLE-001-hello-world/PROMPT.md
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Orchestrator lanes execute tasks through task-runner under the hood, so `/task` and `/orch` share the same core task execution model.
|
|
107
|
+
|
|
108
|
+
## Commands
|
|
109
|
+
|
|
110
|
+
### Pi Session Commands
|
|
111
|
+
|
|
112
|
+
| Command | Description |
|
|
113
|
+
|---------|-------------|
|
|
114
|
+
| `/task <path/to/PROMPT.md>` | Execute one task in the current branch/worktree |
|
|
115
|
+
| `/task-status` | Show current task progress |
|
|
116
|
+
| `/task-pause` | Pause after current worker iteration finishes |
|
|
117
|
+
| `/task-resume` | Resume a paused task |
|
|
118
|
+
| `/orch <areas\|paths\|all>` | Execute tasks via isolated worktrees (recommended default) |
|
|
119
|
+
| `/orch-plan <areas\|paths\|all>` | Preview execution plan without running |
|
|
120
|
+
| `/orch-status` | Show batch progress |
|
|
121
|
+
| `/orch-pause` | Pause batch after current tasks finish |
|
|
122
|
+
| `/orch-resume` | Resume a paused batch |
|
|
123
|
+
| `/orch-abort [--hard]` | Abort batch (graceful or immediate) |
|
|
124
|
+
| `/orch-deps <areas\|paths\|all>` | Show dependency graph |
|
|
125
|
+
| `/orch-sessions` | List active worker sessions |
|
|
126
|
+
|
|
127
|
+
### CLI Commands
|
|
128
|
+
|
|
129
|
+
| Command | Description |
|
|
130
|
+
|---------|-------------|
|
|
131
|
+
| `taskplane init` | Scaffold project config (interactive or `--preset`) |
|
|
132
|
+
| `taskplane doctor` | Validate installation and config |
|
|
133
|
+
| `taskplane version` | Show version info |
|
|
134
|
+
| `taskplane dashboard` | Launch the web dashboard |
|
|
135
|
+
| `taskplane uninstall` | Remove Taskplane project files and optionally uninstall package (`--package`) |
|
|
136
|
+
|
|
137
|
+
## How It Works
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
141
|
+
│ ORCHESTRATOR (/orch) │
|
|
142
|
+
│ Parse tasks → Build dependency DAG → Compute waves │
|
|
143
|
+
│ Assign lanes → Spawn workers → Monitor → Merge │
|
|
144
|
+
└──────┬──────────┬──────────┬────────────────────────────────┘
|
|
145
|
+
│ │ │
|
|
146
|
+
┌────▼────┐ ┌──▼─────┐ ┌──▼─────┐
|
|
147
|
+
│ Lane 1 │ │ Lane 2 │ │ Lane 3 │ ← Git worktrees
|
|
148
|
+
│ /task │ │ /task │ │ /task │ (isolated)
|
|
149
|
+
│ Worker │ │ Worker │ │ Worker │
|
|
150
|
+
│ Review │ │ Review │ │ Review │
|
|
151
|
+
└────┬────┘ └──┬─────┘ └──┬─────┘
|
|
152
|
+
│ │ │
|
|
153
|
+
└─────────┼──────────┘
|
|
154
|
+
│
|
|
155
|
+
┌──────▼──────┐
|
|
156
|
+
│ Merge Agent │ ← Conflict resolution
|
|
157
|
+
│ Integration │ & verification
|
|
158
|
+
│ Branch │
|
|
159
|
+
└─────────────┘
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Single task** (`/task`): Worker iterates in fresh-context loops. STATUS.md is persistent memory. Each checkbox → git checkpoint. Reviewer validates on completion.
|
|
163
|
+
|
|
164
|
+
**Parallel batch** (`/orch`): Tasks are sorted into dependency waves. Each wave runs in parallel across lanes (git worktrees). Completed lanes merge into the integration branch before the next wave starts.
|
|
165
|
+
|
|
166
|
+
## Documentation
|
|
167
|
+
|
|
168
|
+
📖 **[Full Documentation](docs/README.md)**
|
|
169
|
+
|
|
170
|
+
Start at the docs index for tutorials, how-to guides, reference docs, and architecture explanations.
|
|
171
|
+
|
|
172
|
+
## Contributing
|
|
173
|
+
|
|
174
|
+
See **[CONTRIBUTING.md](CONTRIBUTING.md)** for development setup, testing, and contribution guidelines.
|
|
175
|
+
|
|
176
|
+
Maintainers: GitHub governance and branch protection guidance is in [docs/maintainers/repository-governance.md](docs/maintainers/repository-governance.md).
|
|
177
|
+
|
|
178
|
+
## License
|
|
179
|
+
|
|
180
|
+
[MIT](LICENSE) © Henry Lach
|
package/bin/taskplane.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Taskplane CLI — Project scaffolding, diagnostics, and dashboard launcher.
|
|
4
|
+
* Taskplane CLI — Project scaffolding, diagnostics, uninstall, and dashboard launcher.
|
|
5
5
|
*
|
|
6
6
|
* This CLI handles what the pi package system cannot: project-local config
|
|
7
7
|
* scaffolding, installation health checks, and dashboard management.
|
|
@@ -291,6 +291,238 @@ async function autoCommitTaskFiles(projectRoot, tasksRoot) {
|
|
|
291
291
|
}
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
+
function discoverTaskAreaPaths(projectRoot) {
|
|
295
|
+
const runnerPath = path.join(projectRoot, ".pi", "task-runner.yaml");
|
|
296
|
+
if (!fs.existsSync(runnerPath)) return [];
|
|
297
|
+
|
|
298
|
+
const raw = readYaml(runnerPath);
|
|
299
|
+
if (!raw) return [];
|
|
300
|
+
|
|
301
|
+
const lines = raw.split(/\r?\n/);
|
|
302
|
+
let inTaskAreas = false;
|
|
303
|
+
const paths = new Set();
|
|
304
|
+
|
|
305
|
+
for (const line of lines) {
|
|
306
|
+
const trimmed = line.trim();
|
|
307
|
+
|
|
308
|
+
if (!inTaskAreas) {
|
|
309
|
+
if (/^task_areas:\s*$/.test(trimmed)) {
|
|
310
|
+
inTaskAreas = true;
|
|
311
|
+
}
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// End of task_areas block when we hit next top-level key
|
|
316
|
+
if (/^[A-Za-z0-9_]+\s*:\s*$/.test(line)) {
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const m = line.match(/^\s{4}path:\s*["']?([^"'\n#]+)["']?\s*(?:#.*)?$/);
|
|
321
|
+
if (m?.[1]) {
|
|
322
|
+
paths.add(m[1].trim());
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return [...paths];
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function pruneEmptyDir(dirPath) {
|
|
330
|
+
try {
|
|
331
|
+
if (!fs.existsSync(dirPath)) return false;
|
|
332
|
+
if (fs.readdirSync(dirPath).length !== 0) return false;
|
|
333
|
+
fs.rmdirSync(dirPath);
|
|
334
|
+
return true;
|
|
335
|
+
} catch {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function listExampleTaskTemplates() {
|
|
341
|
+
const tasksTemplatesDir = path.join(TEMPLATES_DIR, "tasks");
|
|
342
|
+
try {
|
|
343
|
+
return fs.readdirSync(tasksTemplatesDir, { withFileTypes: true })
|
|
344
|
+
.filter((entry) => entry.isDirectory() && /^EXAMPLE-\d+/i.test(entry.name))
|
|
345
|
+
.map((entry) => entry.name)
|
|
346
|
+
.sort();
|
|
347
|
+
} catch {
|
|
348
|
+
return [];
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
async function cmdUninstall(args) {
|
|
353
|
+
const projectRoot = process.cwd();
|
|
354
|
+
const dryRun = args.includes("--dry-run");
|
|
355
|
+
const yes = args.includes("--yes") || args.includes("-y");
|
|
356
|
+
const removePackage = args.includes("--package") || args.includes("--all") || args.includes("--package-only");
|
|
357
|
+
const packageOnly = args.includes("--package-only");
|
|
358
|
+
const removeProject = !packageOnly;
|
|
359
|
+
const removeTasks = removeProject && (args.includes("--remove-tasks") || args.includes("--all"));
|
|
360
|
+
const local = args.includes("--local");
|
|
361
|
+
const global = args.includes("--global");
|
|
362
|
+
|
|
363
|
+
if (local && global) {
|
|
364
|
+
die("Choose either --local or --global, not both.");
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
console.log(`\n${c.bold}Taskplane Uninstall${c.reset}\n`);
|
|
368
|
+
|
|
369
|
+
const managedFiles = [
|
|
370
|
+
".pi/task-runner.yaml",
|
|
371
|
+
".pi/task-orchestrator.yaml",
|
|
372
|
+
".pi/taskplane.json",
|
|
373
|
+
".pi/agents/task-worker.md",
|
|
374
|
+
".pi/agents/task-reviewer.md",
|
|
375
|
+
".pi/agents/task-merger.md",
|
|
376
|
+
".pi/batch-state.json",
|
|
377
|
+
".pi/batch-history.json",
|
|
378
|
+
".pi/orch-abort-signal",
|
|
379
|
+
];
|
|
380
|
+
|
|
381
|
+
const sidecarPrefixes = [
|
|
382
|
+
"lane-state-",
|
|
383
|
+
"worker-conversation-",
|
|
384
|
+
"merge-result-",
|
|
385
|
+
"merge-request-",
|
|
386
|
+
];
|
|
387
|
+
|
|
388
|
+
const filesToDelete = managedFiles
|
|
389
|
+
.map(rel => ({ rel, abs: path.join(projectRoot, rel) }))
|
|
390
|
+
.filter(({ abs }) => fs.existsSync(abs));
|
|
391
|
+
|
|
392
|
+
const piDir = path.join(projectRoot, ".pi");
|
|
393
|
+
const sidecarsToDelete = fs.existsSync(piDir)
|
|
394
|
+
? fs.readdirSync(piDir)
|
|
395
|
+
.filter(name => sidecarPrefixes.some(prefix => name.startsWith(prefix)))
|
|
396
|
+
.map(name => ({ rel: path.join(".pi", name), abs: path.join(piDir, name) }))
|
|
397
|
+
: [];
|
|
398
|
+
|
|
399
|
+
let taskDirsToDelete = [];
|
|
400
|
+
if (removeTasks) {
|
|
401
|
+
const areaPaths = discoverTaskAreaPaths(projectRoot);
|
|
402
|
+
const rootPrefix = path.resolve(projectRoot) + path.sep;
|
|
403
|
+
taskDirsToDelete = areaPaths
|
|
404
|
+
.map(rel => ({ rel, abs: path.resolve(projectRoot, rel) }))
|
|
405
|
+
.filter(({ abs }) => abs.startsWith(rootPrefix) && fs.existsSync(abs));
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const inferredInstallType = /[\\/]\.pi[\\/]/.test(PACKAGE_ROOT) ? "local" : "global";
|
|
409
|
+
const packageScope = local ? "local" : global ? "global" : inferredInstallType;
|
|
410
|
+
const piRemoveCmd = packageScope === "local"
|
|
411
|
+
? "pi remove -l npm:taskplane"
|
|
412
|
+
: "pi remove npm:taskplane";
|
|
413
|
+
|
|
414
|
+
if (!removeProject && !removePackage) {
|
|
415
|
+
console.log(` ${WARN} Nothing to do. Use one of:`);
|
|
416
|
+
console.log(` ${c.cyan}taskplane uninstall${c.reset} # remove project-scaffolded files`);
|
|
417
|
+
console.log(` ${c.cyan}taskplane uninstall --package${c.reset} # remove installed package via pi`);
|
|
418
|
+
console.log();
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (removeProject) {
|
|
423
|
+
console.log(`${c.bold}Project cleanup:${c.reset}`);
|
|
424
|
+
if (filesToDelete.length === 0 && sidecarsToDelete.length === 0 && taskDirsToDelete.length === 0) {
|
|
425
|
+
console.log(` ${c.dim}No Taskplane-managed project files found.${c.reset}`);
|
|
426
|
+
}
|
|
427
|
+
for (const f of filesToDelete) console.log(` - remove ${f.rel}`);
|
|
428
|
+
for (const f of sidecarsToDelete) console.log(` - remove ${f.rel}`);
|
|
429
|
+
for (const d of taskDirsToDelete) console.log(` - remove dir ${d.rel}`);
|
|
430
|
+
if (removeTasks && taskDirsToDelete.length === 0) {
|
|
431
|
+
console.log(` ${c.dim}No task area directories found from .pi/task-runner.yaml.${c.reset}`);
|
|
432
|
+
}
|
|
433
|
+
if (!removeTasks) {
|
|
434
|
+
console.log(` ${c.dim}Task directories are preserved by default (use --remove-tasks to delete them).${c.reset}`);
|
|
435
|
+
}
|
|
436
|
+
console.log();
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (removePackage) {
|
|
440
|
+
console.log(`${c.bold}Package cleanup:${c.reset}`);
|
|
441
|
+
console.log(` - run ${piRemoveCmd}`);
|
|
442
|
+
console.log(` ${c.dim}(removes extensions, skills, and dashboard files from this install scope)${c.reset}`);
|
|
443
|
+
console.log();
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
if (dryRun) {
|
|
447
|
+
console.log(`${INFO} Dry run complete. No files were changed.\n`);
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (!yes) {
|
|
452
|
+
const proceed = await confirm("Proceed with uninstall?", false);
|
|
453
|
+
if (!proceed) {
|
|
454
|
+
console.log(" Aborted.");
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
if (removeTasks) {
|
|
458
|
+
const taskConfirm = await confirm("This will delete task area directories recursively. Continue?", false);
|
|
459
|
+
if (!taskConfirm) {
|
|
460
|
+
console.log(" Aborted.");
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
let removedCount = 0;
|
|
467
|
+
let failedCount = 0;
|
|
468
|
+
|
|
469
|
+
if (removeProject) {
|
|
470
|
+
for (const item of [...filesToDelete, ...sidecarsToDelete]) {
|
|
471
|
+
try {
|
|
472
|
+
fs.unlinkSync(item.abs);
|
|
473
|
+
removedCount++;
|
|
474
|
+
} catch (err) {
|
|
475
|
+
failedCount++;
|
|
476
|
+
console.log(` ${WARN} Failed to remove ${item.rel}: ${err.message}`);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
for (const dir of taskDirsToDelete) {
|
|
481
|
+
try {
|
|
482
|
+
fs.rmSync(dir.abs, { recursive: true, force: true });
|
|
483
|
+
removedCount++;
|
|
484
|
+
} catch (err) {
|
|
485
|
+
failedCount++;
|
|
486
|
+
console.log(` ${WARN} Failed to remove directory ${dir.rel}: ${err.message}`);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Best-effort cleanup of empty folders
|
|
491
|
+
pruneEmptyDir(path.join(projectRoot, ".pi", "agents"));
|
|
492
|
+
pruneEmptyDir(path.join(projectRoot, ".pi"));
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
if (removePackage) {
|
|
496
|
+
if (!commandExists("pi")) {
|
|
497
|
+
failedCount++;
|
|
498
|
+
console.log(` ${FAIL} pi is not on PATH; could not run: ${piRemoveCmd}`);
|
|
499
|
+
} else {
|
|
500
|
+
try {
|
|
501
|
+
execSync(piRemoveCmd, { cwd: projectRoot, stdio: "inherit" });
|
|
502
|
+
} catch {
|
|
503
|
+
failedCount++;
|
|
504
|
+
console.log(` ${FAIL} Package uninstall failed: ${piRemoveCmd}`);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
console.log();
|
|
510
|
+
if (failedCount === 0) {
|
|
511
|
+
console.log(`${OK} ${c.bold}Uninstall complete.${c.reset}`);
|
|
512
|
+
if (removeProject) {
|
|
513
|
+
console.log(` Removed ${removedCount} project artifact(s).`);
|
|
514
|
+
}
|
|
515
|
+
console.log();
|
|
516
|
+
} else {
|
|
517
|
+
console.log(`${FAIL} Uninstall completed with ${failedCount} error(s).`);
|
|
518
|
+
if (removeProject) {
|
|
519
|
+
console.log(` Removed ${removedCount} project artifact(s).`);
|
|
520
|
+
}
|
|
521
|
+
console.log();
|
|
522
|
+
process.exit(1);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
294
526
|
// ─── init ───────────────────────────────────────────────────────────────────
|
|
295
527
|
|
|
296
528
|
async function cmdInit(args) {
|
|
@@ -326,9 +558,11 @@ async function cmdInit(args) {
|
|
|
326
558
|
vars = await getInteractiveVars(projectRoot);
|
|
327
559
|
}
|
|
328
560
|
|
|
561
|
+
const exampleTemplateDirs = noExamples ? [] : listExampleTaskTemplates();
|
|
562
|
+
|
|
329
563
|
if (dryRun) {
|
|
330
564
|
console.log(`\n${c.bold}Dry run — files that would be created:${c.reset}\n`);
|
|
331
|
-
printFileList(vars, noExamples, preset);
|
|
565
|
+
printFileList(vars, noExamples, preset, exampleTemplateDirs);
|
|
332
566
|
return;
|
|
333
567
|
}
|
|
334
568
|
|
|
@@ -382,37 +616,41 @@ async function cmdInit(args) {
|
|
|
382
616
|
{ skipIfExists, label: `${vars.tasks_root}/CONTEXT.md` }
|
|
383
617
|
);
|
|
384
618
|
|
|
385
|
-
// Example
|
|
619
|
+
// Example tasks
|
|
386
620
|
if (!noExamples) {
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
621
|
+
for (const exampleName of exampleTemplateDirs) {
|
|
622
|
+
const exampleDir = path.join(TEMPLATES_DIR, "tasks", exampleName);
|
|
623
|
+
const destDir = path.join(projectRoot, vars.tasks_root, exampleName);
|
|
624
|
+
for (const file of ["PROMPT.md", "STATUS.md"]) {
|
|
625
|
+
const srcPath = path.join(exampleDir, file);
|
|
626
|
+
if (!fs.existsSync(srcPath)) continue;
|
|
627
|
+
const src = fs.readFileSync(srcPath, "utf-8");
|
|
628
|
+
writeFile(path.join(destDir, file), interpolate(src, vars), {
|
|
629
|
+
skipIfExists,
|
|
630
|
+
label: `${vars.tasks_root}/${exampleName}/${file}`,
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
if (exampleTemplateDirs.length === 0) {
|
|
635
|
+
console.log(` ${WARN} No example task templates found under templates/tasks/EXAMPLE-*`);
|
|
395
636
|
}
|
|
396
637
|
}
|
|
397
638
|
|
|
398
639
|
// Auto-commit task files to git so they're available in worktrees
|
|
399
|
-
|
|
400
|
-
await autoCommitTaskFiles(projectRoot, vars.tasks_root);
|
|
401
|
-
}
|
|
640
|
+
await autoCommitTaskFiles(projectRoot, vars.tasks_root);
|
|
402
641
|
|
|
403
642
|
// Report
|
|
404
643
|
console.log(`\n${OK} ${c.bold}Taskplane initialized!${c.reset}\n`);
|
|
405
644
|
console.log(`${c.bold}Quick start:${c.reset}`);
|
|
406
645
|
console.log(` ${c.cyan}pi${c.reset} # start pi (taskplane auto-loads)`);
|
|
407
|
-
if (!noExamples) {
|
|
408
|
-
console.log(
|
|
409
|
-
` ${c.cyan}/task ${vars.tasks_root}/EXAMPLE-001-hello-world/PROMPT.md${c.reset} # run the example task`
|
|
410
|
-
);
|
|
411
|
-
}
|
|
412
646
|
if (preset !== "runner-only") {
|
|
413
|
-
console.log(
|
|
414
|
-
|
|
415
|
-
|
|
647
|
+
console.log(` ${c.cyan}/orch-plan all${c.reset} # preview waves/lanes/dependencies`);
|
|
648
|
+
console.log(` ${c.cyan}/orch all${c.reset} # run examples via orchestrator`);
|
|
649
|
+
}
|
|
650
|
+
if (!noExamples && exampleTemplateDirs.length > 0) {
|
|
651
|
+
const firstExample = exampleTemplateDirs[0];
|
|
652
|
+
console.log(` ${c.dim}optional single-task mode:${c.reset}`);
|
|
653
|
+
console.log(` ${c.cyan}/task ${vars.tasks_root}/${firstExample}/PROMPT.md${c.reset}`);
|
|
416
654
|
}
|
|
417
655
|
console.log();
|
|
418
656
|
}
|
|
@@ -465,7 +703,7 @@ async function getInteractiveVars(projectRoot) {
|
|
|
465
703
|
};
|
|
466
704
|
}
|
|
467
705
|
|
|
468
|
-
function printFileList(vars, noExamples, preset) {
|
|
706
|
+
function printFileList(vars, noExamples, preset, exampleTemplateDirs = []) {
|
|
469
707
|
const files = [
|
|
470
708
|
".pi/agents/task-worker.md",
|
|
471
709
|
".pi/agents/task-reviewer.md",
|
|
@@ -476,8 +714,10 @@ function printFileList(vars, noExamples, preset) {
|
|
|
476
714
|
files.push(".pi/taskplane.json");
|
|
477
715
|
files.push(`${vars.tasks_root}/CONTEXT.md`);
|
|
478
716
|
if (!noExamples) {
|
|
479
|
-
|
|
480
|
-
|
|
717
|
+
for (const exampleName of exampleTemplateDirs) {
|
|
718
|
+
files.push(`${vars.tasks_root}/${exampleName}/PROMPT.md`);
|
|
719
|
+
files.push(`${vars.tasks_root}/${exampleName}/STATUS.md`);
|
|
720
|
+
}
|
|
481
721
|
}
|
|
482
722
|
for (const f of files) console.log(` ${c.green}create${c.reset} ${f}`);
|
|
483
723
|
console.log();
|
|
@@ -690,11 +930,12 @@ ${c.bold}Commands:${c.reset}
|
|
|
690
930
|
${c.cyan}doctor${c.reset} Validate installation and project configuration
|
|
691
931
|
${c.cyan}version${c.reset} Show version information
|
|
692
932
|
${c.cyan}dashboard${c.reset} Launch the web-based orchestrator dashboard
|
|
933
|
+
${c.cyan}uninstall${c.reset} Remove Taskplane project files and/or package install
|
|
693
934
|
${c.cyan}help${c.reset} Show this help message
|
|
694
935
|
|
|
695
936
|
${c.bold}Init options:${c.reset}
|
|
696
937
|
--preset <name> Use a preset: minimal, full, runner-only
|
|
697
|
-
--no-examples Skip example
|
|
938
|
+
--no-examples Skip example tasks scaffolding
|
|
698
939
|
--force Overwrite existing files without prompting
|
|
699
940
|
--dry-run Show what would be created without writing
|
|
700
941
|
|
|
@@ -702,13 +943,25 @@ ${c.bold}Dashboard options:${c.reset}
|
|
|
702
943
|
--port <number> Port to listen on (default: 8099)
|
|
703
944
|
--no-open Don't auto-open browser
|
|
704
945
|
|
|
946
|
+
${c.bold}Uninstall options:${c.reset}
|
|
947
|
+
--dry-run Show what would be removed
|
|
948
|
+
--yes, -y Skip confirmation prompts
|
|
949
|
+
--package Also remove installed package via pi remove
|
|
950
|
+
--package-only Only remove installed package (skip project cleanup)
|
|
951
|
+
--local Force package uninstall from project-local scope
|
|
952
|
+
--global Force package uninstall from global scope
|
|
953
|
+
--remove-tasks Also remove task area directories from task-runner.yaml
|
|
954
|
+
--all Equivalent to --package + --remove-tasks
|
|
955
|
+
|
|
705
956
|
${c.bold}Examples:${c.reset}
|
|
706
|
-
taskplane init
|
|
707
|
-
taskplane init --preset full
|
|
708
|
-
taskplane init --dry-run
|
|
709
|
-
taskplane doctor
|
|
710
|
-
taskplane dashboard
|
|
711
|
-
taskplane dashboard --port 3000
|
|
957
|
+
taskplane init # Interactive project setup
|
|
958
|
+
taskplane init --preset full # Quick setup with defaults
|
|
959
|
+
taskplane init --dry-run # Preview what would be created
|
|
960
|
+
taskplane doctor # Check installation health
|
|
961
|
+
taskplane dashboard # Launch web dashboard
|
|
962
|
+
taskplane dashboard --port 3000 # Dashboard on custom port
|
|
963
|
+
taskplane uninstall --dry-run # Preview uninstall actions
|
|
964
|
+
taskplane uninstall --package --yes # Remove project files + package install
|
|
712
965
|
|
|
713
966
|
${c.bold}Getting started:${c.reset}
|
|
714
967
|
1. pi install npm:taskplane # Install the pi package
|
|
@@ -738,6 +991,9 @@ switch (command) {
|
|
|
738
991
|
case "dashboard":
|
|
739
992
|
cmdDashboard(args);
|
|
740
993
|
break;
|
|
994
|
+
case "uninstall":
|
|
995
|
+
await cmdUninstall(args);
|
|
996
|
+
break;
|
|
741
997
|
case "help":
|
|
742
998
|
case "--help":
|
|
743
999
|
case "-h":
|
package/package.json
CHANGED
|
@@ -73,8 +73,8 @@ Use the source branch and merge message from the merge request.
|
|
|
73
73
|
Run each verification command from the merge request. Typical commands:
|
|
74
74
|
|
|
75
75
|
```bash
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
npm test # Unit/integration checks
|
|
77
|
+
npm run build # Build/compile checks
|
|
78
78
|
```
|
|
79
79
|
|
|
80
80
|
**If verification passes:** Write result with `status: "SUCCESS"` (or
|
|
@@ -95,29 +95,29 @@ Write a `BUILD_FAILURE` result with the error output from the failed command.
|
|
|
95
95
|
| Different files modified | N/A (git handles automatically) | No action needed |
|
|
96
96
|
| Same file, different sections | Yes — accept both changes | Edit file to include both changes, remove conflict markers |
|
|
97
97
|
| Same file, same lines | **No** — needs human review | Abort merge immediately |
|
|
98
|
-
| Generated files (`
|
|
99
|
-
| `STATUS.md` / `.DONE` files | Yes — keep both | Accept
|
|
100
|
-
| `CONTEXT.md` (append-only sections) | Yes — keep both additions | Merge both additions into
|
|
98
|
+
| Generated files (`package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`) | Yes — regenerate | Run package manager install command to regenerate |
|
|
99
|
+
| `STATUS.md` / `.DONE` files | Yes — keep both | Accept incoming STATUS.md; keep `.DONE` markers |
|
|
100
|
+
| `CONTEXT.md` (append-only sections) | Yes — keep both additions | Merge both additions into relevant sections |
|
|
101
101
|
|
|
102
102
|
### Auto-Resolution Rules
|
|
103
103
|
|
|
104
104
|
1. **Same file, different sections:** Open the file, identify conflict markers
|
|
105
105
|
(`<<<<<<<`, `=======`, `>>>>>>>`). If the conflicting hunks are in clearly
|
|
106
|
-
different sections
|
|
107
|
-
paragraphs), keep both changes. Remove all conflict markers.
|
|
106
|
+
different sections, keep both changes and remove markers.
|
|
108
107
|
|
|
109
|
-
2. **Generated files:** Do NOT manually edit.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
- Then `git add` the regenerated file
|
|
108
|
+
2. **Generated files:** Do NOT manually edit. Regenerate lockfiles using your
|
|
109
|
+
project's package manager command (for example `npm install`,
|
|
110
|
+
`pnpm install`, or `yarn install`), then `git add` the regenerated file.
|
|
113
111
|
|
|
114
|
-
3. **STATUS.md:** These are per-task tracking files. Accept theirs
|
|
112
|
+
3. **STATUS.md:** These are per-task tracking files. Accept theirs:
|
|
113
|
+
```bash
|
|
114
|
+
git checkout --theirs STATUS.md && git add STATUS.md
|
|
115
|
+
```
|
|
115
116
|
|
|
116
|
-
4. **`.DONE` marker files:**
|
|
117
|
+
4. **`.DONE` marker files:** Keep marker files if either side created one.
|
|
117
118
|
|
|
118
119
|
5. **Same lines / ambiguous conflicts:** Do NOT attempt to resolve. Run
|
|
119
|
-
`git merge --abort` and report `CONFLICT_UNRESOLVED`.
|
|
120
|
-
pause the batch for human intervention.
|
|
120
|
+
`git merge --abort` and report `CONFLICT_UNRESOLVED`.
|
|
121
121
|
|
|
122
122
|
---
|
|
123
123
|
|
|
@@ -130,7 +130,7 @@ Write your result as JSON to the path specified in the merge request
|
|
|
130
130
|
{
|
|
131
131
|
"status": "SUCCESS",
|
|
132
132
|
"source_branch": "task/lane-1-abc123",
|
|
133
|
-
"target_branch": "
|
|
133
|
+
"target_branch": "main",
|
|
134
134
|
"merge_commit": "abc1234def5678",
|
|
135
135
|
"conflicts": [],
|
|
136
136
|
"verification": {
|
|
@@ -147,42 +147,25 @@ Write your result as JSON to the path specified in the merge request
|
|
|
147
147
|
|-------|------|-------------|
|
|
148
148
|
| `status` | string | One of: `SUCCESS`, `CONFLICT_RESOLVED`, `CONFLICT_UNRESOLVED`, `BUILD_FAILURE` |
|
|
149
149
|
| `source_branch` | string | The lane branch that was merged (from merge request) |
|
|
150
|
-
| `target_branch` | string |
|
|
151
|
-
| `merge_commit` | string |
|
|
150
|
+
| `target_branch` | string | Target branch from merge request (typically integration branch, e.g. `main`) |
|
|
151
|
+
| `merge_commit` | string | Merge commit SHA (present only if merge succeeded) |
|
|
152
152
|
| `conflicts` | array | List of conflict entries (empty if no conflicts) |
|
|
153
|
-
| `conflicts[].file` | string | Path to
|
|
154
|
-
| `conflicts[].type` | string | Classification
|
|
155
|
-
| `conflicts[].resolved` | boolean | Whether
|
|
156
|
-
| `conflicts[].resolution` | string |
|
|
153
|
+
| `conflicts[].file` | string | Path to conflicted file |
|
|
154
|
+
| `conflicts[].type` | string | Classification (`different-sections`, `same-lines`, `generated`, `status-file`) |
|
|
155
|
+
| `conflicts[].resolved` | boolean | Whether conflict was auto-resolved |
|
|
156
|
+
| `conflicts[].resolution` | string | Resolution summary |
|
|
157
157
|
| `verification.ran` | boolean | Whether verification commands were executed |
|
|
158
|
-
| `verification.passed` | boolean | Whether
|
|
159
|
-
| `verification.output` | string |
|
|
158
|
+
| `verification.passed` | boolean | Whether verification commands passed |
|
|
159
|
+
| `verification.output` | string | Verification output (useful on failures) |
|
|
160
160
|
|
|
161
161
|
### Status Definitions
|
|
162
162
|
|
|
163
163
|
| Status | Meaning | Orchestrator Action |
|
|
164
164
|
|--------|---------|---------------------|
|
|
165
|
-
| `SUCCESS` | Merge completed,
|
|
166
|
-
| `CONFLICT_RESOLVED` | Conflicts
|
|
167
|
-
| `CONFLICT_UNRESOLVED` |
|
|
168
|
-
| `BUILD_FAILURE` | Merge succeeded but verification failed (merge
|
|
169
|
-
|
|
170
|
-
### Example: Clean Merge
|
|
171
|
-
|
|
172
|
-
```json
|
|
173
|
-
{
|
|
174
|
-
"status": "SUCCESS",
|
|
175
|
-
"source_branch": "task/lane-1-abc123",
|
|
176
|
-
"target_branch": "develop",
|
|
177
|
-
"merge_commit": "abc1234def5678",
|
|
178
|
-
"conflicts": [],
|
|
179
|
-
"verification": {
|
|
180
|
-
"ran": true,
|
|
181
|
-
"passed": true,
|
|
182
|
-
"output": ""
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
```
|
|
165
|
+
| `SUCCESS` | Merge completed, verification passed | Continue to next lane |
|
|
166
|
+
| `CONFLICT_RESOLVED` | Conflicts auto-resolved, verification passed | Log details, continue |
|
|
167
|
+
| `CONFLICT_UNRESOLVED` | Conflict requires human intervention | Pause batch, notify user |
|
|
168
|
+
| `BUILD_FAILURE` | Merge succeeded but verification failed (merge reverted) | Pause batch, notify user |
|
|
186
169
|
|
|
187
170
|
### Example: Conflict Resolved
|
|
188
171
|
|
|
@@ -190,20 +173,20 @@ Write your result as JSON to the path specified in the merge request
|
|
|
190
173
|
{
|
|
191
174
|
"status": "CONFLICT_RESOLVED",
|
|
192
175
|
"source_branch": "task/lane-2-abc123",
|
|
193
|
-
"target_branch": "
|
|
176
|
+
"target_branch": "main",
|
|
194
177
|
"merge_commit": "def4567abc8901",
|
|
195
178
|
"conflicts": [
|
|
196
179
|
{
|
|
197
|
-
"file": "
|
|
180
|
+
"file": "package-lock.json",
|
|
198
181
|
"type": "generated",
|
|
199
182
|
"resolved": true,
|
|
200
|
-
"resolution": "regenerated via
|
|
183
|
+
"resolution": "regenerated via npm install"
|
|
201
184
|
},
|
|
202
185
|
{
|
|
203
|
-
"file": "
|
|
186
|
+
"file": "src/routes/api.ts",
|
|
204
187
|
"type": "different-sections",
|
|
205
188
|
"resolved": true,
|
|
206
|
-
"resolution": "kept both
|
|
189
|
+
"resolution": "kept both route additions"
|
|
207
190
|
}
|
|
208
191
|
],
|
|
209
192
|
"verification": {
|
|
@@ -214,43 +197,19 @@ Write your result as JSON to the path specified in the merge request
|
|
|
214
197
|
}
|
|
215
198
|
```
|
|
216
199
|
|
|
217
|
-
### Example: Unresolved Conflict
|
|
218
|
-
|
|
219
|
-
```json
|
|
220
|
-
{
|
|
221
|
-
"status": "CONFLICT_UNRESOLVED",
|
|
222
|
-
"source_branch": "task/lane-3-abc123",
|
|
223
|
-
"target_branch": "develop",
|
|
224
|
-
"merge_commit": "",
|
|
225
|
-
"conflicts": [
|
|
226
|
-
{
|
|
227
|
-
"file": "services/identity-service/internal/domain/services/auth_service.go",
|
|
228
|
-
"type": "same-lines",
|
|
229
|
-
"resolved": false,
|
|
230
|
-
"resolution": ""
|
|
231
|
-
}
|
|
232
|
-
],
|
|
233
|
-
"verification": {
|
|
234
|
-
"ran": false,
|
|
235
|
-
"passed": false,
|
|
236
|
-
"output": ""
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
```
|
|
240
|
-
|
|
241
200
|
### Example: Build Failure
|
|
242
201
|
|
|
243
202
|
```json
|
|
244
203
|
{
|
|
245
204
|
"status": "BUILD_FAILURE",
|
|
246
205
|
"source_branch": "task/lane-1-abc123",
|
|
247
|
-
"target_branch": "
|
|
206
|
+
"target_branch": "main",
|
|
248
207
|
"merge_commit": "",
|
|
249
208
|
"conflicts": [],
|
|
250
209
|
"verification": {
|
|
251
210
|
"ran": true,
|
|
252
211
|
"passed": false,
|
|
253
|
-
"output": "
|
|
212
|
+
"output": "src/server.ts:42:17 - error TS2304: Cannot find name 'createApiRouter'"
|
|
254
213
|
}
|
|
255
214
|
}
|
|
256
215
|
```
|
|
@@ -19,10 +19,10 @@ orchestrator:
|
|
|
19
19
|
max_lanes: 3
|
|
20
20
|
|
|
21
21
|
# Where to create worktree directories.
|
|
22
|
-
# "sibling" = ../{prefix}-{N} (e.g. ../
|
|
23
|
-
# "subdirectory" = .worktrees/{prefix}-{N} (e.g. .worktrees/
|
|
22
|
+
# "sibling" = ../{prefix}-{N} (e.g. ../project-wt-1)
|
|
23
|
+
# "subdirectory" = .worktrees/{prefix}-{N} (e.g. .worktrees/project-wt-1)
|
|
24
24
|
worktree_location: "subdirectory"
|
|
25
|
-
worktree_prefix: "
|
|
25
|
+
worktree_prefix: "project-wt"
|
|
26
26
|
|
|
27
27
|
# Integration branch that lanes merge into.
|
|
28
28
|
integration_branch: "main"
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
# ── Project ───────────────────────────────────────────────────────────
|
|
11
11
|
|
|
12
12
|
project:
|
|
13
|
-
name: "
|
|
14
|
-
description: "
|
|
13
|
+
name: "Your Project"
|
|
14
|
+
description: "Short description of your project"
|
|
15
15
|
|
|
16
16
|
paths:
|
|
17
17
|
tasks: "tasks"
|
|
@@ -21,9 +21,17 @@
|
|
|
21
21
|
## Mission
|
|
22
22
|
|
|
23
23
|
Create a simple `hello-taskplane.md` file in the project root to verify that
|
|
24
|
-
|
|
25
|
-
worker can read this prompt, create the file, and mark the
|
|
26
|
-
installation is healthy.
|
|
24
|
+
Taskplane task execution is working correctly. This is a smoke test — if the
|
|
25
|
+
worker can read this prompt, create the file, checkpoint progress, and mark the
|
|
26
|
+
task done, the installation is healthy.
|
|
27
|
+
|
|
28
|
+
## Expected File Content
|
|
29
|
+
|
|
30
|
+
`hello-taskplane.md` should include:
|
|
31
|
+
|
|
32
|
+
- A title line (for example: `# Hello from Taskplane`)
|
|
33
|
+
- A line containing the task ID: `EXAMPLE-001`
|
|
34
|
+
- A line containing today's date
|
|
27
35
|
|
|
28
36
|
## Dependencies
|
|
29
37
|
|
|
@@ -51,12 +59,12 @@ _No additional context needed._
|
|
|
51
59
|
|
|
52
60
|
### Step 1: Create Hello File
|
|
53
61
|
|
|
54
|
-
- [ ] Create `hello-taskplane.md` in the project root
|
|
55
|
-
- [ ]
|
|
62
|
+
- [ ] Create `hello-taskplane.md` in the project root
|
|
63
|
+
- [ ] Add a title plus lines containing today's date and task ID `EXAMPLE-001`
|
|
56
64
|
|
|
57
65
|
### Step 2: Verification
|
|
58
66
|
|
|
59
|
-
- [ ] Verify `hello-taskplane.md` exists and
|
|
67
|
+
- [ ] Verify `hello-taskplane.md` exists and matches the expected content
|
|
60
68
|
|
|
61
69
|
### Step 3: Delivery
|
|
62
70
|
|
|
@@ -70,6 +78,7 @@ _No additional context needed._
|
|
|
70
78
|
## Completion Criteria
|
|
71
79
|
|
|
72
80
|
- [ ] `hello-taskplane.md` exists in the project root
|
|
81
|
+
- [ ] `hello-taskplane.md` includes a title, task ID (`EXAMPLE-001`), and current date
|
|
73
82
|
- [ ] `.DONE` exists in the task folder
|
|
74
83
|
|
|
75
84
|
## Git Commit Convention
|
|
@@ -22,14 +22,14 @@
|
|
|
22
22
|
**Status:** ⬜ Not Started
|
|
23
23
|
|
|
24
24
|
- [ ] Create `hello-taskplane.md` in project root
|
|
25
|
-
- [ ]
|
|
25
|
+
- [ ] Add title, date, and task ID (EXAMPLE-001)
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
29
29
|
### Step 2: Verification
|
|
30
30
|
**Status:** ⬜ Not Started
|
|
31
31
|
|
|
32
|
-
- [ ] Verify file exists
|
|
32
|
+
- [ ] Verify file exists and matches expected content
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Task: EXAMPLE-002 — Parallel Smoke
|
|
2
|
+
|
|
3
|
+
**Created:** {{date}}
|
|
4
|
+
**Size:** S
|
|
5
|
+
|
|
6
|
+
## Review Level: 0 (None)
|
|
7
|
+
|
|
8
|
+
**Assessment:** Trivial parallel-safe smoke task to demonstrate orchestrator lanes.
|
|
9
|
+
**Score:** 0/8 — Blast radius: 0, Pattern novelty: 0, Security: 0, Reversibility: 0
|
|
10
|
+
|
|
11
|
+
## Canonical Task Folder
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
{{tasks_root}}/EXAMPLE-002-parallel-smoke/
|
|
15
|
+
├── PROMPT.md ← This file (immutable above --- divider)
|
|
16
|
+
├── STATUS.md ← Execution state (worker updates this)
|
|
17
|
+
├── .reviews/ ← Reviewer output (task-runner creates this)
|
|
18
|
+
└── .DONE ← Created when complete
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Mission
|
|
22
|
+
|
|
23
|
+
Create a simple `hello-taskplane-2.md` file in the project root. This task is
|
|
24
|
+
intentionally independent from EXAMPLE-001 so both can run in parallel when
|
|
25
|
+
using `/orch`.
|
|
26
|
+
|
|
27
|
+
## Expected File Content
|
|
28
|
+
|
|
29
|
+
`hello-taskplane-2.md` should include:
|
|
30
|
+
|
|
31
|
+
- A title line (for example: `# Parallel Hello from Taskplane`)
|
|
32
|
+
- A line containing the task ID: `EXAMPLE-002`
|
|
33
|
+
- A short note that this task is parallel-safe
|
|
34
|
+
|
|
35
|
+
## Dependencies
|
|
36
|
+
|
|
37
|
+
- **None**
|
|
38
|
+
|
|
39
|
+
## Context to Read First
|
|
40
|
+
|
|
41
|
+
_No additional context needed._
|
|
42
|
+
|
|
43
|
+
## Environment
|
|
44
|
+
|
|
45
|
+
- **Workspace:** Project root
|
|
46
|
+
- **Services required:** None
|
|
47
|
+
|
|
48
|
+
## File Scope
|
|
49
|
+
|
|
50
|
+
- `hello-taskplane-2.md`
|
|
51
|
+
|
|
52
|
+
## Steps
|
|
53
|
+
|
|
54
|
+
### Step 0: Preflight
|
|
55
|
+
|
|
56
|
+
- [ ] Verify this PROMPT.md is readable
|
|
57
|
+
- [ ] Verify STATUS.md exists in the same folder
|
|
58
|
+
|
|
59
|
+
### Step 1: Create Parallel Hello File
|
|
60
|
+
|
|
61
|
+
- [ ] Create `hello-taskplane-2.md` in the project root
|
|
62
|
+
- [ ] Add title plus lines containing task ID `EXAMPLE-002` and a parallel-safe note
|
|
63
|
+
|
|
64
|
+
### Step 2: Verification
|
|
65
|
+
|
|
66
|
+
- [ ] Verify `hello-taskplane-2.md` exists and matches the expected content
|
|
67
|
+
|
|
68
|
+
### Step 3: Delivery
|
|
69
|
+
|
|
70
|
+
- [ ] `.DONE` created in this folder
|
|
71
|
+
|
|
72
|
+
## Documentation Requirements
|
|
73
|
+
|
|
74
|
+
**Must Update:** None
|
|
75
|
+
**Check If Affected:** None
|
|
76
|
+
|
|
77
|
+
## Completion Criteria
|
|
78
|
+
|
|
79
|
+
- [ ] `hello-taskplane-2.md` exists in the project root
|
|
80
|
+
- [ ] `hello-taskplane-2.md` includes a title, task ID (`EXAMPLE-002`), and a parallel-safe note
|
|
81
|
+
- [ ] `.DONE` exists in the task folder
|
|
82
|
+
|
|
83
|
+
## Git Commit Convention
|
|
84
|
+
|
|
85
|
+
- **Implementation:** `feat(EXAMPLE-002): description`
|
|
86
|
+
- **Checkpoints:** `checkpoint: EXAMPLE-002 description`
|
|
87
|
+
|
|
88
|
+
## Do NOT
|
|
89
|
+
|
|
90
|
+
- Modify any existing project files
|
|
91
|
+
- Create files outside the project root
|
|
92
|
+
- Add dependencies between EXAMPLE-001 and EXAMPLE-002
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Amendments (Added During Execution)
|
|
97
|
+
|
|
98
|
+
<!-- Workers add amendments here if issues discovered during execution. -->
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# EXAMPLE-002: Parallel Smoke — Status
|
|
2
|
+
|
|
3
|
+
**Current Step:** Not Started
|
|
4
|
+
**Status:** 🔵 Ready for Execution
|
|
5
|
+
**Last Updated:** {{date}}
|
|
6
|
+
**Review Level:** 0
|
|
7
|
+
**Review Counter:** 0
|
|
8
|
+
**Iteration:** 0
|
|
9
|
+
**Size:** S
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
### Step 0: Preflight
|
|
14
|
+
**Status:** ⬜ Not Started
|
|
15
|
+
|
|
16
|
+
- [ ] Verify PROMPT.md is readable
|
|
17
|
+
- [ ] Verify STATUS.md exists
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
### Step 1: Create Parallel Hello File
|
|
22
|
+
**Status:** ⬜ Not Started
|
|
23
|
+
|
|
24
|
+
- [ ] Create `hello-taskplane-2.md` in project root
|
|
25
|
+
- [ ] Add title, task ID (EXAMPLE-002), and parallel-safe note
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
### Step 2: Verification
|
|
30
|
+
**Status:** ⬜ Not Started
|
|
31
|
+
|
|
32
|
+
- [ ] Verify file exists and matches expected content
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
### Step 3: Delivery
|
|
37
|
+
**Status:** ⬜ Not Started
|
|
38
|
+
|
|
39
|
+
- [ ] `.DONE` created
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Reviews
|
|
44
|
+
|
|
45
|
+
| # | Type | Step | Verdict | File |
|
|
46
|
+
|---|------|------|---------|------|
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Discoveries
|
|
51
|
+
|
|
52
|
+
| Discovery | Disposition | Location |
|
|
53
|
+
|-----------|-------------|----------|
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Execution Log
|
|
58
|
+
|
|
59
|
+
| Timestamp | Action | Outcome |
|
|
60
|
+
|-----------|--------|---------|
|
|
61
|
+
| {{date}} | Task staged | PROMPT.md and STATUS.md created |
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Blockers
|
|
66
|
+
|
|
67
|
+
*None*
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Notes
|
|
72
|
+
|
|
73
|
+
*This is an example task created by `taskplane init` to demonstrate orchestrator-first onboarding.*
|