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:
| Formato | O que você recebe | Use para |
|---|---|---|
text (padrão) | A resposta final em texto puro | Pessoas, arquivos, scripts simples |
json | Um objeto JSON no final | Scripts que precisam da resposta e dos metadados |
stream-json | Um evento JSON por linha, conforme acontece | Progresso 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:
| Modo | Comportamento em uma execução headless |
|---|---|
dontAsk | Tudo o que não foi pré-aprovado é recusado. A escolha previsível para scripts |
acceptEdits | Edições de arquivo são permitidas sem perguntar |
plan | Só leitura e planejamento, sem edições |
auto | Um classificador revisa cada ação; um bloqueio nega aquela ação e a execução continua |
bypassPermissions | Nenhuma 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 20para depois desse número de turnos do agente e sai com erro. Sem limite por padrão.--max-budget-usd 5.00para 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
timeoutdo 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 hooksSessionEnd.
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 carregar | Flag |
|---|---|
| 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-nameno 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_denialsno resultado JSON e adicione a regra que falta em--allowedTools. - Trabalho em segundo plano. Uma execução
-ppode 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-promptsubstitui 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.