agentic-loop 3.14.1 → 3.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/idea/SKILL.md +56 -0
- package/.claude/skills/prd/SKILL.md +41 -82
- package/.claude/skills/prd-check/SKILL.md +48 -0
- package/README.md +4 -1
- package/bin/ralph.sh +3 -0
- package/dist/loopgram/prd-generator.d.ts +2 -0
- package/dist/loopgram/prd-generator.d.ts.map +1 -1
- package/dist/loopgram/prd-generator.js +2 -0
- package/dist/loopgram/prd-generator.js.map +1 -1
- package/package.json +1 -1
- package/ralph/hooks/protect-prd.sh +1 -1
- package/ralph/loop.sh +37 -17
- package/ralph/prd-check.sh +206 -11
- package/ralph/prd.sh +9 -32
- package/ralph/setup/quick-setup.sh +25 -12
- package/ralph/setup.sh +21 -1
- package/templates/checks/prd/check-example.sh +25 -0
- package/templates/config/fastmcp.json +6 -1
- package/templates/config/fullstack.json +8 -0
- package/templates/config/node.json +8 -0
- package/templates/config/python.json +8 -0
- package/templates/prd-example.json +45 -26
- package/.claude/commands/prd.md +0 -770
|
@@ -64,6 +64,12 @@ Help the user flesh out the idea through conversation:
|
|
|
64
64
|
- Caching needed? How fresh must data be?
|
|
65
65
|
- Database indexes: What will be queried/sorted frequently?
|
|
66
66
|
|
|
67
|
+
**Migration/Refactoring (IMPORTANT - ask if moving or restructuring code):**
|
|
68
|
+
- Source paths: Where does the code currently live?
|
|
69
|
+
- Destination paths: Where should it end up? (be explicit, not vague)
|
|
70
|
+
- Phases: What's the logical order? (move files → update imports → verify)
|
|
71
|
+
- Verification: What commands prove each phase worked?
|
|
72
|
+
|
|
67
73
|
### Step 3: Summarize Before Writing
|
|
68
74
|
|
|
69
75
|
When you have enough information, summarize what you've learned:
|
|
@@ -132,6 +138,36 @@ Once the user confirms, write the idea file:
|
|
|
132
138
|
- **Caching**: What can be cached? For how long?
|
|
133
139
|
- **Database**: What indexes are needed?
|
|
134
140
|
|
|
141
|
+
## Migration Mapping (if moving/restructuring code)
|
|
142
|
+
For refactoring or migration tasks, explicitly map source to destination:
|
|
143
|
+
|
|
144
|
+
| Source | Destination |
|
|
145
|
+
|--------|-------------|
|
|
146
|
+
| `~/Sites/old-project/src/` | `apps/new-location/src/` |
|
|
147
|
+
| `~/Sites/old-project/tests/` | `apps/new-location/tests/` |
|
|
148
|
+
|
|
149
|
+
## Phases & Verification
|
|
150
|
+
Break complex work into phases with explicit verification commands:
|
|
151
|
+
|
|
152
|
+
### Phase 1: [Name]
|
|
153
|
+
**What:** Description of what this phase accomplishes
|
|
154
|
+
**Exit Criteria:**
|
|
155
|
+
```bash
|
|
156
|
+
# These commands must pass before phase is complete
|
|
157
|
+
test -d apps/new-location/src
|
|
158
|
+
cd apps/new-location && uv run pytest -x
|
|
159
|
+
cd apps/new-location && npm run build
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Phase 2: [Name]
|
|
163
|
+
**What:** Description
|
|
164
|
+
**Exit Criteria:**
|
|
165
|
+
```bash
|
|
166
|
+
# Verification commands for phase 2
|
|
167
|
+
docker-compose config | grep -q 'service-name:'
|
|
168
|
+
curl -s http://localhost:8000/health | jq -e '.status == "ok"'
|
|
169
|
+
```
|
|
170
|
+
|
|
135
171
|
## UI Mockup (if applicable)
|
|
136
172
|
```
|
|
137
173
|
┌─────────────────────────────────┐
|
|
@@ -190,6 +226,26 @@ A good idea file has:
|
|
|
190
226
|
- **Specific solution** - Not vague ("improve UX") but concrete ("add inline validation")
|
|
191
227
|
- **Scope boundaries** - What's explicitly out of scope?
|
|
192
228
|
- **Architecture hints** - Where do files go? What patterns to follow?
|
|
229
|
+
- **Verification commands** - How do we know it worked? (executable commands, not prose)
|
|
230
|
+
|
|
231
|
+
### Migration/Refactoring Ideas
|
|
232
|
+
|
|
233
|
+
For ideas that involve moving or restructuring code, MUST include:
|
|
234
|
+
|
|
235
|
+
1. **Explicit path mapping** - Source → Destination for every directory
|
|
236
|
+
```
|
|
237
|
+
❌ "Move GOPA to apps folder"
|
|
238
|
+
✅ "~/Sites/gopa/src/gopa/ → apps/gopa/src/gopa/"
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
2. **Phase-based verification** - Each phase has exit criteria with commands
|
|
242
|
+
```
|
|
243
|
+
❌ "Verify everything still works"
|
|
244
|
+
✅ "cd apps/gopa && uv run pytest -x && uv run python -c 'from gopa.server import mcp'"
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
3. **Order of operations** - What must happen before what?
|
|
248
|
+
- Move files → Update imports → Update configs → Verify
|
|
193
249
|
|
|
194
250
|
### ASCII Art for UI
|
|
195
251
|
|
|
@@ -61,6 +61,8 @@ cat package.json 2>/dev/null | jq '{name, dependencies}' || true
|
|
|
61
61
|
cat pyproject.toml 2>/dev/null | head -20 || true
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
Use the detected tech stack, test runners, and constraints when building each story — these go into each story's `techStack`, `constraints`, and `testing.runner` fields (not at the PRD root).
|
|
65
|
+
|
|
64
66
|
Then say: "I'll create a PRD for: **{description}**
|
|
65
67
|
|
|
66
68
|
Before I generate stories, quick questions:
|
|
@@ -101,6 +103,7 @@ Break the idea into small, executable stories:
|
|
|
101
103
|
- Max 3-4 acceptance criteria per story
|
|
102
104
|
- Max 10 stories (suggest phases if more needed)
|
|
103
105
|
- If appending, start IDs from the next available number
|
|
106
|
+
- **Each story must include its own `techStack`, `constraints`, and `contextFiles`.** Include only what's relevant to that story — don't copy-paste identical context into every story.
|
|
104
107
|
|
|
105
108
|
### Step 5: Write Draft PRD
|
|
106
109
|
|
|
@@ -152,10 +155,13 @@ Does acceptanceCriteria include:
|
|
|
152
155
|
- Query params → "Accepts ?page=N&limit=N"
|
|
153
156
|
- Large datasets → "Database query uses index on [column]"
|
|
154
157
|
|
|
155
|
-
#### 6e. Context (for
|
|
158
|
+
#### 6e. Context (for all stories)
|
|
156
159
|
- Does `contextFiles` include the idea file (has ASCII mockups)?
|
|
157
160
|
- Does `contextFiles` include styleguide (if exists)?
|
|
158
|
-
-
|
|
161
|
+
- Does `techStack` include the relevant stack for this story?
|
|
162
|
+
- Does `constraints` include any rules this story must follow?
|
|
163
|
+
- For frontend: Is `testUrl` set?
|
|
164
|
+
- For frontend: Is `mcp` set to `["playwright", "devtools"]`?
|
|
159
165
|
|
|
160
166
|
**Fix any issues you find:**
|
|
161
167
|
|
|
@@ -168,6 +174,9 @@ Does acceptanceCriteria include:
|
|
|
168
174
|
| List endpoint missing pagination | Add pagination criteria to acceptanceCriteria |
|
|
169
175
|
| Frontend missing contextFiles | Add idea file + styleguide paths |
|
|
170
176
|
| Frontend missing testUrl | Add URL from config |
|
|
177
|
+
| Frontend missing mcp | Add `"mcp": ["playwright", "devtools"]` |
|
|
178
|
+
| Story missing techStack | Add relevant subset of detected tech |
|
|
179
|
+
| Story missing constraints | Add applicable rules for this story |
|
|
171
180
|
|
|
172
181
|
### Step 7: Reorder if Needed
|
|
173
182
|
|
|
@@ -229,45 +238,6 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
229
238
|
"status": "pending"
|
|
230
239
|
},
|
|
231
240
|
|
|
232
|
-
"originalContext": "docs/ideas/{feature-name}.md",
|
|
233
|
-
|
|
234
|
-
"techStack": {
|
|
235
|
-
"frontend": "{detected from package.json}",
|
|
236
|
-
"backend": "{detected from pyproject.toml/go.mod}",
|
|
237
|
-
"database": "{detected or asked}"
|
|
238
|
-
},
|
|
239
|
-
|
|
240
|
-
"testing": {
|
|
241
|
-
"approach": "TDD",
|
|
242
|
-
"unit": {
|
|
243
|
-
"frontend": "{vitest|jest - detected from package.json}",
|
|
244
|
-
"backend": "{pytest|go test - detected from project}"
|
|
245
|
-
},
|
|
246
|
-
"integration": "{playwright|cypress}",
|
|
247
|
-
"e2e": "{playwright|cypress}",
|
|
248
|
-
"coverage": {
|
|
249
|
-
"minimum": 80,
|
|
250
|
-
"enforced": false
|
|
251
|
-
}
|
|
252
|
-
},
|
|
253
|
-
|
|
254
|
-
"architecture": {
|
|
255
|
-
"frontend": "src/components",
|
|
256
|
-
"backend": "src/api",
|
|
257
|
-
"doNotCreate": ["new database tables without migration"]
|
|
258
|
-
},
|
|
259
|
-
|
|
260
|
-
"globalConstraints": [
|
|
261
|
-
"All API calls must have error handling",
|
|
262
|
-
"No console.log in production code",
|
|
263
|
-
"Use existing UI components from src/components/ui"
|
|
264
|
-
],
|
|
265
|
-
|
|
266
|
-
"testUsers": {
|
|
267
|
-
"admin": {"email": "admin@test.com", "password": "test123"},
|
|
268
|
-
"user": {"email": "user@test.com", "password": "test123"}
|
|
269
|
-
},
|
|
270
|
-
|
|
271
241
|
"metadata": {
|
|
272
242
|
"createdAt": "ISO timestamp",
|
|
273
243
|
"estimatedStories": 5,
|
|
@@ -282,6 +252,17 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
282
252
|
"priority": 1,
|
|
283
253
|
"passes": false,
|
|
284
254
|
|
|
255
|
+
"techStack": {
|
|
256
|
+
"frontend": "{detected from package.json}",
|
|
257
|
+
"backend": "{detected from pyproject.toml/go.mod}",
|
|
258
|
+
"database": "{detected or asked}"
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
"constraints": [
|
|
262
|
+
"Rules that apply to this story",
|
|
263
|
+
"E.g. Use existing UI components from src/components/ui"
|
|
264
|
+
],
|
|
265
|
+
|
|
285
266
|
"files": {
|
|
286
267
|
"create": ["paths to new files"],
|
|
287
268
|
"modify": ["paths to existing files"],
|
|
@@ -299,6 +280,7 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
299
280
|
"testing": {
|
|
300
281
|
"types": ["unit", "integration"],
|
|
301
282
|
"approach": "TDD",
|
|
283
|
+
"runner": "vitest|jest|pytest|go test",
|
|
302
284
|
"files": {
|
|
303
285
|
"unit": ["src/components/Dashboard.test.tsx"],
|
|
304
286
|
"integration": ["tests/integration/dashboard.test.ts"],
|
|
@@ -330,6 +312,10 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
330
312
|
"response": {"field": "type"}
|
|
331
313
|
},
|
|
332
314
|
|
|
315
|
+
"testUsers": {
|
|
316
|
+
"admin": {"email": "admin@test.com", "password": "test123"}
|
|
317
|
+
},
|
|
318
|
+
|
|
333
319
|
"prerequisites": [
|
|
334
320
|
"Backend server running",
|
|
335
321
|
"Database seeded"
|
|
@@ -358,19 +344,15 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
358
344
|
|
|
359
345
|
| Field | Required | Description |
|
|
360
346
|
|-------|----------|-------------|
|
|
361
|
-
| `feature` | Yes | Feature name, branch, status |
|
|
362
|
-
| `
|
|
363
|
-
| `techStack` | No | Technologies in use (auto-detect from project) |
|
|
364
|
-
| `testing` | Yes | Testing strategy, tools, coverage requirements |
|
|
365
|
-
| `architecture` | No | Directory structure, patterns, constraints |
|
|
366
|
-
| `globalConstraints` | No | Rules that apply to ALL stories |
|
|
367
|
-
| `testUsers` | No | Test accounts for auth flows |
|
|
368
|
-
| `metadata` | Yes | Created date, complexity estimate |
|
|
347
|
+
| `feature` | Yes | Feature name, ideaFile, branch, status |
|
|
348
|
+
| `metadata` | Yes | Created date, estimated stories, complexity |
|
|
369
349
|
|
|
370
350
|
**Note:** URLs come from `.ralph/config.json`, not the PRD. Use `{config.urls.backend}` in testSteps.
|
|
371
351
|
|
|
372
352
|
### Story-Level Fields
|
|
373
353
|
|
|
354
|
+
Each story is **self-contained** with all the context it needs. No global defaults — include only what's relevant to that story.
|
|
355
|
+
|
|
374
356
|
| Field | Required | Description |
|
|
375
357
|
|-------|----------|-------------|
|
|
376
358
|
| `id` | Yes | Unique ID (TASK-001, TASK-002, etc.) |
|
|
@@ -378,16 +360,19 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
378
360
|
| `title` | Yes | Short description |
|
|
379
361
|
| `priority` | No | Order of importance (1 = highest) |
|
|
380
362
|
| `passes` | Yes | Always starts as `false` |
|
|
363
|
+
| `techStack` | Yes | Technologies relevant to this story (auto-detect from project) |
|
|
364
|
+
| `constraints` | No | Rules/constraints specific to this story |
|
|
381
365
|
| `files` | Yes | create, modify, reuse arrays |
|
|
382
366
|
| `acceptanceCriteria` | Yes | What must be true when done |
|
|
383
367
|
| `errorHandling` | Yes | How to handle failures |
|
|
384
|
-
| `testing` | Yes | Test types, approach, and files for this story |
|
|
368
|
+
| `testing` | Yes | Test types, approach, runner, and files for this story |
|
|
385
369
|
| `testSteps` | Yes | Executable shell commands |
|
|
386
370
|
| `testUrl` | Frontend | URL to verify the feature |
|
|
387
371
|
| `mcp` | Frontend | MCP tools for verification |
|
|
388
372
|
| `contextFiles` | No | Files Claude should read (idea files, styleguides) |
|
|
389
373
|
| `skills` | No | Relevant skills with usage hints |
|
|
390
374
|
| `apiContract` | Backend | Expected request/response format |
|
|
375
|
+
| `testUsers` | No | Test accounts (only for auth stories that need them) |
|
|
391
376
|
| `prerequisites` | No | What must be running/ready |
|
|
392
377
|
| `notes` | No | Human guidance for Claude |
|
|
393
378
|
| `scale` | No | small, medium, large |
|
|
@@ -398,49 +383,22 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
398
383
|
|
|
399
384
|
## Testing Strategy
|
|
400
385
|
|
|
401
|
-
###
|
|
402
|
-
|
|
403
|
-
Define the overall testing strategy for the feature. **Auto-detect tools from project config files:**
|
|
386
|
+
### Story-Level Testing Config
|
|
404
387
|
|
|
405
|
-
|
|
406
|
-
"testing": {
|
|
407
|
-
"approach": "TDD",
|
|
408
|
-
"unit": {
|
|
409
|
-
"frontend": "vitest",
|
|
410
|
-
"backend": "pytest"
|
|
411
|
-
},
|
|
412
|
-
"integration": "playwright",
|
|
413
|
-
"e2e": "playwright",
|
|
414
|
-
"coverage": {
|
|
415
|
-
"minimum": 80,
|
|
416
|
-
"enforced": false
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
```
|
|
388
|
+
Each story defines its own testing configuration. **Auto-detect tools from project config files** and include the relevant runner in each story:
|
|
420
389
|
|
|
421
390
|
**Detection hints:**
|
|
422
391
|
- Check `package.json` for `vitest`, `jest`, `playwright`, `cypress`
|
|
423
392
|
- Check `pyproject.toml` for `pytest`
|
|
424
393
|
- Check `go.mod` for Go projects (use `go test`)
|
|
425
394
|
|
|
426
|
-
|
|
427
|
-
|-------|--------|-------------|
|
|
428
|
-
| `approach` | `TDD`, `test-after` | Write tests first (TDD) or after implementation |
|
|
429
|
-
| `unit.frontend` | `vitest`, `jest` | Frontend unit test runner (detect from package.json) |
|
|
430
|
-
| `unit.backend` | `pytest`, `go test` | Backend unit test runner (detect from project) |
|
|
431
|
-
| `integration` | `playwright`, `cypress` | Integration test tool |
|
|
432
|
-
| `e2e` | `playwright`, `cypress` | End-to-end test tool |
|
|
433
|
-
| `coverage.minimum` | `0-100` | Minimum coverage percentage |
|
|
434
|
-
| `coverage.enforced` | `true/false` | Fail if coverage not met |
|
|
435
|
-
|
|
436
|
-
### Story-Level Testing Config
|
|
437
|
-
|
|
438
|
-
Specify what tests each story needs:
|
|
395
|
+
**Note:** Coverage thresholds (`minimum`, `enforced`) belong in `.ralph/config.json`, not in the PRD.
|
|
439
396
|
|
|
440
397
|
```json
|
|
441
398
|
"testing": {
|
|
442
399
|
"types": ["unit", "integration"],
|
|
443
400
|
"approach": "TDD",
|
|
401
|
+
"runner": "vitest",
|
|
444
402
|
"files": {
|
|
445
403
|
"unit": ["src/components/Dashboard.test.tsx"],
|
|
446
404
|
"integration": ["tests/integration/dashboard.test.ts"],
|
|
@@ -452,7 +410,8 @@ Specify what tests each story needs:
|
|
|
452
410
|
| Field | Description |
|
|
453
411
|
|-------|-------------|
|
|
454
412
|
| `types` | Required test types: `unit`, `integration`, `e2e` |
|
|
455
|
-
| `approach` |
|
|
413
|
+
| `approach` | TDD or test-after for this story |
|
|
414
|
+
| `runner` | Test runner command (vitest, jest, pytest, go test — detected from project) |
|
|
456
415
|
| `files.unit` | Unit test files to create |
|
|
457
416
|
| `files.integration` | Integration test files to create |
|
|
458
417
|
| `files.e2e` | E2E test files to create |
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Run PRD validation to check story quality, test coverage, and structure.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# PRD Check
|
|
6
|
+
|
|
7
|
+
Run PRD validation on demand to check story quality, test coverage, and structure before starting the autonomous loop.
|
|
8
|
+
|
|
9
|
+
## Instructions
|
|
10
|
+
|
|
11
|
+
When the user runs `/prd-check`, validate their PRD file.
|
|
12
|
+
|
|
13
|
+
### Step 1: Check PRD Exists
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
ls -la .ralph/prd.json 2>/dev/null || echo "NOT_FOUND"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
If no PRD exists, tell the user:
|
|
20
|
+
> No PRD found at `.ralph/prd.json`. Generate one first with `/idea` or `/prd`.
|
|
21
|
+
|
|
22
|
+
**STOP** if no PRD found.
|
|
23
|
+
|
|
24
|
+
### Step 2: Run Validation (dry-run)
|
|
25
|
+
|
|
26
|
+
Run validation without auto-fix so you can present results and let the user decide:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx ralph prd-check --dry-run 2>&1
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Step 3: Present Results
|
|
33
|
+
|
|
34
|
+
Show the validation output to the user. If there are issues, summarize them clearly.
|
|
35
|
+
|
|
36
|
+
If issues were found, ask:
|
|
37
|
+
> "Would you like me to fix these issues in the PRD?"
|
|
38
|
+
|
|
39
|
+
**STOP and wait for user response.**
|
|
40
|
+
|
|
41
|
+
If the user says yes, read `.ralph/prd.json`, fix the issues following PRD best practices (executable testSteps with curl/pytest/playwright, apiContract for backends, testUrl for frontends, security criteria for auth stories, pagination for list endpoints), and write the fixed file back.
|
|
42
|
+
|
|
43
|
+
## Notes
|
|
44
|
+
|
|
45
|
+
- This is the same validation that runs automatically at `ralph run` startup
|
|
46
|
+
- `--dry-run` skips auto-fix so you have control over what changes
|
|
47
|
+
- Custom checks in `.ralph/checks/prd/` are also evaluated
|
|
48
|
+
- Run this before `ralph run` to catch and fix issues interactively
|
package/README.md
CHANGED
|
@@ -75,11 +75,14 @@ npx agentic-loop run # Execute PRDs autonomously
|
|
|
75
75
|
|
|
76
76
|
> **Tip:** Use two terminals. Plan with Claude in one, run Ralph in the other.
|
|
77
77
|
|
|
78
|
+
For the full step-by-step walkthrough, see **[Getting Started](docs/GETTING-STARTED.md)**.
|
|
79
|
+
|
|
78
80
|
---
|
|
79
81
|
|
|
80
82
|
## Docs
|
|
81
83
|
|
|
82
|
-
- **[
|
|
84
|
+
- **[Getting Started](docs/GETTING-STARTED.md)** - Full walkthrough from zero to your first loop run
|
|
85
|
+
- [Beginners Guide](docs/BEGINNERS.md) - New to this? Start here (no coding experience required)
|
|
83
86
|
- [PRD Check](docs/PRD-CHECK.md) - Story validation before coding starts
|
|
84
87
|
- [Code Check](docs/CODE-CHECK.md) - Verification pipeline after each story
|
|
85
88
|
- [Customization](docs/CUSTOMIZATION.md) - Personalization and guardrails
|
package/bin/ralph.sh
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prd-generator.d.ts","sourceRoot":"","sources":["../../src/loopgram/prd-generator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAI1C,UAAU,KAAK;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"prd-generator.d.ts","sourceRoot":"","sources":["../../src/loopgram/prd-generator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAI1C,UAAU,KAAK;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAqCD;;GAEG;AACH,wBAAsB,eAAe,CACnC,YAAY,EAAE,OAAO,EAAE,EACvB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,KAAK,EAAE,CAAA;CAAE,CAAC,CAwChF;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,kBAAkB,EAAE,MAAM,EAC1B,UAAU,EAAE,KAAK,EAAE,GAClB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CA4CnD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG;IACjD,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,IAAI,CAwBP"}
|
|
@@ -15,6 +15,8 @@ Output ONLY valid JSON in this exact format:
|
|
|
15
15
|
"id": "kebab-case-id",
|
|
16
16
|
"title": "Short title",
|
|
17
17
|
"description": "What needs to be built",
|
|
18
|
+
"techStack": {"backend": "detected tech"},
|
|
19
|
+
"constraints": ["relevant rules for this story"],
|
|
18
20
|
"acceptanceCriteria": ["Criterion 1", "Criterion 2"],
|
|
19
21
|
"testSteps": ["npm test", "npm run lint"]
|
|
20
22
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prd-generator.js","sourceRoot":"","sources":["../../src/loopgram/prd-generator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC7D,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAG1C,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"prd-generator.js","sourceRoot":"","sources":["../../src/loopgram/prd-generator.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -21,7 +21,7 @@ if [[ "$FILE_PATH" == *"prd.json"* ]]; then
|
|
|
21
21
|
exit 2 # Exit code 2 = blocking error
|
|
22
22
|
fi
|
|
23
23
|
|
|
24
|
-
# Allow all other prd.json edits (adding mcp,
|
|
24
|
+
# Allow all other prd.json edits (adding mcp, constraints, fixing testSteps, etc.)
|
|
25
25
|
echo '{"continue": true}'
|
|
26
26
|
exit 0
|
|
27
27
|
fi
|
package/ralph/loop.sh
CHANGED
|
@@ -181,9 +181,9 @@ run_loop() {
|
|
|
181
181
|
local consecutive_timeouts=0
|
|
182
182
|
local max_story_retries
|
|
183
183
|
local max_timeouts=5 # Skip after 5 consecutive timeouts (likely too large/complex)
|
|
184
|
-
# Default to
|
|
185
|
-
# Override with config.json: "maxStoryRetries":
|
|
186
|
-
max_story_retries=$(get_config '.maxStoryRetries' "
|
|
184
|
+
# Default to 8 retries - enough for transient issues, catches infinite loops
|
|
185
|
+
# Override with config.json: "maxStoryRetries": 12
|
|
186
|
+
max_story_retries=$(get_config '.maxStoryRetries' "8")
|
|
187
187
|
local total_attempts=0
|
|
188
188
|
local skipped_stories=()
|
|
189
189
|
local start_time
|
|
@@ -265,7 +265,7 @@ run_loop() {
|
|
|
265
265
|
"$RALPH_DIR/prd.json" > "$RALPH_DIR/prd.json.tmp" && mv "$RALPH_DIR/prd.json.tmp" "$RALPH_DIR/prd.json"
|
|
266
266
|
|
|
267
267
|
# Circuit breaker: skip to next story after max retries (prevents infinite loops)
|
|
268
|
-
# Note: This is NOT meant to stop legitimate retrying -
|
|
268
|
+
# Note: This is NOT meant to stop legitimate retrying - 8 attempts is enough.
|
|
269
269
|
# If a story consistently fails after this many tries, it likely needs manual review
|
|
270
270
|
# (vague test steps, missing prerequisites, or fundamentally broken requirements).
|
|
271
271
|
if [[ $consecutive_failures -gt $max_story_retries ]]; then
|
|
@@ -381,23 +381,42 @@ run_loop() {
|
|
|
381
381
|
fi
|
|
382
382
|
|
|
383
383
|
# Run Claude with crash detection and retry logic
|
|
384
|
-
local claude_output_log claude_exit_code max_crash_retries=
|
|
384
|
+
local claude_output_log claude_exit_code max_crash_retries=5 crash_attempt=0
|
|
385
385
|
claude_output_log=$(create_temp_file ".log") || { rm -f "$prompt_file"; return 1; }
|
|
386
386
|
|
|
387
|
+
# Filter to hide ugly CLI crash messages from terminal (still captured in log)
|
|
388
|
+
# Strips: "This error originated...", "Error: No messages", stack traces
|
|
389
|
+
_filter_cli_noise() {
|
|
390
|
+
grep -v -E \
|
|
391
|
+
-e "This error originated either by throwing" \
|
|
392
|
+
-e "a catch block, or by rejecting a promise" \
|
|
393
|
+
-e "The promise rejected with the reason:" \
|
|
394
|
+
-e "Error: No messages returned" \
|
|
395
|
+
-e "at [A-Za-z0-9_]+ \(/\\\$bunfs/" \
|
|
396
|
+
-e "at processTicksAndRejections" \
|
|
397
|
+
-e "unhandled.*promise.*rejection" \
|
|
398
|
+
|| true # Don't fail if no lines pass filter
|
|
399
|
+
}
|
|
400
|
+
|
|
387
401
|
while [[ $crash_attempt -lt $max_crash_retries ]]; do
|
|
388
402
|
claude_exit_code=0
|
|
389
403
|
# Use pipefail to capture Claude's exit code, not tee's
|
|
390
404
|
set -o pipefail
|
|
391
|
-
|
|
405
|
+
# Capture full output to log, show filtered output to terminal
|
|
406
|
+
cat "$prompt_file" | run_with_timeout "$timeout_seconds" claude "${claude_args[@]}" 2>&1 | tee "$claude_output_log" | _filter_cli_noise || claude_exit_code=$?
|
|
392
407
|
set +o pipefail
|
|
393
408
|
|
|
394
|
-
# Check for recoverable CLI crashes
|
|
409
|
+
# Check for recoverable CLI crashes (transient API failures)
|
|
395
410
|
if grep -qE "(No messages returned|unhandled.*promise.*rejection)" "$claude_output_log" 2>/dev/null; then
|
|
396
411
|
((crash_attempt++))
|
|
397
|
-
|
|
398
|
-
|
|
412
|
+
# Exponential backoff: 5s, 10s, 20s, 40s, 80s
|
|
413
|
+
local backoff_seconds=$((5 * (2 ** (crash_attempt - 1))))
|
|
414
|
+
echo "" # Clean line after any partial output
|
|
415
|
+
print_warning "API returned empty response - retrying in ${backoff_seconds}s (attempt $crash_attempt/$max_crash_retries)"
|
|
416
|
+
print_info "This is usually a transient issue with the Claude API"
|
|
417
|
+
log_progress "$story" "CLI_CRASH" "API empty response, retry $crash_attempt (backoff ${backoff_seconds}s)"
|
|
399
418
|
session_started=false # Reset session on crash
|
|
400
|
-
sleep
|
|
419
|
+
sleep "$backoff_seconds"
|
|
401
420
|
continue
|
|
402
421
|
fi
|
|
403
422
|
|
|
@@ -408,12 +427,13 @@ run_loop() {
|
|
|
408
427
|
rm -f "$claude_output_log"
|
|
409
428
|
|
|
410
429
|
if [[ $crash_attempt -ge $max_crash_retries ]]; then
|
|
411
|
-
print_error "Claude CLI crashed $max_crash_retries times - stopping loop"
|
|
412
|
-
log_progress "$story" "CLI_CRASH" "Gave up after $max_crash_retries crashes"
|
|
413
|
-
rm -f "$prompt_file"
|
|
414
430
|
echo ""
|
|
415
|
-
|
|
416
|
-
|
|
431
|
+
print_warning "Claude API unavailable after $max_crash_retries attempts"
|
|
432
|
+
print_info "Waiting 60s before retrying... (Ctrl+C to stop, then 'npx agentic-loop run' to restart)"
|
|
433
|
+
log_progress "$story" "CLI_CRASH" "API unavailable, waiting 60s before next iteration"
|
|
434
|
+
rm -f "$prompt_file"
|
|
435
|
+
sleep 60 # Longer cooldown before retrying
|
|
436
|
+
continue # Continue main loop instead of stopping
|
|
417
437
|
fi
|
|
418
438
|
|
|
419
439
|
if [[ $claude_exit_code -ne 0 ]]; then
|
|
@@ -683,6 +703,8 @@ build_prompt() {
|
|
|
683
703
|
echo "## Current Story: $story"
|
|
684
704
|
echo ""
|
|
685
705
|
echo "Read full story details from \`.ralph/prd.json\` - it contains everything you need:"
|
|
706
|
+
echo "- \`story.techStack\` - technologies relevant to this story"
|
|
707
|
+
echo "- \`story.constraints\` - rules for this story"
|
|
686
708
|
echo "- \`story.files\` - which files to create/modify"
|
|
687
709
|
echo "- \`story.acceptanceCriteria\` - what must be true"
|
|
688
710
|
echo "- \`story.testSteps\` - verification commands"
|
|
@@ -691,8 +713,6 @@ build_prompt() {
|
|
|
691
713
|
echo "- \`story.skills\` - relevant skills to reference"
|
|
692
714
|
echo ""
|
|
693
715
|
echo "Also read:"
|
|
694
|
-
echo "- \`prd.techStack\` - technologies in use"
|
|
695
|
-
echo "- \`prd.globalConstraints\` - rules for all stories"
|
|
696
716
|
echo "- \`.ralph/config.json\` - URLs and directories"
|
|
697
717
|
|
|
698
718
|
# Failure context if retrying
|