Claude

Claude Code sin interfaz: cómo usar claude -p en scripts, cron y CI

Con el flag -p, Claude Code responde y termina, como cualquier comando de terminal. Te explico cómo pasarle datos por tubería, obtener JSON, darle permisos justos y usarlo en scripts y CI sin sorpresas.

  • Javi Mata
  • 10 min de lectura
Tabla de contenido

Casi siempre usamos Claude Code en modo conversación: abres la sesión, le pides algo, revisas y sigues. Pero hay tareas que no necesitan conversación: resumir un log, revisar un diff antes de un commit, generar un reporte cada lunes. Para eso existe el modo no interactivo: le pasas un prompt, Claude Code trabaja, imprime el resultado y termina, como cualquier otro comando de terminal.

Si todavía no usas Claude Code, empieza por la guía de inicio. Este artículo se apoya en la documentación oficial consultada el 30 de octubre de 2026 (Claude Code v2.1.312); los flags que piden una versión mínima lo indican.

El flag -p

Basta con agregar -p (o --print) a cualquier comando claude:

claude -p "What does the auth module do?"

Claude Code responde en la salida estándar y termina. Lo importante para un script:

  • Código de salida: 0 si todo fue bien y distinto de 0 si la ejecución falla, así que puedes ramificar con if o &&.
  • Errores de flags: si pasas un flag inválido, el error sale por stderr antes de empezar.
  • Errores durante la ejecución: si algo falla dentro de la ejecución, por ejemplo falta autenticación, Claude Code imprime el fallo como resultado en stdout.

No todas las opciones de la CLI se combinan con -p; la documentación menciona, por ejemplo, que rechaza --bg.

Pasarle datos por tubería

El modo no interactivo lee stdin, así que puedes encadenarlo con otros comandos y redirigir la respuesta a un archivo. Este es el ejemplo oficial con un log de compilación:

cat build-error.txt | claude -p 'concisely explain the root cause of this build error' > output.txt

Hay un límite: lo que entra por stdin se corta en 10 MB. Si lo superas, Claude Code termina con un error y código distinto de 0. Para entradas más grandes, la documentación recomienda guardar el contenido en un archivo y mencionar su ruta en el prompt.

Un uso práctico es meterlo en un script de package.json para que haga de revisor. Este ejemplo está adaptado de la documentación (traduje el prompt): le pasa el diff contra main y le pide reportar erratas. Como el diff llega por tubería, Claude no necesita permiso de Bash para leerlo:

{
  "scripts": {
    "lint:claude": "git diff main | claude -p \"eres un revisor de erratas. Para cada errata en este diff, reporta archivo:línea en una línea y el problema en la siguiente. No devuelvas nada más.\""
  }
}

Lo ejecutas con npm run lint:claude. Las comillas dobles escapadas mantienen el script portable a Windows.

Salida estructurada: texto, JSON o streaming

Con --output-format eliges el formato:

  • text (por defecto): texto plano.
  • json: JSON con el resultado, el ID de sesión y metadatos.
  • stream-json: JSON delimitado por saltos de línea, para recibir eventos en tiempo real.

Con json, el texto de la respuesta va en el campo result, y con jq lo extraes:

claude -p "Summarize this project" --output-format json | jq -r '.result'

La respuesta JSON también incluye total_cost_usd y un desglose del costo por modelo. Ojo: según la documentación son estimaciones del lado del cliente y pueden no coincidir con tu factura.

Respuestas con un esquema concreto

Si necesitas que la salida tenga una forma exacta, combina --output-format json con --json-schema y una definición de JSON Schema. El resultado llega en el campo structured_output:

claude -p "Extract the main function names from auth.py" \
  --output-format json \
  --json-schema '{"type":"object","properties":{"functions":{"type":"array","items":{"type":"string"}}},"required":["functions"]}' \
  | jq '.structured_output'

Dos detalles de la documentación que conviene tener presentes:

  • Si el esquema no es válido, claude termina con Error: --json-schema is not a valid JSON Schema.
  • Si la ejecución termina sin una salida estructurada válida (por ejemplo, porque Claude rechazó la petición), la respuesta no trae el campo structured_output. Comprueba que exista antes de usarlo.

Permisos: lo que no apruebas, no se ejecuta

En modo no interactivo no hay nadie para aprobar avisos. Desde Claude Code v2.1.302, una ejecución con -p arranca en modo Manual si nada fija otro modo, y en ese modo una llamada que necesita aprobación se deniega salvo que algo la apruebe. Si quieres entender los modos y las reglas a fondo, lo expliqué en Permisos y modos de permiso en Claude Code.

Tienes dos formas de darle margen a una ejecución.

Herramientas concretas con --allowedTools

Lista las herramientas que puede usar sin preguntar:

claude -p "Run the test suite and fix any failures" \
  --allowedTools "Bash,Read,Edit"

Puedes afinar con la sintaxis de reglas de permisos. Este ejemplo oficial revisa los cambios preparados y crea un commit, pero solo deja ejecutar esos cuatro comandos de git:

claude -p "Look at my staged changes and create an appropriate commit" \
  --allowedTools "Bash(git diff *),Bash(git log *),Bash(git status *),Bash(git commit *)"

Fíjate en el espacio antes del *: Bash(git diff *) permite cualquier comando que empiece con git diff, pero sin ese espacio, Bash(git diff*) también coincidiría con git diff-index.

Un modo base con --permission-mode

En lugar de listar herramientas, puedes fijar un modo para toda la sesión:

  • acceptEdits: Claude escribe archivos sin preguntar y se aprueban comandos comunes del sistema de archivos como mkdir, touch, mv y cp. Otros comandos de shell siguen necesitando una entrada en --allowedTools o una regla permissions.allow.
  • dontAsk: se deniega todo lo que pediría permiso. La documentación lo señala como útil para ejecuciones de CI bloqueadas.
  • auto: un clasificador revisa la mayoría de las acciones en tu lugar.
claude -p "Apply the lint fixes" --permission-mode acceptEdits

Cuando nadie va a contestar: --permission-prompts none

Para trabajos desatendidos, como uno programado, existe --permission-prompts none (requiere Claude Code v2.1.259 o posterior). Con él, todo lo que pediría permiso se deniega (salvo que un hook PermissionRequest lo permita), a Claude se le dice que nadie puede aprobarlo y que no lo reintente, y la ejecución sigue. Además, se retiran las herramientas que necesitan una respuesta humana, como AskUserQuestion.

claude -p "Update the dependency pins and run the tests" --permission-mode auto --permission-prompts none

--bare: arranque limpio y reproducible

Sin opciones extra, claude -p carga lo mismo que una sesión interactiva: hooks, skills, comandos personalizados, subagentes, plugins instalados, servidores MCP, memoria automática y CLAUDE.md, incluido lo que haya en el directorio de trabajo o en ~/.claude.

Con --bare se salta todo ese descubrimiento automático, arranca más rápido y obtienes el mismo resultado en cualquier máquina:

claude --bare -p "Summarize README.md" --allowedTools "Read"

Lo que debes saber de este modo:

  • No usa tu sesión de suscripción. Nunca lee credenciales OAuth ni el llavero del sistema. Para la API de Anthropic necesitas la variable ANTHROPIC_API_KEY (con una clave creada en la Claude Console) o un apiKeyHelper en el JSON de --settings.
  • Claude tiene acceso a Bash y a las herramientas de leer y editar archivos. Lo demás se lo pasas con flags: --append-system-prompt o --append-system-prompt-file para instrucciones, --settings para configuración, --mcp-config para servidores MCP, --agents para subagentes y --plugin-dir o --plugin-url para un plugin.
  • Es el modo recomendado para llamadas desde scripts y desde el SDK, y la documentación indica que será el comportamiento por defecto de -p en una versión futura.

Por qué importa en un repositorio que no es tuyo

Este punto de la documentación merece su propio apartado: sin --bare, una sesión -p ejecuta los hooks del .claude/settings.json del proyecto y conecta los servidores de su .mcp.json, incluso en una carpeta en la que nunca confiaste, y no muestra el diálogo de confianza ni pide aprobación por servidor. Si tu CI corre claude -p sobre código de terceros (por ejemplo, ramas de un pull request externo), es razonable asumir que quieres --bare. Los hooks los expliqué en Hooks en Claude Code.

Ponerle límites: turnos, presupuesto y persistencia

Tres flags que solo funcionan en modo no interactivo y que vienen bien en automatizaciones:

  • --max-turns: limita el número de turnos agénticos. Al llegar al límite, termina con error. Por defecto no hay límite.
  • --max-budget-usd: detiene la ejecución cuando el gasto estimado en llamadas a la API alcanza esa cantidad. El gasto de los subagentes cuenta, y la documentación advierte que el gasto puede pasarse del tope, así que deja margen.
  • --no-session-persistence: no guarda la sesión en disco, así que no podrás reanudarla.
claude -p --max-turns 3 "query"

Conversaciones de varios pasos

Cada claude -p es una ejecución independiente, pero puedes continuarla. --continue retoma la conversación más reciente:

claude -p "Review this codebase for performance issues"
claude -p "Now focus on the database queries" --continue
claude -p "Generate a summary of all issues found" --continue

Si tienes varias conversaciones a la vez, guarda el ID de sesión y usa --resume:

session_id=$(claude -p "Start a review" --output-format json | jq -r '.session_id')
claude -p "Continue that review" --resume "$session_id"

Instrucciones extra y skills

Con --append-system-prompt agregas instrucciones sin perder el comportamiento por defecto de Claude Code. El ejemplo oficial revisa la seguridad de un pull request con la CLI de GitHub (guárdalo como review.sh y ejecútalo con bash review.sh 123):

gh pr diff "$1" | claude -p \
  --append-system-prompt "You are a security engineer. Review for vulnerabilities." \
  --output-format json

Y si ya tienes skills, también funcionan aquí: incluye /nombre-del-skill en el prompt y Claude Code lo expande antes de ejecutar. Los comandos integrados que solo existen en la interfaz de terminal, como /login, no están disponibles. Si aún no tienes ninguno, mira cómo crear un skill en Claude Code.

Ejemplo: un reporte semanal con cron

Esto es un ejemplo propio, no de la documentación: un script que resume los commits de la semana y lo guarda en un archivo. Usa --bare para no depender de la configuración de la máquina, así que necesita ANTHROPIC_API_KEY en el entorno:

#!/bin/bash
# reporte-semanal.sh (ejemplo)
cd /ruta/a/mi-proyecto || exit 1

git log --since="7 days ago" --oneline \
  | claude --bare -p "Resume estos commits en español, agrupados por tema, en menos de 15 líneas." \
      --max-turns 2 \
      --no-session-persistence \
  > reportes/semana-$(date +%F).txt

No le di ninguna herramienta con --allowedTools: todo lo que necesita llega por stdin. Mi recomendación es empezar siempre así, con lo mínimo, y añadir permisos solo cuando la tarea realmente los pida.

¿Y en GitHub Actions o GitLab?

Para CI hay guías oficiales específicas: GitHub Actions y GitLab CI/CD. Y si necesitas más control que el que da la CLI (callbacks para aprobar herramientas u objetos de mensaje nativos), el mismo motor está disponible como Agent SDK para Python y TypeScript.

Mi recomendación

  1. Usa --bare en scripts y CI, sobre todo si el repositorio no es tuyo.
  2. Da permisos mínimos. Prefiere pasar datos por stdin o reglas como Bash(git diff *) antes que Bash completo.
  3. Pide JSON cuando otro programa vaya a leer la salida, y comprueba que structured_output exista antes de usarlo.
  4. Pon límites con --max-turns y --max-budget-usd en lo que corra sin supervisión.

Conclusión

claude -p convierte a Claude Code en una pieza más de tu terminal: recibe datos, devuelve texto o JSON y sale con un código que tu script entiende. Con --bare, permisos justos y algunos límites, puedes automatizar revisiones, resúmenes y reportes sin tener una sesión abierta.

Fuentes