Modo headless do Claude Code: claude -p em scripts e CI

Modo headless do Claude Code: claude -p, saída JSON e stream-json, --allowedTools, --max-turns, --bare, retomar sessões, entrada via pipe, cron e CI.

Solviera Teknoloji 10 min de leitura

O modo headless do Claude Code é a flag -p. claude -p "your prompt" roda o Claude Code uma vez sem a interface interativa: ele lê o seu prompt (e o que você mandar via pipe), trabalha com as ferramentas que você permitir, imprime o resultado e sai. Código de saída 0 significa sucesso; qualquer outro, que a execução falhou. Isso o transforma em uma ferramenta de linha de comando comum, que você pode colocar em scripts de shell, cron jobs, git hooks e pipelines de CI.

Este guia cobre as flags que você vai usar de verdade: formatos de saída, permissões de ferramentas, limites de turnos e de orçamento, --bare, continuação de sessões e entrada via pipe, seguidos de padrões prontos para scripts, cron e CI, e de quando migrar para o Agent SDK. Cada flag aqui foi conferida na referência oficial da CLI em outubro de 2026.

O básico

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

-p e --print são a mesma flag. A maioria das opções interativas pode ser combinada com ela, como --model, --effort, --append-system-prompt e --mcp-config. Algumas opções existem só no modo print, entre elas --max-turns, --max-budget-usd, --json-schema e --no-session-persistence.

Dois detalhes importam para scripts:

  • Se você passar uma flag inválida, o erro vai para o stderr antes de a execução começar.
  • Se algo falhar dentro da execução, como falta de autenticação, a falha é impressa como resultado no stdout. Verifique o código de saída, não só a saída.

Mande dados via pipe, redirecione os resultados

O modo headless lê o stdin, então logs, diffs e arquivos entram como em qualquer ferramenta Unix:

cat build-error.txt | claude -p 'concisely explain the root cause of this build error' > output.txt
git diff main | claude -p "Review this diff for bugs. List each as file:line and one sentence."

O stdin via pipe tem limite de 10MB. Acima disso, o Claude Code sai com erro; para entradas grandes, escreva o conteúdo em um arquivo e cite o caminho no prompt.

Você também pode ligar isso ao package.json, como a documentação oficial faz com um linter de erros de digitação:

{
  "scripts": {
    "lint:claude": "git diff main | claude -p \"you are a typo linter. for each typo in this diff, report filename:line on one line and the issue on the next. return nothing else.\""
  }
}

Escolha um formato de saída

--output-format aceita três valores:

FormatoO que você recebeUse para
text (padrão)A resposta final em texto puroPessoas, arquivos, scripts simples
jsonUm objeto JSON no finalScripts que precisam da resposta e dos metadados
stream-jsonUm evento JSON por linha, conforme aconteceProgresso ao vivo, interfaces próprias, logs

O objeto JSON traz a resposta em result, além de session_id, números de uso e total_cost_usd. Esse custo é uma estimativa do lado do cliente e pode diferir da sua fatura.

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

Saída estruturada com —json-schema

Quando um script precisa de dados e não de prosa, passe um JSON Schema. O resultado validado cai em 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"]}'

Se a execução terminar sem uma saída estruturada válida, por exemplo porque o Claude recusou, o campo não aparece. Verifique antes de usar:

out=$(claude -p "Extract the main function names from auth.py" --output-format json --json-schema "$(cat schema.json)")
echo "$out" | jq -e '.structured_output' > /dev/null || { echo "no structured output" >&2; exit 1; }

Eventos em streaming

stream-json exige --verbose. Adicione --include-partial-messages para receber os tokens à medida que são gerados. Isto imprime só o texto em streaming:

claude -p "Write a poem" --output-format stream-json --verbose --include-partial-messages | \
  jq -rj 'select(.type == "stream_event" and .event.delta.type? == "text_delta") | .event.delta.text'

O primeiro evento normalmente é system/init, com o modelo, as ferramentas, os servidores MCP e os plugins. A última linha é uma mensagem result com o texto final, o custo e os metadados da sessão. Novas tentativas aparecem como eventos system/api_retry. Uma verificação útil para CI: quando você passa --mcp-config, uma entrada de servidor que não passa na validação é ignorada sem derrubar a execução, e aparece em mcp_server_errors no evento init. Faça o job falhar se esse array não estiver vazio.

Controle o que a execução pode fazer

Em um script não há ninguém para responder a um pedido de permissão, então decida de antemão o que o Claude pode fazer.

--allowedTools pré-aprova ferramentas usando a sintaxe de regras de permissão:

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 *)"

O espaço antes do * importa: Bash(git diff *) casa com comandos que começam com git diff, enquanto Bash(git diff*) também casaria com git diff-index.

--permission-mode define a base para tudo o que não está na lista. Em outubro de 2026 (Claude Code v2.1.302 e posteriores), uma execução -p começa no modo Manual quando nada define um modo, e uma chamada que precisa de aprovação é negada. Valores úteis:

ModoComportamento em uma execução headless
dontAskTudo o que não foi pré-aprovado é recusado. A escolha previsível para scripts
acceptEditsEdições de arquivo são permitidas sem perguntar
planSó leitura e planejamento, sem edições
autoUm classificador revisa cada ação; um bloqueio nega aquela ação e a execução continua
bypassPermissionsNenhuma verificação. Só dentro de um contêiner ou VM descartável

--tools restringe quais ferramentas nativas existem, e --disallowedTools adiciona regras de negação. --permission-prompts none avisa ao Claude que ninguém pode aprovar pedidos, para que ele não fique tentando de novo; as negações aparecem em permission_denials no resultado final. Por que ignorar permissões na sua própria máquina é arriscado está em Claude Code skip permissions.

Coloque limites em toda execução sem supervisão

  • --max-turns 20 para depois desse número de turnos do agente e sai com erro. Sem limite por padrão.
  • --max-budget-usd 5.00 para quando o gasto estimado chega ao valor. Ele usa a estimativa do lado do cliente e o gasto pode passar um pouco do teto, então deixe uma margem.
  • Um timeout do seu shell ou da etapa de CI continua valendo a pena. Se você interromper uma execução com SIGTERM, o Claude Code sai com código 143, não registra resultado para o turno inacabado e ainda roda os hooks SessionEnd.

Use —bare para execuções reproduzíveis

Sem --bare, o claude -p carrega as mesmas coisas de uma sessão interativa: hooks, skills, plugins, servidores MCP, memória automática e CLAUDE.md, do diretório de trabalho e de ~/.claude. Isso significa que o mesmo comando se comporta de um jeito no seu notebook e de outro em um runner de CI.

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

--bare pula toda essa descoberta e inicia mais rápido. Você passa só o que a execução precisa:

Para carregarFlag
Instruções extras--append-system-prompt, --append-system-prompt-file
Configurações--settings <file-or-json>
Servidores MCP--mcp-config <file-or-json>
Agentes personalizados--agents <file-or-json>
Um plugin--plugin-dir <path>

O modo bare nunca lê credenciais OAuth nem o keychain do sistema. Com a API da Anthropic, defina ANTHROPIC_API_KEY ou forneça um apiKeyHelper no JSON de --settings. A documentação oficial recomenda --bare para chamadas em scripts e diz que ele vai virar o padrão do -p em uma versão futura, então escrevê-lo explicitamente agora mantém seus scripts estáveis quando isso acontecer.

Mais um motivo para se importar: sem --bare, uma execução -p em um repositório recém-clonado roda os hooks de projeto e os servidores do .mcp.json desse repositório sem diálogo de confiança. Não aponte uma execução headless sem bare para código que você não revisou.

Continue e retome sessões

Execuções headless são salvas como as interativas, então você pode encadear etapas:

# First request
claude -p "Review this codebase for performance issues"

# Continue the most recent conversation
claude -p "Now focus on the database queries" --continue
claude -p "Generate a summary of all issues found" --continue

Quando várias execuções acontecem ao mesmo tempo, --continue pode pegar a errada. Capture o ID da sessão:

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

--resume encontra a sessão pelo ID a partir de qualquer diretório da máquina, e também aceita um nome ou o caminho para a transcrição .jsonl de uma sessão. --fork-session inicia um novo ramo a partir da conversa retomada em vez de continuar nela, e --no-session-persistence evita que execuções avulsas sejam salvas.

Padrões para scripts, cron e CI

Um loop sobre arquivos

A página oficial de boas práticas tem um bom modelo para uma mudança mecânica em muitos arquivos:

for file in $(cat files.txt); do
  claude --bare -p "Migrate $file to the new logger API and commit. Reply OK or FAIL." \
    --allowedTools "Read,Edit,Bash(git add *),Bash(git commit *)" \
    --permission-mode dontAsk \
    --max-turns 20
done

Rode primeiro em três arquivos, leia os commits, ajuste o prompt e só então rode o resto. Uma execução que bate no limite de turnos sai com erro, que o seu loop pode registrar.

Um script de revisão

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

Salve como review.sh e rode bash review.sh 123; o texto da revisão fica em result.

Um cron job noturno

# crontab -e
0 2 * * * cd /srv/app && claude --bare -p "Run the test suite, fix failing tests, commit on the current branch. Do not push." --allowedTools "Read,Edit,Bash(npm test *),Bash(git add *),Bash(git commit *)" --permission-mode dontAsk --max-turns 30 --output-format json >> /var/log/claude-nightly.jsonl 2>> /var/log/claude-nightly.err

O cron roda com um ambiente mínimo, então garanta que claude esteja no PATH dele e que ANTHROPIC_API_KEY esteja definida para esse usuário. Rode em uma branch ou em um worktree, não na main. Se você adicionar --worktree, note que execuções -p --worktree não são limpas automaticamente; remova-as com git worktree remove <path>. Para a configuração noturna completa com orçamentos e revisão de manhã, veja Como rodar o Claude Code durante a noite, e para timers em cada sistema operacional, Como agendar tarefas do Claude Code.

Pipelines de CI

No CI, use --bare, guarde a chave de API no cofre de secrets do CI e trate o código de saída como o resultado da etapa. No caso do GitHub, a action oficial já embala tudo isso para você, com comentários em PR e menções a @claude: veja Claude Code GitHub Actions. Se você usa uma assinatura em vez de chave de API, claude setup-token imprime um token OAuth de longa duração para CI e scripts; ele não é salvo, então guarde-o como secret na hora. Lembre que --bare ignora OAuth, então um token de assinatura precisa de uma execução sem bare.

Armadilhas

  • Skills e slash commands. Skills do usuário funcionam se você colocar /skill-name no prompt. Comandos que só existem na interface do terminal, como /login, não funcionam.
  • Negações silenciosas de ferramentas. Se o Claude disser que não conseguiu fazer algo, confira permission_denials no resultado JSON e adicione a regra que falta em --allowedTools.
  • Trabalho em segundo plano. Uma execução -p pode ficar aberta esperando comandos em segundo plano ou subagentes que o Claude iniciou; por padrão, ela para de esperar após 10 minutos de inatividade.
  • Substituir o system prompt. --system-prompt substitui o prompt padrão por inteiro, incluindo o retrato do git status. Prefira --append-system-prompt, a menos que você queira mesmo começar do zero.

Quando migrar para o Agent SDK

O claude -p é o motor do Agent SDK por trás de uma CLI. Quando seu script começar a parsear streams, lidar com aprovações ou gerenciar muitas sessões, passe para o Agent SDK em Python ou TypeScript. Ele oferece objetos de mensagem nativos, callbacks de aprovação de ferramentas e saídas estruturadas no código, sem chamar o shell. O post Boas práticas do Claude Code mostra o que preparar antes de deixar qualquer execução sem supervisão.

Fazendo isso com o AgentVera

Execuções headless são do tipo “dispara e esquece”; às vezes você quer a mesma automação com um terminal que dá para acompanhar. No AgentVera, as tarefas agendadas (em todos os planos) enviam um prompt a um agente em uma agenda cron enquanto o app está aberto, e o agente roda em um painel real que você pode abrir e conduzir. As automações (Pro e Team) iniciam um agente quando o CI fica vermelho ou um PR recebe um comentário, e nunca fazem push na branch padrão. A central de CI/CD lista execuções do GitHub Actions, GitLab e Jenkins e pode entregar um log com falha a um agente. O turno da noite (Pro e Team) roda o trabalho enfileirado durante a noite em um worktree, em uma branch night/<date>-<slug>, faz commit sem push e deixa um relatório para a manhã. Baixe o AgentVera se quiser essas execuções visíveis em vez de enterradas em um arquivo de log.

Conclusão

A receita básica do Claude Code headless é curta: claude --bare -p "clear task with a check", uma lista explícita em --allowedTools, --permission-mode dontAsk, --max-turns, --output-format json e um código de saída que o seu script respeite. Comece pequeno, leia o que as primeiras execuções produzem e só depois coloque isso em um timer.

Perguntas frequentes

O que é o modo headless do Claude Code?

É o Claude Code rodando de forma não interativa com a flag -p (ou --print). Você passa um prompt, o Claude faz o trabalho com as ferramentas que você permite, imprime o resultado no stdout e sai. O código de saída 0 indica sucesso e um código diferente de zero indica falha, então os scripts podem decidir com base nele.

Como deixo o claude -p editar arquivos sem pedir confirmação?

Liste as ferramentas com --allowedTools, por exemplo --allowedTools "Read,Edit,Bash(npm test *)". Em outubro de 2026, execuções com -p começam no modo Manual quando nada define um modo, e chamadas de ferramenta que precisam de aprovação são negadas. Adicione --permission-mode dontAsk para deixar isso explícito, ou acceptEdits para permitir todas as edições de arquivo.

Como obtenho saída JSON do Claude Code?

Adicione --output-format json. A resposta é um único objeto JSON com o texto em result, além de session_id, usage e uma estimativa total_cost_usd. Passe para jq -r ".result" para obter o texto. Adicione --json-schema para receber dados validados em structured_output, e confira se o campo existe antes de usá-lo.

Posso continuar uma sessão headless do Claude Code?

Sim. claude -p "next step" --continue retoma a conversa mais recente no diretório atual. Para mirar uma específica, capture o session_id de uma execução JSON e passe para --resume; o Claude Code encontra a sessão pelo ID a partir de qualquer diretório daquela máquina.

O modo headless usa minha assinatura do Claude ou uma chave de API?

Uma execução -p normal usa o login que a máquina tiver. Com --bare, o Claude Code nunca lê credenciais OAuth nem o keychain, então precisa de ANTHROPIC_API_KEY ou de um apiKeyHelper no JSON de --settings. Para CI com assinatura, claude setup-token gera um token OAuth de longa duração.

Reúna seus agentes em uma só mesa.

Baixe o AgentVera de graça; as CLIs que você já instalou estão prontas para usar.

Mais artigos