@herbcaudill/ralph 0.7.0 → 0.8.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.
@@ -85,24 +85,24 @@ describe("EventDisplay replay tests", () => {
85
85
  Good! The build is successful and all tests pass. Now let me check the todo list to find the
86
86
  highest-priority task.
87
87
 
88
- Read .ralph/todo.md
88
+ Read ../.ralph/todo.md
89
89
 
90
90
  Looking at the todo list, I'll prioritize the "Inline code blocks are being put in separate
91
91
  paragraphs" issue. This is a functional bug affecting the display quality, whereas the others are
92
92
  enhancements. Let me investigate this issue first.
93
93
 
94
- Read src/components/StreamingText.tsx
94
+ Read ../src/components/StreamingText.tsx
95
95
 
96
96
  Let me check the tests to understand the expected behavior and see if there's a failing test case:
97
97
 
98
- Read src/components/StreamingText.test.tsx
98
+ Read ../src/components/StreamingText.test.tsx
99
99
 
100
100
  I need to understand where StreamingText is being used and what the actual problem is. Let me check
101
101
  where it's called from and look at some example output:
102
102
 
103
103
  Grep StreamingText
104
104
 
105
- Read src/components/EventDisplay.tsx
105
+ Read ../src/components/EventDisplay.tsx
106
106
 
107
107
  I see the issue now! In EventDisplay.tsx:70, there's a <Box flexDirection="column" gap={1}> which
108
108
  wraps each StreamingText component. Each StreamingText (which represents text blocks) is being
@@ -114,7 +114,7 @@ describe("EventDisplay replay tests", () => {
114
114
 
115
115
  Let me look at how the events are being split into blocks:
116
116
 
117
- Read src/components/eventToBlocks.ts
117
+ Read ../src/components/eventToBlocks.ts
118
118
 
119
119
  Now I understand the issue. Claude's message content can have multiple text blocks (e.g., "Here's
120
120
  the code: ", then a tool_use block, then " and that's it"). Each text block becomes a separate
@@ -124,11 +124,11 @@ describe("EventDisplay replay tests", () => {
124
124
  The fix should be to merge consecutive text blocks together. Let me write a test first to
125
125
  demonstrate the problem:
126
126
 
127
- Read src/components/EventDisplay.test.tsx
127
+ Read ../src/components/EventDisplay.test.tsx
128
128
 
129
129
  Now let me add a test that demonstrates the inline code block problem and then fix it:
130
130
 
131
- Edit src/components/EventDisplay.test.tsx
131
+ Edit ../src/components/EventDisplay.test.tsx
132
132
 
133
133
  Now let me run the test to confirm it fails (demonstrating the problem):
134
134
 
@@ -137,11 +137,11 @@ describe("EventDisplay replay tests", () => {
137
137
  Perfect! The test fails as expected, confirming the bug. Now I need to fix it by modifying
138
138
  eventToBlocks to merge consecutive text blocks:
139
139
 
140
- Edit src/components/eventToBlocks.ts
140
+ Edit ../src/components/eventToBlocks.ts
141
141
 
142
142
  Now I need to also flush the text buffer at the end of the loop:
143
143
 
144
- Edit src/components/eventToBlocks.ts
144
+ Edit ../src/components/eventToBlocks.ts
145
145
 
146
146
  Now let me run the tests again to verify the fix works:
147
147
 
@@ -150,20 +150,20 @@ describe("EventDisplay replay tests", () => {
150
150
  The test still fails. This suggests the problem might also be in EventDisplay, not just
151
151
  eventToBlocks. Let me debug by adding a simpler test to see what's happening in eventToBlocks:
152
152
 
153
- Read src/components/eventToBlocks.test.ts
153
+ Read ../src/components/eventToBlocks.test.ts
154
154
 
155
155
  I see! The existing test "extracts multiple text blocks" expects them NOT to be merged. I need to
156
156
  update this test and add a new one specifically for consecutive text blocks:
157
157
 
158
- Edit src/components/eventToBlocks.test.ts
158
+ Edit ../src/components/eventToBlocks.test.ts
159
159
 
160
160
  Now let me add a test for text blocks separated by tool calls:
161
161
 
162
- Read src/components/eventToBlocks.test.ts
162
+ Read ../src/components/eventToBlocks.test.ts
163
163
 
164
164
  Let me add a test that specifically checks text blocks separated by tool calls:
165
165
 
166
- Edit src/components/eventToBlocks.test.ts
166
+ Edit ../src/components/eventToBlocks.test.ts
167
167
 
168
168
  Now let me run all tests to verify my changes to eventToBlocks work:
169
169
 
@@ -171,12 +171,12 @@ describe("EventDisplay replay tests", () => {
171
171
 
172
172
  I need to look at this failing test:
173
173
 
174
- Read src/components/eventToBlocks.test.ts
174
+ Read ../src/components/eventToBlocks.test.ts
175
175
 
176
176
  This test expects 3 separate IDs for 3 text blocks, but my code now merges them into 1. I need to
177
177
  update this test to reflect the new behavior:
178
178
 
179
- Edit src/components/eventToBlocks.test.ts
179
+ Edit ../src/components/eventToBlocks.test.ts
180
180
 
181
181
  Now let me run the eventToBlocks tests again:
182
182
 
@@ -190,7 +190,7 @@ describe("EventDisplay replay tests", () => {
190
190
  rendered. The issue must be in how EventDisplay merges the events. Let me look more carefully at the
191
191
  EventDisplay logic:
192
192
 
193
- Read src/components/EventDisplay.tsx
193
+ Read ../src/components/EventDisplay.tsx
194
194
 
195
195
  I see! The EventDisplay is doing its own deduplication, but it's NOT merging consecutive text
196
196
  blocks. The text blocks in the test data remain separate even after eventToBlocks merges them,
@@ -235,13 +235,13 @@ describe("EventDisplay replay tests", () => {
235
235
 
236
236
  That should work! Let me check if there's an issue with my implementation. Let me re-read the code:
237
237
 
238
- Read src/components/eventToBlocks.ts
238
+ Read ../src/components/eventToBlocks.ts
239
239
 
240
240
  The code looks correct. Let me check if the EventDisplay is receiving the correct merged content. I
241
241
  think the issue might be in how EventDisplay deduplicates and merges content before calling
242
242
  eventToBlocks. Let me look at that logic again:
243
243
 
244
- Read src/components/EventDisplay.tsx
244
+ Read ../src/components/EventDisplay.tsx
245
245
 
246
246
  Ah! I see the problem now. In the test, we're providing a single event with one message containing 3
247
247
  text blocks. EventDisplay keeps the text blocks separate in uniqueContent (lines 36-54), so they
@@ -269,7 +269,7 @@ describe("EventDisplay replay tests", () => {
269
269
 
270
270
  Let me print what lastFrame() actually returns by modifying the test temporarily:
271
271
 
272
- Edit src/components/EventDisplay.test.tsx
272
+ Edit ../src/components/EventDisplay.test.tsx
273
273
 
274
274
  $ pnpm test EventDisplay.test.tsx 2>&1 | grep -A 20 "merges consecutive"
275
275
 
@@ -280,7 +280,7 @@ describe("EventDisplay replay tests", () => {
280
280
  This means the EventDisplay deduplication logic is keeping them separate, OR there's a bug in my
281
281
  eventToBlocks implementation. Let me add logging to eventToBlocks to see:
282
282
 
283
- Edit src/components/eventToBlocks.ts
283
+ Edit ../src/components/eventToBlocks.ts
284
284
 
285
285
  $ pnpm test EventDisplay.test.tsx 2>&1 | grep -A 30 "eventToBlocks content"
286
286
 
@@ -296,9 +296,9 @@ describe("EventDisplay replay tests", () => {
296
296
  But the output still shows them on 3 separate lines. This means my merging logic isn't working. Let
297
297
  me add more logging to see what's happening in the loop:
298
298
 
299
- Edit src/components/eventToBlocks.ts
299
+ Edit ../src/components/eventToBlocks.ts
300
300
 
301
- Edit src/components/eventToBlocks.ts
301
+ Edit ../src/components/eventToBlocks.ts
302
302
 
303
303
  $ pnpm test EventDisplay.test.tsx 2>&1 | grep -A 50 "merges consecutive text blocks to prevent
304
304
  unwanted gaps"
@@ -341,7 +341,7 @@ describe("EventDisplay replay tests", () => {
341
341
  Let me check if the problem is in how StreamingText uses fragments. When you return a fragment with
342
342
  multiple <Text> components in Ink, they might be rendered on separate lines. Let me check:
343
343
 
344
- Read src/components/StreamingText.tsx
344
+ Read ../src/components/StreamingText.tsx
345
345
 
346
346
  The issue is that StreamingText returns a fragment with multiple <Text> components. In Ink, these
347
347
  might be rendered as separate blocks. The fix is to wrap them in a single <Text> component or use
@@ -350,17 +350,17 @@ describe("EventDisplay replay tests", () => {
350
350
  Let me look at how Ink handles multiple Text components. Actually, the fix is simple - wrap all the
351
351
  text parts in a single Box or Text component with inline rendering:
352
352
 
353
- Edit src/components/StreamingText.tsx
353
+ Edit ../src/components/StreamingText.tsx
354
354
 
355
- Edit src/components/StreamingText.tsx
355
+ Edit ../src/components/StreamingText.tsx
356
356
 
357
357
  Now let me remove the console.log statements and test:
358
358
 
359
- Edit src/components/eventToBlocks.ts
359
+ Edit ../src/components/eventToBlocks.ts
360
360
 
361
- Edit src/components/eventToBlocks.ts
361
+ Edit ../src/components/eventToBlocks.ts
362
362
 
363
- Edit src/components/EventDisplay.test.tsx
363
+ Edit ../src/components/EventDisplay.test.tsx
364
364
 
365
365
  Now let me run all tests:
366
366
 
@@ -372,13 +372,13 @@ describe("EventDisplay replay tests", () => {
372
372
 
373
373
  Excellent! Now let me update the todo list and progress file, then commit:
374
374
 
375
- Read .ralph/todo.md
375
+ Read ../.ralph/todo.md
376
376
 
377
- Edit .ralph/todo.md
377
+ Edit ../.ralph/todo.md
378
378
 
379
- Read .ralph/progress.md
379
+ Read ../.ralph/progress.md
380
380
 
381
- Edit .ralph/progress.md
381
+ Edit ../.ralph/progress.md
382
382
 
383
383
  Now let me format the code with Prettier:
384
384
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@herbcaudill/ralph",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Autonomous AI iteration engine for Claude CLI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -59,7 +59,7 @@
59
59
  "typecheck": "tsc --noEmit",
60
60
  "ralph": "tsx src/index.ts",
61
61
  "test:all": "pnpm typecheck && pnpm test",
62
- "test": "vitest --exclude test/e2e/** run",
62
+ "test": "vitest run",
63
63
  "test:e2e": "vitest --config vitest.e2e.config.ts",
64
64
  "test:watch": "vitest --watch",
65
65
  "test:ui": "vitest --ui",
@@ -19,7 +19,7 @@ If there are none:
19
19
 
20
20
  ### Step 3: Select a task
21
21
 
22
- Select the highest-priority issue to work on. Use your best judgement.
22
+ Select the highest-priority issue to work on. Finish in-progress tasks first. Bugs take priority. Otherwise use your best judgement.
23
23
 
24
24
  ### Step 4: Work on a single task
25
25
 
package/README.md DELETED
@@ -1,183 +0,0 @@
1
- ```
2
- █▀█ ▄▀█ █ █▀█ █ █
3
- █▀▄ █▀█ █▄▄ █▀▀ █▀█
4
- ```
5
-
6
- Autonomous AI iteration engine for Claude CLI. Ralph runs Claude in a loop to systematically work through your codebase's task list, enabling Claude to tackle work items iteratively.
7
-
8
- https://github.com/user-attachments/assets/e8d89a33-8db5-4d72-9c97-927558f92516
9
-
10
- ## Overview
11
-
12
- Ralph spawns individual Claude CLI sessions that:
13
-
14
- 1. Check project health (build, tests)
15
- 2. Select and work on the highest-priority task
16
- 3. Validate changes with tests
17
- 4. Commit changes
18
- 5. Repeat
19
-
20
- ## Installation
21
-
22
- ```bash
23
- pnpm add -D @herbcaudill/ralph
24
- ```
25
-
26
- Or use directly with npx:
27
-
28
- ```bash
29
- npx @herbcaudill/ralph
30
- ```
31
-
32
- ## Quick start
33
-
34
- 1. **Initialize ralph in your project:**
35
-
36
- ```bash
37
- npx @herbcaudill/ralph init
38
- ```
39
-
40
- This creates a `.ralph/` directory with template files:
41
- - `prompt.md` - Instructions for Claude during each iteration
42
- - `todo.md` - Your task list (optional if using bd)
43
- - `events.jsonl` - Event log in JSONL format (auto-generated during runs)
44
-
45
- 2. **Customize the workflow:**
46
-
47
- Edit `.ralph/prompt.md` to match your project's workflow (build commands, test commands, etc.).
48
-
49
- 3. **Add tasks:**
50
-
51
- You can manage tasks using either a markdown file or [beads](https://github.com/steveyegge/beads), a lightweight issue tracker.
52
-
53
- **Option A: Using `.ralph/todo.md`**
54
-
55
- ```markdown
56
- ### To do
57
-
58
- - [ ] Add user authentication
59
- - [ ] Fix login form validation
60
- - [ ] Write tests for auth flow
61
-
62
- ---
63
-
64
- ### Done
65
- ```
66
-
67
- **Option B: Using beads (recommended)**
68
-
69
- ```bash
70
- # Install bd
71
- brew install herbcaudill/tap/bd
72
-
73
- # Initialize in your project
74
- bd init
75
-
76
- # Create issues
77
- bd create "Add user authentication"
78
- bd create "Fix login form validation"
79
- bd create "Write tests for auth flow"
80
-
81
- # View ready work
82
- bd ready
83
- ```
84
-
85
- 4. **Run ralph:**
86
-
87
- ```bash
88
- npx ralph # Run with dynamic default (120% of open issues)
89
- npx ralph 5 # Run 5 iterations
90
- npx ralph --watch # Run and watch for new issues
91
- ```
92
-
93
- ## Commands
94
-
95
- | Command | Description |
96
- | --------------- | -------------------------------------------------------------- |
97
- | `ralph` | Run with dynamic default (120% of open issues, min 10 max 100) |
98
- | `ralph <n>` | Run specified number of iterations |
99
- | `ralph init` | Initialize .ralph directory with templates |
100
- | `ralph --watch` | Watch for new issues after completion |
101
- | `ralph --help` | Show help |
102
-
103
- ## Watch mode
104
-
105
- Watch mode (`--watch`) keeps ralph running after completing all tasks, waiting for new issues to be added:
106
-
107
- ```bash
108
- npx ralph --watch
109
- ```
110
-
111
- When ralph finishes all available work and Claude outputs the completion signal, instead of exiting, it enters a waiting state. When you add a new issue via `bd create` or `bd q`, ralph automatically detects it and starts a new iteration to work on it.
112
-
113
- This enables a "continuous integration" style workflow:
114
-
115
- 1. Start ralph in watch mode: `npx ralph --watch`
116
- 2. Add tasks as you think of them: `bd q "Fix header alignment"`
117
- 3. Ralph automatically picks up and works on new tasks
118
- 4. Keep adding tasks while ralph works
119
-
120
- Watch mode requires **bd** (beads) for issue tracking—it watches for mutations to the beads database.
121
-
122
- ## Configuration
123
-
124
- **`.ralph/prompt.md`**
125
-
126
- Instructions for Claude's workflow. Customize this for your project:
127
-
128
- - Build/typecheck commands
129
- - Test commands
130
- - Project-specific conventions
131
- - Commit message style
132
-
133
- ### Customizing the prompt
134
-
135
- The default prompt ([for beads](./templates/prompt-beads.md) or [for TODO.md](./templates/prompt-todos.md)) works for my projects, but you should customize it for your project. Replace with your actual build/test commands (e.g., `pnpm build`, `cargo test`, `pytest`, etc.).
136
-
137
- ## How it works
138
-
139
- Ralph is a thin wrapper around the Claude CLI that:
140
-
141
- 1. **Spawns Claude CLI** with your project context (prompt, todo, progress files)
142
- 2. **Captures output** as streaming JSON events
143
- 3. **Processes events** to display tool usage (Read, Edit, Bash, etc.) in a readable format
144
- 4. **Logs everything** to `events.jsonl` for debugging
145
- 5. **Detects completion** when Claude outputs `<promise>COMPLETE</promise>`
146
- 6. **Recursively runs** next iteration until count reached or todo list complete
147
-
148
- ## Requirements
149
-
150
- - **Claude CLI** must be installed and configured
151
- - **Node.js** 18 or higher
152
- - Git repository (for commits)
153
-
154
- Install Claude CLI:
155
-
156
- ```bash
157
- # macOS/Linux
158
- curl https://claude.com/cli | sh
159
-
160
- # Or with Homebrew
161
- brew install anthropics/tap/claude
162
- ```
163
-
164
- Configure Claude CLI:
165
-
166
- ```bash
167
- claude auth
168
- ```
169
-
170
- ## Tips
171
-
172
- - **Start with small iteration counts** (3-5) to verify the workflow before running longer sessions
173
- - **Customize prompt.md** for your project's specific needs (build commands, test frameworks, etc.)
174
- - **Break down complex tasks** into smaller subtasks in todo.md
175
- - **Let Claude prioritize** by not ordering tasks strictly - Claude will choose what makes sense
176
-
177
- ## License
178
-
179
- MIT
180
-
181
- ## Author
182
-
183
- Herb Caudill