🚨 ¡Nueva review! 🔇 Los mejores cascos con ANC del mercado: los Sony WH-1000XM4 . ¡Échale un ojo! 👀

Automatizar lo repetitivo: routines y modo headless

Cuando ya te fías de una tarea, lo siguiente es dejar de lanzarla tú

Escrito por domin el 29 de agosto de 2026

Volvemos de vacaciones después de un tiempo de inactividad y seguimos con esta serie de posts de Claude Code In Action para darle carpetazo final, porque me encanta comenzar cosas y dejarlas a medias.

En el post de los hooks la idea era meter código tuyo en un punto fijo de la sesión. Con el capítulo de hoy del curso Claude Code in Action de Anthropic vamos un poco más allá trabajando cuando no hay sesión de Claude porque tú no estás delante para arrancarla de forma manual.

Por un lado tenemos las routines, que corren en la infraestructura de Anthropic y no tienes que montar nada más. En el otro lado tenemos el modo headless y el SDK, que ejecutan Claude Code desde tu propio código. Empezamos por donde menos hay que construir, que es en el de Anthropic.

Routines: un prompt guardado que corre en la nube

Una routine empaqueta tres cosas: el prompt, el repositorio sobre el que trabaja y los conectores que necesite y lo ejecuta cuando toque.

Lo importante es de quién es la máquina. No hay un portátil tuyo encendido toda la noche ni un fichero de workflow que mantener. Describes el trabajo una vez y corre solo.

Se puede disparar de tres maneras. Por un cron, tipo todas las mañanas a las nueve. Por un POST a su endpoint de la API, para lanzarla desde tu propio código y por un evento de GitHub, como por ejemplo que entre un pull request nuevo.

Encaja cualquier cosa que sea el mismo prompt sobre un disparador que se repite. Por ejemplo una auditoría de dependencias por la mañana, un triaje de los PR que van entrando o un repaso diario a los tickets de Sentry para ver cuál corre más prisa.

Se crean desde la web, en claude.ai/code/routines, poniéndole nombre, instrucciones, repo y disparador o sin salir del terminal con:

/schedule auditoría de dependencias todos los días a las 9

Es el mismo bicho por dos puertas distintas.

Tres cosas antes de fiarte

Las routines están en research preview, así que el comportamiento y los límites se van a mover. No te montes un proceso crítico encima todavía, que está en pañales.

Un horario recurrente corre como mucho una vez por hora. Si necesitas algo más frecuente, esto no es lo tuyo.

Y por último, cada ejecución arranca de un clon limpio de tu rama por defecto. Claude sube su trabajo a ramas con el prefijo claude/, que se aceptan siempre. Si tu prompt le manda empujar a otra rama, comprueba el push antes y lo rechaza si la rama está protegida en GitHub, si otra persona tiene un pull request abierto desde ella o si lleva commits de alguien que no eres tú. Viene a ser el hook de PreToolUse del post anterior, el de que nadie suba nada a main, pero puesto de serie.

Headless: el flag -p

Cuando el trabajo necesita tu entorno, o quieres lógica tuya alrededor de la ejecución, bajas al modo headless. El flag es -p (o --print) y ejecuta Claude Code de una vez, sin interfaz. Lee de la entrada estándar y escribe en la salida estándar, así que se conecta por tubería como cualquier otro comando:

git diff | claude -p "resume los cambios de este diff"

Aquí el curso dice una cosa que ya no es verdad, y conviene saberlo porque cambia bastante lo que puedes esperar de un script. Dice que -p se salta el autodescubrimiento de hooks, skills, plugins, servidores MCP y del CLAUDE.md.

Lo he probado en la 2.1.251, dentro de este mismo repo:

claude -p "Responde SOLO con el nombre del script npm que crea un post nuevo, \
  según tus instrucciones de proyecto. Si no tienes instrucciones, responde NADA."

Contesta npm run new-post, que está escrito en el CLAUDE.md del blog y en ningún otro sitio. O sea que -p sí carga el CLAUDE.md, y con él tus hooks y tus reglas. Si lo que quieres es justo lo contrario, arrancarlo desnudo para CI, eso es --bare, otro flag distinto que además exige ANTHROPIC_API_KEY en el entorno porque no lee ni el llavero ni el OAuth.

Que lo cargue no es malo, ojo. Significa que un script en producción hereda tus reglas del proyecto, que normalmente es lo que quieres. Pero si montas un pipeline dando por hecho que -p arranca desnudo, un día alguien toca el CLAUDE.md y te cambia el comportamiento de un cron sin enterarse.

Que te devuelva JSON y no texto

Como esto se comporta como una pipe más, casi nunca quieres párrafos, quieres datos. Le pasas un esquema JSON junto al formato de salida json y la respuesta se ajusta al esquema.

El objeto aterriza en el campo structured_output:

claude -p "Extrae los nombres de las funciones que exporta src/scripts/tools/markdown-viewer-core.js" \
  --output-format json \
  --json-schema '{"type":"object","properties":{"funciones":{"type":"array","items":{"type":"string"}}},"required":["funciones"]}' \
  | jq '.structured_output.funciones'

Esto lo he lanzado tal cual contra el fichero del visor de markdown del blog y devuelve:

["hasFrontmatter", "renderMarkdown", "computeStats", "safeSetItem", "loadPrefs", "savePrefs"]

Que son las seis exactas, comprobadas contra los export function del fichero. Un array limpio para meter en una base de datos o pasárselo al siguiente script.

Ahora la parte que no sale en el curso. Esa misma llamada, en la respuesta completa, trae entre otros estos campos:

{
    "type": "result",
    "subtype": "success",
    "is_error": false,
    "num_turns": 3,
    "total_cost_usd": 0.7051545,
    "session_id": "ae0ffe65-6ef6-49b1-a5c4-ef37b00527a9"
}

Son 12 segundos (duration_ms) y 70 cent por listar seis nombres de función. Con Opus y tres turnos, que ahí se va el dinero. Para una tarea al día es una tontería, pero antes de meter esto en un bucle que recorre doscientos ficheros, echa la cuenta. El total_cost_usd viene en la respuesta precisamente para que lo mires.

Consejo

is_error y total_cost_usd son tus dos amigos en un script. Con el primero decides si sigues, y con el segundo puedes cortar el proceso antes de que la factura haga algo raro. También existe --max-budget-usd para ponerle un techo a la llamada.

Encadenar sesiones

Para trabajos de varios pasos no hace falta meterlo todo en un comando. Guardas el session_id que sale del JSON y lo retomas después:

claude -p "..." --output-format json > /tmp/plan.json
claude -p --resume "$(jq -r .session_id /tmp/plan.json)" "ahora aplica el plan"

Lo he probado con la sesión de las funciones de antes, preguntándole cuántas me acababa de listar. Contesta 6 en menos de siete segundos, así que el contexto viaja entero.

Un script arranca el trabajo y otro lo continúa media hora después sabiendo todo lo anterior. Va muy bien cuando la primera pasada produce un plan y la segunda lo ejecuta, que además te deja meter una revisión humana en medio.

El SDK, para cuando el trabajo vive dentro de tu producto

El último escalón es el Agent SDK, una librería que mete Claude Code dentro de tu aplicación en TypeScript o Python.

Las dos exponen una función query y las mismas piezas que el CLI: allowedTools para acotar lo que puede hacer, un prompt de sistema y un modo de permisos. Iteras sobre los mensajes que va soltando y los manejas como necesite tu aplicación. Es el mismo motor, llamado desde tu código.

Cuál de los tres

HerramientaCuándo
RoutineTrabajo repetido con disparador. No hospedas nada
-pEl trabajo necesita tu entorno o encaja en una tubería tuya
SDKCuando eso va dentro de un producto tuyo

El orden por defecto es de arriba abajo. Empieza por la routine y baja solo cuando el trabajo pida de verdad el control extra, porque cada escalón que bajas es infraestructura que pasa a ser tuya.

Y con las routines, la pregunta no es si la tarea se puede automatizar. Es si te vas a enterar cuando salga mal, que un cron que falla en silencio a las nueve de la mañana lleva tres semanas fallando cuando lo descubres.

EA! Nos vemos en los bares! 🍻