Ralph Wiggum Loop

Ralph Wiggum loop pattern for multi-step task completion with Stop hook.

ammarakk updated 5mo ago
Claude CodeGeneric
View source ↗
---
description: Ralph Wiggum loop pattern for multi-step task completion with Stop hook.
---

# COMMAND: Ralph Wiggum Loop (Multi-Step Task Iteration)

## CONTEXT

The user needs to implement a "Ralph Wiggum Loop" pattern that:

- Keeps Claude iterating until multi-step tasks are complete
- Uses a Stop hook pattern to detect task completion
- Prevents premature termination of complex workflows
- Integrates with the reasoning engine

**Name Origin:** Named after Ralph Wiggum's "I'm winning!" meme - the loop keeps going until it actually wins (completes the task).

## YOUR ROLE

Act as an AI agent architect with expertise in:

- Multi-step task orchestration
- State persistence and tracking
- Loop termination conditions
- Agent hook systems

## OUTPUT STRUCTURE

Create a Ralph Wiggum Loop implementation with:

1. **Stop Hook Pattern** for completion detection
2. **Task State Tracking** with checkpoints
3. **Iteration Logic** with smart stopping
4. **Integration Examples** for reasoning engine
5. **Setup Instructions** for various use cases

## Step 1: Stop Hook Pattern

The Ralph Wiggum Loop uses a "Stop Hook" that checks if work is truly complete.

```python
#!/usr/bin/env python3
"""
Ralph Wiggum Loop - Keep iterating until multi-step tasks are complete

This pattern prevents premature task completion by maintaining state
and checking for actual completion before stopping.
"""

import asyncio
import json
import logging
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger("RalphWiggumLoop")


class TaskState:
    """Track the state of a multi-step task."""

    def __init__(self, task_id: str, total_steps: int, state_dir: Path):
        """
        Initialize task state.

        Args:
            task_id: Unique task identifier
            total_steps: Number of steps in the task
            state_dir: Directory to store state files
        """
        self.task_id = task_id
        self.total_steps = total_steps
        self.state_dir = state_dir
        self.state_file = state_dir / f"{task_id}.json"

        self.completed_steps: List[str] = []
        self.current_step: Optional[str] = None
        self.failed_steps: List[str] = []
        self.iterations = 0
        self.max_iterations = total_steps * 3  # Safety limit

        self._load_state()

    def _load_state(self):
        """Load existing state if available."""
        if self.state_file.exists():
            try:
                data = json.loads(self.state_file.read_text())
                self.completed_steps = data.get('completed_steps', [])
                self.current_step = data.get('current_step')
                self.failed_steps = data.get('failed_steps', [])
                self.iterations = data.get('iterations', 0)
            except Exception as e:
                logger.warning(f"Could not load state: {e}")

    def _save_state(self):
        """Save current state to file."""
        self.state_dir.mkdir(parents=True, exist_ok=True)

        data = {
            'task_id': self.task_id,
            'total_steps': self.total_steps,
            'completed_steps': self.completed_steps,
            'current_step': self.current_step,
            'failed_steps': self.failed_steps,
            'iterations': self.iterations,
            'updated_at': datetime.now().isoformat()
        }

        self.state_file.write_text(json.dumps(data, indent=2))

    def start_step(self, step_name: str):
        """Mark a step as started."""
        self.current_step = step_name
        self._save_state()
        logger.info(f"[{self.task_id}] Starting step: {step_name}")

    def complete_step(self, step_name: str):
        """Mark a step as completed."""
        if step_name not in self.completed_steps:
            self.completed_steps.append(step_name)

        if step_name in self.failed_steps:
            self.failed_steps.remove(step_name)

        self.current_step = None
        self._save_state()
        logger.info(f"[{self.task_id}] Completed step: {step_name} ({len(self.completed_steps)}/{self.total_steps})")

    def fail_step(self, step_name: str, error: str):
        """Mark a step as failed."""
        if step_name not in self.failed_steps:
            self.failed_steps.append(step_name)

        self.current_step = None
        self._save_state()
        logger.warning(f"[{self.task_id}] Failed step: {step_name} - {error}")

    def is_complete(self) -> bool:
        """Check if all steps are completed."""
        return len(self.completed_steps) >= self.total_steps

    def should_continue(self) -> bool:
        """Check if loop should continue iterating."""
        self.iterations += 1
        self._save_state()

        if self.is_complete():
            logger.info(f"[{self.task_id}] Task complete! ✓")
            return False

        if self.iterations >= self.max_iterations:
            logger.warning(f"[{self.task_id}] Max iterations reached ({self.max_iterations})")
            return False

        return True

    def get_next_step(self, all_steps: List[str]) -> Optional[str]:
        """Get the next incomplete step."""
        for step in all_steps:
            if step not in self.completed_steps:
                return step
        return None

    def get_progress(self) -> Dict[str, Any]:
        """Get current progress status."""
        return {
            'task_id': self.task_id,
            'progress': len(self.completed_steps) / self.total_steps * 100,
            'completed': len(self.completed_steps),
            'total': self.total_steps,
            'current': self.current_step,
            'failed': len(self.failed_steps),
            'iterations': self.iterations
        }


class RalphWiggumLoop:
    """
    Main loop orchestration for multi-step tasks.

    Implements the Stop Ho

Maintain Ralph Wiggum Loop?

Let people know it's listed here — add the badge (live metrics, light/dark aware) or a plain link to your README or docs.

[Ralph Wiggum Loop on getagentictools](https://getagentictools.com/loops/ammarakk-command-ralph-wiggum-loop-multi-step-task-iteration?ref=badge)
npx agentictools info loops/ammarakk-command-ralph-wiggum-loop-multi-step-task-iteration

The second line is the CLI lookup for this page — handy in READMEs and docs.