Sign up
Login
New
Trending
Archive
English
English
Sign up
Login
New Paste
Add Image
/** * Ralph Wiggum Loop Runner for OpenCode * A Windows-agnostic TypeScript implementation of the Ralph Loop pattern. * * Usage: bun ralph.ts "task description" [max-iterations] [stack] * * The Ralph Loop: * 1. Orientation: Reads existing plan.md and agent guidelines * 2. Task Selection: Picks the first unchecked [ ] task * 3. Implementation: Makes the smallest possible change * 4. Verification: Runs tests and type checks * 5. Commit: Creates a git commit with proper format * 6. Update Plan: Marks task complete, adds new discoveries * 7. Repeat: Until all tasks are done or max iterations reached */ import { $ } from "bun" import { existsSync, readFileSync } from "fs" import { join } from "path" // Configuration const COMPLETION_SIGNAL = "RALPH_COMPLETE" const BLOCKED_SIGNAL = "[BLOCKED]" const DELAY_MS = 2000 // Colors for console output const colors = { reset: "\x1b[0m", bright: "\x1b[1m", dim: "\x1b[2m", red: "\x1b[31m", green: "\x1b[32m", yellow: "\x1b[33m", blue: "\x1b[34m", cyan: "\x1b[36m", } function log(message: string, color?: keyof typeof colors) { const prefix = color ? colors[color] : "" const suffix = color ? colors.reset : "" console.log(`${prefix}${message}${suffix}`) } function logHeader(iteration: number, maxIterations: number) { console.log("") log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━", "cyan") log(` Iteration ${iteration} / ${maxIterations}`, "bright") log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━", "cyan") console.log("") } function getPlanContent(): string { const planPath = join(process.cwd(), "plan.md") if (!existsSync(planPath)) { return "No plan.md found. Create one with tasks as checkboxes: - [ ] Task description" } return readFileSync(planPath, "utf-8") } function getAgentGuidelines(): string { const agentsPath = join(process.cwd(), "AGENTS.md") if (!existsSync(agentsPath)) { return "" } return readFileSync(agentsPath, "utf-8") } function buildRalphPrompt(task: string, stack: string): string { const plan = getPlanContent() const guidelines = getAgentGuidelines() return `You are Ralph, an autonomous coding agent following the Ralph Loop pattern. ## Your Task ${task} ## Stack ${stack} ## Current Plan (plan.md) \`\`\`markdown ${plan} \`\`\` ${guidelines ? `## Agent Guidelines (AGENTS.md)\n\`\`\`markdown\n${guidelines}\n\`\`\`\n` : ""} ## Ralph Loop Instructions 1. **Orientation**: Review the plan.md and guidelines above 2. **Task Selection**: Find the first unchecked [ ] task in the plan 3. **Implementation**: Make the SMALLEST possible change to complete that task 4. **Verification**: Run appropriate tests/linting (bun lint, bun run bb) 5. **Commit**: Create a git commit with a descriptive message 6. **Update Plan**: - Mark the completed task as [x] in plan.md - Add any new discoveries or subtasks you found 7. **Completion Check**: - If ALL tasks are now [x] complete, output: ${COMPLETION_SIGNAL} - If you've tried a task 3+ times and can't complete it, prefix it with ${BLOCKED_SIGNAL} and move on ## Important Rules - Make ONE small change per iteration - Always verify your changes work before committing - Be honest about blocked tasks - mark them and move on - Output ${COMPLETION_SIGNAL} ONLY when ALL tasks are genuinely complete Now execute one iteration of the Ralph Loop.` } async function runOpencode(prompt: string): Promise<{ output: string; exitCode: number }> { try { // Escape the prompt for shell const result = await $`opencode run ${prompt}`.text() return { output: result, exitCode: 0 } } catch (error) { const err = error as { stdout?: Buffer; stderr?: Buffer; exitCode?: number } const output = [err.stdout?.toString() ?? "", err.stderr?.toString() ?? ""] .filter(Boolean) .join("\n") return { output: output || String(error), exitCode: err.exitCode ?? 1 } } } async function sleep(ms: number): Promise<void> { return new Promise((resolve) => setTimeout(resolve, ms)) } async function main() { const args = process.argv.slice(2) // Parse arguments const task = args[0] const maxIterations = parseInt(args[1] ?? "25", 10) const stack = args[2] ?? "full" if (!task) { log('Usage: bun ralph.ts "task description" [max-iterations] [stack]', "yellow") log("", "reset") log("Arguments:", "bright") log(" task - Description of what Ralph should accomplish (required)") log(" max-iterations - Maximum loop iterations (default: 25)") log(" stack - Technology stack context (default: full)") log("", "reset") log("Example:", "bright") log(' bun ralph.ts "Implement user authentication" 30 nextjs') process.exit(1) } // Check if plan.md exists, create template if not const planPath = join(process.cwd(), "plan.md") if (!existsSync(planPath)) { log("Warning: No plan.md found in current directory.", "yellow") log("Ralph will ask opencode to create initial tasks.", "dim") console.log("") } // Print startup banner console.log("") log("╔═══════════════════════════════════════════════════════════╗", "cyan") log("║ Ralph Wiggum Loop Runner for OpenCode ║", "cyan") log("╚═══════════════════════════════════════════════════════════╝", "cyan") console.log("") log(` Task: ${task}`, "bright") log(` Max Iterations: ${maxIterations}`, "dim") log(` Stack: ${stack}`, "dim") console.log("") let iteration = 0 let blockedCount = 0 while (iteration < maxIterations) { iteration++ logHeader(iteration, maxIterations) // Build the prompt with current plan state const prompt = buildRalphPrompt(task, stack) // Run opencode log("Running opencode...", "dim") const { output, exitCode } = await runOpencode(prompt) // Display output console.log("") console.log(output) console.log("") // Check for completion if (output.includes(COMPLETION_SIGNAL)) { console.log("") log("╔═══════════════════════════════════════════════════════════╗", "green") log( `║ Ralph completed successfully after ${iteration} iteration(s)!`.padEnd(60) + "║", "green" ) log("╚═══════════════════════════════════════════════════════════╝", "green") console.log("") process.exit(0) } // Check for blocked tasks if (output.includes(BLOCKED_SIGNAL)) { blockedCount++ log( `Warning: Blocked task detected (${blockedCount} total). Check plan.md for details.`, "yellow" ) } // Log exit code if non-zero if (exitCode !== 0) { log(`opencode exited with code ${exitCode}`, "yellow") } // Delay before next iteration to prevent rate limiting if (iteration < maxIterations) { log(`Waiting ${DELAY_MS / 1000}s before next iteration...`, "dim") await sleep(DELAY_MS) } } // Max iterations reached console.log("") log("╔═══════════════════════════════════════════════════════════╗", "yellow") log(`║ Max iterations (${maxIterations}) reached.`.padEnd(60) + "║", "yellow") log("║ Check plan.md for remaining tasks.".padEnd(60) + "║", "yellow") log("╚═══════════════════════════════════════════════════════════╝", "yellow") console.log("") if (blockedCount > 0) { log(`Total blocked tasks encountered: ${blockedCount}`, "red") } process.exit(1) } // Run main main().catch((error) => { log(`Fatal error: ${error}`, "red") process.exit(1) })
Settings
Title :
[Optional]
Paste Folder :
[Optional]
Select
Syntax :
[Optional]
Select
Markup
CSS
JavaScript
Bash
C
C#
C++
Java
JSON
Lua
Plaintext
C-like
ABAP
ActionScript
Ada
Apache Configuration
APL
AppleScript
Arduino
ARFF
AsciiDoc
6502 Assembly
ASP.NET (C#)
AutoHotKey
AutoIt
Basic
Batch
Bison
Brainfuck
Bro
CoffeeScript
Clojure
Crystal
Content-Security-Policy
CSS Extras
D
Dart
Diff
Django/Jinja2
Docker
Eiffel
Elixir
Elm
ERB
Erlang
F#
Flow
Fortran
GEDCOM
Gherkin
Git
GLSL
GameMaker Language
Go
GraphQL
Groovy
Haml
Handlebars
Haskell
Haxe
HTTP
HTTP Public-Key-Pins
HTTP Strict-Transport-Security
IchigoJam
Icon
Inform 7
INI
IO
J
Jolie
Julia
Keyman
Kotlin
LaTeX
Less
Liquid
Lisp
LiveScript
LOLCODE
Makefile
Markdown
Markup templating
MATLAB
MEL
Mizar
Monkey
N4JS
NASM
nginx
Nim
Nix
NSIS
Objective-C
OCaml
OpenCL
Oz
PARI/GP
Parser
Pascal
Perl
PHP
PHP Extras
PL/SQL
PowerShell
Processing
Prolog
.properties
Protocol Buffers
Pug
Puppet
Pure
Python
Q (kdb+ database)
Qore
R
React JSX
React TSX
Ren'py
Reason
reST (reStructuredText)
Rip
Roboconf
Ruby
Rust
SAS
Sass (Sass)
Sass (Scss)
Scala
Scheme
Smalltalk
Smarty
SQL
Soy (Closure Template)
Stylus
Swift
TAP
Tcl
Textile
Template Toolkit 2
Twig
TypeScript
VB.Net
Velocity
Verilog
VHDL
vim
Visual Basic
WebAssembly
Wiki markup
Xeora
Xojo (REALbasic)
XQuery
YAML
HTML
Expiration :
[Optional]
Never
Self Destroy
10 Minutes
1 Hour
1 Day
1 Week
2 Weeks
1 Month
6 Months
1 Year
Status :
[Optional]
Public
Unlisted
Private (members only)
Password :
[Optional]
Description:
[Optional]
Tags:
[Optional]
Encrypt Paste
(
?
)
Create Paste
You are currently not logged in, this means you can not edit or delete anything you paste.
Sign Up
or
Login
Site Languages
×
English