EL COMANDO /goal
Un comando, ocho módulos, ~25 minutos. Define la línea de meta, vete — y entiende qué está corriendo por debajo.
Por qué una clase entera sobre un comando
/goal parece azúcar sintáctico — escribes una condición, Claude sigue trabajando hasta que la condición se cumple — pero el movimiento arquitectónico debajo es significativo: el agente haciendo el trabajo ya no es el agente que decide que está listo. Un segundo modelo más pequeño juzga la condición en cada turno. Acierta con la condición y has convertido un loop de chat en un contrato.
Qué vas a aprender
- La sintaxis exacta, incluyendo aliases y el presupuesto de 4.000 caracteres para la condición.
- Cuándo
/goalle gana a/loopy a un Stop hook — y cuándo no. - Los tres ingredientes de una condición que sobrevive a más de 20 turnos.
- Cómo el evaluator realmente decide "listo", y qué nunca puede ver.
/goalheadless en CI, más los anti-patrones que queman dinero silenciosamente.
Construido contra
Claude Code v2.1.143. El comando llegó en v2.1.139 (mayo de 2026). El diálogo de trust debe haberse aceptado en el workspace, ya que /goal es azúcar con alcance de sesión encima del sistema de hooks.
Qué es /goal
fundamentosTL;DR — /goal <condición> define una condición de finalización con alcance de sesión. Después de cada turno, un modelo pequeño y rápido juzga si la condición se cumple. Si no, Claude toma otro turno — automáticamente, sin necesidad de un "sigue" tuyo.
▸ Los tres usos, mismo comando
/goal <condición>— define (o reemplaza) el goal activo. Un turno empieza inmediatamente, la propia condición se vuelve la directiva./goal(sin args) — muestra el estado: condición, tiempo de ejecución, turnos evaluados, gasto en tokens, última razón del evaluator./goal clear— elimina el goal activo. Aliases:stop · off · reset · none · cancel.
▸ La intuición arquitectónica
Esa separación es lo que hace que el comando valga la pena. El worker se queda optimista ("ya casi"); el evaluator es escéptico ("dijiste que los tests pasan — muéstrame"). Dos roles, dos modelos, un loop.
▸ Un primer goal
/goal todos los tests en test/auth pasan y el paso de lint está limpio Mientras el goal está activo, un indicador ◎ /goal active muestra cuánto tiempo lleva corriendo. La condición puede tener hasta 4.000 caracteres — suficiente para detallar restricciones.
/goal vs /loop vs Stop Hook vs Modo Auto
fundamentosTL;DR — cuatro mecanismos mantienen una sesión corriendo entre prompts. Elige por qué debe iniciar el siguiente turno y quién decide que está listo.
▸ La comparación de cuatro
▸ Cuándo usar cada uno
- /goal — trabajo sustancial con un estado final verificable, donde el evaluator puede leer la prueba en el transcript. Migración hasta que los tests pasen. Dividir un archivo hasta que cada parte esté bajo un límite de tamaño.
- /loop — polling programado. "Revisa el deploy cada 5 min." "Vigila una cola de PR." No es una condición de finalización; es una cadencia de re-ejecución.
- Stop hook — cuando quieres un check determinístico (comando shell, exit code) o lógica de prompt customizada que vive en los settings y aplica a toda la sesión.
- Modo auto — combina con cualquiera de los anteriores cuando no quieres prompts de permiso por herramienta. Crítico para uso sin supervisión; ortogonal a "cuándo se para el loop".
Anatomía de una buena condición
prácticaTL;DR — una condición que sobrevive a 20+ turnos tiene tres ingredientes: un estado final medible, un check declarado que Claude puede ejecutar, y restricciones que nombran lo que no puede cambiar.
▸ Ingrediente 1 — Estado final medible
Una cantidad observable que pasa de "todavía no" a "sí" exactamente una vez. No una intuición. Ejemplos que funcionan: exit code de una ejecución de tests, conteo de archivos, longitud de cola, "git status está limpio". Ejemplos que fallan: "el código está bien", "los usuarios estarán contentos", "production-ready".
▸ Ingrediente 2 — Check declarado
Cómo Claude debe probar el estado final. El evaluator lee el transcript; si la prueba no está en el transcript, el goal se atasca. Detalla el comando que Claude debe ejecutar: "npm test sale con exit 0", "jq . config.json tiene éxito", "el directorio build/ contiene index.html".
▸ Ingrediente 3 — Restricciones
Lo que no puede cambiar mientras se alcanza el estado final. Sin esto, el worker puede "arreglar" tests borrándolos o hacer downgrade de una dep en vez de arreglar el bug.
/goal todos los tests en test/auth pasan (npm test --silent sale con exit 0),
el diff solo toca src/auth/* y test/auth/*,
y package.json queda sin cambios. ▸ El presupuesto de 4.000 caracteres
La condición puede ser larga — úsala. Una condición de dos párrafos con restricciones típicamente rinde mejor que una de cinco palabras porque el evaluator tiene más pistas para juzgar. A partir de ~1.000 caracteres el worker también la lee como una mini spec.
Inmersión → Master Class §4 Permisos (el emparejamiento de seguridad)Bueno vs Malo — una galería
prácticaTL;DR — lee estos lado a lado. El patrón se revela más rápido que cualquier regla.
▸ Tests
✓ /goal todos los tests en test/auth pasan (npm test --silent sale con exit 0)
✗ /goal arregla los tests ▸ Migración
✓ /goal cada call site de db.queryOld ha sido reemplazado por db.queryV2,
bun tsc --noEmit sale con exit 0, ningún .ts fuera de src/db toca db.queryOld
✗ /goal migra las llamadas a la base de datos ▸ Limpieza
✓ /goal CHANGELOG.md tiene una entrada por PR mergeado en los últimos 7 días
(verificado por gh pr list --state merged --search "merged:>=2026-05-10");
cada entrada tiene fecha, tipo y enlace.
✗ /goal actualiza el changelog ▸ Refactor
✓ /goal src/parser.ts ha sido dividido de modo que cada archivo resultante tiene ≤200 líneas,
todos los callers compilan, bun test sale con exit 0, ninguna nueva dep en package.json
✗ /goal divide el parser en archivos más pequeños ▸ Backlog
✓ /goal cada issue con label "good-first" está cerrada,
con label "blocked", o tiene un comentario mío explicando el siguiente paso.
Para después de 30 turnos aunque no esté lista.
✗ /goal haz triaje de las issues ▸ El patrón
Cada ejemplo "bueno" nombra una cosa para contar, un comando para ejecutar y lo que queda intacto. Cada ejemplo "malo" nombra un verbo y confía en que el worker defina "listo".
Acotando la ejecución
prácticaTL;DR — no hay tope built-in en una sesión de /goal. Añade una cláusula de parada en la propia condición, o quemarás dinero mientras duermes.
▸ Built-in: nada
Un goal sigue corriendo hasta que el evaluator dice "sí" o tú ejecutas /goal clear. No hay max-turn por defecto, no hay tope de presupuesto por defecto, no hay timeout por defecto.
▸ Tres formas de acotar
- Inline en la condición. Añade
"o para después de 20 turnos"o"o para después de 1 hora". El worker reporta progreso en cada turno; el evaluator lee el progreso y juzga la cláusula. - Topes headless. Al correr con
-p, añade--max-turns Ny--max-budget-usd Xa nivel de CLI. Estos son aplicados por el propio Claude Code, no por el evaluator. - Kill switch externo. Ctrl+C en modo interactivo, o matar el proceso en headless. Brusco pero confiable.
▸ Un goal acotado en la práctica
/goal flake-2-de-5 en test/network/* está resuelto
(ejecutando cada suite 5× y mostrando 5/5 passes en el output),
o para después de 25 turnos. Restricción: no tocar test infra
a menos que el setup de un único archivo de test sea la causa. ▸ Una razón real para poner un tope
Sin tope, un goal que no puede converger iterará para siempre, cada turno costando dinero real. El autor de la herramienta comunitaria pre-oficial claude-goal puso por defecto 500 continuaciones como protección contra runaway — lo que te dice lo malo que puede llegar a ser.
Cómo funciona el evaluator
internosTL;DR — /goal es un wrapper sobre un Stop hook basado en prompt, con alcance de sesión. Después de cada turno, la condición + transcript se envían al modelo pequeño y rápido configurado (por defecto: Haiku). Devuelve sí/no + una razón corta. Esa es toda la máquina.
▸ El loop, en detalle
▸ Qué PUEDE ver el evaluator
- Todo mensaje de usuario y mensaje de assistant en el transcript de la sesión.
- La condición que definiste.
- Llamadas a tools y sus resultados, incluyendo stdout y exit codes que Claude ya ejecutó.
▸ Qué NO PUEDE ver el evaluator
- Archivos en disco que aún no ve en el transcript.
- Cualquier cosa que Claude no imprimió. Un test que pasa silenciosamente no cuenta hasta que Claude muestre el exit code.
- Estado vivo. El evaluator no puede abrir un navegador, no puede pegarle a una API, no puede llamar tools.
▸ El coste
Los tokens del evaluator se cobran en el tier de modelo pequeño y rápido (clase Haiku) y típicamente son insignificantes comparados con el turno principal. Concretamente: una sesión de goal de 20 turnos que cuesta $4 en tokens de worker puede añadir $0.05 en tokens de evaluator.
▸ La nota de implementación que importa
Como /goal ES un Stop hook, no está disponible cuando disableAllHooks está activo o cuando allowManagedHooksOnly lo bloquea. El diálogo de trust debe estar aceptado para el workspace. El comando te dice por qué no está disponible en lugar de silenciosamente no hacer nada.
/goal headless
producciónTL;DR — pasa /goal <condición> como prompt a claude -p y todo el loop corre en una sola invocación. Combínalo con --max-turns + --max-budget-usd + modo auto para tener un agente sin supervisión con techos duros.
▸ La forma headless
claude -p "/goal CHANGELOG.md tiene una entrada por PR mergeado esta semana"
--permission-mode bypassPermissions
--max-turns 30
--max-budget-usd 1.50
--output-format json ▸ Un paso real de GitHub Actions
- name: Triaje nocturno de issues
run: |
claude -p \
--permission-mode bypassPermissions \
--max-turns 40 \
--max-budget-usd 2.00 \
--output-format json \
"/goal cada issue con label 'needs-triage' está
(a) con label de uno de {bug, feature, question, won't-fix},
(b) cerrada con una razón, o
(c) comentada con una pregunta de seguimiento al autor.
Para después de 40 turnos aunque no esté lista."
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} ▸ Comportamiento de resume
Si una sesión termina con un goal todavía activo, --resume o --continue restaura la condición. El conteo de turnos, el timer, y la baseline de tokens se resetean en el resume. Un goal ya achieved no se restaura.
▸ Las tres reglas de disciplina
- Siempre define
--max-turnsY--max-budget-usd. Headless sin topes es un runaway disfrazado de workflow. - Trata el envelope
--output-format jsoncomo un contrato — falla el paso del CI si el JSON está mal formado en vez de dejar que el consumidor downstream consuma basura. - Usa el modo
bypassPermissionssolo en CI, nunca en una estación de trabajo real. Los sandboxes de CI son efímeros; el~de tu laptop no.
Limitaciones & Anti-patrones
producciónTL;DR — cinco modos de fallo queman dinero o publican mal código. Lee esto antes de definir tu primer goal de larga duración.
▸ #1 — La condición no es observable
"Deja la app production-ready" nunca puede probarse en un transcript. El evaluator no tiene noción de "ready"; solo puede revisar lo que Claude imprimió. Síntoma: cada turno el evaluator dice "todavía no" y el loop corre por siempre. Solución: reescríbelo como una lista de estados finales contables ("0 errores de lint, 0 errores de tipo, todos los tests pasan, >80% de cobertura de línea medida por vitest --coverage").
▸ #2 — El worker "arregla" borrando
"Todos los tests pasan" puede satisfacerse borrando los tests que fallan. Síntoma: goal se cumple en 3 turnos, la suite está vacía. Solución: añade una restricción — "ningún archivo de test es borrado; git diff --name-only test/ muestra solo modificaciones, no borrados".
▸ #3 — Goals compuestos abruman al worker
"Migra el DB Y refactoriza el parser Y escribe la doc" son demasiados estados finales independientes. El worker hace context-switch, el evaluator se confunde con señales mezcladas, el loop nunca converge. Solución: secuéncialos — tres goals, uno a la vez, define el siguiente cuando el anterior se cumpla.
▸ #4 — Sin tope de turno en un goal exploratorio
Goals en tareas donde no está claro cuántos turnos se necesitan (debug de un flake, explorar una codebase desconocida) fácilmente corren 100+ turnos. Solución: siempre incluye "o para después de N turnos" para trabajo exploratorio. Siempre puedes definir otro goal después.
▸ #5 — Confiar en la entrada "achieved"
El evaluator puede equivocarse. "Sí, los tests pasan" puede significar "el último comando npm test que Claude ejecutó salió con exit 0" — pero Claude puede haber stubeado la assertion que fallaba. Solución: para goals de alto riesgo, añade un check externo (una ejecución separada de CI, un code review) después de que el goal se cumpla. /goal es un fuerte enfocador de atención, no un sustituto del review.
▸ Cuándo NO usar /goal en absoluto
- Ediciones rápidas. Un fix de dos líneas no necesita un loop; solo pídelo.
- Trabajo genuinamente exploratorio. Si no sabes cómo se ve "listo",
/goalno es la herramienta. Prueba/loopcon un intervalo de polling, o solo itera. - Trabajo que requiere juicio humano por turno. Code review, decisiones de diseño, cualquier cosa con aceptación subjetiva. El evaluator no puede ver tu gusto.