# Ralph Loop Setup Manual

## Purpose

This document explains exactly how to recreate the Ralph Loop task automation system we set up in this OpenClaw workspace. The goal is to let OpenClaw autonomously work through a structured task list one task at a time, write deliverables to a defined output location, and allow the operator to start, stop, and check the loop from Telegram.

This version is written as an implementation manual you can save, email, or hand to another operator.

---

## What We Built

We created five parts:

1. **A structured task list** in `tasks/TASKS.md`
2. **An output folder** at `output/`
3. **A loop runner script** at `ralph.sh`
4. **A loop controller script** at `ralphctl.sh`
5. **A workspace instruction file** at `.openclaw/INSTRUCTIONS.md`
6. **Telegram-invocable Ralph commands** via workspace skills:
   - `start-ralph`
   - `stop-ralph`
   - `ralph-status`

Together, these create a lightweight autonomous execution loop for OpenClaw.

---

## How the System Works

### 1. Task file drives all work

The agent reads `tasks/TASKS.md` at the start of each run.

Each task should:
- live in the correct section (`Active`, `Waiting`, `Paused`, `Done`)
- include a clear status marker
- include a final output path in the `output/` directory
- define goal, next step, blockers, and done criteria

### 2. Allowed task states

Use these markers consistently:

- `[ ] NOT STARTED`
- `[~] IN PROGRESS`
- `[P] PAUSED`
- `[x] DONE`

### 3. Agent behavior per run

On each fresh run, the agent should:
1. read `tasks/TASKS.md`
2. inspect the `output/` directory
3. pick exactly one task from `## Active` marked either `NOT STARTED` or `IN PROGRESS`
4. work only that task
5. save the deliverable to the output path listed for that task
6. validate the deliverable before marking the task `DONE`
7. update the task file before exiting

### 4. Loop behavior

The `ralph.sh` script repeatedly calls OpenClaw.

To prevent runaway token spend, it stops automatically after **50 iterations**.

It also prints progress logs such as:

`Starting iteration 5 of 50`

### 5. Control behavior

The safest version uses a state file plus a controller script.

Ralph control state lives in:
- `/home/clawbot/.openclaw/workspace/.openclaw/ralph-state.json`

The operator controls Ralph through:
- `bash ralphctl.sh start`
- `bash ralphctl.sh stop`
- `bash ralphctl.sh status`
- `bash ralphctl.sh logs`

This avoids relying on fragile Telegram-native skill command execution for process control.

---

## Files Created or Updated

### A. `tasks/TASKS.md`

This is the main task file.

Example structure:

```md
# TASKS

## Active

- [~] IN PROGRESS Weekly NPS survey automation
  - Goal: create an n8n workflow that summarizes weekly NPS feedback and sends a Telegram-ready draft memo every Monday morning
  - Status: planning complete, build starting now
  - Next step: create the workflow safely in n8n and test manually
  - Blockers: none
  - Done when: workflow exists in n8n, runs on schedule, parses both survey sources correctly, and sends the expected Telegram draft
  - Output: `/home/clawbot/.openclaw/workspace/output/weekly-nps-survey-automation.md`

- [ ] NOT STARTED Weekly review automation
  - Goal: set up a weekly review that ships every Friday at 9am CT with live data, shipped items, in-progress carryover, stale items, cron health, metrics, and next-week focus
  - Status: planning received, build not started
  - Next step: create the `weekly-review` skill and attach a cron job
  - Blockers: none
  - Done when: skill exists, cron is scheduled for Fridays 9am CT, and a test run produces the expected formatted output
  - Output: `/home/clawbot/.openclaw/workspace/output/weekly-review-automation.md`

## Waiting

## Paused

- [P] PAUSED Ag market dashboard
  - Goal: deliver a working review site with real commodity, hay, cattle, and recent-news data
  - Status: paused by Shawn for now
  - Next step: resume later with regional market-source logic for KC grain/cattle and OK/Lubbock cotton
  - Blockers: paused by user
  - Done when: dashboard shows correct current prices, distinct 12-month trend lines, visible hay prices, and relevant recent news
  - Output: `/home/clawbot/.openclaw/workspace/output/ag-market-dashboard.md`

## Done
```

---

### B. `.openclaw/INSTRUCTIONS.md`

This file tells OpenClaw exactly how to behave in each fresh run.

Recommended content:

```md
# Ralph Loop Instructions

On every fresh run in this workspace:

1. Read `tasks/TASKS.md`.
2. Inspect the `/home/clawbot/.openclaw/workspace/output` directory before doing any work.
3. Pick exactly one task from the `## Active` section marked either `[ ] NOT STARTED` or `[~] IN PROGRESS`.
4. Do not select tasks marked `[P] PAUSED` or `[x] DONE`.
5. Work on only that single task during the session.
6. Save the task's deliverable to the exact output path listed under that task.
7. Before changing a task to `[x] DONE`, verify that the output file:
   - exists
   - is not empty
   - matches the task's stated goal and done criteria
8. If work has begun but is not finished, mark the task `[~] IN PROGRESS` and update its status or next step.
9. If the task is intentionally halted awaiting a future resume, move it to the `## Paused` section and mark it `[P] PAUSED`.
10. Update `tasks/TASKS.md` with the new status before exiting the session.

Never pick more than one task in a single run.
```

---

### C. `ralph.sh`

This is the main loop runner.

Recommended content:

```bash
#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MAX_ITERATIONS=50
PID_FILE="$ROOT_DIR/.openclaw/ralph.pid"
LOG_FILE="$ROOT_DIR/.openclaw/ralph.log"

cd "$ROOT_DIR"
mkdir -p "$ROOT_DIR/.openclaw"
echo $$ > "$PID_FILE"
trap 'rm -f "$PID_FILE"' EXIT

for ((i=1; i<=MAX_ITERATIONS; i++)); do
  echo "Starting iteration ${i} of ${MAX_ITERATIONS}" | tee -a "$LOG_FILE"
  openclaw agent --message "Read tasks/TASKS.md and the output directory, pick exactly one active task marked [ ] NOT STARTED or [~] IN PROGRESS, work it until you either complete it or reach a clear blocking point, validate any output file before marking the task done, update the task file, then exit." | tee -a "$LOG_FILE"
done

echo "Reached iteration limit (${MAX_ITERATIONS}). Exiting to prevent token drain." | tee -a "$LOG_FILE"
```

Make it executable:

```bash
chmod +x ralph.sh
```

---

### D. `ralphctl.sh`

This is the control script for enabling, disabling, starting, stopping, checking, and viewing logs.

Recommended content:

```bash
#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
STATE_FILE="$ROOT_DIR/.openclaw/ralph-state.json"
PID_FILE="$ROOT_DIR/.openclaw/ralph.pid"
LOG_FILE="$ROOT_DIR/.openclaw/ralph.log"

cd "$ROOT_DIR"
mkdir -p "$ROOT_DIR/.openclaw"

is_running() {
  [[ -f "$PID_FILE" ]] && kill -0 "$(cat "$PID_FILE")" 2>/dev/null
}

write_state() {
  local enabled="$1"
  local source="$2"
  printf '{\n  "enabled": %s,\n  "updatedAt": "%s",\n  "source": "%s"\n}\n' "$enabled" "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "$source" > "$STATE_FILE"
}

case "${1:-}" in
  start)
    write_state true "ralphctl:start"
    if is_running; then
      echo "Ralph enabled. Loop already running with PID $(cat "$PID_FILE")"
      exit 0
    fi
    nohup bash "$ROOT_DIR/ralph.sh" >> "$LOG_FILE" 2>&1 &
    sleep 1
    if is_running; then
      echo "Ralph enabled and loop started with PID $(cat "$PID_FILE")"
    else
      echo "Ralph enabled but loop failed to start"
      exit 1
    fi
    ;;
  stop)
    write_state false "ralphctl:stop"
    if is_running; then
      kill "$(cat "$PID_FILE")"
      sleep 1
      rm -f "$PID_FILE"
      echo "Ralph disabled and loop stopped"
    else
      echo "Ralph disabled. Loop was not running"
    fi
    ;;
  status)
    if [[ -f "$STATE_FILE" ]]; then
      cat "$STATE_FILE"
      echo
    else
      echo '{"enabled": false, "source": "missing-state"}'
      echo
    fi

    if is_running; then
      echo "process=running pid=$(cat "$PID_FILE")"
    else
      echo "process=stopped"
    fi
    ;;
  logs)
    if [[ -f "$LOG_FILE" ]]; then
      tail -n 50 "$LOG_FILE"
    else
      echo "No Ralph log file yet"
    fi
    ;;
  enable)
    write_state true "ralphctl:enable"
    echo "Ralph enabled"
    ;;
  disable)
    write_state false "ralphctl:disable"
    echo "Ralph disabled"
    ;;
  *)
    echo "Usage: bash ralphctl.sh {start|stop|status|logs|enable|disable}"
    exit 1
    ;;
esac
```

Make it executable:

```bash
chmod +x ralphctl.sh
```

---

### E. `output/`

Create the output directory if it does not already exist:

```bash
mkdir -p output
```

Every task should point to a specific file path inside this folder.

---

### F. Ralph Telegram command skills

We created three workspace skills so Ralph can be controlled from Telegram through native OpenClaw skill commands.

Skill folders:

- `skills/start-ralph/`
- `skills/stop-ralph/`
- `skills/ralph-status/`

Each `SKILL.md` is set up as a user-invocable command.

Example pattern:

```md
---
name: start-ralph
description: Start Ralph.
user-invocable: true
command-dispatch: tool
command-tool: exec
command-arg-mode: raw
---

Runs the Ralph loop start command.

Tool input:
`bash /home/clawbot/.openclaw/workspace/ralphctl.sh start`
```

Equivalent commands for stop and status should point to:

```bash
bash /home/clawbot/.openclaw/workspace/ralphctl.sh stop
bash /home/clawbot/.openclaw/workspace/ralphctl.sh status
```

After creating or changing these skills, restart the gateway so Telegram refreshes native command registration.

Restart command:

```bash
openclaw gateway restart
```

Then test these in Telegram:

- `/start_ralph`
- `/stop_ralph`
- `/ralph_status`

---

## Step-by-Step Rebuild Instructions

Follow these steps in order.

### Step 1: Create the output folder

```bash
mkdir -p /home/clawbot/.openclaw/workspace/output
```

### Step 2: Update the task file

Open `tasks/TASKS.md` and do the following:
- prepend every task with one of the state markers
- move paused items into `## Paused`
- ensure every task has an `Output:` line with a concrete file path in `output/`

### Step 3: Create the workspace instructions file

Create:

`/home/clawbot/.openclaw/workspace/.openclaw/INSTRUCTIONS.md`

Paste in the instructions shown above.

### Step 4: Create the main Ralph loop script

Create:

`/home/clawbot/.openclaw/workspace/ralph.sh`

Paste in the `ralph.sh` script shown above.

Then run:

```bash
chmod +x /home/clawbot/.openclaw/workspace/ralph.sh
```

### Step 5: Create the Ralph control script

Create:

`/home/clawbot/.openclaw/workspace/ralphctl.sh`

Paste in the `ralphctl.sh` script shown above.

Then run:

```bash
chmod +x /home/clawbot/.openclaw/workspace/ralphctl.sh
```

### Step 6: Create the Telegram command skills

Create these directories:

```bash
mkdir -p /home/clawbot/.openclaw/workspace/skills/start-ralph
mkdir -p /home/clawbot/.openclaw/workspace/skills/stop-ralph
mkdir -p /home/clawbot/.openclaw/workspace/skills/ralph-status
```

Add a `SKILL.md` file in each one using the examples above.

### Step 7: Restart the gateway

```bash
openclaw gateway restart
```

### Step 8: Test from Telegram

Try these commands:

```text
/start_ralph
/ralph_status
/stop_ralph
```

---

## Suggested Prompt for Recreating This With an Agent

If someone wants to ask OpenClaw to build this from scratch, they can use this prompt:

```text
I want to implement a Ralph Loop to automate my current task list autonomously.

Do not delete my existing tasks; instead, perform the following setup steps immediately:
1. Refactor Task List: Open my existing task file and prepend a status marker to every task. Use explicit markers for Not Started, In Progress, Paused, and Done. Ensure each task has a specific file path defined in an /output directory for its final result.
2. Create Automation Script: Create a shell script named ralph.sh in the root directory. This script must:
   - run a loop that invokes the OpenClaw agent against this workspace
   - include a loop counter that kills the process after 50 iterations to prevent token drain
   - provide a console log showing the current iteration number
3. Create Controller Script: Create ralphctl.sh that can start, stop, report status, and show logs for Ralph.
4. Define System Instructions: Create or update a .openclaw instruction file that tells the agent to:
   - read tasks/TASKS.md and the /output folder at the start of every fresh run
   - pick exactly one eligible active task
   - validate outputs before marking a task done
   - update the task file and output before exiting
5. Initialize: Create the /output folder if it does not exist.
6. Create Telegram-native Ralph commands so I can run start Ralph, stop Ralph, and Ralph status through slash-style Telegram commands.
7. Commit the changes in git and summarize what was created.
```

---

## Suggested Prompt for Updating an Existing Ralph Loop

```text
Update my Ralph Loop implementation to use these task states: [ ] NOT STARTED, [~] IN PROGRESS, [P] PAUSED, [x] DONE.
Then update my existing task file to match those states.
Also create Telegram command controls for start, stop, and status, and make sure the command registration will refresh after a gateway restart.
```

---

## Operating Notes and Caveats

1. **Message-based Ralph control can be implemented by instruction routing** using exact phrases like `start ralph`, `stop ralph`, and `ralph status`.
2. **Actual shell execution from chat still depends on OpenClaw command/tool policy.** If chat-triggered exec is blocked, the intent may be recognized but the command still cannot run.
3. **Do not let Ralph pick paused tasks.** Restrict selection to the `## Active` section.
4. **Every task needs an output path.** Without one, validation becomes unreliable.
5. **Do not mark tasks done without checking the file exists and is non-empty.**
6. **The 50-iteration cap matters.** It is the main protection against runaway token use.
7. **This is a lightweight loop, not a job scheduler.** It is intentionally simple and easy to inspect.

---

## Guardrails Built Into This Version

This version now includes:
- enabled/disabled state control via `.openclaw/ralph-state.json`
- eligible-task detection before agent execution
- automatic exit after repeated no-task or no-progress passes
- a configurable iteration cap
- a configurable idle-pass limit in `.openclaw/ralph-config.json`

## Recommended Enhancements

Future improvements could include:
- only running Ralph during defined hours
- skipping tasks that require human approvals
- recording per-task run history
- sending completion alerts automatically
- adding a stronger lock model to prevent duplicate Ralph processes
- making Telegram commands more conversational through a plugin or custom command layer

---

## Final Summary

The Ralph Loop pattern is a simple autonomous execution framework for OpenClaw:
- task list defines the queue
- output files define deliverables
- instructions constrain behavior
- loop script keeps runs going
- controller script manages execution
- Telegram commands provide remote control

Used carefully, this gives you a practical “work through my backlog one item at a time” operating system inside an OpenClaw workspace.
