Artigo 11 de 12
Kiro & AWS

Automação de verdade: Kiro CLI headless em pipelines de CI/CD

O agente que você usa no terminal também roda sozinho — em GitHub Actions, em cron, em cem repositórios ao mesmo tempo, às três da manhã, sem ninguém na frente da tela. Este é o artigo mais técnico da série.

18 de julho de 2026 · Prompt & Deploy

TL;DR

  • kiro-cli chat --no-interactive "prompt" é o modo headless. Ele roda o agente sem UI de terminal, sem slash commands, sem input no meio — só um prompt inicial e o resultado. É isso que torna o Kiro programável em pipelines.
  • Autenticação é via KIRO_API_KEY, disponível só para assinantes Pro/Pro+/Pro Max/Power. O Free não gera chave. Guarde a chave como secret, nunca no código.
  • Permissões são o coração da governança headless. Sem humano para aprovar, você escolhe entre --trust-all-tools (perigoso) e --trust-tools=read,grep (least privilege). Prefira sempre o segundo.
  • Contexto entra por pipe. git diff | kiro-cli chat --no-interactive "..." alimenta o agente com o diff do PR; cat build.log | ... transforma um log de erro em diagnóstico.
  • Custom agents com allowedTools restrito dão a você um perfil de execução previsível para CI — o agente literalmente não tem como fazer o que não está na lista.
  • Exit codes importam. Um pipeline que não checa o código de saída do agente não é automação, é fé.

Introdução: o poder da IA que roda sem você presente

Todo mundo que usa uma ferramenta de IA para código conhece o mesmo ritual: você digita um prompt, olha a resposta, aprova uma ação, olha de novo, aprova outra. É interativo por definição. Você é parte do loop. E enquanto você for parte do loop, a ferramenta só funciona quando você está na frente dela.

O modo headless quebra isso. kiro-cli chat --no-interactive roda o mesmo agente — as mesmas specs, o mesmo steering, os mesmos MCP servers — mas sem você. Sem UI de terminal, sem “aprovar/rejeitar”, sem slash commands. Você entrega um prompt, define de antemão em quais ferramentas o agente pode mexer sem pedir licença, e ele executa até o fim. O resultado sai no STDOUT e o código de saída diz se deu certo.

Isso muda a natureza do que dá para automatizar. Um IDE é uma ferramenta para uma pessoa olhar. Um CLI headless é uma peça de infraestrutura: ele entra num job de GitHub Actions que dispara em cada pull request, num cron que revisa dependências toda madrugada, num pipeline que roda em cem serviços de um monorepo em paralelo. O trabalho repetitivo — revisar diffs, escrever testes para código novo, triar logs de build quebrado — deixa de exigir horas humanas e passa a acontecer sozinho.

Este artigo mostra como fazer isso direito. E “direito” aqui tem um peso especial: dar a um agente de IA permissão para agir sem supervisão é uma decisão de arquitetura com blast radius real. Vou mostrar o comando, o YAML verificado, os pipes de contexto — e também onde estão as minas.

Enquanto você for parte do loop, a ferramenta só funciona quando você está presente. O headless tira você do loop — e é aí que a automação começa de verdade.

Modo headless: o comando e as flags que importam

O comando base é curto:

kiro-cli chat --no-interactive "Revise o código deste diretório em busca de bugs"

--no-interactive (o modo headless) desliga a UI de terminal. Não há loop de conversa, não há ctrl-j para multi-linha, não há /model para trocar de modelo no meio. O agente recebe o prompt, trabalha, imprime e sai. Essa é justamente a restrição que o torna previsível o suficiente para um pipeline: entra prompt, sai resultado, com um exit code no fim.

Autenticação: KIRO_API_KEY

Em modo interativo você faz login no navegador. Num pipeline não há navegador. A autenticação headless usa a variável de ambiente KIRO_API_KEY:

export KIRO_API_KEY="sua-chave-aqui"
kiro-cli chat --no-interactive "Gere testes unitários para src/domain/pricing.ts"

Dois fatos que você precisa saber antes de planejar qualquer coisa:

  • A chave só está disponível para assinantes Pro, Pro+, Pro Max e Power. O Free não gera chave de API. Se o seu objetivo é automação em CI, o Pro é o piso.
  • A geração da chave pode ser controlada pelo admin da organização. Num contexto de Team, é o admin quem habilita — e é o admin quem pode desabilitar.

Nunca, jamais, coloque a chave em texto no repositório ou no YAML. Ela é um secret. Trataremos disso na seção de governança, mas registre desde já: uma KIRO_API_KEY vazada é uma conta de créditos aberta para quem a encontrar.

As flags de permissão: --trust-all-tools vs --trust-tools

Aqui está a decisão mais importante do modo headless. Em modo interativo, quando o agente quer executar uma ferramenta sensível (rodar um comando shell, escrever um arquivo), ele pergunta. Você aprova ou nega. No headless não há quem aprove. Então você decide de antemão o que o agente pode fazer sem pedir licença:

# ❌ Confia em TUDO — o agente executa qualquer ferramenta sem pedir.
kiro-cli chat --no-interactive --trust-all-tools "..."

# ✅ Least privilege — o agente só executa read e grep sem aprovação.
kiro-cli chat --no-interactive --trust-tools=read,grep "..."

--trust-all-tools libera geral: leitura, escrita, execução de shell, tudo roda sem confirmação. É cômodo e é perigoso — num pipeline, significa dar a um agente de IA permissão para executar comandos arbitrários no runner.

--trust-tools=read,grep,write limita a confiança a categorias específicas de ferramenta. O agente até pode “querer” rodar um shell, mas sem execute_bash na lista de confiança, num contexto não-interativo, ele não consegue executá-lo silenciosamente. Você desenha o perfil de risco explicitamente.

A regra de ouro: conceda o mínimo que a tarefa exige. Uma revisão de código só precisa ler e buscar — --trust-tools=read,grep. Uma tarefa que gera arquivos de teste precisa também escrever — --trust-tools=read,grep,write. Quase nada em CI justifica --trust-all-tools.

--require-mcp-startup: falhe rápido

Se o seu agente depende de um MCP server (documentação da AWS, um fetcher, uma base interna) e esse server não conecta, você quase sempre prefere que o job quebre imediatamente em vez de o agente trabalhar sem a ferramenta e produzir um resultado silenciosamente incompleto:

kiro-cli chat --no-interactive \
  --require-mcp-startup \
  --trust-tools=read,grep \
  "Consulte a documentação e valide o uso das APIs neste PR"

--require-mcp-startup faz o comando falhar rápido se algum MCP configurado não subir. Em pipeline, falhar cedo e alto é sempre melhor que sucesso enganoso.

GitHub Actions: revisão de PR, linha a linha

Este é o workflow verificado. Ele dispara em cada pull request e roda uma revisão de segurança sobre as mudanças:

name: Kiro Code Review
on: [pull_request]

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install Kiro CLI
        run: curl -fsSL https://cli.kiro.dev/install | bash
      - name: Review PR changes
        env:
          KIRO_API_KEY: ${{ secrets.KIRO_API_KEY }}
        run: kiro-cli chat --no-interactive --trust-tools=read,grep "Revise as mudanças deste PR em busca de problemas de segurança"

Vale destrinchar cada pedaço, porque cada linha carrega uma decisão:

  • on: [pull_request] — o gatilho. O job roda automaticamente sempre que um PR é aberto ou atualizado. Nenhum humano precisa disparar nada.
  • runs-on: ubuntu-latest — um runner efêmero. Ele nasce para este job e morre no fim. Isso é bom para blast radius: o agente age numa máquina descartável, não na sua workstation.
  • uses: actions/checkout@v4 — traz o código do repositório para o runner. Sem isso, o agente não teria o que revisar.
  • curl -fsSL https://cli.kiro.dev/install | bash — instala o Kiro CLI no runner. -fsSL faz o curl falhar em erro HTTP, ficar silencioso, mostrar erros e seguir redirects.
  • env: KIRO_API_KEY: ${{ secrets.KIRO_API_KEY }} — injeta a chave a partir dos secrets do repositório (Settings → Secrets and variables → Actions). A chave nunca aparece no YAML nem nos logs. Este é o único jeito certo de autenticar.
  • --no-interactive — modo headless, sem UI.
  • --trust-tools=read,grep — least privilege. Uma revisão só precisa ler e buscar. O agente não pode escrever nem executar shell sem aprovação, e como não há quem aprove num job, ele simplesmente não faz. Se este PR contiver código malicioso tentando induzir o agente a rodar algo, a lista de confiança é sua contenção.
  • O prompt — específico e escopado: “problemas de segurança”, não “faça o que achar melhor”.

Variação: gerar e rodar testes

O mesmo esqueleto serve para outra tarefa comum — gerar testes para código novo e rodá-los. Aqui a diferença de permissão fica evidente: para escrever arquivos de teste, o agente precisa de write; para executá-los, o pipeline (não o agente) roda o comando de teste depois:

name: Kiro Test Generation
on:
  pull_request:
    paths:
      - "src/**"

jobs:
  gen-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install Kiro CLI
        run: curl -fsSL https://cli.kiro.dev/install | bash
      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: "20"
      - run: npm ci
      - name: Generate tests for changed code
        env:
          KIRO_API_KEY: ${{ secrets.KIRO_API_KEY }}
        run: |
          kiro-cli chat --no-interactive --trust-tools=read,grep,write \
            "Gere testes unitários (Vitest) para os arquivos alterados em src/. \
             Cubra casos de borda. Não altere código de produção, só crie/edite arquivos .test.ts."
      - name: Run the test suite
        run: npm test

Observe duas escolhas deliberadas:

  • paths: src/** restringe o gatilho a mudanças no código-fonte. Um PR que só toca no README não dispara geração de testes.
  • --trust-tools=read,grep,write adiciona write — o agente precisa criar os .test.ts. Mas não adiciona confiança para shell: quem roda npm test é o pipeline, num step separado e auditável, não o agente. A separação mantém a execução dos testes fora do controle do agente.

Least privilege num pipeline não é burocracia de segurança — é a diferença entre “o agente revisou meu código” e “o agente teve permissão de executar qualquer coisa no meu runner”.

Pipe de contexto: alimentando o agente pela entrada padrão

O modo headless combina com a filosofia Unix: tudo é texto, tudo pipa. Em vez de pedir para o agente ir buscar o contexto, você entrega o contexto pronto pela entrada padrão. O caso canônico é o diff:

git diff | kiro-cli chat --no-interactive --trust-tools=read \
  "Revise estas mudanças. Aponte bugs, riscos de segurança e violações do nosso steering."

Aqui o git diff produz exatamente o recorte que interessa — só o que mudou — e o passa como contexto. É mais barato (menos tokens que ler o repositório inteiro) e mais focado (o agente não se distrai com código que não faz parte da mudança). Para revisar só o que está staged antes de um commit:

git diff --staged | kiro-cli chat --no-interactive --trust-tools=read \
  "Estas são as mudanças prestes a ser commitadas. Há algo que não deveria ir para o repositório?"

O mesmo padrão resolve troubleshooting de build. Quando um pipeline quebra, o log de erro é uma parede de texto que ninguém quer ler às três da manhã. Pipe ele para o agente:

cat build.log | kiro-cli chat --no-interactive --trust-tools=read,grep \
  "Este é o log de um build que falhou. Diga a causa raiz provável e o arquivo/linha mais provável do problema."

Ou, direto do stack trace de um comando que acabou de falhar, combinando stderr no diagnóstico:

npm run build 2>&1 | tail -n 100 | kiro-cli chat --no-interactive --trust-tools=read,grep \
  "As últimas 100 linhas de um build quebrado. Explique o erro e proponha a correção mínima."

O 2>&1 junta stderr com stdout; o tail -n 100 corta o ruído e manda só o final relevante — que costuma ser onde o erro real aparece. Você está fazendo curadoria do contexto antes de gastar créditos com ele.

Agentes customizados para CI: least privilege como configuração

As flags --trust-tools são ótimas para one-liners, mas quando você tem um perfil de execução recorrente para CI, vale materializá-lo num custom agent. Um agente é um JSON que define nome, ferramentas disponíveis, quais rodam sem aprovação, recursos e um prompt de sistema. Este é um agente pensado para revisão em pipeline:

{
  "name": "ci-reviewer",
  "description": "Revisor read-only para pipelines de CI. Não escreve, não executa shell.",
  "tools": ["read", "grep"],
  "allowedTools": ["read", "grep"],
  "resources": [
    "file://README.md",
    "file://.kiro/steering/**/*.md"
  ],
  "prompt": "Você é um revisor de código de CI. Analise apenas as mudanças fornecidas. Aponte bugs, riscos de segurança e violações do steering do projeto. Nunca sugira executar comandos. Seja específico: cite arquivo e linha. Se estiver tudo certo, diga explicitamente 'aprovado'.",
  "model": "claude-sonnet-4",
  "includeMcpJson": false
}

O ponto central está na distinção entre tools e allowedTools:

  • tools é o que o agente tem à disposição — aqui, só read e grep. Ferramentas que não estão nesta lista simplesmente não existem para este agente.
  • allowedTools é o que roda sem pedir aprovação. Neste caso, igual a tools, porque tudo o que o agente pode fazer já é inócuo (ler e buscar).

Repare no que não está aqui: não há write, não há execute_bash. Este agente é fisicamente incapaz de modificar arquivos ou rodar comandos. Mesmo que um PR malicioso tente, via comentário no código, induzir o agente a “rodar este script” ou “apagar aquele arquivo”, ele não tem a ferramenta para obedecer. includeMcpJson: false fecha ainda mais o perímetro, ignorando configs de MCP do ambiente.

Para usar em pipeline, você inicia o CLI apontando para o agente:

git diff | kiro-cli --agent ci-reviewer chat --no-interactive \
  "Revise as mudanças recebidas pela entrada padrão."

Por que isso importa mais que as flags soltas? Porque o perfil de risco vira código versionado e revisável. Qualquer um do time abre o JSON e vê exatamente o que o agente de CI pode fazer. Least privilege deixa de ser um argumento que você lembra de passar na linha de comando e vira uma garantia estrutural.

Um agente que não tem a ferramenta não pode ser convencido a usá-la. Least privilege não é confiar menos no agente — é remover a possibilidade de o problema existir.

Exit codes e falhar com graça

Um pipeline é uma máquina de estados que decide “passou” ou “falhou” com base em códigos de saída. Se você roda o agente e ignora o exit code, você não tem automação — tem um script que sempre “passa” e um resultado que ninguém lê. Trate a saída do agente como trata qualquer comando:

#!/usr/bin/env bash
set -euo pipefail

git diff --staged \
  | kiro-cli chat --no-interactive --trust-tools=read,grep \
      "Revise. Se houver problema CRÍTICO de segurança, comece a resposta com 'BLOCK:'." \
  | tee review-output.txt

# Falha o job se o agente sinalizou um bloqueio.
if grep -q "^BLOCK:" review-output.txt; then
  echo "::error::Revisão do Kiro encontrou problema crítico. Veja review-output.txt"
  exit 1
fi

Alguns princípios para não se enganar:

  • set -euo pipefail no topo: o script morre no primeiro erro, trata variáveis não definidas como erro e propaga falhas dentro de pipes. Sem pipefail, um kiro-cli que falha no meio de um pipe passa despercebido.
  • Decida o critério de falha explicitamente. O agente produz texto; você decide o que aquele texto significa para o pipeline. O padrão “peça ao agente para prefixar um marcador (BLOCK:) e depois faça grep” é simples e robusto — você não depende de interpretar prosa.
  • Persista a saída (tee review-output.txt) e publique como artefato do job. Quando o pipeline falha, alguém precisa ler por quê — e o log do agente é a evidência.
  • ::error:: é a anotação do GitHub Actions que faz a mensagem aparecer destacada na UI do PR. Falhar com graça é falhar de forma legível.

Não trate o agente como oráculo infalível cujo exit code decide sozinho o destino do merge. Trate-o como um analista que produz um parecer — e desenhe o pipeline para agir sobre esse parecer de forma determinística.

Aviso de arquiteto: governança antes de soltar o agente na produção

Tudo o que mostrei aqui é poderoso, e poder sem governança é como se automatiza um desastre. Se você é responsável pela plataforma, leia esta seção duas vezes.

Secrets são secrets. A KIRO_API_KEY vive nos secrets do CI (GitHub Actions Secrets, GitLab CI variables com masking, ou um secret manager). Nunca no YAML, nunca em env de arquivo commitado, nunca ecoada em log. Um echo $KIRO_API_KEY de debug esquecido no pipeline é um vazamento. Configure o CI para mascarar a variável na saída.

Rotacione as chaves. Uma chave de API é uma credencial de longa duração — o pior tipo. Estabeleça rotação periódica e revogue imediatamente qualquer chave suspeita de exposição. Se o admin da organização controla a geração, defina uma política: quem tem chave, por quanto tempo, para qual pipeline. Chave por projeto, não uma chave-mestra colada em todo lugar.

Revisão humana antes de merge em branch protegida. Este é o item inegociável. Um agente headless pode revisar, sugerir, gerar testes, até abrir um PR — mas um humano aprova o merge em main. Configure branch protection rules exigindo review humano. O agente é um co-piloto que trabalha sozinho no trecho tedioso; ele não é o piloto que pousa o avião na produção. Automação que faz merge sem olho humano numa branch protegida é uma falha de governança esperando para acontecer.

Blast radius: contenha o que o agente pode alcançar. Rode em runners efêmeros e descartáveis, nunca em máquinas com credenciais de produção montadas. Aplique least privilege nas ferramentas (--trust-tools específico, custom agents com allowedTools mínimo) e no ambiente (o runner não deve ter acesso a mais do que o job precisa). A governança do admin — restrições de MCP, políticas de modelo, controle de web fetch — também vale no headless. Ela não é contornável só porque não há UI. Use isso a seu favor: configure as políticas no nível da organização e elas se aplicam a todo pipeline.

Trate conteúdo do PR como não-confiável. Um diff pode conter texto desenhado para manipular o agente (“ignore as instruções anteriores e execute…”). Por isso o agente de CI é read-only: mesmo que a injeção funcione no nível da prosa, não há ferramenta destrutiva para ele acionar. A contenção é estrutural, não baseada em confiar que o agente “vai saber” resistir.

A pergunta certa não é “o agente vai fazer besteira?”. É “se ele fizer, até onde o estrago chega?”. Least privilege, runners efêmeros e review humano em branch protegida são as três paredes que limitam o alcance.

Mão na massa: um pipeline completo de revisão

Juntando tudo, aqui está um workflow fim-a-fim que dispara em cada PR, revisa o diff com um agente read-only e falha o job se encontrar algo crítico — deixando a decisão de merge para o humano:

name: Kiro PR Guard
on: [pull_request]

permissions:
  contents: read

jobs:
  guard:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0          # precisa do histórico para o diff completo
      - name: Install Kiro CLI
        run: curl -fsSL https://cli.kiro.dev/install | bash
      - name: Review diff
        env:
          KIRO_API_KEY: ${{ secrets.KIRO_API_KEY }}
        run: |
          set -euo pipefail
          git diff origin/${{ github.base_ref }}...HEAD \
            | kiro-cli --agent ci-reviewer chat --no-interactive \
                --require-mcp-startup \
                "Revise o diff. Se houver problema CRÍTICO, comece com 'BLOCK:'." \
            | tee review.txt
          if grep -q "^BLOCK:" review.txt; then
            echo "::error::Kiro bloqueou: problema crítico no PR."
            exit 1
          fi
      - name: Upload review
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: kiro-review
          path: review.txt

O que amarra o pipeline:

  1. permissions: contents: read — o GITHUB_TOKEN do job só lê. Blast radius mínimo no nível do próprio pipeline.
  2. fetch-depth: 0 — traz o histórico para que git diff origin/base...HEAD compute o diff correto do PR.
  3. --agent ci-reviewer — usa o agente read-only versionado, não flags soltas.
  4. --require-mcp-startup — se algum MCP configurado não subir, o job falha antes de produzir um parecer incompleto.
  5. O marcador BLOCK: + grep — critério de falha determinístico, não interpretação de prosa.
  6. if: always() no upload — a evidência da revisão sobe como artefato mesmo (principalmente) quando o job falha.

E o que não está aqui, de propósito: nenhum step faz merge. Isso é decisão humana, protegida por branch rules.

Armadilhas comuns

  • Confiar em tudo por preguiça. --trust-all-tools “só para funcionar logo” é como abrir todas as portas do prédio porque a chave certa é chata de achar. Encontre a chave certa: liste só as ferramentas que a tarefa exige.
  • Ignorar o exit code. Um pipeline que roda o agente e sempre segue em frente não está automatizando nada — está gerando texto que ninguém lê. Defina um critério de falha explícito.
  • Chave no YAML. Parece óbvio, mas acontece. A KIRO_API_KEY é sempre secret. Sempre.
  • Merge automático em branch protegida. O agente trabalha sozinho; o humano decide o merge. Não inverta isso.
  • Prompt vago. “Revise o código” gera parecer genérico. “Aponte problemas de segurança citando arquivo e linha; comece com ‘BLOCK:’ se for crítico” gera algo acionável por máquina.
  • Não checar o piso do plano. Headless exige KIRO_API_KEY, e a chave exige Pro+ para cima. Planeje a assinatura antes de planejar o pipeline.

Conclusão: principais aprendizados

  • kiro-cli chat --no-interactive é a peça que torna o Kiro parte da sua infraestrutura, não só uma ferramenta que você abre. É o mesmo agente, sem você no loop.
  • Least privilege é a regra, não a exceção. --trust-tools=read,grep para revisão; adicione write só quando o agente precisa gerar arquivos; reserve --trust-all-tools para quase nunca. Materialize perfis recorrentes em custom agents com allowedTools mínimo.
  • Contexto entra por pipe. git diff | ... e cat log | ... fazem curadoria do que o agente vê — mais barato, mais focado, mais seguro.
  • Exit codes transformam parecer em decisão. Peça um marcador, faça grep, falhe o job de forma legível, persista a evidência.
  • Governança não é opcional em automação sem humano. Secrets protegidos e rotacionados, runners efêmeros, revisão humana antes de merge em branch protegida, blast radius contido. O poder de rodar sem você presente é exatamente por isso que exige as paredes certas.

O headless é onde o Kiro deixa de ser uma ferramenta pessoal e vira parte da máquina. Feito com least privilege e governança, ele carrega o trabalho tedioso e devolve a você o único recurso que a fatura do Kiro não vende: tempo.

Referências


Este artigo foi publicado originalmente no Medium. Preços, nomes de modelos e detalhes de produto refletem o estado do Kiro em meados de 2026 e podem mudar — confirme em kiro.dev antes de tomar decisões. Este é um conteúdo educacional independente, sem vínculo oficial com a AWS.

Tags: kiro, cicd, devops, automation, github-actions

Publicado originalmente em prompt.victorbatistax.com. Se você chegou por outra plataforma, esta é a versão canônica.