Cap 12: Ralph Wiggum Loop
Qué es Ralph Wiggum Loop
Ralph Wiggum Loop es un plugin para Claude Code que permite ejecutar tareas autónomas de larga duración. En lugar de que Claude se detenga y espere aprobación en cada paso, el loop mantiene al agente trabajando continuamente hasta completar la tarea.
El nombre viene del meme de Ralph Wiggum: “I’m in danger” — el agente trabaja de forma autónoma sin supervisión constante.
Cuándo usar
- Refactoring de múltiples archivos
- Migración de código entre frameworks
- Generación de tests para un módulo completo
- Tareas repetitivas que requieren muchos pasos
- Trabajo nocturno o en background
Cuándo NO usar
- Cambios críticos en producción
- Operaciones irreversibles (delete de datos)
- Tareas donde la revisión humana es esencial
- Primer uso con un codebase desconocido
Restricción del clasificador de auto mode
Antes de armar cualquier loop conviene conocer el límite más directamente aplicable a este capítulo: el clasificador de auto mode bloquea por defecto la acción de «lanzar un loop de agente autónomo sin aprobación humana ni sandbox», por ejemplo invocando --dangerously-skip-permissions o --no-sandbox. Desde v2.1.198 esa cobertura incluye también runners de terceros con el aislamiento o la aprobación desactivados (por ejemplo --yes-always).
Además, en Linux y macOS Claude Code se niega a arrancar con --dangerously-skip-permissions bajo root/sudo; la verificación solo se omite dentro de un sandbox reconocido. Para autonomía en contenedor, la documentación recomienda la configuración de dev container con usuario no-root.
La guía vigente ya no recomienda el antiguo “safe YOLO mode”: los tres mecanismos para trabajo autónomo son auto mode, allowlists vía /permissions y sandboxing OS-level vía /sandbox.
Instalación
Ralph Wiggum se instala como plugin de Claude Code:
# Instalar el plugin
claude plugin add ralph-loop
# Verificar instalación
claude plugin list
Nota para entornos gestionados: en equipos con managed settings, la instalación o ejecución del plugin puede estar restringida por claves managed-only como
allowedChannelPlugins,blockedMarketplaces,strictKnownMarketplaces,strictPluginOnlyCustomizationyallowManagedHooksOnly. Estas dos últimas bloquean hooks, skills, agents y servidores MCP provenientes de fuentes de usuario y proyecto, de modo que el plugin puede quedar inhabilitado aunque se instale.
Comandos disponibles
Las skills y comandos de un plugin usan el namespace plugin-name:skill-name, por lo que nunca colisionan con comandos personales o de proyecto. Los tres comandos llevan el prefijo del plugin:
| Comando | Descripción |
|---|---|
/ralph-loop:ralph-loop | Iniciar el loop autónomo |
/ralph-loop:cancel-ralph | Cancelar el loop activo |
/ralph-loop:help | Ver ayuda del plugin |
Recordatorio de precedencia: las skills se resuelven como enterprise (managed) > personal (~/.claude/skills/) > proyecto (.claude/skills/), y las de plugin quedan siempre bajo su namespace.
Uso básico
claude
> /ralph-loop:ralph-loop
# Claude te pedirá la tarea:
> "Migra todos los componentes de clase a functional components en src/components/"
# El loop comienza:
# 1. Claude analiza el scope
# 2. Crea un plan
# 3. Ejecuta paso a paso
# 4. Commitea cada cambio
# 5. Continúa hasta completar
Configuración
Permisos recomendados
Para tareas autónomas, es recomendable limitar lo que Claude puede hacer:
{
"permissions": {
"allow": [
"Read",
"Edit(**/src/**)",
"Bash(bun test *)",
"Bash(git add *)",
"Bash(git commit *)",
"Grep"
],
"deny": [
"Bash(rm -rf *)",
"Bash(git push *)",
"Bash(curl * | bash)"
]
}
}
Tres detalles del sistema de permisos que cambian cómo se lee ese bloque:
1. Solo Edit(path) y Read(path) se evalúan. Desde v2.1.210, Write(path), NotebookEdit(path) y Glob(path) se aceptan en la configuración pero nunca coinciden y generan un warning de arranque. Escribir Write(src/**) da la sensación de estar restringiendo escrituras a src/ sin hacerlo. Además, desde v2.1.208 un deny de Read sobre una ruta bloquea también Edit sobre esa ruta.
2. Un patrón de un solo segmento no cubre cualquier profundidad. Desde v2.1.214, Edit(src/**) coincide únicamente con el src del directorio de trabajo. En un monorepo, apps/app-web/src/... no quedaría autorizado. Para cubrir cualquier profundidad hay que escribir Edit(**/src/**). La misma regla aplica al campo if de los hooks.
3. Las rutas siguen la especificación gitignore con cuatro anclajes: //path es absoluta desde la raíz del filesystem, ~/path es home, /path es relativa al origen del settings (raíz del proyecto, ~/.claude, …) y path o ./path es relativa al cwd.
Cómo se evalúan realmente allow / ask / deny
El deny del bloque anterior no es un muro por sí solo. Conviene tener presente:
- Las reglas de permisos se FUSIONAN entre todos los scopes, no siguen la precedencia normal de settings. Un
denyen cualquier scope bloquea unallowde cualquier otro, incluido--allowedTools. - El orden es deny → ask → allow y la primera coincidencia decide. La especificidad no altera nada:
Bash(aws *)endenybloqueaBash(aws s3 ls)aunque esté enallow. No hay excepciones dentro de un deny. - Los operadores de shell requieren que cada subcomando coincida por separado.
Bash(safe-cmd *)no autorizasafe-cmd && other-cmd. Los separadores reconocidos son&&,||,;,|,|&,&y los saltos de línea. - Hay una lista interna, no configurable, de wrappers que se eliminan antes de evaluar:
timeout,time,nice,nohup,stdbuf, los builtinscommandybuiltin, elnoglobde zsh yxargssin flags. En cambio no se eliminan runners comonpx,docker exec,devbox run,mise execodirenv exec: un allow tipoBash(devbox run *)autoriza cualquier comando interno y evade eldeny. - El espacio antes del
*impone frontera de palabra:Bash(ls *)matcheals -lapero nolsof;Bash(ls*)matchea ambos. El sufijo:*equivale a*y solo se reconoce al final del patrón.
Auto mode
Auto mode (--permission-mode auto, o permissions.defaultMode) es el mecanismo recomendado para trabajo autónomo. Usa un modelo clasificador aparte que revisa cada acción antes de ejecutarla y bloquea escaladas de alcance, infraestructura no reconocida y acciones inducidas por contenido hostil.
claude --permission-mode auto -p "fix all lint errors"
Puntos operativos:
- Está generalizado en todos los planes y superficies (Anthropic API, Claude Platform on AWS, Amazon Bedrock, Google Cloud Agent Platform, Microsoft Foundry y sesiones de gateway).
- El clasificador corre por defecto en Claude Sonnet 5 desde v2.1.210 — no en el modelo de la sesión — y sus llamadas cuentan para el consumo de tokens. En un loop largo ese coste es continuo.
CLAUDE_CODE_ENABLE_AUTO_MODE=1era obligatoria entre v2.1.158 y v2.1.206; desde v2.1.207 no tiene efecto (se acepta solo por compatibilidad).defaultMode: "auto"se ignora si viene de.claude/settings.jsono.claude/settings.local.json(desde v2.1.142), para que un repo no se autoconceda auto mode. Debe ir en~/.claude/settings.jsono en managed settings.- Una organización puede bloquearlo con
permissions.disableAutoMode: "disable".
Sandbox OS-level
El segundo mecanismo es la clave sandbox de settings (o /sandbox en sesión). Corre sobre Seatbelt en macOS y bubblewrap + socat en Linux y WSL2; Windows nativo y WSL1 no están soportados.
{
"sandbox": {
"enabled": true,
"failIfUnavailable": true,
"network": {
"allowedDomains": ["registry.npmjs.org"]
}
}
}
Comportamiento a tener en cuenta antes de dejar un loop corriendo:
- Por defecto la escritura se limita al cwd y al
$TMPDIRde sesión, pero la lectura abarca todo el equipo salvo directorios denegados explícitamente. - Si el sandbox no arranca, por defecto se emite un warning y los comandos corren sin sandbox: falla abierto.
sandbox.failIfUnavailable: trueinvierte ese comportamiento y es lo indicado para un loop desatendido. - El aislamiento de red no pre-permite ningún dominio; el proxy pide aprobación en el primer uso y, desde v2.1.191, un «Yes» habilita el host para el resto de la sesión. Se pre-permite con
sandbox.network.allowedDomainso con reglasWebFetch(domain:...). - Las rutas de
sandbox.filesystem.*usan convenciones estándar y distintas a las de permisos:/tmp/buildes absoluta,~/es home y./o sin prefijo resuelve contra la raíz del proyecto. Aquí no se usa el//de Read/Edit.
Nota relacionada: los subagentes no son una frontera de seguridad — corren en el mismo proceso que la sesión padre y con la misma configuración de sandbox. Su valor es aislamiento de contexto y restricción de herramientas.
Límites de seguridad
# Limitar presupuesto
claude -p --max-budget-usd 10.00 "tarea..."
# Limitar turnos
claude -p --max-turns 50 "tarea..."
A esos límites configurables se suman frenos no configurables de auto mode, determinantes en un loop:
- 3 bloqueos seguidos o 20 bloqueos en total pausan auto mode y devuelven los prompts al usuario.
- Con
-pno hay usuario a quien preguntar: los bloqueos repetidos abortan la sesión.
Es decir, un loop nocturno lanzado con -p puede morir a mitad de camino si el clasificador acumula bloqueos. Si el trabajo es desatendido conviene: acotar el scope para no rozar acciones que el clasificador rechace, dejar allowlists explícitas y guardar progreso en disco tras cada paso para poder reanudar.
Flujo del loop
flowchart TD
I([Inicio]) --> AP[Analizar tarea y crear plan]
AP --> EJ[Ejecutar siguiente paso]
EJ --> VR["Verificar resultado<br/>tests + lint"]
VR --> ER{¿Error?}
ER -->|No| CM[Commitear cambio atómico]
ER -->|Sí| COR[Intentar corregir]
COR --> VR
ER -->|Irrecuperable| REP([Reportar al usuario])
CM --> MP{¿Más pasos?}
MP -->|Sí| EJ
MP -->|No| RF([Resumen final])
Mejores prácticas
- Definir scope claro: “todos los archivos en src/components/” es mejor que “todos los componentes”
- Tests como verificación: asegurar que hay tests que validen el trabajo
- Commits atómicos: el loop commitea cada cambio, facilitando revert
- Revisar al final: siempre revisar los cambios después del loop
- Limitar presupuesto: establecer límites de gasto y turnos
- Branch separado: trabajar en un branch dedicado, no en main
Los cuatro niveles de verificación
Tener tests no basta: hay que forzar que se ejecuten y que su resultado condicione el avance. La guía documenta cuatro niveles, de más blando a más duro:
- Pedir el check en el mismo prompt: “ejecuta
bun testy pega la salida antes de continuar”. - Fijarlo como condición de
/goal, que un evaluador separado revalida tras cada turno. - Un hook
Stopque bloquea el fin del turno hasta que el check pase. Límite crítico: Claude Code anula un hookStoptras 8 bloqueos consecutivos, así que diseñar el gate del loop asumiendo bloqueo indefinido es un antipatrón. - Un subagente verificador (o workflow dinámico) que intente refutar el resultado en una ventana de contexto limpia.
La regla que sostiene todo: «If you can’t verify it, don’t ship it.» Y pedir siempre evidencia — salida de tests, comando ejecutado y su resultado — en vez de aserciones de éxito del propio agente. Sin un check ejecutable, “looks done” es la única señal y el humano termina siendo el loop de verificación.
Un detalle sobre hooks: el filtro if es best-effort, así que para un allow o deny duro corresponde el sistema de permisos, no un hook. Los hooks son deterministas para efectos secundarios, no para enforcement.
Patrón de harness de larga duración
Para trabajo que excede una sesión, el patrón canónico separa dos agentes:
flowchart TD
INIT[Initializer agent] --> FJ["features.json<br/>todas marcadas failing"]
INIT --> SH["init.sh"]
INIT --> GIT[Repo git inicializado]
INIT --> PRG[Archivo de progreso]
FJ --> CA[Coding agent]
SH --> CA
GIT --> CA
PRG --> CA
CA --> ONE[Una feature por sesión]
ONE --> E2E[Test end-to-end]
E2E --> OK{¿Pasa?}
OK -->|Sí| CMT[Commit obligatorio + marcar completa]
OK -->|No| ONE
CMT --> NEXT{¿Quedan features?}
NEXT -->|Sí| RESET["Reset de contexto<br/>con artefactos de handoff"]
RESET --> CA
NEXT -->|No| FIN([Fin])
Reglas del patrón:
- Initializer agent: produce una lista de features en JSON marcadas como failing, un
init.sh, un repo git y un archivo de progreso. - Coding agent: trabaja una feature por sesión, con commit obligatorio y un test end-to-end que debe pasar antes de marcar la feature como completa.
- Usar JSON y no Markdown para el tracking: el modelo lo sobrescribe menos.
- «La compactación no es suficiente» por sí sola. Conviene un reset de contexto con artefactos de handoff en lugar de depender solo de
/compact. - Separar generador de evaluador: afinar un evaluador escéptico independiente es mucho más tratable que hacer que un generador critique su propio trabajo.
Antipatrones nombrados:
- Sobre-especificar las specs técnicas por adelantado: produce errores en cascada.
- Auto-evaluación de un solo agente.
- Asumir el harness estático: cuando el modelo mejora, partes del andamiaje dejan de aportar. Hay que podar el harness.
Alternativa: Print mode con scripting
Si no quieres usar el plugin, puedes simular un loop con print mode:
# Script de loop básico
claude -p --max-turns 20 \
"Migra los componentes de clase a functional components.
Trabaja uno por uno. Commitea cada cambio.
Ejecuta tests después de cada cambio."
--bare para CI
claude -p --bare --max-turns 20 "tarea..."
--bare omite hooks, skills, plugins, MCP, auto memory y CLAUDE.md. Es lo recomendado para CI y para el SDK, y será el default de -p en el futuro. Ten presente que con --bare el plugin Ralph Wiggum tampoco se carga: el loop queda a cargo del prompt y del script.
Salida estructurada
claude -p --json-schema ./resultado.schema.json "tarea..."
--json-schema produce salida estructurada en el campo structured_output, útil para que el script decida si continuar. Alternativamente, --output-format json encadenado a otro comando:
claude -p "<prompt>" --output-format json | your_command
Notas de comportamiento en headless: stream-json requiere --verbose (y --include-partial-messages para tokens), el stdin por pipe está limitado a 10MB desde v2.1.128, y SIGTERM sale con código 143.
Advertencia de seguridad: la verificación de trust está desactivada al correr con
-p. Un pipeline CI no conserva las mismas barreras de confianza que una sesión interactiva: no hay diálogo de workspace trust ni de servidores MCP nuevos. Combínalo con sandbox y allowlists explícitas.
Fan-out para migraciones
El patrón documentado para migraciones masivas es generar la lista de archivos y loopear una invocación por archivo, probando primero con 2 o 3 archivos antes de lanzar el set completo:
for file in $(git ls-files 'src/components/*.tsx' | head -3); do
claude -p "Migrate $file from class component to a functional component.
Run the tests. Return OK or FAIL." \
--allowedTools "Edit,Bash(git commit *)"
done
--allowedTools usa la misma sintaxis de las reglas de permisos, así que el espacio en Bash(git commit *) importa. Recuerda que un deny de cualquier scope gana sobre --allowedTools.
Background y worktrees
Para el caso de “trabajo nocturno o en background”:
# Sesión en background
claude --bg "tarea larga..."
# Sesión aislada en un worktree dedicado
claude --worktree feature-auth
claude -w feature-auth
Gestión de agentes en background:
claude agents # listar
claude attach # adjuntarse a uno
claude stop # detener
claude respawn # relanzar
claude logs # ver logs
Los worktrees permiten sesiones paralelas sin que los loops se pisen entre sí, y encajan con la recomendación de trabajar siempre en un branch dedicado.
Siguiente: CLI Reference