@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 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