Ralph without Docker: opencode & pi coding agent (Linux + Windows)

Ralph is a technique for running AI coding agents in a loop: you run the same prompt repeatedly, the AI picks its own tasks from a PRD, commits after each feature, and you come back later to working code.

Adapted from Getting Started with Ralph (AI Hero). The original uses Claude Code + Docker Desktop on Linux. This version swaps in two open-source agents — opencode and pi coding agent — drops Docker entirely, and covers Linux and Windows. Shared concepts appear once; each OS/agent combo gets its own section with only what's different.

What is Ralph?

Ralph is a technique for running AI coding agents in a loop: you run the same prompt repeatedly, the AI picks its own tasks from a PRD, commits after each feature, and you come back later to working code. The loop stays the same no matter which agent or OS you use:

Piece Purpose
PRD.md Defines the end state — a checklist, list of tasks, or prose the agent can pull individual tasks from
progress.txt Tracks what's done between runs
One prompt "Find the next task, implement it, commit" — the loop body
Completion sigil <promise>COMPLETE</promise> — printed when the PRD is finished so the loop can stop

For tips on task sizing, prioritization, and feedback loops, see the 11 tips for AI coding with Ralph.

What changes without Docker

Docker Desktop sandboxes gave you three things you now own yourself:

  1. No sandbox. docker sandbox run claude isolated the agent. opencode and pi run directly with your user's permissions — they can install packages, run servers, and touch any file you can. Start in a disposable VM or a scratch folder, run the once-script a few times first, and review commits before going fully AFK.
  2. Git identity is on you. Sandboxes auto-injected git config for commit attribution. Without Docker, set it once:
    git config --global user.name "You"
    git config --global user.email "you@example.com"
  3. Credentials are yours to manage. No Docker volume — each agent stores auth in its own config directory. For scripted (headless) runs, prefer exporting a provider API key in your shell.

Step 1 — Write the PRD (identical for all four combos)

Ask the agent for a plan, iterate until you're happy, then save it as PRD.md:

  • opencode: the TUI has a plan mode — press Tab to switch modes, iterate, then tell it to save the plan to PRD.md.
  • pi: no built-in plan mode (by design). Ask pi interactively to draft a plan, iterate in chat, then have it write PRD.md.

Create the empty progress file:

touch progress.txt

The PRD can be any format (markdown checklist, JSON, prose). What matters: clear scope, and tasks the agent can pull out one at a time.

Step 2 — Install & authenticate (pick your combo)

# Combo Install Auth
A Linux + opencode curl -fsSL https://opencode.ai/install \| bash or npm install -g opencode-ai opencode/connect → pick provider, or export ANTHROPIC_API_KEY=...
B Linux + pi npm install -g --ignore-scripts @earendil-works/pi-coding-agent (or curl -fsSL https://pi.dev/install.sh \| sh) pi/login → pick provider, or export ANTHROPIC_API_KEY=...
C Windows + opencode scoop install opencode or choco install opencode (Node optional: npm i -g opencode-ai) opencode/connect, or set ANTHROPIC_API_KEY env var
D Windows + pi npm install -g --ignore-scripts @earendil-works/pi-coding-agent (needs Node.js) + Git for Windows — pi requires a bash shell pi/login, or export ANTHROPIC_API_KEY=... in Git Bash

Auth done in the TUI persists for later headless runs; an exported API key works everywhere including scripts.


A. Linux + opencode (no Docker)

Human-in-the-loop runralph-once.sh (watch it, run it again):

#!/bin/bash
opencode run -p --auto "@PRD.md @progress.txt
1. Read the PRD and progress file.
2. Find the next incomplete task and implement it.
3. Commit your changes.
4. Update progress.txt with what you did.
ONLY DO ONE TASK AT A TIME."
chmod +x ralph-once.sh
./ralph-once.sh
  • --auto auto-approves permission requests so the loop never stalls (omit it for a stricter run).
  • -p/--print formats output cleanly; @file attaches files to the prompt.

AFK loopafk-ralph.sh (run with a cap: ./afk-ralph.sh 20):

#!/bin/bash
set -e
if [ -z "$1" ]; then
  echo "Usage: $0 <iterations>"
  exit 1
fi
for ((i=1; i<=$1; i++)); do
  result=$(opencode run -p --auto "@PRD.md @progress.txt
1. Find the highest-priority task and implement it.
2. Run your tests and type checks.
3. Update the PRD with what was done.
4. Append your progress to progress.txt.
5. Commit your changes.
ONLY WORK ON A SINGLE TASK.
If the PRD is complete, output <promise>COMPLETE</promise>.")
  echo "$result"
  if [[ "$result" == *"<promise>COMPLETE</promise>"* ]]; then
    echo "PRD complete after $i iterations."
    exit 0
  fi
done

set -e exits on errors, $1 caps iterations (runaway-cost protection), and the sigil check stops the loop early when the PRD is done.


B. Linux + pi coding agent (no Docker)

Human-in-the-loop runralph-once.sh:

#!/bin/bash
pi -p "@PRD.md @progress.txt
1. Read the PRD and progress file.
2. Find the next incomplete task and implement it.
3. Commit your changes.
4. Update progress.txt with what you did.
ONLY DO ONE TASK AT A TIME."
chmod +x ralph-once.sh
./ralph-once.sh
  • pi has no permission popups by design — tool calls just execute. -p is print (headless) mode; @file attaches files. Use --tools read,write,edit,bash (the default set) or a narrower allowlist if you want extra safety without a sandbox.

AFK loopafk-ralph.sh:

#!/bin/bash
set -e
if [ -z "$1" ]; then
  echo "Usage: $0 <iterations>"
  exit 1
fi
for ((i=1; i<=$1; i++)); do
  result=$(pi -p "@PRD.md @progress.txt
1. Find the highest-priority task and implement it.
2. Run your tests and type checks.
3. Update the PRD with what was done.
4. Append your progress to progress.txt.
5. Commit your changes.
ONLY WORK ON A SINGLE TASK.
If the PRD is complete, output <promise>COMPLETE</promise>.")
  echo "$result"
  if [[ "$result" == *"<promise>COMPLETE</promise>"* ]]; then
    echo "PRD complete after $i iterations."
    exit 0
  fi
done

C. Windows + opencode (no Docker)

Runs fine from PowerShell (scripts below) or cmd. Install with scoop install opencode or choco install opencode, run opencode once, /connect, and pick a provider.

Human-in-the-loop runralph-once.ps1:

# Run once, watch it, run again.
opencode run -p --auto "@PRD.md @progress.txt
1. Read the PRD and progress file.
2. Find the next incomplete task and implement it.
3. Commit your changes.
4. Update progress.txt with what you did.
ONLY DO ONE TASK AT A TIME."
Set-ExecutionPolicy -Scope Process Bypass   # if scripts are blocked
.\ralph-once.ps1

AFK loopafk-ralph.ps1 (run with .\afk-ralph.ps1 20):

param([int]$Iterations)
if (-not $Iterations) { Write-Host "Usage: .\afk-ralph.ps1 <iterations>"; exit 1 }

for ($i = 1; $i -le $Iterations; $i++) {
  $result = opencode run -p --auto "@PRD.md @progress.txt
1. Find the highest-priority task and implement it.
2. Run your tests and type checks.
3. Update the PRD with what was done.
4. Append your progress to progress.txt.
5. Commit your changes.
ONLY WORK ON A SINGLE TASK.
If the PRD is complete, output <promise>COMPLETE</promise>."
  Write-Output $result
  if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
  if ($result -match "<promise>COMPLETE</promise>") {
    Write-Host "PRD complete after $i iterations."
    exit 0
  }
}

$result collects opencode's stdout, $LASTEXITCODE propagates failures, and -match detects the completion sigil.


D. Windows + pi coding agent (no Docker)

pi requires a bash shell on Windows — install Git for Windows (pi auto-detects C:\Program Files\Git\bin\bash.exe). Everything below is bash run from a Git Bash terminal. Install pi, then authenticate (pi/login, or export ANTHROPIC_API_KEY in the Git Bash session).

Human-in-the-loop runralph-once.sh (in Git Bash):

#!/bin/bash
pi -p "@PRD.md @progress.txt
1. Read the PRD and progress file.
2. Find the next incomplete task and implement it.
3. Commit your changes.
4. Update progress.txt with what you did.
ONLY DO ONE TASK AT A TIME."
chmod +x ralph-once.sh
./ralph-once.sh

AFK loopafk-ralph.sh:

#!/bin/bash
set -e
if [ -z "$1" ]; then
  echo "Usage: $0 <iterations>"
  exit 1
fi
for ((i=1; i<=$1; i++)); do
  result=$(pi -p "@PRD.md @progress.txt
1. Find the highest-priority task and implement it.
2. Run your tests and type checks.
3. Update the PRD with what was done.
4. Append your progress to progress.txt.
5. Commit your changes.
ONLY WORK ON A SINGLE TASK.
If the PRD is complete, output <promise>COMPLETE</promise>.")
  echo "$result"
  if [[ "$result" == *"<promise>COMPLETE</promise>"* ]]; then
    echo "PRD complete after $i iterations."
    exit 0
  fi
done

Same as the Linux+pi variant — the only difference is where the shell comes from (Git Bash), so these files work verbatim on both. If pi ever says it can't find a shell, point it at Git Bash via shellPath in ~/.pi/agent/settings.json:

{ "shellPath": "C:\\Program Files\\Git\\bin\\bash.exe" }

Customizing the loop

Ralph is just a loop, so it's endlessly swappable:

  • Swap the task source. Instead of a local PRD, pull from GitHub Issues, Linear, or beads — the agent still picks what to work on.
  • Change the output. Instead of committing to main, create a branch + PR per iteration to triage a backlog.
  • Different loop types: test coverage (write tests until coverage hits target), linting (fix errors one by one), duplication (refactor jscpd clones), or entropy (clean up code smells).
  • Per-agent extras: pi can load skills/extensions that gate tools or checkpoint git commits; opencode supports custom agent modes and permissions config. Both work fine inside the same loop.

Original article: Getting Started with Ralph · Tips: 11 tips for AI coding with Ralph

Share:

Comments

No comments yet.