agentic-loop 3.14.2 → 3.16.2
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/prd/SKILL.md +43 -86
- package/.claude/skills/prd-check/SKILL.md +48 -0
- package/README.md +7 -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 +171 -3
- package/ralph/prd.sh +9 -32
- package/ralph/setup.sh +19 -0
- package/templates/checks/prd/check-example.sh +25 -0
- package/templates/prd-example.json +45 -26
- package/.claude/commands/prd.md +0 -770
|
@@ -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,11 +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
|
-
-
|
|
159
|
-
-
|
|
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"]`?
|
|
160
165
|
|
|
161
166
|
**Fix any issues you find:**
|
|
162
167
|
|
|
@@ -170,6 +175,8 @@ Does acceptanceCriteria include:
|
|
|
170
175
|
| Frontend missing contextFiles | Add idea file + styleguide paths |
|
|
171
176
|
| Frontend missing testUrl | Add URL from config |
|
|
172
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 |
|
|
173
180
|
|
|
174
181
|
### Step 7: Reorder if Needed
|
|
175
182
|
|
|
@@ -192,7 +199,7 @@ open -a TextEdit .ralph/prd.json
|
|
|
192
199
|
Say: "I've {created|updated} the PRD with {N} stories and opened it in TextEdit.
|
|
193
200
|
|
|
194
201
|
Review the PRD and let me know:
|
|
195
|
-
- **'approved'** - Ready
|
|
202
|
+
- **'approved'** - Ready to run in your other terminal
|
|
196
203
|
- **'edit [changes]'** - Tell me what to change
|
|
197
204
|
- Or edit the JSON directly and say **'done'**"
|
|
198
205
|
|
|
@@ -207,9 +214,9 @@ Once approved, say:
|
|
|
207
214
|
**Source:** `{idea-file-path}`
|
|
208
215
|
**PRD:** `.ralph/prd.json` ({N} stories)
|
|
209
216
|
|
|
210
|
-
To start autonomous development:
|
|
217
|
+
To start autonomous development, open another terminal and run:
|
|
211
218
|
```bash
|
|
212
|
-
|
|
219
|
+
npx agentic-loop run
|
|
213
220
|
```
|
|
214
221
|
|
|
215
222
|
Ralph will work through each story, running tests and committing as it goes."
|
|
@@ -231,45 +238,6 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
231
238
|
"status": "pending"
|
|
232
239
|
},
|
|
233
240
|
|
|
234
|
-
"originalContext": "docs/ideas/{feature-name}.md",
|
|
235
|
-
|
|
236
|
-
"techStack": {
|
|
237
|
-
"frontend": "{detected from package.json}",
|
|
238
|
-
"backend": "{detected from pyproject.toml/go.mod}",
|
|
239
|
-
"database": "{detected or asked}"
|
|
240
|
-
},
|
|
241
|
-
|
|
242
|
-
"testing": {
|
|
243
|
-
"approach": "TDD",
|
|
244
|
-
"unit": {
|
|
245
|
-
"frontend": "{vitest|jest - detected from package.json}",
|
|
246
|
-
"backend": "{pytest|go test - detected from project}"
|
|
247
|
-
},
|
|
248
|
-
"integration": "{playwright|cypress}",
|
|
249
|
-
"e2e": "{playwright|cypress}",
|
|
250
|
-
"coverage": {
|
|
251
|
-
"minimum": 80,
|
|
252
|
-
"enforced": false
|
|
253
|
-
}
|
|
254
|
-
},
|
|
255
|
-
|
|
256
|
-
"architecture": {
|
|
257
|
-
"frontend": "src/components",
|
|
258
|
-
"backend": "src/api",
|
|
259
|
-
"doNotCreate": ["new database tables without migration"]
|
|
260
|
-
},
|
|
261
|
-
|
|
262
|
-
"globalConstraints": [
|
|
263
|
-
"All API calls must have error handling",
|
|
264
|
-
"No console.log in production code",
|
|
265
|
-
"Use existing UI components from src/components/ui"
|
|
266
|
-
],
|
|
267
|
-
|
|
268
|
-
"testUsers": {
|
|
269
|
-
"admin": {"email": "admin@test.com", "password": "test123"},
|
|
270
|
-
"user": {"email": "user@test.com", "password": "test123"}
|
|
271
|
-
},
|
|
272
|
-
|
|
273
241
|
"metadata": {
|
|
274
242
|
"createdAt": "ISO timestamp",
|
|
275
243
|
"estimatedStories": 5,
|
|
@@ -284,6 +252,17 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
284
252
|
"priority": 1,
|
|
285
253
|
"passes": false,
|
|
286
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
|
+
|
|
287
266
|
"files": {
|
|
288
267
|
"create": ["paths to new files"],
|
|
289
268
|
"modify": ["paths to existing files"],
|
|
@@ -301,6 +280,7 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
301
280
|
"testing": {
|
|
302
281
|
"types": ["unit", "integration"],
|
|
303
282
|
"approach": "TDD",
|
|
283
|
+
"runner": "vitest|jest|pytest|go test",
|
|
304
284
|
"files": {
|
|
305
285
|
"unit": ["src/components/Dashboard.test.tsx"],
|
|
306
286
|
"integration": ["tests/integration/dashboard.test.ts"],
|
|
@@ -332,6 +312,10 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
332
312
|
"response": {"field": "type"}
|
|
333
313
|
},
|
|
334
314
|
|
|
315
|
+
"testUsers": {
|
|
316
|
+
"admin": {"email": "admin@test.com", "password": "test123"}
|
|
317
|
+
},
|
|
318
|
+
|
|
335
319
|
"prerequisites": [
|
|
336
320
|
"Backend server running",
|
|
337
321
|
"Database seeded"
|
|
@@ -360,19 +344,15 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
360
344
|
|
|
361
345
|
| Field | Required | Description |
|
|
362
346
|
|-------|----------|-------------|
|
|
363
|
-
| `feature` | Yes | Feature name, branch, status |
|
|
364
|
-
| `
|
|
365
|
-
| `techStack` | No | Technologies in use (auto-detect from project) |
|
|
366
|
-
| `testing` | Yes | Testing strategy, tools, coverage requirements |
|
|
367
|
-
| `architecture` | No | Directory structure, patterns, constraints |
|
|
368
|
-
| `globalConstraints` | No | Rules that apply to ALL stories |
|
|
369
|
-
| `testUsers` | No | Test accounts for auth flows |
|
|
370
|
-
| `metadata` | Yes | Created date, complexity estimate |
|
|
347
|
+
| `feature` | Yes | Feature name, ideaFile, branch, status |
|
|
348
|
+
| `metadata` | Yes | Created date, estimated stories, complexity |
|
|
371
349
|
|
|
372
350
|
**Note:** URLs come from `.ralph/config.json`, not the PRD. Use `{config.urls.backend}` in testSteps.
|
|
373
351
|
|
|
374
352
|
### Story-Level Fields
|
|
375
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
|
+
|
|
376
356
|
| Field | Required | Description |
|
|
377
357
|
|-------|----------|-------------|
|
|
378
358
|
| `id` | Yes | Unique ID (TASK-001, TASK-002, etc.) |
|
|
@@ -380,16 +360,19 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
380
360
|
| `title` | Yes | Short description |
|
|
381
361
|
| `priority` | No | Order of importance (1 = highest) |
|
|
382
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 |
|
|
383
365
|
| `files` | Yes | create, modify, reuse arrays |
|
|
384
366
|
| `acceptanceCriteria` | Yes | What must be true when done |
|
|
385
367
|
| `errorHandling` | Yes | How to handle failures |
|
|
386
|
-
| `testing` | Yes | Test types, approach, and files for this story |
|
|
368
|
+
| `testing` | Yes | Test types, approach, runner, and files for this story |
|
|
387
369
|
| `testSteps` | Yes | Executable shell commands |
|
|
388
370
|
| `testUrl` | Frontend | URL to verify the feature |
|
|
389
371
|
| `mcp` | Frontend | MCP tools for verification |
|
|
390
372
|
| `contextFiles` | No | Files Claude should read (idea files, styleguides) |
|
|
391
373
|
| `skills` | No | Relevant skills with usage hints |
|
|
392
374
|
| `apiContract` | Backend | Expected request/response format |
|
|
375
|
+
| `testUsers` | No | Test accounts (only for auth stories that need them) |
|
|
393
376
|
| `prerequisites` | No | What must be running/ready |
|
|
394
377
|
| `notes` | No | Human guidance for Claude |
|
|
395
378
|
| `scale` | No | small, medium, large |
|
|
@@ -400,49 +383,22 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
400
383
|
|
|
401
384
|
## Testing Strategy
|
|
402
385
|
|
|
403
|
-
###
|
|
404
|
-
|
|
405
|
-
Define the overall testing strategy for the feature. **Auto-detect tools from project config files:**
|
|
386
|
+
### Story-Level Testing Config
|
|
406
387
|
|
|
407
|
-
|
|
408
|
-
"testing": {
|
|
409
|
-
"approach": "TDD",
|
|
410
|
-
"unit": {
|
|
411
|
-
"frontend": "vitest",
|
|
412
|
-
"backend": "pytest"
|
|
413
|
-
},
|
|
414
|
-
"integration": "playwright",
|
|
415
|
-
"e2e": "playwright",
|
|
416
|
-
"coverage": {
|
|
417
|
-
"minimum": 80,
|
|
418
|
-
"enforced": false
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
```
|
|
388
|
+
Each story defines its own testing configuration. **Auto-detect tools from project config files** and include the relevant runner in each story:
|
|
422
389
|
|
|
423
390
|
**Detection hints:**
|
|
424
391
|
- Check `package.json` for `vitest`, `jest`, `playwright`, `cypress`
|
|
425
392
|
- Check `pyproject.toml` for `pytest`
|
|
426
393
|
- Check `go.mod` for Go projects (use `go test`)
|
|
427
394
|
|
|
428
|
-
|
|
429
|
-
|-------|--------|-------------|
|
|
430
|
-
| `approach` | `TDD`, `test-after` | Write tests first (TDD) or after implementation |
|
|
431
|
-
| `unit.frontend` | `vitest`, `jest` | Frontend unit test runner (detect from package.json) |
|
|
432
|
-
| `unit.backend` | `pytest`, `go test` | Backend unit test runner (detect from project) |
|
|
433
|
-
| `integration` | `playwright`, `cypress` | Integration test tool |
|
|
434
|
-
| `e2e` | `playwright`, `cypress` | End-to-end test tool |
|
|
435
|
-
| `coverage.minimum` | `0-100` | Minimum coverage percentage |
|
|
436
|
-
| `coverage.enforced` | `true/false` | Fail if coverage not met |
|
|
437
|
-
|
|
438
|
-
### Story-Level Testing Config
|
|
439
|
-
|
|
440
|
-
Specify what tests each story needs:
|
|
395
|
+
**Note:** Coverage thresholds (`minimum`, `enforced`) belong in `.ralph/config.json`, not in the PRD.
|
|
441
396
|
|
|
442
397
|
```json
|
|
443
398
|
"testing": {
|
|
444
399
|
"types": ["unit", "integration"],
|
|
445
400
|
"approach": "TDD",
|
|
401
|
+
"runner": "vitest",
|
|
446
402
|
"files": {
|
|
447
403
|
"unit": ["src/components/Dashboard.test.tsx"],
|
|
448
404
|
"integration": ["tests/integration/dashboard.test.ts"],
|
|
@@ -454,7 +410,8 @@ Specify what tests each story needs:
|
|
|
454
410
|
| Field | Description |
|
|
455
411
|
|-------|-------------|
|
|
456
412
|
| `types` | Required test types: `unit`, `integration`, `e2e` |
|
|
457
|
-
| `approach` |
|
|
413
|
+
| `approach` | TDD or test-after for this story |
|
|
414
|
+
| `runner` | Test runner command (vitest, jest, pytest, go test — detected from project) |
|
|
458
415
|
| `files.unit` | Unit test files to create |
|
|
459
416
|
| `files.integration` | Integration test files to create |
|
|
460
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
|
@@ -77,9 +77,15 @@ npx agentic-loop run # Execute PRDs autonomously
|
|
|
77
77
|
|
|
78
78
|
---
|
|
79
79
|
|
|
80
|
+
> [!NOTE]
|
|
81
|
+
> **New here?** Follow the **[Getting Started Guide](docs/GETTING-STARTED.md)** for a full step-by-step walkthrough — from install to your first autonomous loop run.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
80
85
|
## Docs
|
|
81
86
|
|
|
82
|
-
- **[
|
|
87
|
+
- **[Getting Started](docs/GETTING-STARTED.md)** - Full walkthrough from zero to your first loop run
|
|
88
|
+
- [Beginners Guide](docs/BEGINNERS.md) - New to this? Start here (no coding experience required)
|
|
83
89
|
- [PRD Check](docs/PRD-CHECK.md) - Story validation before coding starts
|
|
84
90
|
- [Code Check](docs/CODE-CHECK.md) - Verification pipeline after each story
|
|
85
91
|
- [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
|