agentic-loop 3.4.7 → 3.5.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/commands/idea.md +42 -252
- package/.claude/commands/prd.md +474 -71
- package/README.md +4 -1
- package/package.json +1 -1
- package/ralph/ci.sh +193 -34
- package/ralph/hooks/protect-prd.sh +12 -20
- package/ralph/loop.sh +51 -194
- package/ralph/prd.sh +5 -0
- package/ralph/setup.sh +298 -16
- package/ralph/verify/tests.sh +58 -3
- package/templates/PROMPT.md +143 -191
- package/templates/config/fullstack.json +1 -1
- package/templates/examples/CLAUDE-fullstack.md +3 -2
- package/templates/examples/CLAUDE-node.md +2 -1
- package/templates/examples/CLAUDE-react.md +2 -1
- package/templates/github/workflows/nightly.yml +9 -74
- package/templates/github/workflows/pr.yml +7 -31
- package/templates/signs.json +7 -0
package/.claude/commands/prd.md
CHANGED
|
@@ -57,12 +57,14 @@ I'll now split this into {N} stories for Ralph. Continue?"
|
|
|
57
57
|
If working from a direct description, first explore the codebase briefly:
|
|
58
58
|
```bash
|
|
59
59
|
ls -la src/ app/ 2>/dev/null | head -20
|
|
60
|
+
cat package.json 2>/dev/null | jq '{name, dependencies}' || true
|
|
61
|
+
cat pyproject.toml 2>/dev/null | head -20 || true
|
|
60
62
|
```
|
|
61
63
|
|
|
62
64
|
Then say: "I'll create a PRD for: **{description}**
|
|
63
65
|
|
|
64
66
|
Before I generate stories, quick questions:
|
|
65
|
-
1. **Type:** Frontend
|
|
67
|
+
1. **Type:** Frontend or backend?
|
|
66
68
|
2. **Scale:** Any specific limits (users, items, rate limits)?
|
|
67
69
|
3. **Anything else** I should know?
|
|
68
70
|
|
|
@@ -77,7 +79,7 @@ cat .ralph/prd.json 2>/dev/null
|
|
|
77
79
|
```
|
|
78
80
|
|
|
79
81
|
If it exists, read it and say:
|
|
80
|
-
"
|
|
82
|
+
"`.ralph/prd.json` exists with {N} stories ({M} completed, {P} pending).
|
|
81
83
|
|
|
82
84
|
Options:
|
|
83
85
|
- **'append'** - Add new stories to the existing PRD (recommended)
|
|
@@ -141,7 +143,7 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
141
143
|
|
|
142
144
|
---
|
|
143
145
|
|
|
144
|
-
## PRD JSON
|
|
146
|
+
## Complete PRD JSON Schema
|
|
145
147
|
|
|
146
148
|
```json
|
|
147
149
|
{
|
|
@@ -151,16 +153,58 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
151
153
|
"branch": "feature/{feature-name}",
|
|
152
154
|
"status": "pending"
|
|
153
155
|
},
|
|
156
|
+
|
|
157
|
+
"originalContext": "docs/ideas/{feature-name}.md",
|
|
158
|
+
|
|
159
|
+
"techStack": {
|
|
160
|
+
"frontend": "{detected from package.json}",
|
|
161
|
+
"backend": "{detected from pyproject.toml/go.mod}",
|
|
162
|
+
"database": "{detected or asked}"
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
"testing": {
|
|
166
|
+
"approach": "TDD",
|
|
167
|
+
"unit": {
|
|
168
|
+
"frontend": "{vitest|jest - detected from package.json}",
|
|
169
|
+
"backend": "{pytest|go test - detected from project}"
|
|
170
|
+
},
|
|
171
|
+
"integration": "{playwright|cypress}",
|
|
172
|
+
"e2e": "{playwright|cypress}",
|
|
173
|
+
"coverage": {
|
|
174
|
+
"minimum": 80,
|
|
175
|
+
"enforced": false
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
"architecture": {
|
|
180
|
+
"frontend": "src/components",
|
|
181
|
+
"backend": "src/api",
|
|
182
|
+
"doNotCreate": ["new database tables without migration"]
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
"globalConstraints": [
|
|
186
|
+
"All API calls must have error handling",
|
|
187
|
+
"No console.log in production code",
|
|
188
|
+
"Use existing UI components from src/components/ui"
|
|
189
|
+
],
|
|
190
|
+
|
|
191
|
+
"testUsers": {
|
|
192
|
+
"admin": {"email": "admin@test.com", "password": "test123"},
|
|
193
|
+
"user": {"email": "user@test.com", "password": "test123"}
|
|
194
|
+
},
|
|
195
|
+
|
|
154
196
|
"metadata": {
|
|
155
197
|
"createdAt": "ISO timestamp",
|
|
156
198
|
"estimatedStories": 5,
|
|
157
199
|
"complexity": "low|medium|high"
|
|
158
200
|
},
|
|
201
|
+
|
|
159
202
|
"stories": [
|
|
160
203
|
{
|
|
161
204
|
"id": "TASK-001",
|
|
162
205
|
"type": "frontend|backend",
|
|
163
206
|
"title": "Short description",
|
|
207
|
+
"priority": 1,
|
|
164
208
|
"passes": false,
|
|
165
209
|
|
|
166
210
|
"files": {
|
|
@@ -177,110 +221,469 @@ Ralph will work through each story, running tests and committing as it goes."
|
|
|
177
221
|
"What happens when things fail"
|
|
178
222
|
],
|
|
179
223
|
|
|
224
|
+
"testing": {
|
|
225
|
+
"types": ["unit", "integration"],
|
|
226
|
+
"approach": "TDD",
|
|
227
|
+
"files": {
|
|
228
|
+
"unit": ["src/components/Dashboard.test.tsx"],
|
|
229
|
+
"integration": ["tests/integration/dashboard.test.ts"],
|
|
230
|
+
"e2e": ["tests/e2e/dashboard.spec.ts"]
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
|
|
180
234
|
"testSteps": [
|
|
181
|
-
"
|
|
235
|
+
"Executable shell commands - see examples below"
|
|
182
236
|
],
|
|
183
237
|
|
|
184
|
-
"
|
|
238
|
+
"testUrl": "{config.urls.frontend}/feature-page",
|
|
239
|
+
|
|
240
|
+
"mcp": ["playwright", "devtools"],
|
|
241
|
+
|
|
242
|
+
"contextFiles": [
|
|
243
|
+
"docs/ideas/feature.md",
|
|
244
|
+
"src/styles/styleguide.html"
|
|
245
|
+
],
|
|
246
|
+
|
|
247
|
+
"skills": [
|
|
248
|
+
{"name": "styleguide", "usage": "Reference for UI components"},
|
|
249
|
+
{"name": "vibe-check", "usage": "Run after implementation"}
|
|
250
|
+
],
|
|
185
251
|
|
|
186
|
-
"
|
|
252
|
+
"apiContract": {
|
|
253
|
+
"endpoint": "GET /api/resource",
|
|
254
|
+
"response": {"field": "type"}
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
"prerequisites": [
|
|
258
|
+
"Backend server running",
|
|
259
|
+
"Database seeded"
|
|
260
|
+
],
|
|
261
|
+
|
|
262
|
+
"notes": "Human guidance - preferences, warnings, tips",
|
|
263
|
+
|
|
264
|
+
"scale": "small|medium|large",
|
|
265
|
+
|
|
266
|
+
"architecture": {
|
|
267
|
+
"pattern": "React Query for data fetching",
|
|
268
|
+
"constraints": ["No Redux"]
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
"dependsOn": []
|
|
187
272
|
}
|
|
188
273
|
]
|
|
189
274
|
}
|
|
190
275
|
```
|
|
191
276
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Field Reference
|
|
280
|
+
|
|
281
|
+
### PRD-Level Fields
|
|
282
|
+
|
|
283
|
+
| Field | Required | Description |
|
|
284
|
+
|-------|----------|-------------|
|
|
285
|
+
| `feature` | Yes | Feature name, branch, status |
|
|
286
|
+
| `originalContext` | Yes | Path to idea file (Claude reads this for full context) |
|
|
287
|
+
| `techStack` | No | Technologies in use (auto-detect from project) |
|
|
288
|
+
| `testing` | Yes | Testing strategy, tools, coverage requirements |
|
|
289
|
+
| `architecture` | No | Directory structure, patterns, constraints |
|
|
290
|
+
| `globalConstraints` | No | Rules that apply to ALL stories |
|
|
291
|
+
| `testUsers` | No | Test accounts for auth flows |
|
|
292
|
+
| `metadata` | Yes | Created date, complexity estimate |
|
|
293
|
+
|
|
294
|
+
**Note:** URLs come from `.ralph/config.json`, not the PRD. Use `{config.urls.backend}` in testSteps.
|
|
295
|
+
|
|
296
|
+
### Story-Level Fields
|
|
297
|
+
|
|
298
|
+
| Field | Required | Description |
|
|
299
|
+
|-------|----------|-------------|
|
|
300
|
+
| `id` | Yes | Unique ID (TASK-001, TASK-002, etc.) |
|
|
301
|
+
| `type` | Yes | frontend or backend (keep stories atomic) |
|
|
302
|
+
| `title` | Yes | Short description |
|
|
303
|
+
| `priority` | No | Order of importance (1 = highest) |
|
|
304
|
+
| `passes` | Yes | Always starts as `false` |
|
|
305
|
+
| `files` | Yes | create, modify, reuse arrays |
|
|
306
|
+
| `acceptanceCriteria` | Yes | What must be true when done |
|
|
307
|
+
| `errorHandling` | Yes | How to handle failures |
|
|
308
|
+
| `testing` | Yes | Test types, approach, and files for this story |
|
|
309
|
+
| `testSteps` | Yes | Executable shell commands |
|
|
310
|
+
| `testUrl` | Frontend | URL to verify the feature |
|
|
311
|
+
| `mcp` | Frontend | MCP tools for verification |
|
|
312
|
+
| `contextFiles` | No | Files Claude should read (idea files, styleguides) |
|
|
313
|
+
| `skills` | No | Relevant skills with usage hints |
|
|
314
|
+
| `apiContract` | Backend | Expected request/response format |
|
|
315
|
+
| `prerequisites` | No | What must be running/ready |
|
|
316
|
+
| `notes` | No | Human guidance for Claude |
|
|
317
|
+
| `scale` | No | small, medium, large |
|
|
318
|
+
| `architecture` | No | Story-specific patterns/constraints |
|
|
319
|
+
| `dependsOn` | No | Story IDs that must complete first |
|
|
197
320
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Testing Strategy
|
|
324
|
+
|
|
325
|
+
### PRD-Level Testing Config
|
|
326
|
+
|
|
327
|
+
Define the overall testing strategy for the feature. **Auto-detect tools from project config files:**
|
|
328
|
+
|
|
329
|
+
```json
|
|
330
|
+
"testing": {
|
|
331
|
+
"approach": "TDD",
|
|
332
|
+
"unit": {
|
|
333
|
+
"frontend": "vitest",
|
|
334
|
+
"backend": "pytest"
|
|
335
|
+
},
|
|
336
|
+
"integration": "playwright",
|
|
337
|
+
"e2e": "playwright",
|
|
338
|
+
"coverage": {
|
|
339
|
+
"minimum": 80,
|
|
340
|
+
"enforced": false
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
```
|
|
204
344
|
|
|
205
|
-
|
|
206
|
-
-
|
|
207
|
-
-
|
|
208
|
-
-
|
|
345
|
+
**Detection hints:**
|
|
346
|
+
- Check `package.json` for `vitest`, `jest`, `playwright`, `cypress`
|
|
347
|
+
- Check `pyproject.toml` for `pytest`
|
|
348
|
+
- Check `go.mod` for Go projects (use `go test`)
|
|
209
349
|
|
|
210
|
-
|
|
350
|
+
| Field | Values | Description |
|
|
351
|
+
|-------|--------|-------------|
|
|
352
|
+
| `approach` | `TDD`, `test-after` | Write tests first (TDD) or after implementation |
|
|
353
|
+
| `unit.frontend` | `vitest`, `jest` | Frontend unit test runner (detect from package.json) |
|
|
354
|
+
| `unit.backend` | `pytest`, `go test` | Backend unit test runner (detect from project) |
|
|
355
|
+
| `integration` | `playwright`, `cypress` | Integration test tool |
|
|
356
|
+
| `e2e` | `playwright`, `cypress` | End-to-end test tool |
|
|
357
|
+
| `coverage.minimum` | `0-100` | Minimum coverage percentage |
|
|
358
|
+
| `coverage.enforced` | `true/false` | Fail if coverage not met |
|
|
211
359
|
|
|
212
|
-
###
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
360
|
+
### Story-Level Testing Config
|
|
361
|
+
|
|
362
|
+
Specify what tests each story needs:
|
|
363
|
+
|
|
364
|
+
```json
|
|
365
|
+
"testing": {
|
|
366
|
+
"types": ["unit", "integration"],
|
|
367
|
+
"approach": "TDD",
|
|
368
|
+
"files": {
|
|
369
|
+
"unit": ["src/components/Dashboard.test.tsx"],
|
|
370
|
+
"integration": ["tests/integration/dashboard.test.ts"],
|
|
371
|
+
"e2e": ["tests/e2e/dashboard.spec.ts"]
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
| Field | Description |
|
|
377
|
+
|-------|-------------|
|
|
378
|
+
| `types` | Required test types: `unit`, `integration`, `e2e` |
|
|
379
|
+
| `approach` | Override PRD-level approach for this story |
|
|
380
|
+
| `files.unit` | Unit test files to create |
|
|
381
|
+
| `files.integration` | Integration test files to create |
|
|
382
|
+
| `files.e2e` | E2E test files to create |
|
|
383
|
+
|
|
384
|
+
### Test Types
|
|
385
|
+
|
|
386
|
+
| Type | What it Tests | When to Use |
|
|
387
|
+
|------|---------------|-------------|
|
|
388
|
+
| **Unit** | Individual functions, components in isolation | Always - every new file needs unit tests |
|
|
389
|
+
| **Integration** | How pieces work together (API + DB, Component + Hook) | When story involves multiple modules |
|
|
390
|
+
| **E2E** | Full user flows in browser | User-facing features with interactions |
|
|
391
|
+
|
|
392
|
+
### TDD Workflow
|
|
393
|
+
|
|
394
|
+
When `approach: "TDD"`:
|
|
395
|
+
|
|
396
|
+
1. **Write failing test first** - Define expected behavior
|
|
397
|
+
2. **Implement minimum code** - Make the test pass
|
|
398
|
+
3. **Refactor** - Clean up while tests stay green
|
|
399
|
+
4. **Repeat** - Next acceptance criterion
|
|
400
|
+
|
|
401
|
+
Example for a Dashboard component:
|
|
402
|
+
```
|
|
403
|
+
1. Write test: "renders user name in header"
|
|
404
|
+
2. Run test → FAIL (component doesn't exist)
|
|
405
|
+
3. Create Dashboard.tsx with user name
|
|
406
|
+
4. Run test → PASS
|
|
407
|
+
5. Write test: "shows loading state"
|
|
408
|
+
6. Run test → FAIL
|
|
409
|
+
7. Add loading state
|
|
410
|
+
8. Run test → PASS
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Testing Anti-Patterns (AVOID THESE)
|
|
414
|
+
|
|
415
|
+
**The "grep for code" trap:**
|
|
416
|
+
```json
|
|
417
|
+
// ❌ BAD - verifies code exists, not that it works
|
|
418
|
+
"testSteps": [
|
|
419
|
+
"grep -q 'astream_events' app/domains/chat/agent/graph.py"
|
|
420
|
+
]
|
|
421
|
+
|
|
422
|
+
// ✅ GOOD - verifies actual behavior
|
|
423
|
+
"testSteps": [
|
|
424
|
+
"curl -N {config.urls.backend}/chat -d '{\"message\":\"test\"}' | grep -q 'progress'"
|
|
425
|
+
]
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
**Missing integration points:**
|
|
429
|
+
```json
|
|
430
|
+
// ❌ BAD - creates function but doesn't verify callers use it
|
|
431
|
+
{
|
|
432
|
+
"files": {"modify": ["graph.py"]},
|
|
433
|
+
"acceptanceCriteria": ["Create stream_agent function"]
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// ✅ GOOD - verifies the full chain
|
|
437
|
+
{
|
|
438
|
+
"files": {"modify": ["graph.py", "service.py"]},
|
|
439
|
+
"acceptanceCriteria": [
|
|
440
|
+
"service.py calls stream_agent() (not run_agent)",
|
|
441
|
+
"POST /chat returns progress SSE events"
|
|
442
|
+
]
|
|
443
|
+
}
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### Removing/Modifying UI - Update Tests!
|
|
447
|
+
|
|
448
|
+
**CRITICAL: When a story removes or modifies UI elements, it MUST update related tests.**
|
|
449
|
+
|
|
450
|
+
Stories that remove UI must include:
|
|
451
|
+
```json
|
|
452
|
+
{
|
|
453
|
+
"files": {
|
|
454
|
+
"modify": ["src/components/Dashboard.tsx"],
|
|
455
|
+
"delete": ["src/components/SelectionPanel.tsx"]
|
|
456
|
+
},
|
|
457
|
+
"acceptanceCriteria": [
|
|
458
|
+
"Selection panel removed from dashboard",
|
|
459
|
+
"All tests referencing 'Auto-select' button updated or removed"
|
|
460
|
+
],
|
|
461
|
+
"testSteps": [
|
|
462
|
+
"grep -r 'Auto-select' tests/ && exit 1 || echo 'No stale test references'",
|
|
463
|
+
"npx playwright test tests/e2e/dashboard.spec.ts"
|
|
464
|
+
]
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
The `grep ... && exit 1` pattern ensures the story fails if stale test references exist.
|
|
469
|
+
|
|
470
|
+
### Acceptance Criteria Rules
|
|
471
|
+
|
|
472
|
+
1. **Behavior over implementation** - Describe what the user/API sees, not what code exists
|
|
473
|
+
2. **Verifiable** - Each criterion must be testable with a curl, pytest, or playwright
|
|
474
|
+
3. **Include callers** - If adding a new function, verify callers use it
|
|
475
|
+
4. **Update tests** - If removing UI, verify no tests reference removed elements
|
|
476
|
+
|
|
477
|
+
```
|
|
478
|
+
❌ "Use astream_events() for progress"
|
|
479
|
+
✅ "POST /chat streams progress events before final response"
|
|
480
|
+
|
|
481
|
+
❌ "Create stream_agent function"
|
|
482
|
+
✅ "service.py send_message_stream() calls stream_agent()"
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### Integration Test Requirements
|
|
486
|
+
|
|
487
|
+
Backend stories that modify internal functions MUST have integration tests that verify the API behavior:
|
|
488
|
+
|
|
489
|
+
```python
|
|
490
|
+
# ✅ GOOD - tests actual API behavior
|
|
491
|
+
async def test_send_message_streams_progress_events():
|
|
492
|
+
"""Verify the API actually streams progress events."""
|
|
493
|
+
async with client.stream("POST", f"/chat/{conv_id}/messages",
|
|
494
|
+
json={"content": "test"}) as response:
|
|
495
|
+
events = [e async for e in parse_sse(response)]
|
|
496
|
+
progress_events = [e for e in events if e["event_type"] == "progress"]
|
|
497
|
+
assert len(progress_events) > 0, "No progress events streamed"
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
### Example Stories by Type
|
|
501
|
+
|
|
502
|
+
**Frontend story:**
|
|
503
|
+
```json
|
|
504
|
+
"testing": {
|
|
505
|
+
"types": ["unit", "e2e"],
|
|
506
|
+
"approach": "TDD",
|
|
507
|
+
"files": {
|
|
508
|
+
"unit": ["src/components/Dashboard.test.tsx"],
|
|
509
|
+
"e2e": ["tests/e2e/dashboard.spec.ts"]
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
**Backend API story:**
|
|
515
|
+
```json
|
|
516
|
+
"testing": {
|
|
517
|
+
"types": ["unit", "integration"],
|
|
518
|
+
"approach": "TDD",
|
|
519
|
+
"files": {
|
|
520
|
+
"unit": ["tests/unit/test_stream_agent.py"],
|
|
521
|
+
"integration": ["tests/integration/test_chat_streaming.py"]
|
|
522
|
+
}
|
|
523
|
+
},
|
|
524
|
+
"acceptanceCriteria": [
|
|
525
|
+
"service.py calls stream_agent() instead of run_agent()",
|
|
526
|
+
"POST /chat/messages returns SSE stream with progress events",
|
|
527
|
+
"Progress events include tool name and status"
|
|
528
|
+
],
|
|
529
|
+
"testSteps": [
|
|
530
|
+
"pytest tests/integration/test_chat_streaming.py -v",
|
|
531
|
+
"curl -N {config.urls.backend}/chat/1/messages -d '{\"content\":\"test\"}' | grep -q 'progress'"
|
|
532
|
+
]
|
|
533
|
+
```
|
|
217
534
|
|
|
218
535
|
---
|
|
219
536
|
|
|
220
|
-
##
|
|
537
|
+
## MCP Tools
|
|
221
538
|
|
|
222
|
-
|
|
223
|
-
- **Order by dependency** - Foundation stories first
|
|
224
|
-
- **Specify files explicitly** - Every story says which files to create/modify (max 3-4 files)
|
|
225
|
-
- **Define error handling** - Every story specifies failure behavior
|
|
226
|
-
- **Notes field** - Claude fills this as it works (files created, decisions made)
|
|
539
|
+
Specify which MCP tools Claude should use for verification:
|
|
227
540
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
541
|
+
| Tool | When to Use |
|
|
542
|
+
|------|-------------|
|
|
543
|
+
| `playwright` | UI testing, screenshots, form interactions, a11y |
|
|
544
|
+
| `devtools` | Console errors, network inspection, DOM debugging |
|
|
545
|
+
| `postgres` | Database verification (future) |
|
|
233
546
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
547
|
+
**Frontend stories** default to `["playwright", "devtools"]`.
|
|
548
|
+
**Backend-only stories** can use `[]` or omit.
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
## Skills Reference
|
|
553
|
+
|
|
554
|
+
Point Claude to relevant skills for guidance:
|
|
555
|
+
|
|
556
|
+
| Skill | When to Use |
|
|
557
|
+
|-------|-------------|
|
|
558
|
+
| `styleguide` | Frontend stories - reference UI components |
|
|
559
|
+
| `vibe-check` | Any story - check for AI anti-patterns after |
|
|
560
|
+
| `review` | Security-sensitive stories - OWASP checks |
|
|
561
|
+
| `explain` | Complex logic - document decisions |
|
|
562
|
+
|
|
563
|
+
Example:
|
|
564
|
+
```json
|
|
565
|
+
"skills": [
|
|
566
|
+
{"name": "styleguide", "usage": "Use existing Card, Button components"},
|
|
567
|
+
{"name": "vibe-check", "usage": "Run after implementation to catch issues"}
|
|
568
|
+
]
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
---
|
|
239
572
|
|
|
240
|
-
|
|
573
|
+
## Test Steps - CRITICAL
|
|
241
574
|
|
|
242
|
-
### Test Steps - CRITICAL
|
|
243
575
|
**Test steps MUST be executable shell commands.** Ralph runs them with bash.
|
|
244
576
|
|
|
245
|
-
|
|
577
|
+
### Backend Stories MUST Have Curl Tests
|
|
578
|
+
|
|
579
|
+
**CRITICAL: Every backend story MUST include curl commands that verify actual API behavior.**
|
|
580
|
+
|
|
581
|
+
Use `{config.urls.backend}` - Ralph expands this from `.ralph/config.json`:
|
|
582
|
+
|
|
246
583
|
```json
|
|
584
|
+
// ✅ REQUIRED for backend stories
|
|
247
585
|
"testSteps": [
|
|
248
|
-
"curl -s
|
|
249
|
-
"curl -s -
|
|
250
|
-
"
|
|
251
|
-
"grep -q 'export function Button' frontend/src/components/Button.tsx",
|
|
252
|
-
"cd frontend && npx tsc --noEmit",
|
|
253
|
-
"docker compose exec -T web python manage.py test app.tests.TestUserAPI",
|
|
254
|
-
"npx playwright test tests/e2e/dashboard.spec.ts",
|
|
255
|
-
"npx playwright test --grep 'login flow'",
|
|
256
|
-
"cd frontend && npm test -- --testPathPattern=Button.test.tsx"
|
|
586
|
+
"curl -s {config.urls.backend}/users | jq -e '.data | length > 0'",
|
|
587
|
+
"curl -s -X POST {config.urls.backend}/users -d '{\"email\":\"test@test.com\"}' | jq -e '.id'",
|
|
588
|
+
"curl -N {config.urls.backend}/chat/1/messages -d '{\"content\":\"test\"}' | grep -q 'progress'"
|
|
257
589
|
]
|
|
258
590
|
```
|
|
259
591
|
|
|
260
|
-
|
|
592
|
+
Ralph reads `.ralph/config.json` and expands `{config.urls.backend}` before running.
|
|
593
|
+
|
|
594
|
+
**Why?** Grep tests verify code exists. Curl tests verify the feature works.
|
|
595
|
+
|
|
261
596
|
```json
|
|
597
|
+
// ❌ NEVER DO THIS for backend stories
|
|
262
598
|
"testSteps": [
|
|
263
|
-
"
|
|
599
|
+
"grep -q 'astream_events' app/domains/chat/agent/graph.py"
|
|
264
600
|
]
|
|
601
|
+
// This passed but the feature was broken!
|
|
265
602
|
```
|
|
266
603
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
604
|
+
### Test Steps by Story Type
|
|
605
|
+
|
|
606
|
+
| Story Type | Required testSteps |
|
|
607
|
+
|------------|-------------------|
|
|
608
|
+
| `backend` | curl commands using `{config.urls.backend}` to verify API behavior |
|
|
609
|
+
| `frontend` | `tsc --noEmit` (type errors) + `npm test` (unit) + playwright (e2e) |
|
|
610
|
+
| `e2e` | playwright test commands |
|
|
611
|
+
|
|
612
|
+
**Frontend stories MUST include TypeScript check** - curl won't catch type errors:
|
|
613
|
+
```json
|
|
614
|
+
// ✅ Frontend story testSteps
|
|
615
|
+
"testSteps": [
|
|
616
|
+
"npx tsc --noEmit",
|
|
617
|
+
"npm test -- --testPathPattern=Dashboard",
|
|
618
|
+
"npx playwright test tests/e2e/dashboard.spec.ts"
|
|
619
|
+
]
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### Good Test Steps (executable)
|
|
623
|
+
```json
|
|
624
|
+
// Backend story - use {config.urls.backend}
|
|
625
|
+
"testSteps": [
|
|
626
|
+
"curl -s {config.urls.backend}/health | jq -e '.status == \"ok\"'",
|
|
627
|
+
"curl -s -X POST {config.urls.backend}/users -H 'Content-Type: application/json' -d '{\"email\":\"test@example.com\"}' | jq -e '.id'",
|
|
628
|
+
"pytest tests/integration/test_users.py -v"
|
|
629
|
+
]
|
|
630
|
+
|
|
631
|
+
// Frontend story
|
|
632
|
+
"testSteps": [
|
|
633
|
+
"npm test -- --testPathPattern=Button.test.tsx",
|
|
634
|
+
"npx tsc --noEmit"
|
|
635
|
+
]
|
|
636
|
+
|
|
637
|
+
// E2E story
|
|
638
|
+
"testSteps": [
|
|
639
|
+
"npx playwright test tests/e2e/user-signup.spec.ts"
|
|
640
|
+
]
|
|
641
|
+
```
|
|
273
642
|
|
|
274
|
-
|
|
643
|
+
### Bad Test Steps (will fail or miss bugs)
|
|
275
644
|
```json
|
|
276
645
|
"testSteps": [
|
|
277
|
-
"
|
|
278
|
-
"
|
|
279
|
-
"
|
|
280
|
-
"Form validates correctly",
|
|
281
|
-
"Chat panel renders in top 60%",
|
|
282
|
-
"Check DevTools for errors"
|
|
646
|
+
"grep -q 'function createUser' app/services/user.py", // ❌ Just checks code exists
|
|
647
|
+
"Visit http://localhost:3000/dashboard", // ❌ Not executable
|
|
648
|
+
"User can see the dashboard" // ❌ Not executable
|
|
283
649
|
]
|
|
284
650
|
```
|
|
285
651
|
|
|
286
|
-
**If a step can't be automated**,
|
|
652
|
+
**If a step can't be automated**, put it in `acceptanceCriteria` instead. Claude will verify it visually using MCP tools.
|
|
653
|
+
|
|
654
|
+
---
|
|
655
|
+
|
|
656
|
+
## Context Files
|
|
657
|
+
|
|
658
|
+
Use `contextFiles` to point Claude to important reference material:
|
|
659
|
+
|
|
660
|
+
```json
|
|
661
|
+
"contextFiles": [
|
|
662
|
+
"docs/ideas/dashboard.md",
|
|
663
|
+
"src/styles/styleguide.html",
|
|
664
|
+
"docs/api-spec.md"
|
|
665
|
+
]
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
This is where ASCII mockups, design specs, and detailed requirements live. Claude reads these during the Orient step.
|
|
669
|
+
|
|
670
|
+
---
|
|
671
|
+
|
|
672
|
+
## Guidelines
|
|
673
|
+
|
|
674
|
+
- **Keep stories small** - Max 3-4 acceptance criteria (~1000 tokens)
|
|
675
|
+
- **Order by dependency** - Foundation stories first
|
|
676
|
+
- **Specify files explicitly** - Max 3-4 files per story
|
|
677
|
+
- **Define error handling** - Every story specifies failure behavior
|
|
678
|
+
- **Include contextFiles** - Point to idea files with full context (ASCII art, mockups)
|
|
679
|
+
- **Add relevant skills** - Help Claude find the right patterns
|
|
680
|
+
|
|
681
|
+
### UI Stories Must Include
|
|
682
|
+
- `testUrl` - Where to verify
|
|
683
|
+
- `mcp: ["playwright", "devtools"]` - Browser tools
|
|
684
|
+
- Acceptance criteria for: page loads, elements render, mobile works
|
|
685
|
+
|
|
686
|
+
### API Stories Must Include
|
|
687
|
+
- `apiContract` - Expected request/response
|
|
688
|
+
- `errorHandling` - What happens on 400, 401, 500, etc.
|
|
689
|
+
- `testSteps` with curl commands to verify endpoints
|
package/README.md
CHANGED
|
@@ -81,6 +81,7 @@ Patterns Ralph learns from failures. If Ralph keeps making the same mistake, add
|
|
|
81
81
|
## Docs
|
|
82
82
|
|
|
83
83
|
- [How Ralph Works](docs/RALPH.md) - Architecture, config, verification pipeline
|
|
84
|
+
- [Technical Architecture](docs/ARCHITECTURE.md) - Deep dive for developers
|
|
84
85
|
- [Cheatsheet](docs/CHEATSHEET.md) - All commands at a glance
|
|
85
86
|
- [Hooks Reference](docs/HOOKS.md) - Pre-commit and Claude Code hooks
|
|
86
87
|
- [Troubleshooting](docs/TROUBLESHOOTING.md) - Common issues and fixes
|
|
@@ -88,4 +89,6 @@ Patterns Ralph learns from failures. If Ralph keeps making the same mistake, add
|
|
|
88
89
|
|
|
89
90
|
---
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
Inspired by [Ralph](https://ghuntley.com/ralph/) and [Anthropic's guidance on long-running agents](https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents).
|
|
93
|
+
|
|
94
|
+
Built by [@allierays](https://github.com/allierays) | MIT License - [AllThrive AI](https://allthrive.ai)
|