@atlashub/smartstack-cli 1.35.0 → 1.37.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/package.json +1 -1
- package/templates/skills/_shared.md +7 -7
- package/templates/skills/application/steps/step-01-navigation.md +226 -43
- package/templates/skills/application/steps/step-03-roles.md +160 -38
- package/templates/skills/application/steps/step-04-backend.md +126 -19
- package/templates/skills/application/steps/step-05-frontend.md +4 -1
- package/templates/skills/application/templates-backend.md +8 -8
- package/templates/skills/application/templates-frontend.md +8 -8
- package/templates/skills/application/templates-seed.md +200 -1
- package/templates/skills/gitflow/_shared.md +188 -53
- package/templates/skills/gitflow/phases/abort.md +28 -16
- package/templates/skills/gitflow/phases/cleanup.md +13 -9
- package/templates/skills/gitflow/phases/status.md +16 -17
- package/templates/skills/gitflow/steps/step-commit.md +11 -5
- package/templates/skills/gitflow/steps/step-finish.md +43 -33
- package/templates/skills/gitflow/steps/step-init.md +7 -2
- package/templates/skills/gitflow/steps/step-merge.md +24 -10
- package/templates/skills/gitflow/steps/step-pr.md +42 -28
- package/templates/skills/gitflow/steps/step-start.md +19 -13
- package/templates/skills/gitflow/templates/config.json +7 -4
- package/templates/skills/ralph-loop/SKILL.md +57 -11
- package/templates/skills/ralph-loop/steps/step-00-init.md +170 -30
- package/templates/skills/ralph-loop/steps/step-01-task.md +243 -40
- package/templates/skills/ralph-loop/steps/step-02-execute.md +142 -24
- package/templates/skills/ralph-loop/steps/step-03-commit.md +140 -36
- package/templates/skills/ralph-loop/steps/step-04-check.md +128 -44
- package/templates/skills/ralph-loop/steps/step-05-report.md +175 -88
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: step-00-init
|
|
3
|
-
description: Initialize Ralph loop - parse args, verify MCP, setup state
|
|
3
|
+
description: Initialize Ralph loop - parse args, verify MCP, setup state, migrate v1
|
|
4
4
|
next_step: steps/step-01-task.md
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -13,10 +13,11 @@ next_step: steps/step-01-task.md
|
|
|
13
13
|
- ONLY check for resume if -r flag is set
|
|
14
14
|
- YOU ARE AN INITIALIZER, not an executor
|
|
15
15
|
- FORBIDDEN to load step-01 until init is complete
|
|
16
|
+
- ALWAYS check prd.json version and migrate if v1
|
|
16
17
|
|
|
17
18
|
## YOUR TASK:
|
|
18
19
|
|
|
19
|
-
Initialize the Ralph loop by parsing flags, verifying MCP availability,
|
|
20
|
+
Initialize the Ralph loop by parsing flags, verifying MCP availability, setting up the execution environment, and validating integrity on resume.
|
|
20
21
|
|
|
21
22
|
---
|
|
22
23
|
|
|
@@ -73,26 +74,32 @@ mcp__smartstack__validate_conventions:
|
|
|
73
74
|
|
|
74
75
|
**Check Context7 MCP:**
|
|
75
76
|
```
|
|
76
|
-
|
|
77
|
+
mcp__context7__resolve-library-id:
|
|
77
78
|
libraryName: "test"
|
|
78
79
|
query: "connectivity check"
|
|
79
80
|
(just to verify connectivity)
|
|
80
81
|
```
|
|
81
82
|
|
|
83
|
+
**Record MCP status for metadata:**
|
|
84
|
+
```
|
|
85
|
+
{mcp_smartstack} = true/false
|
|
86
|
+
{mcp_context7} = true/false
|
|
87
|
+
```
|
|
88
|
+
|
|
82
89
|
**If ANY MCP fails:**
|
|
83
90
|
```
|
|
84
91
|
╔══════════════════════════════════════════════════════════════════╗
|
|
85
|
-
║ ❌ MCP SERVER UNAVAILABLE
|
|
92
|
+
║ ❌ MCP SERVER UNAVAILABLE ║
|
|
86
93
|
╠══════════════════════════════════════════════════════════════════╣
|
|
87
|
-
║ Server: {failed_server}
|
|
88
|
-
║ Status: Connection failed
|
|
94
|
+
║ Server: {failed_server} ║
|
|
95
|
+
║ Status: Connection failed ║
|
|
89
96
|
╠══════════════════════════════════════════════════════════════════╣
|
|
90
|
-
║ RALPH CANNOT PROCEED WITHOUT MCP
|
|
91
|
-
║
|
|
92
|
-
║ Troubleshooting:
|
|
93
|
-
║ 1. Run: smartstack check-mcp
|
|
94
|
-
║ 2. Restart Claude Code
|
|
95
|
-
║ 3. Check MCP server configuration
|
|
97
|
+
║ RALPH CANNOT PROCEED WITHOUT MCP ║
|
|
98
|
+
║ ║
|
|
99
|
+
║ Troubleshooting: ║
|
|
100
|
+
║ 1. Run: smartstack check-mcp ║
|
|
101
|
+
║ 2. Restart Claude Code ║
|
|
102
|
+
║ 3. Check MCP server configuration ║
|
|
96
103
|
╚══════════════════════════════════════════════════════════════════╝
|
|
97
104
|
|
|
98
105
|
STOP - Do not proceed.
|
|
@@ -103,16 +110,122 @@ STOP - Do not proceed.
|
|
|
103
110
|
**If {resume_mode} = true:**
|
|
104
111
|
|
|
105
112
|
1. Check for existing `.ralph/prd.json`
|
|
106
|
-
2. If found:
|
|
107
|
-
- Read prd.json to restore state
|
|
108
|
-
- Read progress.txt for context
|
|
109
|
-
- Set {current_iteration} from state
|
|
110
|
-
- Continue to step-01
|
|
111
|
-
3. If not found:
|
|
113
|
+
2. If not found:
|
|
112
114
|
- Error: "No active Ralph loop to resume"
|
|
113
115
|
- Ask user to start new loop
|
|
116
|
+
- STOP
|
|
117
|
+
|
|
118
|
+
3. If found, **validate schema version:**
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
const prd = readJSON('.ralph/prd.json');
|
|
114
122
|
|
|
115
|
-
|
|
123
|
+
// v1 detection: has "passes" field in tasks or no "$version"
|
|
124
|
+
const isV1 = !prd.$version || prd.tasks?.some(t => 'passes' in t);
|
|
125
|
+
|
|
126
|
+
if (isV1) {
|
|
127
|
+
// AUTO-MIGRATE v1 → v2
|
|
128
|
+
migrateV1toV2(prd);
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**v1 → v2 Migration logic:**
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
function migrateV1toV2(prd) {
|
|
136
|
+
prd.$version = "2.0.0";
|
|
137
|
+
prd.status = prd.tasks.every(t => t.passes) ? "completed" : "in_progress";
|
|
138
|
+
prd.updated_at = new Date().toISOString();
|
|
139
|
+
|
|
140
|
+
// Migrate source field
|
|
141
|
+
if (typeof prd.source === 'string') {
|
|
142
|
+
prd.source = { type: "ba-handoff", handoff_path: prd.source, frd_path: null, brd_path: null };
|
|
143
|
+
} else if (prd.source === null || prd.source === undefined) {
|
|
144
|
+
prd.source = null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Group flat config fields
|
|
148
|
+
prd.config = {
|
|
149
|
+
max_iterations: prd.max_iterations || 50,
|
|
150
|
+
completion_promise: prd.completion_promise || "COMPLETE",
|
|
151
|
+
current_iteration: prd.current_iteration || 1
|
|
152
|
+
};
|
|
153
|
+
delete prd.max_iterations;
|
|
154
|
+
delete prd.completion_promise;
|
|
155
|
+
delete prd.current_iteration;
|
|
156
|
+
|
|
157
|
+
// Add metadata
|
|
158
|
+
prd.metadata = {
|
|
159
|
+
cli_version: "unknown (migrated)",
|
|
160
|
+
branch: getCurrentBranch(),
|
|
161
|
+
project_path: process.cwd(),
|
|
162
|
+
mcp_servers: { smartstack: {mcp_smartstack}, context7: {mcp_context7} }
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// Migrate tasks
|
|
166
|
+
prd.tasks = prd.tasks.map(t => ({
|
|
167
|
+
id: t.id,
|
|
168
|
+
description: t.description,
|
|
169
|
+
status: t.passes ? "completed" : "pending",
|
|
170
|
+
category: "other",
|
|
171
|
+
dependencies: [],
|
|
172
|
+
acceptance_criteria: null,
|
|
173
|
+
started_at: null,
|
|
174
|
+
completed_at: t.passes ? prd.updated_at : null,
|
|
175
|
+
iteration: null,
|
|
176
|
+
commit_hash: null,
|
|
177
|
+
files_changed: { created: [], modified: [] },
|
|
178
|
+
validation: null,
|
|
179
|
+
error: null
|
|
180
|
+
}));
|
|
181
|
+
|
|
182
|
+
// Initialize history
|
|
183
|
+
prd.history = [];
|
|
184
|
+
|
|
185
|
+
// Write migrated file
|
|
186
|
+
writeJSON('.ralph/prd.json', prd);
|
|
187
|
+
echo "✅ Migrated prd.json from v1 to v2";
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
4. **Validate integrity (v2 resume):**
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
# Check branch consistency
|
|
195
|
+
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
|
196
|
+
PRD_BRANCH={prd.metadata.branch}
|
|
197
|
+
|
|
198
|
+
if [ "$CURRENT_BRANCH" != "$PRD_BRANCH" ]; then
|
|
199
|
+
echo "⚠️ Branch mismatch: prd.json was created on '$PRD_BRANCH', now on '$CURRENT_BRANCH'"
|
|
200
|
+
# Ask user: continue on current branch or switch
|
|
201
|
+
AskUserQuestion:
|
|
202
|
+
header: "Branch"
|
|
203
|
+
question: "prd.json was created on '$PRD_BRANCH' but you're on '$CURRENT_BRANCH'. Continue?"
|
|
204
|
+
options:
|
|
205
|
+
- label: "Continue on $CURRENT_BRANCH"
|
|
206
|
+
description: "Update metadata and continue"
|
|
207
|
+
- label: "Cancel"
|
|
208
|
+
description: "Switch branch manually first"
|
|
209
|
+
fi
|
|
210
|
+
|
|
211
|
+
# Check for external commits since last update
|
|
212
|
+
LAST_UPDATED={prd.updated_at}
|
|
213
|
+
EXTERNAL_COMMITS=$(git log --since="$LAST_UPDATED" --oneline --not --author="Co-Authored-By: Claude" | wc -l)
|
|
214
|
+
|
|
215
|
+
if [ "$EXTERNAL_COMMITS" -gt 0 ]; then
|
|
216
|
+
echo "⚠️ $EXTERNAL_COMMITS external commits detected since last Ralph iteration"
|
|
217
|
+
echo " prd.json state may not reflect current code state"
|
|
218
|
+
fi
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
5. **Restore state from prd.json:**
|
|
222
|
+
- Read `prd.config.current_iteration` → `{current_iteration}`
|
|
223
|
+
- Read `prd.config.completion_promise` → `{completion_promise}`
|
|
224
|
+
- Read `prd.config.max_iterations` → `{max_iterations}`
|
|
225
|
+
- Read progress.txt for context
|
|
226
|
+
- Continue to step-01
|
|
227
|
+
|
|
228
|
+
### 4. Initialize .ralph/ Structure (new loop)
|
|
116
229
|
|
|
117
230
|
**Create directory structure:**
|
|
118
231
|
|
|
@@ -149,7 +262,27 @@ AskUserQuestion:
|
|
|
149
262
|
description: "Specify custom text"
|
|
150
263
|
```
|
|
151
264
|
|
|
152
|
-
### 6.
|
|
265
|
+
### 6. Collect Metadata
|
|
266
|
+
|
|
267
|
+
**Gather execution context:**
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
CLI_VERSION=$(node -e "console.log(require('package.json').version)" 2>/dev/null || echo "unknown")
|
|
271
|
+
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
|
272
|
+
PROJECT_PATH=$(pwd)
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Store metadata for prd.json creation (step-01):**
|
|
276
|
+
```
|
|
277
|
+
{metadata} = {
|
|
278
|
+
cli_version: CLI_VERSION,
|
|
279
|
+
branch: CURRENT_BRANCH,
|
|
280
|
+
project_path: PROJECT_PATH,
|
|
281
|
+
mcp_servers: { smartstack: {mcp_smartstack}, context7: {mcp_context7} }
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### 7. Log Initialization
|
|
153
286
|
|
|
154
287
|
**If {verbose_mode} = true:**
|
|
155
288
|
|
|
@@ -159,25 +292,29 @@ Write to `.ralph/logs/{timestamp}.log`:
|
|
|
159
292
|
Task: {task_description}
|
|
160
293
|
Max iterations: {max_iterations}
|
|
161
294
|
Completion promise: {completion_promise}
|
|
162
|
-
MCP Status: SmartStack
|
|
295
|
+
MCP Status: SmartStack {mcp_smartstack ? "✅" : "❌"}, Context7 {mcp_context7 ? "✅" : "❌"}
|
|
296
|
+
Schema: v2.0.0
|
|
297
|
+
Branch: {CURRENT_BRANCH}
|
|
163
298
|
```
|
|
164
299
|
|
|
165
|
-
###
|
|
300
|
+
### 8. Show Summary and Proceed
|
|
166
301
|
|
|
167
302
|
**Always show COMPACT summary:**
|
|
168
303
|
|
|
169
304
|
```
|
|
170
305
|
╔══════════════════════════════════════════════════════════════════╗
|
|
171
|
-
║ RALPH LOOP INITIALIZED
|
|
306
|
+
║ RALPH LOOP INITIALIZED ║
|
|
172
307
|
╠══════════════════════════════════════════════════════════════════╣
|
|
173
|
-
║ Task: {task_description}
|
|
174
|
-
║ Max iterations: {max_iterations}
|
|
175
|
-
║ Completion: <promise>{completion_promise}</promise>
|
|
176
|
-
║ MCP: ✅ Ready
|
|
308
|
+
║ Task: {task_description} ║
|
|
309
|
+
║ Max iterations: {max_iterations} ║
|
|
310
|
+
║ Completion: <promise>{completion_promise}</promise> ║
|
|
311
|
+
║ MCP: ✅ Ready ║
|
|
312
|
+
║ Schema: v2.0.0 ║
|
|
313
|
+
║ Branch: {CURRENT_BRANCH} ║
|
|
177
314
|
╠══════════════════════════════════════════════════════════════════╣
|
|
178
|
-
║ Files:
|
|
179
|
-
║ - .ralph/prd.json (tasks)
|
|
180
|
-
║ - .ralph/progress.txt (memory)
|
|
315
|
+
║ Files: ║
|
|
316
|
+
║ - .ralph/prd.json (tasks) ║
|
|
317
|
+
║ - .ralph/progress.txt (memory) ║
|
|
181
318
|
╚══════════════════════════════════════════════════════════════════╝
|
|
182
319
|
|
|
183
320
|
-> Loading tasks...
|
|
@@ -193,6 +330,9 @@ MCP Status: SmartStack ✅, Context7 ✅
|
|
|
193
330
|
- MCP servers verified and available
|
|
194
331
|
- .ralph/ directory structure created
|
|
195
332
|
- Completion promise defined
|
|
333
|
+
- Metadata collected (branch, version, MCP status)
|
|
334
|
+
- v1 prd.json migrated to v2 (if resume)
|
|
335
|
+
- Branch integrity validated (if resume)
|
|
196
336
|
- Output is COMPACT
|
|
197
337
|
- Proceeded to step-01 immediately after summary
|
|
198
338
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: step-01-task
|
|
3
|
-
description: Load or create tasks from prd.json
|
|
3
|
+
description: Load or create tasks from prd.json (v2 schema)
|
|
4
4
|
next_step: steps/step-02-execute.md
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ next_step: steps/step-02-execute.md
|
|
|
8
8
|
|
|
9
9
|
## YOUR TASK:
|
|
10
10
|
|
|
11
|
-
Load the current task from prd.json or create initial task breakdown.
|
|
11
|
+
Load the current task from prd.json or create initial task breakdown with categories, dependencies, and acceptance criteria.
|
|
12
12
|
|
|
13
13
|
**ULTRA THINK about task decomposition.**
|
|
14
14
|
|
|
@@ -20,9 +20,9 @@ Load the current task from prd.json or create initial task breakdown.
|
|
|
20
20
|
|
|
21
21
|
**If `.ralph/prd.json` exists:**
|
|
22
22
|
- Read and parse the file
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
- Skip to step
|
|
23
|
+
- Verify `$version` is `"2.0.0"` (if not, STOP - run step-00 migration first)
|
|
24
|
+
- Find the next eligible task (see step 5)
|
|
25
|
+
- Skip to step 5
|
|
26
26
|
|
|
27
27
|
**If `.ralph/prd.json` does NOT exist:**
|
|
28
28
|
- Continue to step 2 (create tasks)
|
|
@@ -35,42 +35,162 @@ Load the current task from prd.json or create initial task breakdown.
|
|
|
35
35
|
- What order should they be executed?
|
|
36
36
|
- What are the success criteria for each?
|
|
37
37
|
- What files will be modified?
|
|
38
|
+
- What layer does each task belong to?
|
|
39
|
+
- What dependencies exist between tasks?
|
|
40
|
+
|
|
41
|
+
**Check for BA handoff source:**
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# If a handoff document exists, use it to derive tasks
|
|
45
|
+
HANDOFF=$(find . -path "*development-handoff*" -name "*.md" | head -1)
|
|
46
|
+
BA_OUTPUT=$(find . -path ".claude/output/ba/*" -name "4-*.md" | head -1)
|
|
47
|
+
SOURCE_PATH=${HANDOFF:-$BA_OUTPUT}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**If handoff found:**
|
|
51
|
+
- Read the handoff document
|
|
52
|
+
- Derive tasks from its specifications (per-layer breakdown)
|
|
53
|
+
- Set `source.type = "ba-handoff"` and `source.handoff_path`
|
|
54
|
+
- Look for FRD and BRD in the same directory
|
|
55
|
+
|
|
56
|
+
**If no handoff:**
|
|
57
|
+
- Generate task breakdown from `{task_description}`
|
|
58
|
+
- Set `source = null`
|
|
38
59
|
|
|
39
60
|
**Generate task breakdown:**
|
|
40
61
|
|
|
41
|
-
For `{task_description}`, identify 3-
|
|
62
|
+
For `{task_description}`, identify **3-30 subtasks** organized by category.
|
|
63
|
+
|
|
64
|
+
**Task categories (use SmartStack layer order):**
|
|
65
|
+
|
|
66
|
+
| Category | Description | Examples |
|
|
67
|
+
|----------|-------------|---------|
|
|
68
|
+
| `domain` | Domain entities and value objects | Create entities, enums, interfaces |
|
|
69
|
+
| `application` | CQRS handlers, DTOs, validators | Commands, Queries, DTOs, FluentValidation |
|
|
70
|
+
| `infrastructure` | EF Core, external services | DbContext configs, migrations, services |
|
|
71
|
+
| `api` | Controllers, middleware | REST endpoints, filters, middleware |
|
|
72
|
+
| `frontend` | React pages, components, hooks | Pages, API services, React Query hooks |
|
|
73
|
+
| `i18n` | Translations | Translation JSON files |
|
|
74
|
+
| `test` | Unit and integration tests | xUnit tests, React testing library |
|
|
75
|
+
| `validation` | Build, lint, MCP checks | dotnet build, pnpm build, MCP validate |
|
|
76
|
+
| `other` | Anything else | Documentation, configuration |
|
|
42
77
|
|
|
43
78
|
**Example for "implement user authentication":**
|
|
44
79
|
```json
|
|
45
80
|
{
|
|
46
81
|
"tasks": [
|
|
47
|
-
{
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
82
|
+
{
|
|
83
|
+
"id": 1,
|
|
84
|
+
"description": "Create User entity in SmartStack.Domain/Entities/Business/",
|
|
85
|
+
"status": "pending",
|
|
86
|
+
"category": "domain",
|
|
87
|
+
"dependencies": [],
|
|
88
|
+
"acceptance_criteria": "Entity compiles with all required properties per handoff spec"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"id": 2,
|
|
92
|
+
"description": "Add User DbSet to ApplicationDbContext and create EF Core configuration",
|
|
93
|
+
"status": "pending",
|
|
94
|
+
"category": "infrastructure",
|
|
95
|
+
"dependencies": [1],
|
|
96
|
+
"acceptance_criteria": "DbContext compiles, configuration maps all properties"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"id": 3,
|
|
100
|
+
"description": "Create EF Core migration for User table",
|
|
101
|
+
"status": "pending",
|
|
102
|
+
"category": "infrastructure",
|
|
103
|
+
"dependencies": [2],
|
|
104
|
+
"acceptance_criteria": "Migration applies without errors, 3 files present"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"id": 4,
|
|
108
|
+
"description": "Implement IPasswordService and IJwtService",
|
|
109
|
+
"status": "pending",
|
|
110
|
+
"category": "application",
|
|
111
|
+
"dependencies": [1],
|
|
112
|
+
"acceptance_criteria": "Services compile, follow existing patterns"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"id": 5,
|
|
116
|
+
"description": "Create CQRS Commands: LoginCommand + RegisterCommand with handlers",
|
|
117
|
+
"status": "pending",
|
|
118
|
+
"category": "application",
|
|
119
|
+
"dependencies": [4],
|
|
120
|
+
"acceptance_criteria": "Handlers compile, validators defined"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"id": 6,
|
|
124
|
+
"description": "Create AuthController with login/register endpoints",
|
|
125
|
+
"status": "pending",
|
|
126
|
+
"category": "api",
|
|
127
|
+
"dependencies": [5],
|
|
128
|
+
"acceptance_criteria": "Endpoints respond correctly, Swagger displays them"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"id": 7,
|
|
132
|
+
"description": "Write unit tests for User entity and validators",
|
|
133
|
+
"status": "pending",
|
|
134
|
+
"category": "test",
|
|
135
|
+
"dependencies": [5],
|
|
136
|
+
"acceptance_criteria": "All tests pass, >80% coverage on new code"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"id": 8,
|
|
140
|
+
"description": "Run dotnet build, dotnet test, MCP validate_conventions",
|
|
141
|
+
"status": "pending",
|
|
142
|
+
"category": "validation",
|
|
143
|
+
"dependencies": [6, 7],
|
|
144
|
+
"acceptance_criteria": "Build succeeds, all tests pass, MCP validation clean"
|
|
145
|
+
}
|
|
55
146
|
]
|
|
56
147
|
}
|
|
57
148
|
```
|
|
58
149
|
|
|
59
|
-
|
|
150
|
+
**Task count validation:**
|
|
151
|
+
- MINIMUM: 3 tasks (anything less is too coarse)
|
|
152
|
+
- MAXIMUM: 30 tasks (anything more needs re-grouping)
|
|
153
|
+
- If over 30, merge related subtasks into larger units
|
|
154
|
+
|
|
155
|
+
### 3. Create prd.json (v2)
|
|
60
156
|
|
|
61
157
|
**Write `.ralph/prd.json`:**
|
|
62
158
|
|
|
63
159
|
```json
|
|
64
160
|
{
|
|
161
|
+
"$version": "2.0.0",
|
|
65
162
|
"feature": "{task_description}",
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
163
|
+
"status": "in_progress",
|
|
164
|
+
"created": "{ISO_TIMESTAMP}",
|
|
165
|
+
"updated_at": "{ISO_TIMESTAMP}",
|
|
166
|
+
"metadata": {metadata},
|
|
167
|
+
"config": {
|
|
168
|
+
"max_iterations": {max_iterations},
|
|
169
|
+
"completion_promise": "{completion_promise}",
|
|
170
|
+
"current_iteration": 1
|
|
171
|
+
},
|
|
172
|
+
"source": {source_object_or_null},
|
|
173
|
+
"tasks": [{generated_tasks_with_all_fields}],
|
|
174
|
+
"history": []
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**IMPORTANT: Every task MUST have ALL fields:**
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"id": 1,
|
|
182
|
+
"description": "...",
|
|
183
|
+
"status": "pending",
|
|
184
|
+
"category": "domain|application|infrastructure|api|frontend|i18n|test|validation|other",
|
|
185
|
+
"dependencies": [],
|
|
186
|
+
"acceptance_criteria": "...",
|
|
187
|
+
"started_at": null,
|
|
188
|
+
"completed_at": null,
|
|
189
|
+
"iteration": null,
|
|
190
|
+
"commit_hash": null,
|
|
191
|
+
"files_changed": { "created": [], "modified": [] },
|
|
192
|
+
"validation": null,
|
|
193
|
+
"error": null
|
|
74
194
|
}
|
|
75
195
|
```
|
|
76
196
|
|
|
@@ -81,6 +201,8 @@ For `{task_description}`, identify 3-10 subtasks.
|
|
|
81
201
|
|
|
82
202
|
## Task: {task_description}
|
|
83
203
|
## Started: {timestamp}
|
|
204
|
+
## Schema: v2.0.0
|
|
205
|
+
## Source: {source_type or "direct"}
|
|
84
206
|
|
|
85
207
|
---
|
|
86
208
|
|
|
@@ -93,27 +215,102 @@ Starting fresh implementation.
|
|
|
93
215
|
(To be updated after each iteration)
|
|
94
216
|
```
|
|
95
217
|
|
|
96
|
-
### 4.
|
|
218
|
+
### 4. Validate Task Integrity
|
|
97
219
|
|
|
98
|
-
**
|
|
220
|
+
**After creation, verify:**
|
|
99
221
|
|
|
100
222
|
```javascript
|
|
101
|
-
|
|
223
|
+
// Check all tasks have required fields
|
|
224
|
+
const requiredFields = ['id', 'description', 'status', 'category',
|
|
225
|
+
'dependencies', 'acceptance_criteria', 'started_at', 'completed_at',
|
|
226
|
+
'iteration', 'commit_hash', 'files_changed', 'validation', 'error'];
|
|
227
|
+
|
|
228
|
+
for (const task of prd.tasks) {
|
|
229
|
+
for (const field of requiredFields) {
|
|
230
|
+
if (!(field in task)) {
|
|
231
|
+
ERROR: "Task ${task.id} missing field: ${field}";
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Check dependency references are valid
|
|
237
|
+
const taskIds = prd.tasks.map(t => t.id);
|
|
238
|
+
for (const task of prd.tasks) {
|
|
239
|
+
for (const dep of task.dependencies) {
|
|
240
|
+
if (!taskIds.includes(dep)) {
|
|
241
|
+
ERROR: "Task ${task.id} depends on non-existent task ${dep}";
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Check no circular dependencies
|
|
247
|
+
// (simple: a task cannot depend on a task with higher or equal id)
|
|
248
|
+
for (const task of prd.tasks) {
|
|
249
|
+
for (const dep of task.dependencies) {
|
|
250
|
+
if (dep >= task.id) {
|
|
251
|
+
ERROR: "Task ${task.id} has forward/circular dependency on task ${dep}";
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Check task count
|
|
257
|
+
if (prd.tasks.length < 3 || prd.tasks.length > 30) {
|
|
258
|
+
WARNING: "Task count ${prd.tasks.length} outside recommended range (3-30)";
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### 5. Find Current Task
|
|
263
|
+
|
|
264
|
+
**Find the next eligible task:**
|
|
265
|
+
|
|
266
|
+
```javascript
|
|
267
|
+
function findNextTask(tasks) {
|
|
268
|
+
for (const task of tasks) {
|
|
269
|
+
if (task.status !== 'pending') continue;
|
|
270
|
+
|
|
271
|
+
// Check all dependencies are completed
|
|
272
|
+
const depsOk = task.dependencies.every(depId => {
|
|
273
|
+
const dep = tasks.find(t => t.id === depId);
|
|
274
|
+
return dep && dep.status === 'completed';
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// Check if any dependency failed (→ block this task)
|
|
278
|
+
const depsBlocked = task.dependencies.some(depId => {
|
|
279
|
+
const dep = tasks.find(t => t.id === depId);
|
|
280
|
+
return dep && (dep.status === 'failed' || dep.status === 'blocked');
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
if (depsBlocked) {
|
|
284
|
+
task.status = 'blocked';
|
|
285
|
+
task.error = `Blocked by failed dependency`;
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (depsOk) return task;
|
|
290
|
+
}
|
|
291
|
+
return null; // No eligible tasks
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const currentTask = findNextTask(prd.tasks);
|
|
102
295
|
```
|
|
103
296
|
|
|
104
|
-
**If
|
|
105
|
-
-
|
|
106
|
-
-
|
|
297
|
+
**If no eligible task found:**
|
|
298
|
+
- Check if all tasks are completed → skip to step-05 (report)
|
|
299
|
+
- Check if remaining tasks are all blocked → report as partial, step-05
|
|
300
|
+
- Otherwise → unexpected state, STOP
|
|
107
301
|
|
|
108
302
|
**Store in state:**
|
|
109
303
|
```
|
|
110
304
|
{current_task_id} = currentTask.id
|
|
111
305
|
{current_task_description} = currentTask.description
|
|
112
|
-
{
|
|
306
|
+
{current_task_category} = currentTask.category
|
|
307
|
+
{current_task_criteria} = currentTask.acceptance_criteria
|
|
308
|
+
{tasks_completed} = tasks.filter(t => t.status === 'completed').length
|
|
113
309
|
{tasks_total} = tasks.length
|
|
310
|
+
{tasks_blocked} = tasks.filter(t => t.status === 'blocked').length
|
|
114
311
|
```
|
|
115
312
|
|
|
116
|
-
###
|
|
313
|
+
### 6. Read Previous Progress
|
|
117
314
|
|
|
118
315
|
**If iteration > 1:**
|
|
119
316
|
|
|
@@ -123,23 +320,26 @@ Read `.ralph/progress.txt` to understand:
|
|
|
123
320
|
- Files that were modified
|
|
124
321
|
- Issues encountered
|
|
125
322
|
|
|
126
|
-
**
|
|
323
|
+
**Also read `history[]` from prd.json for structured context.**
|
|
127
324
|
|
|
128
|
-
###
|
|
325
|
+
### 7. Show Task Status
|
|
129
326
|
|
|
130
327
|
**Display current state:**
|
|
131
328
|
|
|
132
329
|
```
|
|
133
330
|
╔══════════════════════════════════════════════════════════════════╗
|
|
134
|
-
║ ITERATION {current_iteration} / {max_iterations}
|
|
331
|
+
║ ITERATION {current_iteration} / {max_iterations} ║
|
|
135
332
|
╠══════════════════════════════════════════════════════════════════╣
|
|
136
|
-
║ Progress: {tasks_completed} / {tasks_total} tasks complete
|
|
137
|
-
║
|
|
138
|
-
║
|
|
139
|
-
║
|
|
333
|
+
║ Progress: {tasks_completed} / {tasks_total} tasks complete ║
|
|
334
|
+
║ Blocked: {tasks_blocked} ║
|
|
335
|
+
║ ║
|
|
336
|
+
║ Current Task: ║
|
|
337
|
+
║ [{current_task_id}] {current_task_description} ║
|
|
338
|
+
║ Category: {current_task_category} ║
|
|
339
|
+
║ Criteria: {current_task_criteria} ║
|
|
140
340
|
╠══════════════════════════════════════════════════════════════════╣
|
|
141
|
-
║ Previous Learnings:
|
|
142
|
-
║ {summary from progress.txt}
|
|
341
|
+
║ Previous Learnings: ║
|
|
342
|
+
║ {summary from progress.txt} ║
|
|
143
343
|
╚══════════════════════════════════════════════════════════════════╝
|
|
144
344
|
|
|
145
345
|
-> Executing task...
|
|
@@ -157,7 +357,10 @@ Task Loaded:
|
|
|
157
357
|
| Iteration | {current_iteration} / {max_iterations} |
|
|
158
358
|
| Task ID | {current_task_id} |
|
|
159
359
|
| Task | {current_task_description} |
|
|
360
|
+
| Category | {current_task_category} |
|
|
361
|
+
| Criteria | {current_task_criteria} |
|
|
160
362
|
| Progress | {tasks_completed} / {tasks_total} |
|
|
363
|
+
| Blocked | {tasks_blocked} |
|
|
161
364
|
|
|
162
365
|
-> Executing...
|
|
163
366
|
```
|