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
- El flag -p
- Pasarle datos por tubería
- Salida estructurada: texto, JSON o streaming
- Respuestas con un esquema concreto
- Permisos: lo que no apruebas, no se ejecuta
- Herramientas concretas con --allowedTools
- Un modo base con --permission-mode
- Cuando nadie va a contestar: --permission-prompts none
- --bare: arranque limpio y reproducible
- Por qué importa en un repositorio que no es tuyo
- Ponerle límites: turnos, presupuesto y persistencia
- Conversaciones de varios pasos
- Instrucciones extra y skills
- Ejemplo: un reporte semanal con cron
- ¿Y en GitHub Actions o GitLab?
- Mi recomendación
- Conclusión
- Fuentes
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
ifo&&. - Errores de flags: si pasas un flag inválido, el error sale por
stderrantes 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,
claudetermina conError: --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 comomkdir,touch,mvycp. Otros comandos de shell siguen necesitando una entrada en--allowedToolso una reglapermissions.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 unapiKeyHelperen 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-prompto--append-system-prompt-filepara instrucciones,--settingspara configuración,--mcp-configpara servidores MCP,--agentspara subagentes y--plugin-diro--plugin-urlpara 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
-pen 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
- Usa
--bareen scripts y CI, sobre todo si el repositorio no es tuyo. - Da permisos mínimos. Prefiere pasar datos por
stdino reglas comoBash(git diff *)antes queBashcompleto. - Pide JSON cuando otro programa vaya a leer la salida, y comprueba que
structured_outputexista antes de usarlo. - Pon límites con
--max-turnsy--max-budget-usden 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
Etiquetas:
Compartir: