@mthanhlm/autodev 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PUBLISH.md +1 -1
- package/README.md +36 -3
- package/agents/autodev-task-worker.md +28 -0
- package/autodev/bin/autodev-tools.cjs +132 -5
- package/autodev/templates/plan.md +17 -6
- package/autodev/templates/project-state.md +2 -0
- package/autodev/templates/state.md +2 -0
- package/autodev/templates/summary.md +5 -1
- package/autodev/templates/task-summary.md +18 -0
- package/autodev/templates/task.md +23 -0
- package/autodev/templates/track-state.md +2 -0
- package/autodev/workflows/autodev.md +2 -2
- package/autodev/workflows/execute-phase.md +61 -19
- package/autodev/workflows/help.md +6 -4
- package/autodev/workflows/new-project.md +4 -0
- package/autodev/workflows/plan-phase.md +38 -8
- package/autodev/workflows/review-phase.md +2 -0
- package/autodev/workflows/verify-work.md +4 -0
- package/commands/autodev/execute-phase.md +5 -2
- package/commands/autodev/plan-phase.md +3 -2
- package/hooks/autodev-statusline.js +41 -1
- package/hooks/autodev-workflow-guard.js +1 -1
- package/package.json +2 -2
package/PUBLISH.md
CHANGED
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
- Installs a small Claude Code workflow under `~/.claude/` or `./.claude/`
|
|
8
8
|
- Keeps project state in `.autodev/`
|
|
9
9
|
- Uses `/autodev` as the main command
|
|
10
|
-
- Organizes work as `project -> track -> phase`
|
|
10
|
+
- Organizes work as `project -> track -> phase -> tasks`
|
|
11
11
|
- Maps brownfield repos with four parallel codebase agents
|
|
12
12
|
- Runs a four-agent review pass after execution
|
|
13
13
|
- Ships manual commands when you want direct control:
|
|
@@ -59,12 +59,45 @@ Typical brownfield route:
|
|
|
59
59
|
/autodev
|
|
60
60
|
-> new project
|
|
61
61
|
-> explore codebase
|
|
62
|
-
-> plan
|
|
63
|
-
-> execute
|
|
62
|
+
-> plan phase
|
|
63
|
+
-> execute next task
|
|
64
|
+
-> execute next task
|
|
64
65
|
-> review
|
|
65
66
|
-> verify
|
|
66
67
|
```
|
|
67
68
|
|
|
69
|
+
## Workflow Model
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
project -> track -> phase -> tasks
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- `project`
|
|
76
|
+
The repo or product context.
|
|
77
|
+
- `track`
|
|
78
|
+
One initiative stream.
|
|
79
|
+
- `phase`
|
|
80
|
+
One milestone-sized slice inside a track.
|
|
81
|
+
- `task`
|
|
82
|
+
One reviewable implementation unit inside a phase.
|
|
83
|
+
|
|
84
|
+
### Why Tasks Exist Under A Phase
|
|
85
|
+
|
|
86
|
+
- Large phases are too big for one uninterrupted execution context
|
|
87
|
+
- Developers need control over what changes next
|
|
88
|
+
- Each task can run in a fresh background agent context
|
|
89
|
+
- The main `/autodev` session stays small and orchestration-focused
|
|
90
|
+
|
|
91
|
+
### Execution Model
|
|
92
|
+
|
|
93
|
+
- `/autodev` remains the single entrypoint
|
|
94
|
+
- A phase is planned into one phase overview plus multiple task files
|
|
95
|
+
- The phase keeps one user-facing orchestration session
|
|
96
|
+
- Each task is executed by a fresh worker agent in the background
|
|
97
|
+
- After each task, the worker reports back with files changed, verification, and blockers
|
|
98
|
+
- No waves by default
|
|
99
|
+
- No parallel execution unless the user explicitly asks for it later
|
|
100
|
+
|
|
68
101
|
## Git Policy
|
|
69
102
|
|
|
70
103
|
`autodev` does not stage, commit, branch, merge, worktree, pull, push, or initialize git repositories. Read-only git commands like `git status`, `git diff`, and `git log` remain allowed.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# autodev-task-worker
|
|
2
|
+
|
|
3
|
+
Execute one assigned task inside the current phase and report back to the main phase session.
|
|
4
|
+
|
|
5
|
+
## Goal
|
|
6
|
+
|
|
7
|
+
- Read the assigned phase context and task file
|
|
8
|
+
- Make only the code changes needed for that task
|
|
9
|
+
- Run the requested verification
|
|
10
|
+
- Write the matching task summary
|
|
11
|
+
|
|
12
|
+
## Rules
|
|
13
|
+
|
|
14
|
+
- You are not alone in the codebase.
|
|
15
|
+
- Stay inside the assigned task scope.
|
|
16
|
+
- Do not run git write commands.
|
|
17
|
+
- Do not silently expand into the next task.
|
|
18
|
+
- If blocked, say so clearly and write the blocker into the task summary.
|
|
19
|
+
|
|
20
|
+
## Output
|
|
21
|
+
|
|
22
|
+
- Update the repository code for the assigned task only.
|
|
23
|
+
- Write only the assigned `TASK-NN-SUMMARY.md`.
|
|
24
|
+
- Return a concise report:
|
|
25
|
+
- task id
|
|
26
|
+
- files changed
|
|
27
|
+
- verification run
|
|
28
|
+
- blocker or done
|
|
@@ -249,6 +249,98 @@ function phasePaths(cwd, slug, phase) {
|
|
|
249
249
|
};
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
+
function readSingleLineField(content, label) {
|
|
253
|
+
if (!content) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
const match = content.match(new RegExp(`^${label}:\\s*(.+)$`, 'mi'));
|
|
257
|
+
return match ? match[1].trim() : null;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function parseTaskDependsOn(value) {
|
|
261
|
+
if (!value || /^none$/i.test(value)) {
|
|
262
|
+
return [];
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return String(value)
|
|
266
|
+
.split(/[,\s]+/)
|
|
267
|
+
.map(part => part.trim())
|
|
268
|
+
.filter(Boolean)
|
|
269
|
+
.map(part => {
|
|
270
|
+
const match = part.match(/(\d+)/);
|
|
271
|
+
return match ? Number(match[1]) : null;
|
|
272
|
+
})
|
|
273
|
+
.filter(number => Number.isFinite(number));
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function readTaskTitle(content, fallbackNumber) {
|
|
277
|
+
if (!content) {
|
|
278
|
+
return `Task ${String(fallbackNumber).padStart(2, '0')}`;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const heading = content.match(/^#\s+Task\s+\d+\s*:\s*(.+)$/mi);
|
|
282
|
+
if (heading) {
|
|
283
|
+
return heading[1].trim();
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const generic = content.match(/^#\s+(.+)$/m);
|
|
287
|
+
return generic ? generic[1].trim() : `Task ${String(fallbackNumber).padStart(2, '0')}`;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function listTasksForPhaseDetails(phaseDetails) {
|
|
291
|
+
if (!phaseDetails || !fileExists(phaseDetails.dir)) {
|
|
292
|
+
return [];
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const entries = fs.readdirSync(phaseDetails.dir, { withFileTypes: true })
|
|
296
|
+
.filter(entry => entry.isFile())
|
|
297
|
+
.map(entry => entry.name);
|
|
298
|
+
|
|
299
|
+
const tasks = entries
|
|
300
|
+
.map(name => {
|
|
301
|
+
const match = name.match(/^TASK-(\d+)\.md$/);
|
|
302
|
+
if (!match) {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const number = Number(match[1]);
|
|
307
|
+
const padded = String(number).padStart(2, '0');
|
|
308
|
+
const taskPath = path.join(phaseDetails.dir, name);
|
|
309
|
+
const summaryPath = path.join(phaseDetails.dir, `TASK-${padded}-SUMMARY.md`);
|
|
310
|
+
const content = readText(taskPath);
|
|
311
|
+
const status = readSingleLineField(content, 'Status') || 'pending';
|
|
312
|
+
const dependsOn = parseTaskDependsOn(readSingleLineField(content, 'Depends On'));
|
|
313
|
+
const summaryExists = fileExists(summaryPath);
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
number,
|
|
317
|
+
padded,
|
|
318
|
+
title: readTaskTitle(content, number),
|
|
319
|
+
status,
|
|
320
|
+
dependsOn,
|
|
321
|
+
taskPath,
|
|
322
|
+
summaryPath,
|
|
323
|
+
summaryExists
|
|
324
|
+
};
|
|
325
|
+
})
|
|
326
|
+
.filter(Boolean)
|
|
327
|
+
.sort((left, right) => left.number - right.number);
|
|
328
|
+
|
|
329
|
+
const doneSet = new Set(tasks.filter(task => task.summaryExists).map(task => task.number));
|
|
330
|
+
|
|
331
|
+
return tasks.map(task => ({
|
|
332
|
+
...task,
|
|
333
|
+
ready: !task.summaryExists && task.dependsOn.every(dep => doneSet.has(dep)),
|
|
334
|
+
effectiveStatus: task.summaryExists ? 'done' : task.status
|
|
335
|
+
}));
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function nextExecutableTask(tasks) {
|
|
339
|
+
return tasks.find(task => !task.summaryExists && task.ready)
|
|
340
|
+
|| tasks.find(task => !task.summaryExists)
|
|
341
|
+
|| null;
|
|
342
|
+
}
|
|
343
|
+
|
|
252
344
|
function listPhases(cwd, slug = readActiveTrack(cwd)) {
|
|
253
345
|
const track = trackPaths(cwd, slug);
|
|
254
346
|
if (!track || !fileExists(track.roadmap)) {
|
|
@@ -261,12 +353,19 @@ function listPhases(cwd, slug = readActiveTrack(cwd)) {
|
|
|
261
353
|
const summaryExists = fileExists(details.summaryPath);
|
|
262
354
|
const reviewExists = fileExists(details.reviewPath);
|
|
263
355
|
const uatExists = fileExists(details.uatPath);
|
|
356
|
+
const tasks = listTasksForPhaseDetails(details);
|
|
357
|
+
const taskCount = tasks.length;
|
|
358
|
+
const taskDoneCount = tasks.filter(task => task.summaryExists).length;
|
|
264
359
|
const status = uatExists
|
|
265
360
|
? 'verified'
|
|
266
361
|
: reviewExists
|
|
267
362
|
? 'reviewed'
|
|
268
363
|
: summaryExists
|
|
269
364
|
? 'executed'
|
|
365
|
+
: planExists && taskCount > 0 && taskDoneCount === taskCount
|
|
366
|
+
? 'tasks_complete'
|
|
367
|
+
: planExists && taskDoneCount > 0
|
|
368
|
+
? 'executing'
|
|
270
369
|
: planExists
|
|
271
370
|
? 'planned'
|
|
272
371
|
: 'pending';
|
|
@@ -278,6 +377,9 @@ function listPhases(cwd, slug = readActiveTrack(cwd)) {
|
|
|
278
377
|
summaryExists,
|
|
279
378
|
reviewExists,
|
|
280
379
|
uatExists,
|
|
380
|
+
taskCount,
|
|
381
|
+
taskDoneCount,
|
|
382
|
+
nextTask: nextExecutableTask(tasks)?.number || null,
|
|
281
383
|
status
|
|
282
384
|
};
|
|
283
385
|
});
|
|
@@ -467,7 +569,9 @@ function buildProgress(cwd) {
|
|
|
467
569
|
planned: phases.filter(phase => phase.planExists).length,
|
|
468
570
|
executed: phases.filter(phase => phase.summaryExists).length,
|
|
469
571
|
reviewed: phases.filter(phase => phase.reviewExists).length,
|
|
470
|
-
verified: phases.filter(phase => phase.uatExists).length
|
|
572
|
+
verified: phases.filter(phase => phase.uatExists).length,
|
|
573
|
+
tasks: phases.reduce((total, phase) => total + phase.taskCount, 0),
|
|
574
|
+
tasksDone: phases.reduce((total, phase) => total + phase.taskDoneCount, 0)
|
|
471
575
|
},
|
|
472
576
|
route,
|
|
473
577
|
nextCommand: route.command,
|
|
@@ -492,16 +596,18 @@ function renderProgressTable(progress) {
|
|
|
492
596
|
`Executed: ${progress.counts.executed}`,
|
|
493
597
|
`Reviewed: ${progress.counts.reviewed}`,
|
|
494
598
|
`Verified: ${progress.counts.verified}`,
|
|
599
|
+
`Tasks: ${progress.counts.tasks}`,
|
|
600
|
+
`Task Summaries: ${progress.counts.tasksDone}`,
|
|
495
601
|
`Next: ${progress.route.command}`,
|
|
496
602
|
progress.route.manualCommand ? `Manual Shortcut: ${progress.route.manualCommand}` : null,
|
|
497
603
|
'',
|
|
498
|
-
'| Phase | Type | Name | Plan | Summary | Review | UAT | Status |',
|
|
499
|
-
'| --- | --- | --- | --- | --- | --- | --- | --- |'
|
|
604
|
+
'| Phase | Type | Name | Tasks | Done | Plan | Summary | Review | UAT | Status |',
|
|
605
|
+
'| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |'
|
|
500
606
|
].filter(Boolean);
|
|
501
607
|
|
|
502
608
|
for (const phase of progress.phases) {
|
|
503
609
|
lines.push(
|
|
504
|
-
`| ${phase.number} | ${phase.type} | ${phase.name} | ${phase.planExists ? 'yes' : 'no'} | ${phase.summaryExists ? 'yes' : 'no'} | ${phase.reviewExists ? 'yes' : 'no'} | ${phase.uatExists ? 'yes' : 'no'} | ${phase.status} |`
|
|
610
|
+
`| ${phase.number} | ${phase.type} | ${phase.name} | ${phase.taskCount} | ${phase.taskDoneCount} | ${phase.planExists ? 'yes' : 'no'} | ${phase.summaryExists ? 'yes' : 'no'} | ${phase.reviewExists ? 'yes' : 'no'} | ${phase.uatExists ? 'yes' : 'no'} | ${phase.status} |`
|
|
505
611
|
);
|
|
506
612
|
}
|
|
507
613
|
|
|
@@ -598,6 +704,8 @@ function initPayload(cwd, mode, requestedPhase) {
|
|
|
598
704
|
const track = trackPaths(cwd, activeTrack);
|
|
599
705
|
const phaseMode = mode === 'review-phase' ? 'review' : mode === 'verify-work' ? 'verify' : mode === 'execute-phase' ? 'execute' : mode === 'plan-phase' ? 'plan' : null;
|
|
600
706
|
const phase = phaseMode && activeTrack ? resolvePhase(cwd, activeTrack, requestedPhase, phaseMode) : null;
|
|
707
|
+
const tasks = phase ? listTasksForPhaseDetails(phase) : [];
|
|
708
|
+
const nextTask = nextExecutableTask(tasks);
|
|
601
709
|
const codebase = codebasePaths(cwd);
|
|
602
710
|
|
|
603
711
|
return {
|
|
@@ -641,6 +749,23 @@ function initPayload(cwd, mode, requestedPhase) {
|
|
|
641
749
|
summary_exists: phase ? phase.summaryExists : false,
|
|
642
750
|
review_exists: phase ? phase.reviewExists : false,
|
|
643
751
|
uat_exists: phase ? phase.uatExists : false,
|
|
752
|
+
tasks_dir: phase ? phase.dir : null,
|
|
753
|
+
task_count: tasks.length,
|
|
754
|
+
task_done_count: tasks.filter(task => task.summaryExists).length,
|
|
755
|
+
all_tasks_done: tasks.length > 0 && tasks.every(task => task.summaryExists),
|
|
756
|
+
next_task_number: nextTask ? nextTask.number : null,
|
|
757
|
+
next_task_path: nextTask ? nextTask.taskPath : null,
|
|
758
|
+
next_task_summary_path: nextTask ? nextTask.summaryPath : null,
|
|
759
|
+
tasks: tasks.map(task => ({
|
|
760
|
+
number: task.number,
|
|
761
|
+
title: task.title,
|
|
762
|
+
status: task.effectiveStatus,
|
|
763
|
+
depends_on: task.dependsOn,
|
|
764
|
+
ready: task.ready,
|
|
765
|
+
task_path: task.taskPath,
|
|
766
|
+
summary_path: task.summaryPath,
|
|
767
|
+
summary_exists: task.summaryExists
|
|
768
|
+
})),
|
|
644
769
|
workflow: config.workflow,
|
|
645
770
|
git_mode: config.git.mode
|
|
646
771
|
};
|
|
@@ -743,5 +868,7 @@ module.exports = {
|
|
|
743
868
|
renderProgressTable,
|
|
744
869
|
resolvePhase,
|
|
745
870
|
rootPaths,
|
|
746
|
-
trackPaths
|
|
871
|
+
trackPaths,
|
|
872
|
+
listTasksForPhaseDetails,
|
|
873
|
+
nextExecutableTask
|
|
747
874
|
};
|
|
@@ -13,17 +13,28 @@ Type: [feature|bugfix|refactor|research|polish]
|
|
|
13
13
|
- ROADMAP.md
|
|
14
14
|
- Current codebase state
|
|
15
15
|
|
|
16
|
-
##
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
## Execution Model
|
|
17
|
+
- This phase is executed through task files.
|
|
18
|
+
- Keep one orchestration session for the phase.
|
|
19
|
+
- Execute one task at a time.
|
|
20
|
+
- No waves by default.
|
|
19
21
|
|
|
20
|
-
##
|
|
21
|
-
- [
|
|
22
|
+
## Phase-Level Risks
|
|
23
|
+
- [Risk]
|
|
22
24
|
|
|
23
|
-
## Verification
|
|
25
|
+
## Shared Verification
|
|
24
26
|
- [Command]
|
|
25
27
|
- [Manual check]
|
|
26
28
|
|
|
29
|
+
## Task List
|
|
30
|
+
| Task | Status | Depends On | Goal |
|
|
31
|
+
| --- | --- | --- | --- |
|
|
32
|
+
| 01 | pending | none | [Concrete task goal] |
|
|
33
|
+
| 02 | pending | 01 | [Concrete task goal] |
|
|
34
|
+
|
|
35
|
+
## Notes
|
|
36
|
+
- [Anything the worker agents must know]
|
|
37
|
+
|
|
27
38
|
## Git Policy
|
|
28
39
|
- Read-only only.
|
|
29
40
|
- Allowed: `git status`, `git diff`, `git log`, `git show`, `git rev-parse`, `git ls-files`, `git branch --show-current`.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Task [NN] Summary: [Name]
|
|
2
|
+
|
|
3
|
+
Status: done
|
|
4
|
+
|
|
5
|
+
## Completed
|
|
6
|
+
- [What changed]
|
|
7
|
+
|
|
8
|
+
## Files Changed
|
|
9
|
+
- [path]
|
|
10
|
+
|
|
11
|
+
## Verification
|
|
12
|
+
- [Command and result]
|
|
13
|
+
|
|
14
|
+
## Risks Or Follow-Up
|
|
15
|
+
- [Risk or none]
|
|
16
|
+
|
|
17
|
+
## Recommended Next Step
|
|
18
|
+
- Return to `/autodev`
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Task [NN]: [Name]
|
|
2
|
+
|
|
3
|
+
Status: pending
|
|
4
|
+
Depends On: none
|
|
5
|
+
|
|
6
|
+
## Goal
|
|
7
|
+
[What this task accomplishes]
|
|
8
|
+
|
|
9
|
+
## Why This Task Exists
|
|
10
|
+
- [Why this should be a separate unit]
|
|
11
|
+
|
|
12
|
+
## Files Likely To Change
|
|
13
|
+
- [path]
|
|
14
|
+
|
|
15
|
+
## Implementation Notes
|
|
16
|
+
- [Concrete implementation guidance]
|
|
17
|
+
|
|
18
|
+
## Verification
|
|
19
|
+
- [Command]
|
|
20
|
+
- [Manual check]
|
|
21
|
+
|
|
22
|
+
## Done Looks Like
|
|
23
|
+
- [Observable completion signal]
|
|
@@ -5,7 +5,7 @@ Use `/autodev` as the single entrypoint for the normal workflow. Route automatic
|
|
|
5
5
|
<rules>
|
|
6
6
|
- Prefer `/autodev` over telling the user to run a different command manually.
|
|
7
7
|
- Manual commands remain valid escape hatches. Mention them only as shortcuts.
|
|
8
|
-
- Keep the model `project -> track -> phase`.
|
|
8
|
+
- Keep the model `project -> track -> phase -> tasks`.
|
|
9
9
|
- Brownfield repositories should be mapped before detailed phase planning.
|
|
10
10
|
- Never run git write commands.
|
|
11
11
|
</rules>
|
|
@@ -23,7 +23,7 @@ node "$HOME/.claude/autodev/bin/autodev-tools.cjs" status
|
|
|
23
23
|
- `init_project`: perform the new-project workflow.
|
|
24
24
|
- `explore_codebase`: perform the explore-codebase workflow.
|
|
25
25
|
- `plan_phase`: perform the plan-phase workflow.
|
|
26
|
-
- `execute_phase`: perform the execute-phase workflow.
|
|
26
|
+
- `execute_phase`: perform the execute-phase workflow, which should advance one task-sized unit in the current phase session.
|
|
27
27
|
- `review_phase`: perform the review-phase workflow.
|
|
28
28
|
- `verify_phase`: perform the verify-work workflow.
|
|
29
29
|
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
<purpose>
|
|
2
|
-
Execute an active-track phase
|
|
2
|
+
Execute an active-track phase through task-sized worker runs, keep the main session orchestration-focused, and capture both task summaries and the final phase summary.
|
|
3
3
|
</purpose>
|
|
4
4
|
|
|
5
5
|
<rules>
|
|
6
6
|
- Never run git write commands.
|
|
7
7
|
- Do not create commits, branches, merges, or worktrees.
|
|
8
8
|
- Stay within the current phase. Do not silently expand scope.
|
|
9
|
-
- Execute
|
|
9
|
+
- Execute one task at a time by default.
|
|
10
|
+
- Do not use waves.
|
|
11
|
+
- Use a fresh background worker for each task so the phase session does not bloat.
|
|
10
12
|
</rules>
|
|
11
13
|
|
|
12
14
|
<process>
|
|
@@ -23,37 +25,77 @@ node "$HOME/.claude/autodev/bin/autodev-tools.cjs" init execute-phase "$ARGUMENT
|
|
|
23
25
|
- `.autodev/tracks/<active-track>/STATE.md`
|
|
24
26
|
- `.autodev/codebase/summary.md` if it exists
|
|
25
27
|
- the target `NN-PLAN.md`
|
|
26
|
-
-
|
|
28
|
+
- all `TASK-*.md`
|
|
29
|
+
- all existing `TASK-*-SUMMARY.md`
|
|
27
30
|
|
|
28
|
-
4.
|
|
31
|
+
4. If the phase has no `TASK-*.md` files:
|
|
32
|
+
- create `TASK-01.md` as a compatibility bridge from the current phase plan
|
|
33
|
+
- keep it narrow and explicit
|
|
34
|
+
- then continue
|
|
29
35
|
|
|
30
|
-
5.
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
- any scope adjustments the user explicitly approved
|
|
36
|
+
5. Determine the next executable task:
|
|
37
|
+
- prefer the first task without a summary whose dependencies are already done
|
|
38
|
+
- if no executable task remains and all task summaries exist, move to phase aggregation
|
|
39
|
+
- if task dependencies are inconsistent, stop and ask the user how to repair the plan
|
|
35
40
|
|
|
36
|
-
6.
|
|
37
|
-
-
|
|
38
|
-
- files
|
|
39
|
-
- verification
|
|
40
|
-
-
|
|
41
|
-
- next step
|
|
41
|
+
6. Before running a task, show the user:
|
|
42
|
+
- task id and title
|
|
43
|
+
- likely files to touch
|
|
44
|
+
- verification plan
|
|
45
|
+
- any dependency note
|
|
42
46
|
|
|
43
|
-
7.
|
|
47
|
+
7. Spawn one fresh background worker using `autodev-task-worker` for the selected task.
|
|
48
|
+
Tell it:
|
|
49
|
+
- phase path
|
|
50
|
+
- task path
|
|
51
|
+
- summary path to write
|
|
52
|
+
- required context files to read first
|
|
53
|
+
- to return a concise outcome only
|
|
54
|
+
|
|
55
|
+
8. After the worker returns:
|
|
56
|
+
- confirm `TASK-NN-SUMMARY.md` exists
|
|
57
|
+
- inspect whether the task is done or blocked
|
|
58
|
+
- report the result to the user
|
|
59
|
+
|
|
60
|
+
9. If more tasks remain:
|
|
61
|
+
- update project and track state to:
|
|
62
|
+
- `Current Step: execution`
|
|
63
|
+
- `Current Task: <next-task>`
|
|
64
|
+
- `Current Task Status: ready`
|
|
65
|
+
- `Next Command: /autodev`
|
|
66
|
+
- end by telling the user `/autodev` will continue with the next task
|
|
67
|
+
|
|
68
|
+
10. If all tasks are done:
|
|
69
|
+
- write or update `NN-SUMMARY.md` from the template with:
|
|
70
|
+
- completed tasks
|
|
71
|
+
- aggregate files changed
|
|
72
|
+
- overall verification results
|
|
73
|
+
- remaining risks
|
|
74
|
+
- next step
|
|
75
|
+
|
|
76
|
+
11. Update the active track `STATE.md` so it points to:
|
|
44
77
|
- `Current Phase: N`
|
|
45
78
|
- `Current Phase Type: <type>`
|
|
46
79
|
- `Current Step: review`
|
|
80
|
+
- `Current Task: none`
|
|
81
|
+
- `Current Task Status: complete`
|
|
47
82
|
- `Next Command: /autodev`
|
|
48
83
|
- current ISO timestamp
|
|
49
84
|
|
|
50
|
-
|
|
85
|
+
12. Update `.autodev/STATE.md` so it points to:
|
|
51
86
|
- `Active Track: <slug>`
|
|
52
87
|
- `Current Step: review`
|
|
88
|
+
- `Current Task: none`
|
|
89
|
+
- `Current Task Status: complete`
|
|
53
90
|
- `Next Command: /autodev`
|
|
54
91
|
- current ISO timestamp
|
|
55
92
|
|
|
56
|
-
|
|
93
|
+
13. If the current task is blocked or incomplete:
|
|
94
|
+
- say so clearly in the task summary
|
|
95
|
+
- set both state files to `Current Step: execution`
|
|
96
|
+
- set `Current Task: <same-task>`
|
|
97
|
+
- set `Current Task Status: blocked`
|
|
98
|
+
- keep `Next Command: /autodev`
|
|
57
99
|
|
|
58
|
-
|
|
100
|
+
14. End with a short outcome summary and the next recommended command. Mention that the automatic review bundle is the next routed step only when the whole phase is complete.
|
|
59
101
|
</process>
|
|
@@ -16,9 +16,9 @@ Lean Claude Code workflow. No automatic commits. No branches. No worktrees. Git
|
|
|
16
16
|
- `/autodev-explore-codebase`
|
|
17
17
|
Spawns four parallel agents to map a brownfield repo into `.autodev/codebase/`.
|
|
18
18
|
- `/autodev-plan-phase [phase]`
|
|
19
|
-
Creates or revises one phase plan in `.autodev/tracks/<track>/phases/NN-type-name
|
|
19
|
+
Creates or revises one phase plan plus task files in `.autodev/tracks/<track>/phases/NN-type-name/`.
|
|
20
20
|
- `/autodev-execute-phase [phase]`
|
|
21
|
-
|
|
21
|
+
Orchestrates one phase task-by-task and writes `TASK-NN-SUMMARY.md` plus the final `NN-SUMMARY.md`.
|
|
22
22
|
- `/autodev-review-phase [phase]`
|
|
23
23
|
Spawns four review agents for code quality, security, integration, and polish, then writes `NN-REVIEW.md`.
|
|
24
24
|
- `/autodev-verify-work [phase]`
|
|
@@ -31,7 +31,7 @@ Lean Claude Code workflow. No automatic commits. No branches. No worktrees. Git
|
|
|
31
31
|
## Workflow Model
|
|
32
32
|
|
|
33
33
|
```text
|
|
34
|
-
project -> track -> phase
|
|
34
|
+
project -> track -> phase -> tasks
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
- `project`
|
|
@@ -39,7 +39,9 @@ project -> track -> phase
|
|
|
39
39
|
- `track`
|
|
40
40
|
The current initiative, feature line, refactor, or bugfix stream.
|
|
41
41
|
- `phase`
|
|
42
|
-
Small
|
|
42
|
+
Small milestone slices inside the active track.
|
|
43
|
+
- `task`
|
|
44
|
+
Reviewable execution units inside a phase.
|
|
43
45
|
|
|
44
46
|
## Default Flow
|
|
45
47
|
|
|
@@ -49,6 +49,8 @@ node "$HOME/.claude/autodev/bin/autodev-tools.cjs" init new-project
|
|
|
49
49
|
- `Project Type: ...`
|
|
50
50
|
- `Active Track: <slug>`
|
|
51
51
|
- `Current Step: initialized`
|
|
52
|
+
- `Current Task: none`
|
|
53
|
+
- `Current Task Status: idle`
|
|
52
54
|
- `Status: active`
|
|
53
55
|
- `Next Command: /autodev`
|
|
54
56
|
- current ISO timestamp
|
|
@@ -79,6 +81,8 @@ Each phase must include:
|
|
|
79
81
|
- `Current Phase: 1`
|
|
80
82
|
- `Current Phase Type: <type>`
|
|
81
83
|
- `Current Step: planning`
|
|
84
|
+
- `Current Task: none`
|
|
85
|
+
- `Current Task Status: idle`
|
|
82
86
|
- `Status: active`
|
|
83
87
|
- `Next Command: /autodev`
|
|
84
88
|
- current ISO timestamp
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
<purpose>
|
|
2
|
-
Create one practical phase plan for the active track
|
|
2
|
+
Create one practical phase plan for the active track, then break it into reviewable task files that are small enough for fresh worker-agent execution.
|
|
3
3
|
</purpose>
|
|
4
4
|
|
|
5
5
|
<rules>
|
|
6
6
|
- One plan file per phase: `NN-PLAN.md`.
|
|
7
|
+
- Use task files as the execution unit.
|
|
7
8
|
- Prefer direct action over deep orchestration.
|
|
8
9
|
- Optional research is allowed only when the user asks for it or `workflow.research` is true.
|
|
9
10
|
- Never include git write commands in the plan.
|
|
11
|
+
- Do not use waves by default.
|
|
10
12
|
</rules>
|
|
11
13
|
|
|
12
14
|
<process>
|
|
@@ -42,24 +44,52 @@ node "$HOME/.claude/autodev/bin/autodev-tools.cjs" init plan-phase "$ARGUMENTS"
|
|
|
42
44
|
7. Write or replace `NN-PLAN.md` from the template. The plan must include:
|
|
43
45
|
- phase type
|
|
44
46
|
- goal
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
- verification commands
|
|
48
|
-
- manual checks
|
|
47
|
+
- shared verification commands
|
|
48
|
+
- task list overview
|
|
49
49
|
- explicit git read-only reminder
|
|
50
50
|
|
|
51
|
-
8.
|
|
51
|
+
8. Create task files in the same phase directory:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
TASK-01.md
|
|
55
|
+
TASK-02.md
|
|
56
|
+
...
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Each task should be:
|
|
60
|
+
- small enough for one fresh worker agent context
|
|
61
|
+
- clear about likely files to touch
|
|
62
|
+
- explicit about verification
|
|
63
|
+
- reviewable as a standalone unit
|
|
64
|
+
- sequential by default unless there is an obvious safe dependency split
|
|
65
|
+
|
|
66
|
+
Each task file must include:
|
|
67
|
+
- task title
|
|
68
|
+
- `Status: pending`
|
|
69
|
+
- `Depends On: ...`
|
|
70
|
+
- goal
|
|
71
|
+
- why it is separate
|
|
72
|
+
- files likely to change
|
|
73
|
+
- implementation notes
|
|
74
|
+
- verification
|
|
75
|
+
- done looks like
|
|
76
|
+
|
|
77
|
+
9. Update the active track `STATE.md` so it points to:
|
|
52
78
|
- `Current Phase: N`
|
|
53
79
|
- `Current Phase Type: <type>`
|
|
54
80
|
- `Current Step: planned`
|
|
81
|
+
- `Current Task: 01` if tasks exist, otherwise `none`
|
|
82
|
+
- `Current Task Status: ready`
|
|
55
83
|
- `Next Command: /autodev`
|
|
56
84
|
- current ISO timestamp
|
|
57
85
|
|
|
58
|
-
|
|
86
|
+
10. Update `.autodev/STATE.md` so it points to:
|
|
59
87
|
- `Active Track: <slug>`
|
|
60
88
|
- `Current Step: planned`
|
|
89
|
+
- `Current Task: 01` if tasks exist, otherwise `none`
|
|
90
|
+
- `Current Task Status: ready`
|
|
61
91
|
- `Next Command: /autodev`
|
|
62
92
|
- current ISO timestamp
|
|
63
93
|
|
|
64
|
-
|
|
94
|
+
11. End with a short summary and direct the user to `/autodev`. Mention `/autodev-execute-phase N` as the manual shortcut.
|
|
65
95
|
</process>
|
|
@@ -22,6 +22,8 @@ node "$HOME/.claude/autodev/bin/autodev-tools.cjs" init review-phase "$ARGUMENTS
|
|
|
22
22
|
- `.autodev/STATE.md`
|
|
23
23
|
- the active track `STATE.md`
|
|
24
24
|
- `NN-PLAN.md`
|
|
25
|
+
- all `TASK-*.md`
|
|
26
|
+
- all `TASK-*-SUMMARY.md`
|
|
25
27
|
- `NN-SUMMARY.md`
|
|
26
28
|
- relevant source files and tests
|
|
27
29
|
|
|
@@ -19,6 +19,8 @@ node "$HOME/.claude/autodev/bin/autodev-tools.cjs" init verify-work "$ARGUMENTS"
|
|
|
19
19
|
|
|
20
20
|
3. Read:
|
|
21
21
|
- `NN-PLAN.md`
|
|
22
|
+
- all `TASK-*.md`
|
|
23
|
+
- all `TASK-*-SUMMARY.md`
|
|
22
24
|
- `NN-SUMMARY.md`
|
|
23
25
|
- `NN-REVIEW.md`
|
|
24
26
|
- relevant code or UI files
|
|
@@ -40,6 +42,8 @@ node "$HOME/.claude/autodev/bin/autodev-tools.cjs" init verify-work "$ARGUMENTS"
|
|
|
40
42
|
- if verification passed and another phase remains, move to the next phase and set `Current Step: planning`
|
|
41
43
|
- if verification passed and no phase remains, set `Current Step: complete`
|
|
42
44
|
- if verification failed, keep the same phase active and set `Current Step: execution`
|
|
45
|
+
- when moving to another phase, set `Current Task: none` and `Current Task Status: idle`
|
|
46
|
+
- when verification failed, set `Current Task: none` and `Current Task Status: idle`
|
|
43
47
|
- always set `Next Command: /autodev`
|
|
44
48
|
- always refresh the ISO timestamp
|
|
45
49
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: autodev:execute-phase
|
|
3
|
-
description: Execute an active-track phase
|
|
3
|
+
description: Execute an active-track phase task by task with fresh background workers and no git writes
|
|
4
4
|
argument-hint: "[phase-number]"
|
|
5
5
|
allowed-tools:
|
|
6
6
|
- Read
|
|
@@ -11,14 +11,17 @@ allowed-tools:
|
|
|
11
11
|
- Glob
|
|
12
12
|
- TodoWrite
|
|
13
13
|
- AskUserQuestion
|
|
14
|
+
- Task
|
|
14
15
|
---
|
|
15
16
|
<objective>
|
|
16
|
-
Execute one active-track phase
|
|
17
|
+
Execute one active-track phase through task-sized worker runs and record both task-level and phase-level summaries.
|
|
17
18
|
</objective>
|
|
18
19
|
|
|
19
20
|
<execution_context>
|
|
20
21
|
@~/.claude/autodev/workflows/execute-phase.md
|
|
21
22
|
@~/.claude/autodev/templates/summary.md
|
|
23
|
+
@~/.claude/autodev/templates/task-summary.md
|
|
24
|
+
@~/.claude/autodev/agents/autodev-task-worker.md
|
|
22
25
|
</execution_context>
|
|
23
26
|
|
|
24
27
|
<process>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: autodev:plan-phase
|
|
3
|
-
description: Create a practical plan
|
|
3
|
+
description: Create a practical phase plan and break it into reviewable task files
|
|
4
4
|
argument-hint: "[phase-number]"
|
|
5
5
|
allowed-tools:
|
|
6
6
|
- Read
|
|
@@ -12,12 +12,13 @@ allowed-tools:
|
|
|
12
12
|
- WebFetch
|
|
13
13
|
---
|
|
14
14
|
<objective>
|
|
15
|
-
Create or update a single executable phase plan under the active track in `.autodev/tracks/<track>/phases
|
|
15
|
+
Create or update a single executable phase plan under the active track in `.autodev/tracks/<track>/phases/`, plus task files for controlled execution.
|
|
16
16
|
</objective>
|
|
17
17
|
|
|
18
18
|
<execution_context>
|
|
19
19
|
@~/.claude/autodev/workflows/plan-phase.md
|
|
20
20
|
@~/.claude/autodev/templates/plan.md
|
|
21
|
+
@~/.claude/autodev/templates/task.md
|
|
21
22
|
</execution_context>
|
|
22
23
|
|
|
23
24
|
<process>
|
|
@@ -4,6 +4,41 @@ const fs = require('fs');
|
|
|
4
4
|
const os = require('os');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
|
|
7
|
+
function readStateFields(cwd) {
|
|
8
|
+
try {
|
|
9
|
+
let cursor = cwd;
|
|
10
|
+
let statePath = null;
|
|
11
|
+
while (cursor && cursor !== path.dirname(cursor)) {
|
|
12
|
+
const candidate = path.join(cursor, '.autodev', 'STATE.md');
|
|
13
|
+
if (fs.existsSync(candidate)) {
|
|
14
|
+
statePath = candidate;
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
cursor = path.dirname(cursor);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!statePath) {
|
|
21
|
+
return {
|
|
22
|
+
currentTask: '',
|
|
23
|
+
currentTaskStatus: ''
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const content = fs.readFileSync(statePath, 'utf8');
|
|
28
|
+
const currentTask = content.match(/^Current Task:\s*(.+)$/mi)?.[1]?.trim() || '';
|
|
29
|
+
const currentTaskStatus = content.match(/^Current Task Status:\s*(.+)$/mi)?.[1]?.trim() || '';
|
|
30
|
+
return {
|
|
31
|
+
currentTask: currentTask && currentTask !== 'none' ? currentTask : '',
|
|
32
|
+
currentTaskStatus: currentTaskStatus && currentTaskStatus !== 'idle' ? currentTaskStatus : ''
|
|
33
|
+
};
|
|
34
|
+
} catch {
|
|
35
|
+
return {
|
|
36
|
+
currentTask: '',
|
|
37
|
+
currentTaskStatus: ''
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
7
42
|
let input = '';
|
|
8
43
|
const stdinTimeout = setTimeout(() => process.exit(0), 3000);
|
|
9
44
|
process.stdin.setEncoding('utf8');
|
|
@@ -19,6 +54,7 @@ process.stdin.on('end', () => {
|
|
|
19
54
|
const currentDir = data.workspace?.current_dir || process.cwd();
|
|
20
55
|
const remaining = data.context_window?.remaining_percentage;
|
|
21
56
|
const sessionId = data.session_id || '';
|
|
57
|
+
const taskState = readStateFields(currentDir);
|
|
22
58
|
|
|
23
59
|
let contextLabel = '';
|
|
24
60
|
if (typeof remaining === 'number') {
|
|
@@ -38,7 +74,11 @@ process.stdin.on('end', () => {
|
|
|
38
74
|
}
|
|
39
75
|
}
|
|
40
76
|
|
|
41
|
-
|
|
77
|
+
const taskLabel = taskState.currentTask
|
|
78
|
+
? ` | task ${taskState.currentTask}${taskState.currentTaskStatus ? ` (${taskState.currentTaskStatus})` : ''}`
|
|
79
|
+
: '';
|
|
80
|
+
|
|
81
|
+
process.stdout.write(`${model} | ${path.basename(currentDir)}${taskLabel}${contextLabel}`);
|
|
42
82
|
} catch {
|
|
43
83
|
process.exit(0);
|
|
44
84
|
}
|
|
@@ -42,7 +42,7 @@ process.stdin.on('end', () => {
|
|
|
42
42
|
hookEventName: 'PreToolUse',
|
|
43
43
|
additionalContext:
|
|
44
44
|
`WORKFLOW ADVISORY: you are editing ${path.basename(filePath)} outside .autodev state files. ` +
|
|
45
|
-
'If this belongs to the current phase, keep STATE.md and the phase summary aligned.'
|
|
45
|
+
'If this belongs to the current phase, keep STATE.md, task summaries, and the phase summary aligned.'
|
|
46
46
|
}
|
|
47
47
|
}));
|
|
48
48
|
} catch {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mthanhlm/autodev",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A lean Claude Code workflow system with a single entrypoint,
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "A lean Claude Code workflow system with a single entrypoint, task-based phase execution, and read-only git.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"autodev": "bin/install.js"
|
|
7
7
|
},
|