@wavilikhin/ralph-wiggum 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +340 -0
- package/package.json +30 -0
- package/src/cli.js +181 -0
- package/templates/IMPLEMENTATION_PLAN.md +60 -0
- package/templates/PROMPT.md +115 -0
- package/templates/ralph-loop.sh +344 -0
package/README.md
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
# Ralph Wiggum
|
|
2
|
+
|
|
3
|
+
Autonomous coding loop for [OpenCode](https://opencode.ai). One task, one commit, fresh context per iteration.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
____ _ _ __ ___
|
|
7
|
+
| _ \ __ _| |_ __ | |__ \ \ / (_) __ _ _ _ _ _ _ __
|
|
8
|
+
| |_) / _` | | '_ \| '_ \ \ \ /\ / /| |/ _` | | | | | | | '_ \
|
|
9
|
+
| _ < (_| | | |_) | | | | \ V V / | | (_| | |_| | |_| | | | |
|
|
10
|
+
|_| \_\__,_|_| .__/|_| |_| \_/\_/ |_|\__, |\__,_|\__,_|_| |_|
|
|
11
|
+
|_| |___/
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## What is this?
|
|
15
|
+
|
|
16
|
+
Ralph Wiggum runs OpenCode in a loop, where each iteration:
|
|
17
|
+
|
|
18
|
+
1. Starts with **fresh context** (new `opencode run` process)
|
|
19
|
+
2. Picks **exactly one task** from your implementation plan
|
|
20
|
+
3. Implements it and runs **validation gates** (lint, test, build)
|
|
21
|
+
4. Creates **exactly one commit** (local only, no push)
|
|
22
|
+
5. Repeats until all tasks are complete
|
|
23
|
+
|
|
24
|
+
This approach keeps context focused and produces clean, atomic commits.
|
|
25
|
+
|
|
26
|
+
## Model Requirements
|
|
27
|
+
|
|
28
|
+
> **Warning**: Ralph Wiggum requires the latest generation of AI models to work reliably.
|
|
29
|
+
>
|
|
30
|
+
> The autonomous loop requires models capable of:
|
|
31
|
+
> - Following complex multi-step instructions precisely
|
|
32
|
+
> - Making exactly one commit per iteration
|
|
33
|
+
> - Running validation commands and fixing failures
|
|
34
|
+
> - Updating state files accurately
|
|
35
|
+
>
|
|
36
|
+
> **Recommended models:**
|
|
37
|
+
> - `anthropic/claude-opus-4-20250514`
|
|
38
|
+
> - `openai/gpt-5.2`
|
|
39
|
+
>
|
|
40
|
+
> Using older or less capable models will likely result in failed iterations.
|
|
41
|
+
|
|
42
|
+
## Prerequisites
|
|
43
|
+
|
|
44
|
+
- [OpenCode CLI](https://opencode.ai) installed and configured
|
|
45
|
+
- Node.js 18+
|
|
46
|
+
- Git repository
|
|
47
|
+
- **AGENTS.md file in your repo root** (see below)
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Verify opencode is working
|
|
51
|
+
opencode --version
|
|
52
|
+
|
|
53
|
+
# List available models
|
|
54
|
+
opencode models
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### AGENTS.md Requirement
|
|
58
|
+
|
|
59
|
+
Ralph Wiggum expects your repository to have a well-configured `AGENTS.md` file at the root. This file tells the AI agent how to validate changes in your project.
|
|
60
|
+
|
|
61
|
+
Your `AGENTS.md` must include:
|
|
62
|
+
|
|
63
|
+
1. **Validation commands** - How to run formatting, linting, type checking, and tests
|
|
64
|
+
2. **Project structure** - Overview of your codebase layout
|
|
65
|
+
3. **Coding standards** - Any conventions the agent should follow
|
|
66
|
+
|
|
67
|
+
Example minimal `AGENTS.md`:
|
|
68
|
+
|
|
69
|
+
```markdown
|
|
70
|
+
## Validation Commands
|
|
71
|
+
|
|
72
|
+
Run these commands to validate changes:
|
|
73
|
+
|
|
74
|
+
1. Format: `npm run format`
|
|
75
|
+
2. Lint: `npm run lint`
|
|
76
|
+
3. Typecheck: `npm run typecheck`
|
|
77
|
+
4. Test: `npm test`
|
|
78
|
+
|
|
79
|
+
## Project Structure
|
|
80
|
+
|
|
81
|
+
- `src/` - Source code
|
|
82
|
+
- `tests/` - Test files
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
See [OpenCode AGENTS.md documentation](https://opencode.ai/docs/agents-md) for best practices.
|
|
86
|
+
|
|
87
|
+
## Quick Start
|
|
88
|
+
|
|
89
|
+
### 1. Initialize in your repo
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
cd your-project
|
|
93
|
+
npx ralph-wiggum init
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
This creates a `.ralph/` directory with:
|
|
97
|
+
- `PROMPT.md` - Instructions for the AI agent (has mandatory + customizable sections)
|
|
98
|
+
- `IMPLEMENTATION_PLAN.md` - Your task list template
|
|
99
|
+
- `run.sh` - The loop runner
|
|
100
|
+
- `logs/` - Directory for iteration logs
|
|
101
|
+
|
|
102
|
+
### 2. Fill in your implementation plan
|
|
103
|
+
|
|
104
|
+
Edit `.ralph/IMPLEMENTATION_PLAN.md` with your tasks:
|
|
105
|
+
|
|
106
|
+
```markdown
|
|
107
|
+
## Phase 1: Foundation
|
|
108
|
+
|
|
109
|
+
- [ ] Set up project structure with src/ and tests/ directories
|
|
110
|
+
- [ ] Add TypeScript configuration
|
|
111
|
+
- [ ] Create initial CI pipeline
|
|
112
|
+
|
|
113
|
+
## Phase 2: Core Implementation
|
|
114
|
+
|
|
115
|
+
- [ ] Implement user authentication module
|
|
116
|
+
- [ ] Add database connection layer
|
|
117
|
+
- [ ] Create REST API endpoints
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Use the checkbox format (`- [ ]` / `- [x]`) - the agent marks tasks complete as it works.
|
|
121
|
+
|
|
122
|
+
### 3. Run the loop
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
.ralph/run.sh --max-iterations 20 --model anthropic/claude-opus-4-20250514
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The loop runs until:
|
|
129
|
+
- All tasks are complete (agent outputs `<promise>COMPLETE</promise>`)
|
|
130
|
+
- Max iterations reached
|
|
131
|
+
- You press Ctrl+C
|
|
132
|
+
|
|
133
|
+
## CLI Options
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
.ralph/run.sh [options]
|
|
137
|
+
|
|
138
|
+
Options:
|
|
139
|
+
--max-iterations N Maximum iterations (default: 50)
|
|
140
|
+
--model MODEL Model to use (default: anthropic/claude-opus-4-20250514)
|
|
141
|
+
--variant NAME Optional variant name for opencode
|
|
142
|
+
--verbose Enable verbose logging (keeps full opencode output)
|
|
143
|
+
--help Show help
|
|
144
|
+
|
|
145
|
+
Environment variables:
|
|
146
|
+
RALPH_MAX_ITERATIONS Default max iterations
|
|
147
|
+
RALPH_MODEL Default model
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Logging
|
|
151
|
+
|
|
152
|
+
Ralph Wiggum maintains two types of logs in `.ralph/logs/`:
|
|
153
|
+
|
|
154
|
+
### Status Log (`.ralph/logs/ralph.log`)
|
|
155
|
+
|
|
156
|
+
Always written. Contains iteration status with timestamps:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
[2025-01-19 14:30:15] [ITER] === Iteration 1/20 STARTED ===
|
|
160
|
+
[2025-01-19 14:32:47] [ITER] === Iteration 1 FINISHED: SUCCESS (152s) - feat: add user auth module ===
|
|
161
|
+
[2025-01-19 14:32:48] [ITER] === Iteration 2/20 STARTED ===
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Use this to monitor progress:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# Watch progress in real-time
|
|
168
|
+
tail -f .ralph/logs/ralph.log
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Verbose Logs (`.ralph/logs/ralph_iter_N.log`)
|
|
172
|
+
|
|
173
|
+
Full opencode output per iteration. By default, these are deleted after successful iterations. Use `--verbose` to keep them:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
.ralph/run.sh --verbose --max-iterations 10
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
On failure, the iteration log is always preserved for debugging.
|
|
180
|
+
|
|
181
|
+
## Examples
|
|
182
|
+
|
|
183
|
+
### Run with Claude Opus 4
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
.ralph/run.sh --max-iterations 10 --model anthropic/claude-opus-4-20250514
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Run with GPT-5.2
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
.ralph/run.sh --max-iterations 10 --model openai/gpt-5.2
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Run with environment variables
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
export RALPH_MODEL="anthropic/claude-opus-4-20250514"
|
|
199
|
+
export RALPH_MAX_ITERATIONS=30
|
|
200
|
+
.ralph/run.sh
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Dry run (single iteration)
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
.ralph/run.sh --max-iterations 1
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Debug mode (verbose + single iteration)
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
.ralph/run.sh --verbose --max-iterations 1
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## How It Works
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
.ralph/run.sh
|
|
219
|
+
|
|
|
220
|
+
v
|
|
221
|
+
+---------------------------------------+
|
|
222
|
+
| Iteration N |
|
|
223
|
+
| +----------------------------------+ |
|
|
224
|
+
| | 1. Record git HEAD | |
|
|
225
|
+
| | 2. Run: opencode run ... | |
|
|
226
|
+
| | 3. Agent reads PROMPT.md | |
|
|
227
|
+
| | 4. Agent picks ONE task | |
|
|
228
|
+
| | 5. Agent implements + validates | |
|
|
229
|
+
| | 6. Agent commits (local only) | |
|
|
230
|
+
| | 7. Check: exactly 1 commit? | |
|
|
231
|
+
| | 8. Check: working tree clean? | |
|
|
232
|
+
| | 9. Check: COMPLETE marker? | |
|
|
233
|
+
| +----------------------------------+ |
|
|
234
|
+
+---------------------------------------+
|
|
235
|
+
|
|
|
236
|
+
+------------+------------+
|
|
237
|
+
v v
|
|
238
|
+
[COMPLETE] [Continue]
|
|
239
|
+
Exit 0 Iteration N+1
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Each iteration is a fresh `opencode run` process, so the agent:
|
|
243
|
+
- Has no memory of previous iterations
|
|
244
|
+
- Must re-read PROMPT.md, AGENTS.md, IMPLEMENTATION_PLAN.md
|
|
245
|
+
- Stays focused on one task at a time
|
|
246
|
+
|
|
247
|
+
## File Structure
|
|
248
|
+
|
|
249
|
+
After initialization, your repo will have:
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
your-project/
|
|
253
|
+
├── .ralph/
|
|
254
|
+
│ ├── PROMPT.md # Agent instructions (edit [CUSTOMIZABLE] sections)
|
|
255
|
+
│ ├── IMPLEMENTATION_PLAN.md # Your task list (fill this in)
|
|
256
|
+
│ ├── run.sh # Loop runner script
|
|
257
|
+
│ └── logs/
|
|
258
|
+
│ ├── ralph.log # Iteration status log
|
|
259
|
+
│ └── ralph_iter_N.log # Per-iteration logs (verbose/error only)
|
|
260
|
+
├── AGENTS.md # Your validation commands (required, you create this)
|
|
261
|
+
└── .gitignore # Updated to ignore .ralph/logs/
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### .ralph/PROMPT.md
|
|
265
|
+
|
|
266
|
+
Contains instructions the agent follows each iteration. Has two types of sections:
|
|
267
|
+
|
|
268
|
+
- **[MANDATORY] sections**: Core loop mechanics - don't modify these
|
|
269
|
+
- **[CUSTOMIZABLE] sections**: Add project-specific context, quality standards
|
|
270
|
+
|
|
271
|
+
### .ralph/IMPLEMENTATION_PLAN.md
|
|
272
|
+
|
|
273
|
+
Your task list. Structure it in phases:
|
|
274
|
+
|
|
275
|
+
```markdown
|
|
276
|
+
## Phase 1: Foundation
|
|
277
|
+
- [ ] Task 1
|
|
278
|
+
- [x] Task 2 (completed)
|
|
279
|
+
|
|
280
|
+
## Phase 2: Core
|
|
281
|
+
- [ ] Task 3
|
|
282
|
+
|
|
283
|
+
## Discovered Tasks
|
|
284
|
+
<!-- Agent adds tasks here as it finds them -->
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### AGENTS.md (your file, repo root)
|
|
288
|
+
|
|
289
|
+
Your project's agent configuration. Must exist in repo root before running.
|
|
290
|
+
|
|
291
|
+
## Safety Features
|
|
292
|
+
|
|
293
|
+
- **Local only**: Never pushes to remote
|
|
294
|
+
- **One commit per iteration**: Enforced by the loop
|
|
295
|
+
- **Clean working tree**: Verified after each iteration
|
|
296
|
+
- **Max iterations**: Hard stop to prevent runaway loops
|
|
297
|
+
- **Validation gates**: All must pass before commit
|
|
298
|
+
|
|
299
|
+
## Troubleshooting
|
|
300
|
+
|
|
301
|
+
### "opencode CLI not found"
|
|
302
|
+
|
|
303
|
+
Install OpenCode:
|
|
304
|
+
```bash
|
|
305
|
+
npm install -g opencode
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### "AGENTS.md not found"
|
|
309
|
+
|
|
310
|
+
Create an `AGENTS.md` file in your repo root with validation commands. See the [AGENTS.md Requirement](#agentsmd-requirement) section.
|
|
311
|
+
|
|
312
|
+
### "No commit was created"
|
|
313
|
+
|
|
314
|
+
The agent must create exactly one commit per iteration. Check `.ralph/logs/ralph_iter_N.log` to see what happened. Common causes:
|
|
315
|
+
- Validation gates failed
|
|
316
|
+
- Agent got stuck on a complex task
|
|
317
|
+
- Task was already complete
|
|
318
|
+
- Model not capable enough (try a more advanced model)
|
|
319
|
+
|
|
320
|
+
### "Working tree is not clean"
|
|
321
|
+
|
|
322
|
+
The agent left uncommitted changes. This usually means validation failed. Check the log and fix manually, then restart.
|
|
323
|
+
|
|
324
|
+
### Loop never completes
|
|
325
|
+
|
|
326
|
+
- Check if tasks in `.ralph/IMPLEMENTATION_PLAN.md` are achievable
|
|
327
|
+
- Ensure validation commands in AGENTS.md are correct
|
|
328
|
+
- Try running with `--verbose --max-iterations 1` to debug a single iteration
|
|
329
|
+
- Consider using a more capable model
|
|
330
|
+
|
|
331
|
+
### Iterations failing consistently
|
|
332
|
+
|
|
333
|
+
This often indicates the model isn't capable enough for autonomous operation. Try:
|
|
334
|
+
- Using `anthropic/claude-opus-4-20250514` or `openai/gpt-5.2`
|
|
335
|
+
- Simplifying tasks in IMPLEMENTATION_PLAN.md
|
|
336
|
+
- Adding more context to AGENTS.md
|
|
337
|
+
|
|
338
|
+
## License
|
|
339
|
+
|
|
340
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wavilikhin/ralph-wiggum",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Autonomous coding loop for OpenCode - one task, one commit, fresh context per iteration",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ralph-wiggum": "./src/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"src/",
|
|
11
|
+
"templates/"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"opencode",
|
|
15
|
+
"ai",
|
|
16
|
+
"autonomous",
|
|
17
|
+
"coding",
|
|
18
|
+
"agent",
|
|
19
|
+
"loop"
|
|
20
|
+
],
|
|
21
|
+
"author": "wavilikhin",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/wavilikhin/ralph-wiggum.git"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18.0.0"
|
|
29
|
+
}
|
|
30
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { dirname, join } from "path";
|
|
5
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, copyFileSync, chmodSync } from "fs";
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = dirname(__filename);
|
|
9
|
+
const TEMPLATES_DIR = join(__dirname, "..", "templates");
|
|
10
|
+
|
|
11
|
+
const RED = "\x1b[31m";
|
|
12
|
+
const CYAN = "\x1b[36m";
|
|
13
|
+
const GREEN = "\x1b[32m";
|
|
14
|
+
const YELLOW = "\x1b[33m";
|
|
15
|
+
const BOLD = "\x1b[1m";
|
|
16
|
+
const RESET = "\x1b[0m";
|
|
17
|
+
const DIM = "\x1b[2m";
|
|
18
|
+
|
|
19
|
+
function printBanner() {
|
|
20
|
+
console.log(`
|
|
21
|
+
${CYAN}${BOLD} ____ _ _ __ ___
|
|
22
|
+
| _ \\ __ _| |_ __ | |__ \\ \\ / (_) __ _ _ _ _ _ _ __
|
|
23
|
+
| |_) / _\` | | '_ \\| '_ \\ \\ \\ /\\ / /| |/ _\` | | | | | | | '_ \\
|
|
24
|
+
| _ < (_| | | |_) | | | | \\ V V / | | (_| | |_| | |_| | | | |
|
|
25
|
+
|_| \\_\\__,_|_| .__/|_| |_| \\_/\\_/ |_|\\__, |\\__,_|\\__,_|_| |_|
|
|
26
|
+
|_| |___/ ${RESET}
|
|
27
|
+
${DIM} Autonomous coding loop for OpenCode${RESET}
|
|
28
|
+
`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function printUsage() {
|
|
32
|
+
console.log(`${BOLD}Usage:${RESET}
|
|
33
|
+
npx ralph-wiggum init Scaffold ralph-wiggum files in .ralph/ directory
|
|
34
|
+
npx ralph-wiggum help Show this help message
|
|
35
|
+
`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function checkAgentsMd(targetDir) {
|
|
39
|
+
const agentsPath = join(targetDir, "AGENTS.md");
|
|
40
|
+
return existsSync(agentsPath);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function printNextSteps(hasAgentsMd) {
|
|
44
|
+
console.log(`
|
|
45
|
+
${GREEN}${BOLD}Files created successfully!${RESET}
|
|
46
|
+
|
|
47
|
+
${YELLOW}${BOLD}Next steps:${RESET}
|
|
48
|
+
`);
|
|
49
|
+
|
|
50
|
+
if (!hasAgentsMd) {
|
|
51
|
+
console.log(`${RED}${BOLD}[REQUIRED]${RESET} Create AGENTS.md in your repo root:
|
|
52
|
+
${DIM}This file must contain your validation commands (lint, test, build).${RESET}
|
|
53
|
+
${DIM}The agent reads this file to know how to validate changes.${RESET}
|
|
54
|
+
${DIM}See: https://opencode.ai/docs/agents-md${RESET}
|
|
55
|
+
`);
|
|
56
|
+
} else {
|
|
57
|
+
console.log(`${GREEN}[OK]${RESET} AGENTS.md found in repo root
|
|
58
|
+
`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log(`${BOLD}1.${RESET} Fill in your implementation plan:
|
|
62
|
+
${DIM}Edit ${CYAN}.ralph/IMPLEMENTATION_PLAN.md${RESET}${DIM} with your tasks using the checkbox format${RESET}
|
|
63
|
+
|
|
64
|
+
${BOLD}2.${RESET} (Optional) Customize the prompt:
|
|
65
|
+
${DIM}Edit ${CYAN}.ralph/PROMPT.md${RESET}${DIM} - mandatory sections are marked, customize the rest${RESET}
|
|
66
|
+
|
|
67
|
+
${BOLD}3.${RESET} Run the loop:
|
|
68
|
+
${CYAN}.ralph/run.sh --max-iterations 10 --model anthropic/claude-opus-4-20250514${RESET}
|
|
69
|
+
|
|
70
|
+
${YELLOW}${BOLD}Important:${RESET} This tool works best with the latest generation models.
|
|
71
|
+
${DIM}Recommended: anthropic/claude-opus-4-20250514 or openai/gpt-5.2${RESET}
|
|
72
|
+
|
|
73
|
+
${YELLOW}Available loop options:${RESET}
|
|
74
|
+
--max-iterations N Maximum iterations before stopping (default: 50)
|
|
75
|
+
--model provider/m Model to use (default: anthropic/claude-opus-4-20250514)
|
|
76
|
+
--variant name Optional variant name passed to opencode
|
|
77
|
+
--verbose Enable verbose logging (full opencode output)
|
|
78
|
+
|
|
79
|
+
${DIM}Logs are written to ${CYAN}.ralph/logs/ralph.log${RESET}${DIM} (iteration status)${RESET}
|
|
80
|
+
${DIM}Verbose logs: ${CYAN}.ralph/logs/ralph_iter_N.log${RESET}${DIM} (full output per iteration)${RESET}
|
|
81
|
+
|
|
82
|
+
${DIM}The loop stops automatically when all tasks are complete (<promise>COMPLETE</promise>)${RESET}
|
|
83
|
+
`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function copyTemplate(templateName, destPath, options = {}) {
|
|
87
|
+
const templatePath = join(TEMPLATES_DIR, templateName);
|
|
88
|
+
|
|
89
|
+
if (!existsSync(templatePath)) {
|
|
90
|
+
console.error(`Template not found: ${templateName}`);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (existsSync(destPath) && !options.overwrite) {
|
|
95
|
+
console.log(`${YELLOW}Skipping${RESET} ${destPath} (already exists)`);
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const destDir = dirname(destPath);
|
|
100
|
+
if (!existsSync(destDir)) {
|
|
101
|
+
mkdirSync(destDir, { recursive: true });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
copyFileSync(templatePath, destPath);
|
|
105
|
+
|
|
106
|
+
if (destPath.endsWith(".sh")) {
|
|
107
|
+
chmodSync(destPath, "755");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.log(`${GREEN}Created${RESET} ${destPath}`);
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function ensureGitignore(targetDir) {
|
|
115
|
+
const gitignorePath = join(targetDir, ".gitignore");
|
|
116
|
+
const logsEntry = ".ralph/logs/";
|
|
117
|
+
|
|
118
|
+
if (existsSync(gitignorePath)) {
|
|
119
|
+
const content = readFileSync(gitignorePath, "utf-8");
|
|
120
|
+
if (!content.includes(logsEntry)) {
|
|
121
|
+
writeFileSync(gitignorePath, content.trimEnd() + "\n" + logsEntry + "\n");
|
|
122
|
+
console.log(`${GREEN}Updated${RESET} .gitignore (added .ralph/logs/)`);
|
|
123
|
+
} else {
|
|
124
|
+
console.log(`${YELLOW}Skipping${RESET} .gitignore (.ralph/logs/ already ignored)`);
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
writeFileSync(gitignorePath, logsEntry + "\n");
|
|
128
|
+
console.log(`${GREEN}Created${RESET} .gitignore`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function initCommand(targetDir) {
|
|
133
|
+
const ralphDir = join(targetDir, ".ralph");
|
|
134
|
+
|
|
135
|
+
console.log(`${BOLD}Initializing ralph-wiggum in ${ralphDir}${RESET}\n`);
|
|
136
|
+
|
|
137
|
+
// Create .ralph directory
|
|
138
|
+
if (!existsSync(ralphDir)) {
|
|
139
|
+
mkdirSync(ralphDir, { recursive: true });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Copy templates into .ralph/
|
|
143
|
+
copyTemplate("PROMPT.md", join(ralphDir, "PROMPT.md"));
|
|
144
|
+
copyTemplate("IMPLEMENTATION_PLAN.md", join(ralphDir, "IMPLEMENTATION_PLAN.md"));
|
|
145
|
+
copyTemplate("ralph-loop.sh", join(ralphDir, "run.sh"));
|
|
146
|
+
|
|
147
|
+
// Create logs directory inside .ralph/
|
|
148
|
+
const logsDir = join(ralphDir, "logs");
|
|
149
|
+
if (!existsSync(logsDir)) {
|
|
150
|
+
mkdirSync(logsDir, { recursive: true });
|
|
151
|
+
writeFileSync(join(logsDir, ".gitkeep"), "");
|
|
152
|
+
console.log(`${GREEN}Created${RESET} .ralph/logs/.gitkeep`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Update .gitignore to ignore .ralph/logs/
|
|
156
|
+
ensureGitignore(targetDir);
|
|
157
|
+
|
|
158
|
+
const hasAgentsMd = checkAgentsMd(targetDir);
|
|
159
|
+
printNextSteps(hasAgentsMd);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const args = process.argv.slice(2);
|
|
163
|
+
const command = args[0];
|
|
164
|
+
|
|
165
|
+
printBanner();
|
|
166
|
+
|
|
167
|
+
switch (command) {
|
|
168
|
+
case "init":
|
|
169
|
+
initCommand(process.cwd());
|
|
170
|
+
break;
|
|
171
|
+
case "help":
|
|
172
|
+
case "--help":
|
|
173
|
+
case "-h":
|
|
174
|
+
case undefined:
|
|
175
|
+
printUsage();
|
|
176
|
+
break;
|
|
177
|
+
default:
|
|
178
|
+
console.error(`Unknown command: ${command}\n`);
|
|
179
|
+
printUsage();
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **Instructions**: Fill in your tasks below using the checkbox format.
|
|
4
|
+
> The AI agent will pick one task per iteration, implement it, and mark it complete.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Definition of Done
|
|
9
|
+
|
|
10
|
+
A task is complete when:
|
|
11
|
+
- [ ] Implementation is finished
|
|
12
|
+
- [ ] All validation gates pass (see AGENTS.md)
|
|
13
|
+
- [ ] Code is committed locally
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Phase 1: Foundation
|
|
18
|
+
<!-- Core setup, dependencies, project structure -->
|
|
19
|
+
|
|
20
|
+
- [ ] Task 1: Description here
|
|
21
|
+
- [ ] Task 2: Description here
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Phase 2: Core Implementation
|
|
26
|
+
<!-- Main features and functionality -->
|
|
27
|
+
|
|
28
|
+
- [ ] Task 3: Description here
|
|
29
|
+
- [ ] Task 4: Description here
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Phase 3: Integration
|
|
34
|
+
<!-- Connecting components, APIs, external services -->
|
|
35
|
+
|
|
36
|
+
- [ ] Task 5: Description here
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Phase 4: Polish
|
|
41
|
+
<!-- Error handling, edge cases, UX improvements -->
|
|
42
|
+
|
|
43
|
+
- [ ] Task 6: Description here
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Phase 5: Validation
|
|
48
|
+
<!-- Final testing, documentation, cleanup -->
|
|
49
|
+
|
|
50
|
+
- [ ] Task 7: Description here
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Discovered Tasks
|
|
55
|
+
<!-- Agent will add tasks here as they're discovered during implementation -->
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Notes & Learnings
|
|
60
|
+
<!-- Agent will add notes here about decisions made, blockers found, etc. -->
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Ralph Wiggum - Single Iteration Prompt
|
|
2
|
+
|
|
3
|
+
> This file instructs the AI agent on what to do in ONE iteration of the autonomous loop.
|
|
4
|
+
> Sections marked [MANDATORY] must not be modified. Sections marked [CUSTOMIZABLE] can be adjusted.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## [MANDATORY] Orientation Phase
|
|
9
|
+
|
|
10
|
+
Before doing anything:
|
|
11
|
+
|
|
12
|
+
1. **Read `AGENTS.md`** - contains validation commands (lint, test, build) you MUST run
|
|
13
|
+
2. **Read `IMPLEMENTATION_PLAN.md`** - contains the task list with priorities and completion status
|
|
14
|
+
3. **Search the codebase** before assuming anything is missing - use grep/glob to verify
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## [MANDATORY] Task Selection
|
|
19
|
+
|
|
20
|
+
Pick **exactly ONE** task from `IMPLEMENTATION_PLAN.md`:
|
|
21
|
+
|
|
22
|
+
- Choose the highest-priority incomplete item (marked `- [ ]`)
|
|
23
|
+
- If multiple items have the same priority, pick the one that unblocks others
|
|
24
|
+
- Do NOT work on multiple tasks in a single iteration
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## [MANDATORY] Implementation + Validation
|
|
29
|
+
|
|
30
|
+
1. **Implement** the selected task completely
|
|
31
|
+
2. **Run ALL validation gates** from `AGENTS.md`:
|
|
32
|
+
- Formatting
|
|
33
|
+
- Linting
|
|
34
|
+
- Type checking
|
|
35
|
+
- Tests
|
|
36
|
+
3. **Fix any failures** before proceeding - do not leave broken code
|
|
37
|
+
4. Iterate until all gates pass
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## [MANDATORY] State Persistence
|
|
42
|
+
|
|
43
|
+
After implementation is validated:
|
|
44
|
+
|
|
45
|
+
1. **Update `IMPLEMENTATION_PLAN.md`**:
|
|
46
|
+
- Mark the completed task: `- [ ]` → `- [x]`
|
|
47
|
+
- Add any discovered follow-up tasks to the appropriate phase
|
|
48
|
+
- Update any notes or learnings
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## [MANDATORY] Commit (Local Only)
|
|
53
|
+
|
|
54
|
+
Create exactly ONE commit for this iteration:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
git add -A
|
|
58
|
+
git commit -m "<type>: <concise description of what was done>"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Rules:
|
|
62
|
+
- **Do NOT push** - local commits only
|
|
63
|
+
- **Exactly ONE commit** per iteration
|
|
64
|
+
- Use conventional commit format: `feat:`, `fix:`, `refactor:`, `docs:`, `test:`, `chore:`
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## [MANDATORY] Completion Check
|
|
69
|
+
|
|
70
|
+
**Only if ALL of the following are true:**
|
|
71
|
+
- Every task in `IMPLEMENTATION_PLAN.md` is marked `[x]`
|
|
72
|
+
- All validation gates pass
|
|
73
|
+
- No pending follow-up tasks remain
|
|
74
|
+
|
|
75
|
+
**Then output exactly:**
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
<promise>COMPLETE</promise>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Otherwise, do NOT output this marker.** The loop will continue with a fresh context.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## [CUSTOMIZABLE] Project-Specific Context
|
|
86
|
+
|
|
87
|
+
<!-- Add any project-specific instructions here -->
|
|
88
|
+
<!-- Examples: -->
|
|
89
|
+
<!-- - Preferred coding patterns -->
|
|
90
|
+
<!-- - Architecture decisions to follow -->
|
|
91
|
+
<!-- - Files/directories to avoid modifying -->
|
|
92
|
+
<!-- - Special considerations for this codebase -->
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## [CUSTOMIZABLE] Quality Standards
|
|
97
|
+
|
|
98
|
+
<!-- Define your quality bar here -->
|
|
99
|
+
<!-- Examples: -->
|
|
100
|
+
<!-- - Test coverage requirements -->
|
|
101
|
+
<!-- - Documentation requirements -->
|
|
102
|
+
<!-- - Performance considerations -->
|
|
103
|
+
<!-- - Security considerations -->
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Summary
|
|
108
|
+
|
|
109
|
+
Each iteration you must:
|
|
110
|
+
1. Orient (read AGENTS.md, IMPLEMENTATION_PLAN.md)
|
|
111
|
+
2. Pick ONE task
|
|
112
|
+
3. Implement + validate (all gates must pass)
|
|
113
|
+
4. Update IMPLEMENTATION_PLAN.md
|
|
114
|
+
5. Make exactly ONE local commit
|
|
115
|
+
6. Output `<promise>COMPLETE</promise>` only when truly done
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Ralph Wiggum Loop - Autonomous coding loop for OpenCode
|
|
5
|
+
# Each iteration: fresh context, one task, one commit
|
|
6
|
+
|
|
7
|
+
# Get the directory where this script is located
|
|
8
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
+
# Go up one level to get to the repo root
|
|
10
|
+
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
11
|
+
|
|
12
|
+
#=============================================================================
|
|
13
|
+
# Configuration
|
|
14
|
+
#=============================================================================
|
|
15
|
+
|
|
16
|
+
MAX_ITERATIONS="${RALPH_MAX_ITERATIONS:-50}"
|
|
17
|
+
MODEL="${RALPH_MODEL:-anthropic/claude-opus-4-20250514}"
|
|
18
|
+
VARIANT=""
|
|
19
|
+
VERBOSE=false
|
|
20
|
+
|
|
21
|
+
# All ralph files are in .ralph/
|
|
22
|
+
RALPH_DIR="$SCRIPT_DIR"
|
|
23
|
+
LOGS_DIR="$RALPH_DIR/logs"
|
|
24
|
+
LOG_FILE="$LOGS_DIR/ralph.log"
|
|
25
|
+
PROMPT_FILE="$RALPH_DIR/PROMPT.md"
|
|
26
|
+
PLAN_FILE="$RALPH_DIR/IMPLEMENTATION_PLAN.md"
|
|
27
|
+
|
|
28
|
+
#=============================================================================
|
|
29
|
+
# Colors
|
|
30
|
+
#=============================================================================
|
|
31
|
+
|
|
32
|
+
RED='\033[0;31m'
|
|
33
|
+
GREEN='\033[0;32m'
|
|
34
|
+
YELLOW='\033[1;33m'
|
|
35
|
+
CYAN='\033[0;36m'
|
|
36
|
+
BOLD='\033[1m'
|
|
37
|
+
DIM='\033[2m'
|
|
38
|
+
NC='\033[0m'
|
|
39
|
+
|
|
40
|
+
#=============================================================================
|
|
41
|
+
# Logging
|
|
42
|
+
#=============================================================================
|
|
43
|
+
|
|
44
|
+
log_to_file() {
|
|
45
|
+
local level="$1"
|
|
46
|
+
local message="$2"
|
|
47
|
+
local timestamp
|
|
48
|
+
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
49
|
+
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
log_info() {
|
|
53
|
+
echo -e "${CYAN}[INFO]${NC} $1"
|
|
54
|
+
log_to_file "INFO" "$1"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
log_success() {
|
|
58
|
+
echo -e "${GREEN}[OK]${NC} $1"
|
|
59
|
+
log_to_file "OK" "$1"
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
log_warn() {
|
|
63
|
+
echo -e "${YELLOW}[WARN]${NC} $1"
|
|
64
|
+
log_to_file "WARN" "$1"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
log_error() {
|
|
68
|
+
echo -e "${RED}[ERROR]${NC} $1"
|
|
69
|
+
log_to_file "ERROR" "$1"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
log_iteration_start() {
|
|
73
|
+
local iter="$1"
|
|
74
|
+
local max="$2"
|
|
75
|
+
log_to_file "ITER" "=== Iteration $iter/$max STARTED ==="
|
|
76
|
+
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
77
|
+
echo -e "${BOLD} Iteration $iter / $max${NC}"
|
|
78
|
+
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
79
|
+
echo ""
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
log_iteration_end() {
|
|
83
|
+
local iter="$1"
|
|
84
|
+
local status="$2"
|
|
85
|
+
local commit_msg="$3"
|
|
86
|
+
local duration="$4"
|
|
87
|
+
log_to_file "ITER" "=== Iteration $iter FINISHED: $status (${duration}s) - $commit_msg ==="
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
#=============================================================================
|
|
91
|
+
# Helper Functions
|
|
92
|
+
#=============================================================================
|
|
93
|
+
|
|
94
|
+
print_banner() {
|
|
95
|
+
echo -e "${CYAN}${BOLD}"
|
|
96
|
+
echo ' ____ _ _ __ ___ '
|
|
97
|
+
echo ' | _ \ __ _| |_ __ | |__ \ \ / (_) __ _ _ _ _ _ _ __ '
|
|
98
|
+
echo ' | |_) / _` | | '"'"'_ \| '"'"'_ \ \ \ /\ / /| |/ _` | | | | | | | '"'"'_ \'
|
|
99
|
+
echo ' | _ < (_| | | |_) | | | | \ V V / | | (_| | |_| | |_| | | | |'
|
|
100
|
+
echo ' |_| \_\__,_|_| .__/|_| |_| \_/\_/ |_|\__, |\__,_|\__,_|_| |_|'
|
|
101
|
+
echo ' |_| |___/ '
|
|
102
|
+
echo -e "${NC}"
|
|
103
|
+
echo -e "${DIM} Autonomous coding loop for OpenCode${NC}"
|
|
104
|
+
echo ""
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
print_usage() {
|
|
108
|
+
echo "Usage: $0 [options]"
|
|
109
|
+
echo ""
|
|
110
|
+
echo "Options:"
|
|
111
|
+
echo " --max-iterations N Maximum iterations (default: $MAX_ITERATIONS)"
|
|
112
|
+
echo " --model MODEL Model to use (default: $MODEL)"
|
|
113
|
+
echo " --variant NAME Variant name for opencode"
|
|
114
|
+
echo " --verbose Enable verbose logging (full opencode output)"
|
|
115
|
+
echo " --help Show this help"
|
|
116
|
+
echo ""
|
|
117
|
+
echo "Environment variables:"
|
|
118
|
+
echo " RALPH_MAX_ITERATIONS Default max iterations"
|
|
119
|
+
echo " RALPH_MODEL Default model"
|
|
120
|
+
echo ""
|
|
121
|
+
echo "Logs:"
|
|
122
|
+
echo " .ralph/logs/ralph.log Iteration status (always written)"
|
|
123
|
+
echo " .ralph/logs/ralph_iter_N.log Full opencode output (verbose mode or on error)"
|
|
124
|
+
echo ""
|
|
125
|
+
echo "Example:"
|
|
126
|
+
echo " $0 --max-iterations 10 --model anthropic/claude-opus-4-20250514"
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
check_prerequisites() {
|
|
130
|
+
if ! command -v opencode &> /dev/null; then
|
|
131
|
+
log_error "opencode CLI not found. Install it first:"
|
|
132
|
+
echo " npm install -g opencode"
|
|
133
|
+
exit 1
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
if [[ ! -f "$PROMPT_FILE" ]]; then
|
|
137
|
+
log_error "PROMPT.md not found at $PROMPT_FILE"
|
|
138
|
+
log_error "Run 'npx ralph-wiggum init' first."
|
|
139
|
+
exit 1
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
if [[ ! -f "$PLAN_FILE" ]]; then
|
|
143
|
+
log_error "IMPLEMENTATION_PLAN.md not found at $PLAN_FILE"
|
|
144
|
+
log_error "Run 'npx ralph-wiggum init' first."
|
|
145
|
+
exit 1
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
if [[ ! -f "$REPO_ROOT/AGENTS.md" ]]; then
|
|
149
|
+
log_error "AGENTS.md not found in repo root."
|
|
150
|
+
echo ""
|
|
151
|
+
echo "Ralph Wiggum requires an AGENTS.md file with your validation commands."
|
|
152
|
+
echo "This file tells the agent how to lint, test, and build your project."
|
|
153
|
+
echo ""
|
|
154
|
+
echo "Create AGENTS.md with at minimum:"
|
|
155
|
+
echo " - Formatting command"
|
|
156
|
+
echo " - Linting command"
|
|
157
|
+
echo " - Type checking command (if applicable)"
|
|
158
|
+
echo " - Test command"
|
|
159
|
+
echo ""
|
|
160
|
+
echo "See: https://opencode.ai/docs/agents-md"
|
|
161
|
+
exit 1
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
if ! git -C "$REPO_ROOT" rev-parse --git-dir > /dev/null 2>&1; then
|
|
165
|
+
log_error "Not in a git repository."
|
|
166
|
+
exit 1
|
|
167
|
+
fi
|
|
168
|
+
|
|
169
|
+
if [[ -n "$(git -C "$REPO_ROOT" status --porcelain)" ]]; then
|
|
170
|
+
log_warn "Uncommitted changes detected. Consider committing or stashing first."
|
|
171
|
+
echo ""
|
|
172
|
+
git -C "$REPO_ROOT" status --short
|
|
173
|
+
echo ""
|
|
174
|
+
read -p "Continue anyway? [y/N] " -n 1 -r
|
|
175
|
+
echo
|
|
176
|
+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
177
|
+
exit 1
|
|
178
|
+
fi
|
|
179
|
+
fi
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
#=============================================================================
|
|
183
|
+
# Parse Arguments
|
|
184
|
+
#=============================================================================
|
|
185
|
+
|
|
186
|
+
while [[ $# -gt 0 ]]; do
|
|
187
|
+
case $1 in
|
|
188
|
+
--max-iterations)
|
|
189
|
+
MAX_ITERATIONS="$2"
|
|
190
|
+
shift 2
|
|
191
|
+
;;
|
|
192
|
+
--model)
|
|
193
|
+
MODEL="$2"
|
|
194
|
+
shift 2
|
|
195
|
+
;;
|
|
196
|
+
--variant)
|
|
197
|
+
VARIANT="$2"
|
|
198
|
+
shift 2
|
|
199
|
+
;;
|
|
200
|
+
--verbose)
|
|
201
|
+
VERBOSE=true
|
|
202
|
+
shift
|
|
203
|
+
;;
|
|
204
|
+
--help|-h)
|
|
205
|
+
print_usage
|
|
206
|
+
exit 0
|
|
207
|
+
;;
|
|
208
|
+
*)
|
|
209
|
+
log_error "Unknown option: $1"
|
|
210
|
+
print_usage
|
|
211
|
+
exit 1
|
|
212
|
+
;;
|
|
213
|
+
esac
|
|
214
|
+
done
|
|
215
|
+
|
|
216
|
+
#=============================================================================
|
|
217
|
+
# Main Loop
|
|
218
|
+
#=============================================================================
|
|
219
|
+
|
|
220
|
+
print_banner
|
|
221
|
+
|
|
222
|
+
log_info "Configuration:"
|
|
223
|
+
echo -e " ${DIM}Max iterations:${NC} $MAX_ITERATIONS"
|
|
224
|
+
echo -e " ${DIM}Model:${NC} $MODEL"
|
|
225
|
+
echo -e " ${DIM}Verbose:${NC} $VERBOSE"
|
|
226
|
+
echo -e " ${DIM}Repo root:${NC} $REPO_ROOT"
|
|
227
|
+
[[ -n "$VARIANT" ]] && echo -e " ${DIM}Variant:${NC} $VARIANT"
|
|
228
|
+
echo ""
|
|
229
|
+
|
|
230
|
+
check_prerequisites
|
|
231
|
+
|
|
232
|
+
mkdir -p "$LOGS_DIR"
|
|
233
|
+
|
|
234
|
+
# Initialize log file
|
|
235
|
+
echo "========================================" >> "$LOG_FILE"
|
|
236
|
+
echo "Ralph Wiggum Loop Started: $(date '+%Y-%m-%d %H:%M:%S')" >> "$LOG_FILE"
|
|
237
|
+
echo "Model: $MODEL" >> "$LOG_FILE"
|
|
238
|
+
echo "Max Iterations: $MAX_ITERATIONS" >> "$LOG_FILE"
|
|
239
|
+
echo "Repo: $REPO_ROOT" >> "$LOG_FILE"
|
|
240
|
+
echo "========================================" >> "$LOG_FILE"
|
|
241
|
+
|
|
242
|
+
log_info "Starting autonomous loop..."
|
|
243
|
+
log_info "Status log: $LOG_FILE"
|
|
244
|
+
echo ""
|
|
245
|
+
|
|
246
|
+
# Change to repo root for git operations
|
|
247
|
+
cd "$REPO_ROOT"
|
|
248
|
+
|
|
249
|
+
for i in $(seq 1 "$MAX_ITERATIONS"); do
|
|
250
|
+
ITER_START=$(date +%s)
|
|
251
|
+
ITER_LOG_FILE="$LOGS_DIR/ralph_iter_${i}.log"
|
|
252
|
+
|
|
253
|
+
log_iteration_start "$i" "$MAX_ITERATIONS"
|
|
254
|
+
|
|
255
|
+
BEFORE_HEAD=$(git rev-parse HEAD)
|
|
256
|
+
log_info "HEAD before: ${DIM}${BEFORE_HEAD:0:8}${NC}"
|
|
257
|
+
|
|
258
|
+
OPENCODE_CMD=(
|
|
259
|
+
opencode run
|
|
260
|
+
--model "$MODEL"
|
|
261
|
+
--file "$PROMPT_FILE"
|
|
262
|
+
--file "$PLAN_FILE"
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
if [[ -n "$VARIANT" ]]; then
|
|
266
|
+
OPENCODE_CMD+=(--variant "$VARIANT")
|
|
267
|
+
fi
|
|
268
|
+
|
|
269
|
+
OPENCODE_CMD+=("Follow the attached PROMPT.md. Use AGENTS.md for validation commands and IMPLEMENTATION_PLAN.md for task selection. Do exactly one task and one commit.")
|
|
270
|
+
|
|
271
|
+
log_info "Running opencode..."
|
|
272
|
+
|
|
273
|
+
set +e
|
|
274
|
+
if [[ "$VERBOSE" == true ]]; then
|
|
275
|
+
OUTPUT=$("${OPENCODE_CMD[@]}" 2>&1 | tee "$ITER_LOG_FILE")
|
|
276
|
+
else
|
|
277
|
+
OUTPUT=$("${OPENCODE_CMD[@]}" 2>&1)
|
|
278
|
+
echo "$OUTPUT" > "$ITER_LOG_FILE"
|
|
279
|
+
fi
|
|
280
|
+
EXIT_CODE=$?
|
|
281
|
+
set -e
|
|
282
|
+
|
|
283
|
+
ITER_END=$(date +%s)
|
|
284
|
+
ITER_DURATION=$((ITER_END - ITER_START))
|
|
285
|
+
|
|
286
|
+
if [[ $EXIT_CODE -ne 0 ]]; then
|
|
287
|
+
log_error "opencode exited with code $EXIT_CODE"
|
|
288
|
+
log_error "Check log: $ITER_LOG_FILE"
|
|
289
|
+
log_iteration_end "$i" "FAILED" "opencode error" "$ITER_DURATION"
|
|
290
|
+
exit 1
|
|
291
|
+
fi
|
|
292
|
+
|
|
293
|
+
if echo "$OUTPUT" | grep -q '<promise>COMPLETE</promise>'; then
|
|
294
|
+
echo ""
|
|
295
|
+
log_success "All tasks complete!"
|
|
296
|
+
echo ""
|
|
297
|
+
echo -e "${GREEN}${BOLD}Loop finished successfully after $i iteration(s)${NC}"
|
|
298
|
+
log_iteration_end "$i" "COMPLETE" "all tasks done" "$ITER_DURATION"
|
|
299
|
+
log_to_file "INFO" "=== LOOP COMPLETED SUCCESSFULLY ==="
|
|
300
|
+
exit 0
|
|
301
|
+
fi
|
|
302
|
+
|
|
303
|
+
AFTER_HEAD=$(git rev-parse HEAD)
|
|
304
|
+
log_info "HEAD after: ${DIM}${AFTER_HEAD:0:8}${NC}"
|
|
305
|
+
|
|
306
|
+
if [[ "$BEFORE_HEAD" == "$AFTER_HEAD" ]]; then
|
|
307
|
+
log_error "No commit was created in this iteration!"
|
|
308
|
+
log_error "The agent must create exactly one commit per iteration."
|
|
309
|
+
log_error "Check log: $ITER_LOG_FILE"
|
|
310
|
+
log_iteration_end "$i" "FAILED" "no commit created" "$ITER_DURATION"
|
|
311
|
+
exit 1
|
|
312
|
+
fi
|
|
313
|
+
|
|
314
|
+
COMMIT_COUNT=$(git rev-list --count "$BEFORE_HEAD".."$AFTER_HEAD")
|
|
315
|
+
if [[ "$COMMIT_COUNT" -ne 1 ]]; then
|
|
316
|
+
log_error "Expected 1 commit, but $COMMIT_COUNT were created!"
|
|
317
|
+
log_iteration_end "$i" "FAILED" "multiple commits" "$ITER_DURATION"
|
|
318
|
+
exit 1
|
|
319
|
+
fi
|
|
320
|
+
|
|
321
|
+
if [[ -n "$(git status --porcelain)" ]]; then
|
|
322
|
+
log_error "Working tree is not clean after iteration!"
|
|
323
|
+
echo ""
|
|
324
|
+
git status --short
|
|
325
|
+
log_iteration_end "$i" "FAILED" "dirty working tree" "$ITER_DURATION"
|
|
326
|
+
exit 1
|
|
327
|
+
fi
|
|
328
|
+
|
|
329
|
+
COMMIT_MSG=$(git log -1 --format='%s')
|
|
330
|
+
log_success "Commit created: $COMMIT_MSG"
|
|
331
|
+
log_iteration_end "$i" "SUCCESS" "$COMMIT_MSG" "$ITER_DURATION"
|
|
332
|
+
|
|
333
|
+
if [[ "$VERBOSE" != true ]]; then
|
|
334
|
+
rm -f "$ITER_LOG_FILE"
|
|
335
|
+
fi
|
|
336
|
+
|
|
337
|
+
echo ""
|
|
338
|
+
done
|
|
339
|
+
|
|
340
|
+
echo ""
|
|
341
|
+
log_warn "Max iterations ($MAX_ITERATIONS) reached without completion."
|
|
342
|
+
log_warn "Check IMPLEMENTATION_PLAN.md for remaining tasks."
|
|
343
|
+
log_to_file "WARN" "=== LOOP STOPPED: MAX ITERATIONS REACHED ==="
|
|
344
|
+
exit 1
|