Desenvolvimento Ágil com IA — Guia Completo para Devs

 

Desenvolvimento Ágil com IA — Guia Completo para Devs

Metodologias, Ferramentas e Fluxos para o Desenvolvedor Moderno


"A IA não vai roubar o seu emprego. Um desenvolvedor usando IA vai."
— Paráfrase que circula em todo lugar, e que merece uma resposta muito mais nuançada do que parece.*


Sumário

Parte I — Fundamentos e Metodologias



Capítulo 1: O que muda no ágil quando o dev tem um copiloto IA


Introdução: o ágil nasceu para humanos, agora tem um não-humano no time

O Manifesto Ágil foi assinado em fevereiro de 2001, num resort de esqui no Utah, por dezessete desenvolvedores que estavam frustrados com processos pesados, documentação excessiva e a incapacidade de responder a mudanças. O documento que nasceu dali priorizava indivíduos e interações, software funcionando, colaboração com o cliente e resposta à mudança. Cada um desses quatro valores pressupõe algo: que os "indivíduos" são humanos.

Vinte e cinco anos depois, os times de desenvolvimento incluem um novo tipo de colaborador que não dorme, não tem ego, nunca vai embora de férias, responde em segundos, e é simultaneamente o dev mais rápido e o mais perigoso que você já teve na equipe. A IA generativa entrou no fluxo de trabalho dos times de software não como uma ferramenta de nicho — como um linter avançado ou um gerador de boilerplate — mas como um agente que participa ativamente do processo de construção de software. E isso quebra muitas das premissas que sustentam o ágil como o conhecemos.

Não se trata de um ajuste cosmético nos processos. Quando um desenvolvedor sênior consegue produzir em um dia o que antes levava uma semana, toda a cerimônia construída em torno de estimativas de esforço humano precisa ser repensada. Quando um agente de IA consegue gerar cem testes unitários em trinta segundos, o significado de "Definition of Done" muda. Quando um assistente de IA pode analisar um épico e sugerir a decomposição em stories, o papel do Scrum Master precisa evoluir.

Este capítulo não vai dizer que o ágil morreu. Vai argumentar que o ágil está passando pela maior revisão desde sua criação — e que os devs que entenderem isso antes dos outros vão ter uma vantagem competitiva enorme nos próximos anos.

⚠️ Armadilha: Não caia na armadilha de achar que "basta continuar fazendo ágil e usar IA nas tarefas de código". A IA não é apenas uma ferramenta de codificação — ela altera o fluxo inteiro, das estimativas ao review. Times que tratam IA como "autocomplete glorificado" deixam 80% do valor na mesa.


Velocidade de ciclos: sprints menores ou flow contínuo?

A questão central que emerge quando você coloca IA no processo ágil é: se o custo de produzir código caiu drasticamente, faz sentido continuar organizando o trabalho em sprints de duas semanas? Há dois campos com argumentos sólidos, e a resposta correta depende do contexto do seu time.

O argumento pelo sprint mais curto: Se a IA comprime o tempo de implementação, um sprint de duas semanas vira uma unidade excessivamente grande. Uma feature que antes levava quatro dias agora leva um dia. Uma story que era complexa agora é gerada em horas e revisada em mais algumas. Nesse cenário, sprints de uma semana — ou até de três dias para times muito maduros — fazem mais sentido. O feedback loop fica mais apertado, os ciclos de aprendizado se multiplicam, e o time se adapta muito mais rápido às mudanças de prioridade.

Times que adotaram sprints de uma semana com IA relatam consistentemente dois efeitos: o primeiro é que a cerimônia se torna mais leve (planejamento de 30 minutos em vez de 2 horas, retrospectiva rápida), e o segundo é que a pressão por qualidade aumenta porque não há tempo de "empurrar para o próximo sprint". Ou a story entra completa e testada, ou não entra. Essa pressão saudável tende a elevar o padrão de engenharia do time.

O argumento pelo flow contínuo (Kanban-like): Por outro lado, o flow contínuo (continuous flow) — modelo popularizado pelo Kanban — pode ser mais natural para times onde a IA permite entregas incrementais várias vezes ao dia. Se você consegue fazer deploy de uma feature em produção em algumas horas depois de abrir uma issue, o conceito de "sprint" começa a parecer artificial. Por que acumular trabalho numa janela de duas semanas se você pode entregar continuamente?

Esse argumento é especialmente forte em times com CI/CD (Integração Contínua / Entrega Contínua) maduro, onde o pipeline de qualidade é sólido o suficiente para absorver frequência de deploys alta. A IA, nesse contexto, atua como um acelerador de throughput (taxa de vazão), e o Kanban com WIP limits (limites de trabalho em progresso) bem calibrados se torna o framework natural.

A síntese pragmática: A maioria dos times pleno/sênior que trabalha com IA hoje adota uma posição híbrida: mantém sprints como unidade de planejamento e comprometimento com stakeholders, mas trabalha internamente em modo mais fluido. Os sprints viram "janelas de entrega de valor" acordadas externamente, enquanto o trabalho interno segue um fluxo mais contínuo. Isso é especialmente válido quando o negócio ainda opera com expectativas de sprint — mudar o contrato externo sem mudar a cultura da empresa primeiro é receita para conflito.

💡 Dica: Se o seu time está cogitando migrar de sprints de 2 semanas para 1 semana com IA, faça uma transição de 2 sprints experimentais. Meça o cycle time médio das stories antes e depois. Se o cycle time das stories caiu mais do que o comprimento do sprint, faz sentido continuar. Se não caiu, o gargalo não é o sprint — é outra coisa (provavelmente review ou deploy).


O papel do dev muda: de "digitador de código" para "revisor, arquiteto e orquestrador"

Uma das mudanças mais profundas — e que mais gera resistência — é a redefinição do que significa "ser desenvolvedor" num time que usa IA de forma séria. Historicamente, boa parte do valor de um dev sênior vinha da sua capacidade de produzir código complexo com velocidade e qualidade. Esse diferencial ainda existe, mas está sendo progressivamente comprimido.

O que não é comprimido — e que, na verdade, se torna mais valioso — é a capacidade de revisar, questionar, refinar e arquitetar. A IA gera código com uma fluidez impressionante, mas ela gera na direção que você aponta. Se você aponta na direção errada, ela vai com convicção total para o lugar errado. O dev sênior que sabe fazer as perguntas certas, que consegue identificar quando o código gerado resolve o problema superficial mas cria uma dívida técnica (technical debt) estrutural, que entende o domínio de negócio profundamente o suficiente para notar quando a IA está "inventando" uma solução que não se encaixa — esse dev se torna exponencialmente mais valioso.

Pense na analogia com o surgimento das IDEs modernas. Antes do autocomplete inteligente, do refactoring automatizado, do debugger integrado, programar era mais laborioso. As IDEs não eliminaram desenvolvedores — elevaram o nível mínimo de produtividade e permitiram que devs focassem em problemas mais complexos. A IA é uma IDEpotencializada por várias ordens de magnitude. O dev que resiste a usá-la vai ficar para trás, mas o dev que a usa sem julgamento crítico vai introduzir bugs e problemas que antes eram filtrados pela fricção natural do processo de codificação manual.

O novo papel do dev sênior pode ser descrito em três dimensões:

  1. Orquestrador de agentes: Saber decompor um problema em partes que a IA consegue resolver bem, sequenciar o trabalho, integrar os resultados e manter coerência global.

  2. Revisor crítico: Revisar output de IA com profundidade técnica — não apenas "esse código compila", mas "esse código faz o que deveria? Tem edge cases? Tem implicações de segurança? Tem problema de performance em escala?"

  3. Guardião de arquitetura: A IA não tem memória de longo prazo sobre as decisões arquiteturais do seu sistema. Ela vai sugerir soluções que fazem sentido localmente mas violam padrões globais. O dev sênior é o guardião dessas decisões.

⚠️ Armadilha: Desenvolvedores júnior e pleno que usam IA sem entender o que ela está gerando são um risco sério para o time. A IA pode produzir código que parece certo mas tem falhas sutis de concorrência, vazamento de memória, ou problemas de segurança que só aparecem em produção. É tentador aceitar o código gerado sem entender — resist isso.

// Exemplo: IA gerou esse código para buscar usuário
// Parece correto à primeira vista...
async function getUser(id: string) {
  const user = await db.query(`SELECT * FROM users WHERE id = ${id}`);
  return user;
}

// Problema: SQL injection clássico.
// O dev que não revisou com atenção deixou isso passar.
// Versão correta:
async function getUserSafe(id: string) {
  const user = await db.query('SELECT * FROM users WHERE id = $1', [id]);
  return user;
}

Impacto em estimativas: story points perdem sentido?

Story points (pontos de história) foram criados para capturar esforço relativo, não tempo absoluto. A ideia era: ao invés de dizer "isso vai levar 3 dias", você diz "isso é mais complexo que aquilo, então é um 8 comparado ao 3". A relatividade protegia as estimativas da falácia de planejamento e das pressões de negócio por datas fixas.

Com IA, o modelo quebra de um jeito específico: a distribuição de esforço dentro das stories muda de forma não-linear e imprevisível. Uma story de backend que antes era um 5 pode virar um 1 com IA. Uma story de integração com sistema legado que antes era um 8 pode continuar sendo um 8 porque o legado é opaco demais para a IA ajudar. O problema é que você não sabe, antes de tentar, qual categoria a story vai cair.

Além disso, o que a IA comprime é principalmente o tempo de implementação. Ela não comprime (e muitas vezes expande) o tempo de:

  • Entendimento do problema (discovery)
  • Review e validação do código gerado
  • Integração com partes do sistema que a IA não conhece
  • Debugging quando o código gerado tem bugs sutis

Então as estimativas em story points ficam voláteis de uma forma nova: stories que pareciam similares em complexidade acabam tendo tempos muito diferentes dependendo de quanto a IA consegue ajudar.

O que usar no lugar (ou em complemento)? Algumas alternativas que times sênior estão experimentando:

Métrica Como funciona Vantagem Desvantagem
T-shirt sizing com IA-flag S/M/L/XL + flag se IA vai ajudar muito Simples, captura a variável IA Ainda é estimativa
Cycle time histórico Medir tempo real das últimas N stories similares Baseado em dados reais Requer histórico com IA
Splitting agressivo Quebrar até stories não estimáveis ficarem estimáveis Elimina incerteza Overhead de processo
Flow metrics (vazão) Medir throughput real e usar para forecast Científico, baseado em dados Não diz nada sobre stories individuais
Confidence-based Escala 1-5 de confiança na estimativa Captura incerteza explicitamente Requer maturidade do time

A tendência mais sólida entre times maduros é reduzir a ênfase em estimativas por story e aumentar a ênfase em métricas de fluxo. Se o seu time consegue medir consistentemente o cycle time (tempo de ciclo) médio por tipo de story (feature, bug, refactor), você tem uma base muito mais sólida para forecasting do que qualquer estimativa em pontos.

🔧 Na prática: Experimente adicionar um campo simples no seu Jira/Linear/GitHub: "IA-Assist Level" com valores Low/Medium/High. Ao final do sprint, compare o cycle time real por nível de assist. Em 2-3 sprints, você vai ter dados empíricos sobre o quanto a IA impacta o seu time específico — e pode calibrar estimativas com base nisso.


Planning poker com IA: como adaptar a cerimônia

O planning poker (pôquer de planejamento) tem uma função que vai além da estimativa: é uma cerimônia de alinhamento. Quando toda a equipe vota e os votos divergem, a conversa que se segue é onde o real entendimento coletivo da story acontece. Essa função não desaparece com IA — de certa forma, fica mais importante.

O que muda é o conteúdo da cerimônia. Algumas adaptações práticas que times estão adotando:

Antes da sessão de planning:

  • Use a IA para gerar uma análise preliminar da story: "Dado esse requisito, quais são as ambiguidades? Quais edge cases não foram considerados? Qual seria uma abordagem técnica inicial?"
  • Isso não substitui a discussão do time — serve como material de partida que garante que todos chegam na mesma página mínima.

Durante a estimativa:

  • Inclua explicitamente a pergunta: "Quanto dessa story a IA consegue gerar diretamente?"
  • Crie uma convenção no seu baralho: cartas normais para esforço total, e um marcador adicional indicando "IA Heavy" (mais de 60% gerado por IA) ou "IA Light" (menos de 30%).
  • Votos muito discrepantes podem indicar que diferentes membros têm visões diferentes do quanto a IA vai ajudar — o que é uma informação valiosa.

Após o sprint:

  • Revise sistematicamente: as stories marcadas como "IA Heavy" de fato levaram menos tempo? A estimativa foi acurada?
// Exemplo de prompt para usar na fase de preparação do planning:
const storyAnalysisPrompt = `
Analise a seguinte user story e responda:
1. Quais são as ambiguidades ou lacunas nos critérios de aceite?
2. Quais edge cases não estão cobertos?
3. Qual seria a abordagem técnica de alto nível?
4. Estimativa de quanto dessa implementação pode ser gerada diretamente por IA (0-100%)?
5. Quais partes requerem mais julgamento humano?

Story: ${story.description}
Critérios de aceite: ${story.acceptanceCriteria}
Contexto técnico: ${technicalContext}
`;

💡 Dica: Não elimine o planning poker. A cerimônia tem valor social e de alinhamento que a IA não substitui. O que muda é o objeto da discussão: menos "quanto tempo para implementar" e mais "qual é o risco dessa story, quais decisões técnicas precisamos tomar antes de começar".


O paradoxo da produtividade: mais output ≠ mais valor entregue

Esse é talvez o ponto mais contraintuitivo — e mais importante — deste capítulo. Com IA, a capacidade de gerar output de software (código, testes, documentação, configurações) aumenta dramaticamente. Times relatam aumento de 2x a 4x na quantidade de código produzido. E aí está a armadilha.

Mais código não é necessariamente mais valor. Software bem projetado tem o mínimo de código necessário para resolver o problema. Código desnecessário é passivo — ele precisa ser mantido, testado, entendido, migrado. Um time que usa IA para produzir três vezes mais código pode estar criando três vezes mais dívida técnica se não houver rigor na curadoria do output.

O paradoxo se manifesta de formas específicas:

O efeito "sim" fácil demais: Quando implementar uma feature leva horas em vez de dias, fica difícil dizer não para requisitos que antes seriam descartados pelo custo de implementação. O negócio descobre isso e começa a pedir mais coisas. O produto cresce em features, mas nem sempre em valor percebido pelo usuário. O fenômeno tem nome: feature creep (inchaço de funcionalidades), e a IA pode acelerar ele drasticamente.

O problema da qualidade oculta: Um dev experiente, ao implementar manualmente uma feature complexa, naturalmente faz escolhas de design que refletem anos de experiência. A IA, ao gerar o mesmo código, pode fazer escolhas tecnicamente corretas mas arquiteturalmente inadequadas para o contexto — e como o código "funciona", esse problema não aparece imediatamente.

A armadilha do throughput como métrica: Times que começam a medir produtividade pelo número de stories fechadas por sprint vão entrar num loop perverso: stories são quebradas em partes menores para parecer que mais coisas estão sendo entregues, a IA fecha cada parte rapidamente, os números são impressionantes, mas o valor real entregue ao usuário não cresce na mesma proporção.

A resposta para esse paradoxo não é usar menos IA — é elevar o padrão de curadoria e clareza de valor. Cada story precisa ter uma hipótese de valor clara: "Esperamos que isso aumente X métrica em Y%". Sem isso, você não tem como saber se o output de IA está sendo convertido em valor real.

⚠️ Armadilha: Cuidado com o "velocity theater" (teatro de velocidade): times que aumentam velocity dramaticamente com IA mas não têm métricas de valor correspondentes estão apenas simulando produtividade. Stakeholders eventualmente percebem que features são entregues mas problemas reais não são resolvidos.


Code review ganha importância: IA gera volume, humano garante qualidade

Se há uma prática ágil que se torna mais importante, não menos, na era da IA, é o code review (revisão de código). Historicamente, em times de alta pressão, o code review era tratado como burocracia — um checkbox necessário antes do merge. Com IA gerando código em escala, essa prática se torna a linha de defesa primária contra degradação de qualidade.

O código gerado por IA tem características específicas que o tornam diferente do código humano:

  1. Confiança aparente: O código de IA parece certo. Está bem formatado, tem nomes razoáveis, segue padrões. Isso cria uma ilusão de qualidade que pode diminuir a atenção do revisor.

  2. Correção local, problema global: A IA otimiza para o contexto imediato. Um componente pode ser implementado de forma excelente isoladamente, mas violar convenções do projeto, duplicar lógica existente em outro módulo, ou criar acoplamento desnecessário.

  3. Edge cases ausentes: A IA tende a implementar o caminho feliz (happy path) muito bem. Edge cases, tratamento de erros, comportamentos em condições de rede ruim, race conditions — esses são frequentemente esquecidos ou implementados de forma superficial.

  4. Segurança: Como vimos no exemplo de SQL injection, a IA pode gerar código com vulnerabilidades de segurança clássicas, especialmente quando o prompt não especifica explicitamente os requisitos de segurança.

A implicação prática é que o code review precisa ser mais estruturado, não menos. Um bom framework de review para código gerado por IA inclui:

// Checklist de code review para código gerado por IA

interface AICodeReviewChecklist {
  correctness: {
    happyPath: boolean;        // O caminho principal funciona?
    edgeCases: boolean;        // Edge cases foram considerados?
    errorHandling: boolean;    // Erros são tratados adequadamente?
  };
  architecture: {
    duplication: boolean;      // Não há lógica duplicada no projeto?
    coupling: boolean;         // Acoplamento está adequado?
    patterns: boolean;         // Segue os padrões do projeto?
  };
  security: {
    injection: boolean;        // Sem SQL/Command injection?
    xss: boolean;              // Sem XSS se aplicável?
    auth: boolean;             // Autorização verificada onde necessário?
    secrets: boolean;          // Sem segredos hardcoded?
  };
  performance: {
    nPlusOne: boolean;         // Sem N+1 queries?
    memoryLeaks: boolean;      // Sem memory leaks óbvios?
    bigO: boolean;             // Complexidade aceitável?
  };
  tests: {
    coverage: boolean;         // Testes cobrem casos relevantes?
    quality: boolean;          // Testes testam comportamento, não implementação?
    edge: boolean;             // Edge cases testados?
  };
}

Além disso, a IA pode ser usada no próprio review — mas com cuidado. Pedir à IA para revisar código gerado pela IA pode criar um loop de confirmação onde ambos concordam com soluções incorretas. O melhor modelo é: IA gera, humano revisa com assistência de IA para pontos específicos (segurança, performance), humano toma a decisão final.

💡 Dica: Considere adicionar ao seu processo uma etapa de "adversarial review": após o review normal, peça explicitamente à IA "Quais são os três piores problemas nesse código que um revisor humano poderia ter perdido?" Isso frequentemente revela issues que passaram pelo review inicial.


Definition of Done na era IA: o que muda?

O Definition of Done (Definição de Pronto) é o contrato do time sobre o que significa "terminado". Na era da IA, essa definição precisa ser explicitamente atualizada para endereçar os novos riscos introduzidos pelo código gerado automaticamente.

Um DoD tradicional pode incluir itens como: código revisado, testes passando, documentação atualizada, deploy em staging, aceite do PO. Esses itens continuam válidos, mas alguns ganham novas camadas de significado e novos itens precisam ser adicionados.

Itens que ganham nova camada de significado:

  • "Código revisado" agora significa revisado com a consciência de que foi parcialmente gerado por IA, aplicando o checklist mais rigoroso descrito acima.
  • "Testes passando" agora inclui a pergunta: "Os testes foram escritos por humano ou gerados por IA? Se gerados por IA, um humano os revisou para garantir que testam o comportamento correto?"
  • "Documentação atualizada" inclui agora: "O ADR (Architecture Decision Record) foi atualizado se decisões arquiteturais foram tomadas, mesmo que a implementação tenha sido gerada por IA?"

Novos itens para considerar:

  • IA-assisted review completado: O código passou por pelo menos uma análise de segurança assistida por IA além do review humano.
  • Edge cases documentados: Os edge cases identificados durante o desenvolvimento (seja por humano ou IA) estão documentados, testados ou explicitamente descartados com justificativa.
  • Sem code smells de IA: O código não contém padrões típicos de geração por IA sem revisão: comentários excessivos e óbvios, nomes genéricos demais, over-engineering para o problema simples.
  • Hipótese de valor validável: A feature tem uma métrica associada que permitirá validar se gerou o valor esperado.

🔧 Na prática: Faça uma sessão de retrospectiva específica para revisar e atualizar o DoD do time considerando o uso de IA. Mostre exemplos concretos de bugs que chegaram a produção porque o DoD tradicional não capturava os riscos específicos de código gerado por IA. Isso tende a gerar engajamento real com a mudança.


🔧 Na prática: checklist de adaptação do seu processo ágil atual

Abaixo, um checklist acionável para times que estão começando a usar IA de forma séria e precisam adaptar seu processo. Não faça tudo de uma vez — escolha 2-3 itens por sprint para experimentar.

Sprint e cerimônias:

  • Avaliar se sprint de 1 semana faz sentido para o contexto do time
  • Adicionar "AI-Assist Level" como campo nas stories
  • Adaptar o planning para incluir análise prévia de IA das stories
  • Criar slot de 5 minutos na daily para "o que a IA ajudou/travou ontem"
  • Adicionar métricas de IA na retrospectiva (tempo economizado, bugs introduzidos)

Estimativas:

  • Começar a medir cycle time real por categoria de story
  • Experimentar confidence-based estimation em paralelo com story points
  • Criar histórico separado de estimativas "IA Heavy" vs "IA Light"

Code review:

  • Criar checklist específico para código gerado por IA
  • Implementar "adversarial review" como step opcional
  • Definir critério claro de quando IA pode revisar IA vs quando humano é obrigatório

Definition of Done:

  • Revisar e atualizar DoD com itens específicos de IA
  • Adicionar requisito de hipótese de valor mensurável por feature
  • Incluir review de edge cases como item explícito

Métricas:

  • Parar de usar velocity como métrica primária de saúde do time
  • Começar a medir cycle time, throughput e bug rate em produção
  • Criar dashboard simples com: stories entregues, cycle time médio, bugs pós-deploy

Resumo de bolso

  • O ágil não morreu, mas precisa de revisão profunda: As cerimônias e valores continuam válidos, mas as premissas de esforço humano que os sustentam mudaram.
  • O papel do dev sênior evolui para orquestrador, revisor e guardião de arquitetura: Produzir código perde peso relativo; revisar, questionar e arquitetar ganham.
  • Story points ficam voláteis com IA: Experimente métricas de fluxo (cycle time, throughput) como complemento ou substituto.
  • Mais output não é mais valor: O paradoxo da produtividade exige que cada feature tenha hipótese de valor clara; code review se torna mais, não menos, importante.
  • Atualize seu DoD explicitamente: Os riscos do código gerado por IA não são capturados pelo DoD tradicional — adicione itens específicos para cobri-los.


Capítulo 2: BMAD Method — Guia Completo


O que é BMAD

BMAD — sigla para BMad Agentic Development Method (Método de Desenvolvimento Agêntico BMad) — é uma metodologia estruturada para desenvolvimento de software com agentes de IA. O nome vem do seu criador, um desenvolvedor que publicou o método em repositórios públicos e ganhou tração significativa na comunidade de desenvolvedores que trabalham com agentes de IA de forma séria.

Em sua essência, o BMAD é uma resposta ao "vibe coding" desestruturado: ele pega a ideia de usar IA para gerar software, mas coloca estrutura, papéis, artefatos e um fluxo claro em cima disso. O resultado é uma metodologia que consegue capturar a velocidade do desenvolvimento assistido por IA sem abrir mão da disciplina arquitetural e de produto que projetos reais exigem.

O BMAD define um conjunto de personas de IA especializadas — cada uma com um papel, contexto e conjunto de responsabilidades bem definidos. Em vez de jogar um prompt gigante para uma IA e esperar um sistema completo sair, o BMAD guia o desenvolvedor por uma sequência de interações com diferentes personas, cada uma produzindo artefatos específicos que alimentam a próxima etapa.

Pense no BMAD como um processo de consultoria condensado: você passa por fases de discovery, product management, arquitetura, planejamento e implementação, mas cada fase é acelerada por uma persona de IA especializada e produz documentos concretos que funcionam como contratos entre as fases.


Origem e filosofia: "vibe coding" estruturado com agentes especializados

Para entender por que o BMAD existe, é preciso entender o fenômeno que ele responde. O "vibe coding" — termo cunhado por Andrej Karpathy, ex-diretor de IA da Tesla e pesquisador fundador da OpenAI — descreve uma forma de programar onde você descreve o que quer para uma IA em linguagem natural, ela gera o código, e você aceita sem necessariamente entender cada linha. "Vibe in, code out."

Esse modelo funciona surpreendentemente bem para protótipos, scripts descartáveis e exploração de ideias. É genuinamente libertador: qualquer pessoa com uma ideia e capacidade de articulá-la em linguagem natural consegue criar software funcional em horas. Isso democratiza a criação de software de uma forma que o mundo nunca viu.

O problema é que o vibe coding puro não escala. Quando o projeto cresce além de alguns arquivos, quando múltiplos devs precisam trabalhar juntos, quando o código vai para produção com usuários reais, a falta de estrutura começa a cobrar seu preço. A IA não mantém consistência arquitetural entre sessões. Decisões de design que pareciam razoáveis em isolamento criam conflitos quando integradas. O código funciona, mas ninguém — nem o humano nem a IA — entende o sistema como um todo.

O BMAD não rejeita o poder do vibe coding. Ele o abraça e coloca estrutura ao redor para que os resultados sejam aproveitáveis em projetos reais. A filosofia central é: use agentes especializados para cada fase, produza artefatos que capturam decisões, e trate esses artefatos como a memória persistente que a IA não tem nativamente.

💡 Dica: O BMAD funciona melhor quando você trata os artefatos como documentos vivos, não como burocracia. Um PRD bem escrito não é overhead — é a fundação que vai guiar o agente de implementação semanas depois sem que você precise re-explicar tudo.


O problema que o BMAD resolve

Para ser preciso sobre o valor do BMAD, é útil nomear os problemas concretos que ele resolve:

Problema 1: Inconsistência entre sessões de IA
Uma IA generativa não tem memória entre sessões (ou tem memória limitada dentro de uma janela de contexto). Se você desenvolve uma feature hoje e outra amanhã, a IA da segunda sessão não "sabe" as decisões que foram tomadas na primeira. O resultado são inconsistências — nomes diferentes para o mesmo conceito, padrões diferentes para casos similares, duplicação de lógica. O BMAD resolve isso com artefatos: o Architecture Doc, o PRD, os Data Models são documentos que você carrega no contexto da IA a cada sessão, garantindo consistência.

Problema 2: Falta de direção de produto
O vibe coding começa com "cria um app de X" e a IA faz suas próprias escolhas sobre o que X significa. Essas escolhas podem não corresponder ao que o usuário real precisa. O BMAD coloca o Product Manager (PM) persona na frente do processo, forçando clareza sobre usuários, problemas e métricas de sucesso antes de qualquer linha de código ser gerada.

Problema 3: Decisões arquiteturais precipitadas
Sem uma fase de arquitetura, a IA vai fazer escolhas de tech stack e design baseada nas soluções mais comuns que viu no treinamento. Essas escolhas podem não ser adequadas para o contexto específico do projeto. O BMAD tem uma fase dedicada de arquitetura com um Architect persona que explicitamente considera os trade-offs antes de decidir.

Problema 4: Stories mal definidas levando a implementações erradas
Uma story vaga resulta em implementação que tecnicamente satisfaz o texto da story mas não o intent por trás dela. O BMAD tem um Scrum Master persona dedicado a quebrar requisitos em stories com critérios de aceite claros e testáveis.

Problema 5: Falta de validação estruturada
No vibe coding puro, a validação é "parece que funciona". O BMAD tem um QA persona que gera checklists de validação baseados nos critérios de aceite das stories, garantindo que a implementação é testada de forma sistemática.

⚠️ Armadilha: O BMAD não vai fazer decisões de negócio por você. As personas de IA são excelentes em estruturar e sugerir, mas as decisões de priorização, escopo e trade-offs ainda precisam vir de humanos com contexto de negócio real. Não delegar isso para a IA é fundamental.


As personas e agentes do BMAD

O coração do BMAD são suas personas especializadas. Cada persona é, na prática, um prompt de sistema (system prompt) ou um conjunto de instruções que configura a IA para operar com um papel específico, usando terminologia e frameworks adequados para aquele papel.

Analyst (Analista)

O Analyst é a primeira persona ativada em qualquer projeto BMAD. Seu papel é entender o problema antes de qualquer solução ser considerada.

Responsabilidades:

  • Conduzir pesquisa de domínio: entender o problema de negócio, o mercado, os usuários
  • Identificar stakeholders e suas necessidades
  • Mapear constraints: técnicos, regulatórios, de tempo, de orçamento
  • Produzir um documento de Discovery que captura o entendimento inicial do problema

Como ativar: Em ferramentas como Claude Code, o Analyst é tipicamente ativado via uma instrução de sistema que define seu papel. Em sessões de chat, você instrui explicitamente: "Atue como Analyst para o projeto X. Seu trabalho é me ajudar a entender o problema antes de qualquer solução."

Artefato de saída: Discovery Document — um documento de 1-3 páginas cobrindo problema, usuários, jobs-to-be-done (trabalhos a realizar), métricas de sucesso e constraints.

// Exemplo de prompt para ativar o Analyst
const analystPrompt = `
Você é o Analyst do projeto ${projectName}.

Seu papel é conduzir o discovery do projeto ANTES de qualquer decisão técnica.
Você deve:
1. Fazer perguntas para entender profundamente o problema de negócio
2. Identificar os usuários primários e secundários e seus jobs-to-be-done
3. Mapear constraints (tempo, budget, técnicos, regulatórios)
4. Identificar riscos e incertezas críticas
5. Produzir um Discovery Document estruturado ao final

NÃO faça sugestões de solução técnica. Seu foco é entender o problema.
Comece fazendo as 5 perguntas mais importantes sobre o projeto.
`;

Product Manager (PM)

O PM entra após o Discovery. Com o entendimento do problema em mãos, o PM transforma isso em um documento de requisitos estruturado.

Responsabilidades:

  • Transformar o Discovery Document em um PRD (Product Requirements Document — Documento de Requisitos de Produto)
  • Definir user stories de alto nível
  • Estabelecer métricas de sucesso mensuráveis
  • Priorizar funcionalidades com critérios explícitos
  • Definir o escopo do MVP (Produto Mínimo Viável) vs fases futuras

Artefato de saída: PRD — um documento estruturado com overview do produto, user personas, user stories, métricas de sucesso, e escopo por fase.

Architect (Arquiteto)

O Architect transforma os requisitos do PRD em decisões técnicas estruturadas.

Responsabilidades:

  • Definir o tech stack com justificativas claras
  • Projetar a arquitetura do sistema (componentes, integrações, data flow)
  • Criar data models iniciais
  • Definir API contracts de alto nível
  • Produzir diagramas de arquitetura (em texto/Mermaid quando em contexto de IA)
  • Identificar riscos técnicos e mitigações

Artefato de saída: Architecture Document — tech stack, diagrama de componentes, data models, API contracts, decisões arquiteturais (ADRs).

// Exemplo de um diagrama de arquitetura em Mermaid gerado pelo Architect persona
const architectureDiagram = `
graph TD
    Client[React Frontend] --> API[Node.js API Gateway]
    API --> Auth[Auth Service]
    API --> Core[Core Business Logic]
    Core --> DB[(PostgreSQL)]
    Core --> Cache[(Redis)]
    Core --> Queue[Message Queue]
    Queue --> Worker[Background Workers]
    Worker --> DB
    Worker --> External[External APIs]
`;

Scrum Master / Project Manager

Após a arquitetura definida, o Scrum Master quebra o trabalho em unidades implementáveis.

Responsabilidades:

  • Criar épicos a partir das funcionalidades do PRD
  • Quebrar épicos em stories com critérios de aceite claros
  • Sequenciar stories considerando dependências
  • Estimar complexidade relativa com justificativa
  • Garantir que cada story é independente, negociável, valiosa, estimável, pequena e testável (critérios INVEST)

Artefato de saída: Story Map — conjunto de épicos e stories organizados por prioridade, com critérios de aceite em formato Given/When/Then.

Developer (Desenvolvedor)

O Developer persona é ativado story a story durante a implementação.

Responsabilidades:

  • Implementar a story especificada seguindo os padrões do Architecture Document
  • Gerar testes (unitários e de integração) para o código implementado
  • Seguir os padrões de código definidos no projeto
  • Documentar decisões de implementação não óbvias
  • Identificar e reportar quando a story tem ambiguidades ou problemas

Nota importante: O Developer persona opera com o contexto dos artefatos anteriores (PRD, Architecture Doc, Story), não em isolamento. Isso é o que garante consistência.

QA (Quality Assurance — Garantia de Qualidade)

O QA valida a implementação contra os critérios de aceite.

Responsabilidades:

  • Gerar checklists de validação baseados nos critérios de aceite
  • Identificar casos de teste negativos (o que deveria falhar)
  • Revisar o código sob perspectiva de qualidade e segurança
  • Produzir relatório de validação antes do merge

🔧 Na prática: Você não precisa ativar todas as personas para todo projeto. Para um MVP simples, você pode pular o Analyst e começar do PM. Para um hotfix, você vai direto ao Developer. O BMAD é um menu, não um trilho fixo.


Fluxo completo passo a passo

Passo 1: Discovery (Analyst)

O Discovery é a fase mais negligenciada no desenvolvimento tradicional e a mais negligenciada no vibe coding. É também onde mais valor é destruído — ao pular o discovery, você arrisca construir a coisa certa do jeito errado, ou pior, a coisa errada do jeito certo.

No BMAD, você ativa o Analyst persona e conduz uma sessão estruturada de perguntas e respostas. A IA faz perguntas, você responde com o conhecimento que tem sobre o domínio. O Analyst sintetiza isso em um Discovery Document.

Duração típica: 30-60 minutos de conversa com o Analyst. Pode ser mais para domínios complexos.

Perguntas-chave que o Analyst deve endereçar:

  • Qual é o problema que estamos resolvendo? Para quem?
  • Quais são os jobs-to-be-done dos usuários primários?
  • O que existe hoje que resolve esse problema parcialmente? Por que não é suficiente?
  • Quais são os constraints inegociáveis (tempo, regulatório, técnico)?
  • Qual é a definição de sucesso em 3, 6 e 12 meses?
  • Quais são as maiores incertezas que poderiam fazer esse projeto falhar?

Passo 2: PRD (Product Manager)

Com o Discovery Document em mãos, você ativa o PM persona e pede para transformá-lo em um PRD. O PM vai estruturar o documento, fazer perguntas de clarificação onde o Discovery foi vago, e produzir algo que pode ser usado como base para arquitetura e planejamento.

Um bom PRD do BMAD inclui:

  • Overview: O que é o produto, para quem, por quê agora
  • User Personas: 2-3 personas com necessidades e contexto claros
  • User Stories de alto nível: Épicos escritos como "Como [persona], quero [ação] para [benefício]"
  • Métricas de sucesso: KPIs mensuráveis por fase
  • Escopo: O que está IN para o MVP, o que está OUT, o que está em fases futuras
  • Constraints: Técnicos, de negócio, de tempo

Passo 3: Architecture Document (Architect)

O Architect recebe o PRD e produz o Architecture Document. Esta é a fase que mais diferencia o BMAD do vibe coding puro — a IA não escolhe tecnologia arbitrariamente, ela analisa os requisitos e constraints e justifica cada escolha.

Para cada decisão técnica importante, o Architect deve documentar:

  • A decisão tomada
  • As alternativas consideradas
  • O racional para a escolha feita
  • As implicações e trade-offs

Isso cria o que são chamados de ADRs (Architecture Decision Records — Registros de Decisão de Arquitetura), que servem como memória do projeto.

Passo 4: Story Mapping (Scrum Master)

Com PRD e Architecture Document, o Scrum Master quebra o trabalho. O processo é:

  1. Identificar épicos a partir das funcionalidades do PRD
  2. Para cada épico, identificar as stories
  3. Para cada story, escrever critérios de aceite em formato Given/When/Then
  4. Sequenciar as stories considerando dependências técnicas e valor de negócio
## Template de Story BMAD

### Story: [ID] — [Título]

**Como** [persona]
**Quero** [ação]
**Para** [benefício]

### Critérios de Aceite

**Cenário 1: [nome do cenário]**
- **Dado** [estado inicial do sistema]
- **Quando** [ação do usuário ou evento]
- **Então** [resultado esperado]

**Cenário 2: [caso de erro ou alternativo]**
- **Dado** [estado inicial]
- **Quando** [ação]
- **Então** [resultado]

### Notas Técnicas
- Referência ao componente do Architecture Doc: [componente]
- Data model envolvido: [modelo]
- APIs relevantes: [endpoints]
- Dependências: [stories que devem vir antes]

### Definição de Pronto
- [ ] Implementação completa seguindo Architecture Doc
- [ ] Testes unitários cobrindo critérios de aceite
- [ ] Code review aprovado
- [ ] QA checklist completado

Passo 5: Implementação (Developer)

A implementação no BMAD segue um padrão específico: o Developer persona recebe uma story por vez, junto com o contexto dos artefatos relevantes (Architecture Doc, data models, API contracts). Isso garante que cada implementação é coerente com o projeto como um todo.

O Developer é instruído a:

  1. Ler a story e critérios de aceite completamente antes de escrever código
  2. Verificar o Architecture Doc para entender os padrões a seguir
  3. Implementar o mínimo necessário para satisfazer os critérios de aceite
  4. Gerar testes que validam os critérios de aceite
  5. Reportar ambiguidades ao invés de inventar soluções

Passo 6: QA e Review

O QA persona gera um checklist de validação baseado nos critérios de aceite e verifica a implementação. Isso não substitui o code review humano — complementa ele com uma perspectiva estruturada.


Artefatos do BMAD

Os artefatos são a memória do projeto. Eles são o que transforma o BMAD de vibe coding estruturado para metodologia de engenharia real.

Artefato Persona Conteúdo Uso nas fases seguintes
Discovery Document Analyst Problema, usuários, constraints, incertezas Alimenta o PRD
PRD Product Manager Personas, stories, métricas, escopo Alimenta arquitetura e stories
Architecture Document Architect Tech stack, componentes, data models, ADRs Alimenta todas as implementações
Tech Stack Doc Architect Versões, dependências, configurações Dev e DevOps
Data Models Architect Schemas, relacionamentos, validações Dev e DB
Epic Map Scrum Master Lista de épicos com descrição e prioridade Planejamento
Story Templates Scrum Master Stories com critérios de aceite Dev e QA
QA Checklist QA Validações por story Review e aceite

Exemplo de PRD para um app de Todo List

A seguir, um exemplo condensado mas representativo de como um PRD BMAD se parece para um projeto simples — um app de gestão de tarefas (todo list) com foco em times pequenos.


# PRD — TaskFlow (App de Gestão de Tarefas para Times)

## Versão: 1.0 | Data: Maio 2026 | Status: Aprovado

---

## 1. Overview

### Problema
Times pequenos (2-8 pessoas) gastam tempo excessivo em ferramentas de gestão de
tarefas complexas demais para suas necessidades, ou usam planilhas e chats que
não têm estrutura suficiente.

### Solução
TaskFlow é um app web de gestão de tarefas focado em simplicidade radical para
times pequenos. Sem Gantt charts, sem campos customizados infinitos, sem
integrações complexas na v1.

### Por que agora
A adoção de ferramentas de trabalho assíncrono aumentou 40% pós-pandemia.
Times remotos precisam de ferramentas simples que funcionem.

---

## 2. User Personas

### Ana — Tech Lead
- 32 anos, lidera time de 5 devs em startup
- Job-to-be-done: ver o status do que o time está fazendo sem precisar
  interromper as pessoas
- Frustrações atuais: Jira é pesado demais, Trello não tem visão de quem está
  fazendo o quê

### Carlos — Dev Fullstack
- 28 anos, membro do time da Ana
- Job-to-be-done: saber o que precisa fazer hoje sem reuniões desnecessárias
- Frustrações atuais: recebe tarefas via Slack e perde o contexto

---

## 3. User Stories de Alto Nível (Épicos)

### Épico 1: Gestão de Tarefas
- Como Ana, quero criar e atribuir tarefas para membros do time para organizar
  o trabalho
- Como Carlos, quero ver minhas tarefas do dia em uma view clara para saber
  o que fazer

### Épico 2: Visibilidade do Time
- Como Ana, quero ver o status de todas as tarefas em andamento para identificar
  bloqueios
- Como Ana, quero receber notificação quando uma tarefa crítica fica sem
  andamento por 2+ dias

### Épico 3: Colaboração Simples
- Como Carlos, quero comentar em uma tarefa para comunicar bloqueios ou
  progresso sem usar o Slack
- Como Ana, quero ver o histórico de uma tarefa para entender como ela evoluiu

---

## 4. Métricas de Sucesso

### MVP (3 meses):
- 100 times cadastrados
- Retention 30 dias: >40%
- NPS: >30
- Tempo médio para criar primeira tarefa: <2 minutos

### v1.1 (6 meses):
- 500 times ativos mensais
- Retention 90 dias: >30%
- Churn mensal: <5%

---

## 5. Escopo

### IN — MVP:
- Autenticação (email/senha + convite por email)
- Criar, editar, excluir tarefas
- Atribuir tarefas a membros
- Status: To Do / In Progress / Done
- View de board (Kanban simples)
- View "Minhas Tarefas Hoje"
- Comentários em tarefas
- Notificações por email (tarefa atribuída, comentário)

### OUT — MVP:
- Mobile app nativo
- Integrações (Slack, GitHub, etc.)
- Campos customizados
- Relatórios e dashboards
- Sub-tarefas
- Datas de prazo (adicionado v1.1)

### Fases Futuras:
- v1.1: Deadlines, labels, busca
- v1.2: Integrações Slack e GitHub
- v2.0: Mobile app

---

## 6. Constraints

- **Tempo:** MVP em 6 semanas (time de 2 devs)
- **Técnico:** Deve funcionar sem necessidade de app nativo na v1
- **Infraestrutura:** Budget de infra máximo $200/mês no MVP
- **Regulatório:** Dados de usuários na mesma região (LGPD compliance básico)

BMAD + Claude Code: mapeando personas para agentes

O Claude Code tem uma feature de "skills" ou "agents" que se mapeia naturalmente para o modelo de personas do BMAD. Cada persona pode ser implementada como um agente com seu próprio system prompt, conjunto de ferramentas e artefatos de contexto.

O mapeamento prático:

// Estrutura de um agente BMAD no Claude Code
interface BMADAgent {
  name: string;
  systemPrompt: string;
  contextFiles: string[];   // Artefatos que este agente lê
  outputFiles: string[];    // Artefatos que este agente escreve
  tools: string[];          // Tools disponíveis para este agente
}

const bmadAgents: BMADAgent[] = [
  {
    name: "Analyst",
    systemPrompt: "Você é o Analyst. Foque em entender o problema, não em solucioná-lo...",
    contextFiles: [],
    outputFiles: ["docs/discovery.md"],
    tools: ["WebSearch", "Read", "Write"]
  },
  {
    name: "ProductManager",
    systemPrompt: "Você é o Product Manager. Transforme o discovery em requisitos estruturados...",
    contextFiles: ["docs/discovery.md"],
    outputFiles: ["docs/prd.md"],
    tools: ["Read", "Write"]
  },
  {
    name: "Architect",
    systemPrompt: "Você é o Architect. Tome decisões técnicas baseadas nos requisitos...",
    contextFiles: ["docs/prd.md"],
    outputFiles: ["docs/architecture.md", "docs/data-models.md"],
    tools: ["Read", "Write", "Glob"]
  },
  {
    name: "ScrumMaster",
    systemPrompt: "Você é o Scrum Master. Quebre o trabalho em stories implementáveis...",
    contextFiles: ["docs/prd.md", "docs/architecture.md"],
    outputFiles: ["docs/epics/", "docs/stories/"],
    tools: ["Read", "Write"]
  },
  {
    name: "Developer",
    systemPrompt: "Você é o Developer. Implemente a story especificada seguindo a arquitetura...",
    contextFiles: [
      "docs/architecture.md",
      "docs/data-models.md",
      "docs/stories/current-story.md"
    ],
    outputFiles: ["src/"],
    tools: ["Read", "Write", "Edit", "Bash", "Glob", "Grep"]
  },
  {
    name: "QA",
    systemPrompt: "Você é o QA. Valide a implementação contra os critérios de aceite...",
    contextFiles: [
      "docs/stories/current-story.md",
      "src/"
    ],
    outputFiles: ["docs/qa/validation-report.md"],
    tools: ["Read", "Bash", "Grep"]
  }
];

Na prática com Claude Code, você cria um arquivo de instrução para cada persona e o carrega no início da sessão correspondente. Uma convenção útil é manter uma pasta bmad/ na raiz do projeto com:

bmad/
  personas/
    analyst.md
    pm.md
    architect.md
    scrum-master.md
    developer.md
    qa.md
  artefatos/
    discovery.md
    prd.md
    architecture.md
    data-models.md
    epics/
    stories/
    qa-reports/

💡 Dica: Use o comando /init do Claude Code para criar um arquivo CLAUDE.md que define o projeto e referencia os artefatos BMAD. Isso garante que qualquer sessão tem acesso ao contexto básico do projeto sem que você precise re-explicar tudo.


Quando usar e quando não usar BMAD

Quando usar BMAD:

Projetos greenfield (do zero): O BMAD brilha quando você está começando algo novo e tem a oportunidade de fazer as coisas certas desde o início. A fase de discovery e arquitetura pagam dividendos enormes ao longo da vida do projeto.

MVPs com ambição de crescer: Se você está construindo um MVP que você espera iterar e escalar, o BMAD garante que as fundações são sólidas. Um MVP construído com BMAD tem arquitetura documentada, decisões justificadas e código coerente — o que acelera dramaticamente as iterações seguintes.

Refactoring grande: Quando você precisa refatorar um sistema legado significativamente, o BMAD pode guiar o processo: o Analyst entende o sistema atual, o PM define o estado desejado, o Architect planeja a transição, e o Developer executa story a story.

Times novos trabalhando juntos: O BMAD cria um vocabulário e processo compartilhado que ajuda times novos a alinhar rapidamente. Os artefatos servem como documentação viva do projeto.

Projetos com múltiplos stakeholders: O PRD e o Discovery Document são excelentes ferramentas de alinhamento com stakeholders não-técnicos. Eles capturam decisões de negócio de forma que todos podem revisar.

Quando NÃO usar BMAD:

Hotfix urgente em produção: Se há um bug crítico em produção, o BMAD é overhead desnecessário. Vá direto ao Developer (ou ao código, sem IA intermediária se o risco for alto).

Bug fix simples: Para bugs isolados e bem definidos, criar toda a estrutura BMAD é desproporcional. Use a IA diretamente para análise e correção.

Scripts descartáveis: Se você está escrevendo um script para processar um arquivo CSV uma vez e nunca mais, o vibe coding puro é mais eficiente.

Exploração e protótipagem: Quando o objetivo é aprender sobre um domínio ou explorar possibilidades, a liberdade do vibe coding é mais adequada que a estrutura do BMAD.

Time sem aderência ao processo: O BMAD requer que o time respeite os artefatos e siga o fluxo. Se o time vai ignorar os artefatos e fazer vibe coding de qualquer jeito, o BMAD vira overhead sem benefício.

Cenário BMAD? Por quê
Novo produto SaaS Sim Fundações importam
Feature em produto existente Parcial (SM + Dev) Arquitetura já existe
Hotfix urgente Não Velocidade > Processo
Bug fix isolado Não Desproporcional
MVP em 2 semanas Sim (versão lite) Vale o investimento
Script descartável Não Vibe coding é mais rápido
Refactoring grande Sim Sem estrutura, caos
Exploração/protótipo Não Liberdade > Estrutura

Dicas práticas e armadilhas comuns

Dica 1: Comece pelo Discovery mesmo que pareça óbvio
A tentação de pular o Discovery porque "eu já sei o que precisa ser construído" é enorme. Resista. O Analyst frequentemente revela ambiguidades e constraints que você não havia considerado. Uma hora de Discovery pode evitar semanas de retrabalho.

Dica 2: Trate os artefatos como documentos vivos
Os artefatos do BMAD não são documentação estática — eles evoluem conforme o projeto evolui. Quando o Architect decide mudar uma abordagem no meio do desenvolvimento, o Architecture Document precisa ser atualizado. Senão, ele se torna mentira documentada.

Dica 3: A granularidade das stories importa muito
Stories muito grandes para a IA implementar corretamente. Stories muito pequenas viram micro-tasks que perdem contexto. O sweet spot é uma story que pode ser implementada em 1-4 horas de sessão com IA, com critérios de aceite claros o suficiente para não haver ambiguidade.

Dica 4: Não deixe as personas decidirem por você
As personas de IA são consultores, não decisores. Quando o PM persona sugere um escopo, você pode — e deve — questionar e ajustar. Quando o Architect sugere uma tecnologia, você pode escolher diferente. A IA estrutura a conversa; você toma as decisões.

Dica 5: Context is king
A qualidade do output do BMAD é diretamente proporcional à qualidade do contexto que você fornece. Prompts vagos geram artefatos vagos. Artefatos vagos geram código ruim. Invista tempo em fornecer contexto rico, especialmente na fase de Discovery.

⚠️ Armadilha: O artefato como burocracia
O maior risco do BMAD é que os artefatos se tornem burocracia — documentos criados pro forma que ninguém lê ou atualiza. Se isso acontecer, você tem overhead sem benefício. A solução é tratar cada artefato como uma ferramenta de trabalho real, não como documentação para auditor.

⚠️ Armadilha: Persona drift (deriva de persona)
Em sessões longas, a IA pode "esquecer" que está atuando como uma persona específica e começar a misturar responsabilidades. O Architect começa a sugerir histórias de usuário; o Developer começa a questionar decisões de produto. Reforce a persona explicitamente quando isso acontecer: "Lembre-se que você está atuando como Architect. Seu foco agora é a decisão técnica, não o requisito de produto."

⚠️ Armadilha: Artefato desatualizado
Um Architecture Document que não reflete o código real é pior que não ter um — porque cria uma ilusão de documentação. Crie um processo (pode ser automatizado) para verificar regularmente se os artefatos estão sincronizados com a realidade do código.

// Exemplo: script simples para verificar se o Architecture Doc
// menciona os módulos que realmente existem no projeto
import { readFileSync, readdirSync } from 'fs';
import { join } from 'path';

function checkArchitectureSync(
  archDocPath: string,
  srcPath: string
): { missing: string[]; undocumented: string[] } {
  const archDoc = readFileSync(archDocPath, 'utf-8');
  const srcModules = readdirSync(srcPath, { withFileTypes: true })
    .filter(d => d.isDirectory())
    .map(d => d.name);

  const missing = srcModules.filter(m => !archDoc.includes(m));
  const documented = (archDoc.match(/## Componente: (\w+)/g) || [])
    .map(m => m.replace('## Componente: ', ''));
  const undocumented = documented.filter(d => !srcModules.includes(d));

  return { missing, undocumented };
}

const sync = checkArchitectureSync('./bmad/artefatos/architecture.md', './src');
if (sync.missing.length > 0) {
  console.warn('Módulos sem documentação:', sync.missing);
}
if (sync.undocumented.length > 0) {
  console.warn('Documentação sem módulo correspondente:', sync.undocumented);
}

Resumo de bolso

  • BMAD estrutura o vibe coding: É vibe coding com personas especializadas, artefatos vivos e fluxo definido — resolve o caos do vibe coding puro sem o overhead do waterfall.
  • As personas são a chave: Analyst (discovery), PM (produto), Architect (técnico), Scrum Master (stories), Developer (código), QA (validação) — cada um com escopo claro e artefato de saída.
  • Artefatos são a memória do projeto: O que a IA não tem nativamente, os artefatos fornecem — consistência entre sessões, decisões justificadas, contexto sempre disponível.
  • Use quando vale a pena: Greenfield, MVPs, refactoring grande — evite para hotfixes, bugs simples, scripts descartáveis.
  • O dev decide, a IA estrutura: As personas consultam, questionam e sugerem; as decisões finais são sempre do time humano.


Capítulo 3: Outras Metodologias AI-first — Comparativo


Agentic Scrum: sprints com agentes IA como membros do time

O Agentic Scrum (Scrum Agêntico) é uma evolução do Scrum onde agentes de IA não são apenas ferramentas que desenvolvedores usam, mas membros formais do time com papéis definidos, participação em cerimônias e responsabilidades claras. É, em alguns aspectos, a concretização mais literal da ideia de "IA no time ágil".

Como funciona

No Agentic Scrum, o time é composto de humanos e agentes. Um time típico pode ter:

  • 2-3 desenvolvedores humanos
  • 1 agente de desenvolvimento (que implementa stories)
  • 1 agente de QA (que valida automaticamente critérios de aceite)
  • 1 agente de documentação (que mantém docs atualizadas)

Os agentes participam das cerimônias de forma adaptada:

Sprint Planning: O agente de desenvolvimento recebe as stories priorizadas e produz uma estimativa de confiança (não tempo, mas confiança) para cada uma. Onde a confiança é baixa, o time discute o que está faltando para aumentá-la.

Daily Standup: Cada agente reporta o status das suas tasks automaticamente no início do dia: "Implementei a story X, encontrei ambiguidade no critério Y, aguardo clarificação". Isso alimenta o daily assíncrono do time humano.

Sprint Review: O agente de QA produz um relatório de validação automático para cada story implementada. O time humano revisa o relatório e toma a decisão de aceite ou rejeição.

Retrospectiva: Métricas dos agentes entram na retrospectiva: quantas stories precisaram de re-trabalho humano, quantas vezes o agente encontrou ambiguidades, onde o agente foi mais/menos eficaz.

Exemplo de sprint com agente

Considere um sprint de uma semana com uma story de criação de endpoint de API:

Segunda-feira (Planejamento):
- PM humano prioriza stories
- Agente Dev analisa stories e reporta confiança:
  * "Story AUTH-12 (refresh token): confiança 90%, contexto suficiente"
  * "Story API-34 (export CSV): confiança 60%, formato de saída não especificado"
- Time discute API-34 e esclarece formato → confiança sobe para 85%

Terça a Quinta (Implementação):
- Agente Dev implementa stories sequencialmente
- Daily automático às 9h: "Completei AUTH-12, iniciando API-34"
- Dev humano revisa código do agente ao final do dia (30 min)
- Agente QA valida cada story contra critérios de aceite

Sexta (Review + Retro):
- Agente QA produz relatório: 2 stories com 100% dos critérios aprovados,
  1 story com critério falhando (comportamento de erro não implementado)
- Time humano decide: aceita as 2, devolve a 3 com clarificação
- Retro: 10 min analisando métricas dos agentes

💡 Dica: O Agentic Scrum funciona melhor quando as stories têm critérios de aceite muito precisos. A ambiguidade que um desenvolvedor humano resolve com julgamento é uma oportunidade de erro para um agente. Invista tempo nos critérios de aceite e o agente vai ser muito mais eficaz.

⚠️ Armadilha: Não trate o agente como infalível só porque produziu resultado rápido. O Agentic Scrum requer review humano obrigatório de todo output de agente antes do merge. Times que removem essa etapa para ganhar velocidade pagam o preço em bugs de produção.


AI-Augmented XP: pair programming humano+IA

O XP (Extreme Programming — Programação Extrema) já foi considerado radical quando surgiu nos anos 90. TDD (Test-Driven Development — Desenvolvimento Guiado por Testes), pair programming (programação em par), integração contínua — práticas que hoje são mainstream começaram como XP. O AI-Augmented XP aplica a mesma filosofia de qualidade extrema, mas com IA como parceiro no par.

IA como driver vs navigator

No pair programming tradicional, há dois papéis que se alternam: o driver (que digita) e o navigator (que pensa em voz alta sobre estratégia, identifica problemas, sugere abordagens). Com IA, essa dinâmica se torna mais interessante:

IA como driver: O dev humano é o navigator — descreve o que precisa ser feito, revisa o código que a IA gera, sugere correções e direção. Esse modo é especialmente eficaz para código boilerplate, implementações padrão, e quando o dev humano tem clareza sobre o que quer mas não quer gastar tempo digitando.

IA como navigator: O dev humano escreve código enquanto a IA observa e sugere — aponta problemas potenciais, sugere refactors, identifica edge cases. Esse modo é mais eficaz para código crítico onde o dev quer manter controle total da implementação mas aproveitar a perspectiva adicional da IA.

Modo alternado: Em sessões longas, alternar entre os dois modos é natural e produtivo. Comece com IA como driver para estrutura inicial, mude para IA como navigator quando o código fica complexo e requer julgamento mais fino.

TDD com IA gerando testes

O TDD com IA tem uma dinâmica interessante. O fluxo clássico de TDD é:

  1. Escreva um teste que falha (Red)
  2. Escreva o mínimo de código para fazer o teste passar (Green)
  3. Refatore sem quebrar os testes (Refactor)

Com IA, o fluxo pode ser:

  1. Humano descreve o comportamento desejado em linguagem natural
  2. IA gera os testes (Red — e eles devem falhar)
  3. Humano revisa os testes: eles capturam o comportamento real? Edge cases incluídos?
  4. IA gera a implementação mínima para passar nos testes
  5. Humano revisa a implementação e faz a IA refatorar se necessário
// Exemplo de TDD com IA — step by step

// Passo 1: Humano descreve o comportamento
// "Preciso de uma função que valida um CPF brasileiro.
// Deve retornar true para CPFs válidos e false para inválidos.
// Deve rejeitar CPFs com todos os dígitos iguais (111.111.111-11)"

// Passo 2: IA gera os testes (antes da implementação)
describe('validateCPF', () => {
  it('deve retornar true para um CPF válido', () => {
    expect(validateCPF('529.982.247-25')).toBe(true);
  });

  it('deve retornar false para CPF com dígitos todos iguais', () => {
    expect(validateCPF('111.111.111-11')).toBe(false);
    expect(validateCPF('000.000.000-00')).toBe(false);
  });

  it('deve aceitar CPF sem formatação', () => {
    expect(validateCPF('52998224725')).toBe(true);
  });

  it('deve retornar false para CPF com comprimento errado', () => {
    expect(validateCPF('123.456.789')).toBe(false);
  });

  it('deve retornar false para CPF com caracteres inválidos', () => {
    expect(validateCPF('123.456.78A-09')).toBe(false);
  });

  it('deve retornar false para string vazia', () => {
    expect(validateCPF('')).toBe(false);
  });
});

// Passo 3: Humano revisa — todos os casos relevantes estão cobertos?
// Adiciona caso faltante: CPF nulo/undefined
it('deve retornar false para null ou undefined', () => {
  expect(validateCPF(null as any)).toBe(false);
  expect(validateCPF(undefined as any)).toBe(false);
});

// Passo 4: IA gera a implementação mínima que passa nos testes
function validateCPF(cpf: string | null | undefined): boolean {
  if (!cpf) return false;

  const cleaned = cpf.replace(/[.\-]/g, '');

  if (!/^\d{11}$/.test(cleaned)) return false;
  if (/^(\d)\1{10}$/.test(cleaned)) return false;

  const calcDigit = (cpf: string, length: number): number => {
    let sum = 0;
    for (let i = 0; i < length; i++) {
      sum += parseInt(cpf[i]) * (length + 1 - i);
    }
    const remainder = (sum * 10) % 11;
    return remainder >= 10 ? 0 : remainder;
  };

  const digit1 = calcDigit(cleaned, 9);
  const digit2 = calcDigit(cleaned, 10);

  return (
    digit1 === parseInt(cleaned[9]) &&
    digit2 === parseInt(cleaned[10])
  );
}

🔧 Na prática: O maior valor do TDD com IA não é a geração de código mais rápida — é a geração de testes mais abrangentes. Devs humanos tendem a escrever testes para os casos que conhecem. IA tende a cobrir uma variedade maior de edge cases, incluindo casos que o dev não considerou.


Prompt-Driven Development (PDD)

O Prompt-Driven Development (Desenvolvimento Guiado por Prompts) é uma metodologia onde os requisitos são expressos como prompts executáveis e versionados junto com o código. A ideia central: se sua aplicação é gerada a partir de prompts, então os prompts são tão importantes quanto o código — e devem ser tratados como tal.

Requisitos como prompts executáveis

No PDD, ao invés de uma story tradicional ("Como usuário, quero fazer login"), você tem um prompt de implementação estruturado que pode ser executado diretamente em uma sessão de IA:

# PROMPT-001: Autenticação de Usuário

## Contexto
Sistema: TaskFlow (ver architecture.md)
Módulo: Authentication
Stack: Node.js + Express + PostgreSQL + JWT

## Requisito
Implemente um endpoint POST /auth/login que:
1. Recebe email e password no body
2. Valida credenciais contra a tabela users
3. Retorna JWT token com expiração de 24h se credenciais válidas
4. Retorna 401 com mensagem genérica se inválidas
5. Rate limiting de 5 tentativas por IP por minuto

## Restrições
- Senhas devem ser comparadas com bcrypt (nunca texto plano)
- Logs de falha de autenticação devem ser gerados (sem incluir senha)
- Token deve incluir userId e email no payload
- Seguir o padrão de erro definido em error-handling.md

## Critérios de aceite verificáveis
- [ ] POST /auth/login com credenciais válidas retorna 200 + token
- [ ] POST /auth/login com senha errada retorna 401
- [ ] POST /auth/login com email inexistente retorna 401 (mesma mensagem)
- [ ] 6+ tentativas do mesmo IP em 1 minuto retorna 429
- [ ] Token expirado retorna 401 em endpoints protegidos

## Referências
- Padrão de erro: docs/error-handling.md
- Schema de users: docs/data-models.md#users
- Middleware de autenticação existente: src/middleware/auth.ts

Versionamento de prompts junto com código

A disciplina central do PDD é versionar os prompts no mesmo repositório que o código. Isso cria um histórico auditável: "qual prompt gerou qual código", "qual versão do prompt foi usada para gerar a feature X", "quando o prompt foi atualizado e por quê".

Estrutura de diretórios para PDD:

projeto/
  prompts/
    features/
      PROMPT-001-auth-login.md
      PROMPT-002-user-profile.md
    refactors/
      PROMPT-R001-migrate-to-prisma.md
    fixes/
      PROMPT-F001-fix-race-condition.md
  src/
    ... código gerado ...
  docs/
    ... artefatos de contexto ...

Cada prompt deve ter um frontmatter com metadados:

---
id: PROMPT-001
version: 1.2
created: 2026-03-15
updated: 2026-04-01
author: walter@empresa.com
model: claude-sonnet-4-6
status: implemented
related-code: src/routes/auth.ts, src/services/authService.ts
---

O PDD tem uma vantagem específica em projetos com compliance: você pode mostrar exatamente quais instruções geraram quais partes do sistema. Para auditorias de segurança ou regulatórias, isso é valioso.

⚠️ Armadilha: O PDD pode criar falsa sensação de reprodutibilidade. O mesmo prompt com o mesmo modelo pode gerar código diferente em sessões diferentes (temperatura, versão do modelo, contexto da sessão). Versionar prompts não garante que re-executar um prompt vai gerar o mesmo código. O código gerado é que deve ser versionado como a fonte de verdade.


Vibe Coding: o conceito de Andrej Karpathy

Andrej Karpathy — que co-fundou a OpenAI e liderou a IA da Tesla — cunhou o termo "vibe coding" em fevereiro de 2025. A descrição original era direta: "Eu apenas vejo o que a IA gera, aceito tudo, e não leio o código de verdade. (...) A IA escreve todo o código e às vezes eu nem entendo o que está acontecendo no codebase."

O que é vibe coding

O vibe coding é o desenvolvimento de software onde você descreve o que quer para uma IA em linguagem natural, aceita o código gerado sem entender completamente cada linha, itera rapidamente quando algo não funciona, e mantém o foco no resultado em vez do processo de codificação.

É uma inversão do paradigma tradicional: em vez de "eu entendo o código que escrevo", é "eu entendo o comportamento que o sistema exibe". A IA é o tradutor entre intenção e implementação.

Quando funciona

O vibe coding brilha em contextos específicos:

Protótipos e experimentos: Quando o objetivo é "isso funciona?" e não "isso está pronto para produção?", a velocidade do vibe coding é insuperável. Você pode explorar dez ideias diferentes em um dia que no modelo tradicional levaria uma semana.

Ferramentas internas: Scripts de automação, dashboards internos, ferramentas de análise de dados — sistemas onde o custo de um bug é baixo e o valor de velocidade é alto.

Aprendizado de novas tecnologias: Usar vibe coding para aprender uma nova linguagem ou framework tem um valor paradoxal: você vê código funcionando rapidamente, pode questionar a IA sobre o que cada parte faz, e aprende pelo contexto.

Projetos solo sem usuários externos: Quando você é o único usuário e entende os limites do que construiu, o vibe coding é razoável.

Quando é perigoso

O vibe coding é perigoso exatamente onde a maioria das organizações tenta aplicá-lo:

Código em produção com usuários reais: Código que você não entende é código que você não consegue manter, debugar ou evoluir com confiança. Quando algo quebra em produção às 3h da manhã, você precisa entender o código.

Sistemas com requisitos de segurança: Código gerado sem review humano rigoroso é um vetor de ataque. Vulnerabilidades de segurança tendem a ser sutis e invisíveis para quem não sabe o que procurar.

Código que lida com dinheiro ou dados sensíveis: Race conditions, overflow de inteiro, tratamento inadequado de erros — esses bugs têm consequências graves em sistemas financeiros.

Sistemas que outras pessoas precisam manter: Se você vai embora ou o projeto cresce, outras pessoas vão precisar entender e modificar o código. Código de vibe coding sem review tende a ser difícil de manter.

Como tornar o vibe coding mais seguro

// Técnica: "Explain After Generate"
// Após receber código gerado, peça sempre explicação antes de aceitar

const saferVibeCodingPrompt = `
[código gerado anteriormente]

Antes de eu aceitar esse código, explique:
1. O que cada parte principal faz?
2. Quais são os edge cases que esse código NÃO trata?
3. Há algum risco de segurança que devo conhecer?
4. O que poderia dar errado em produção?
`;

// Técnica: "Test First, Vibe Second"
// Escreva (ou peça para IA escrever) os testes ANTES de aceitar o código
// Se os testes passam E você entende os testes, o risco é menor

// Técnica: "Vibe Small"
// Limite o vibe coding a funções isoladas, não sistemas inteiros
// Uma função pequena que você pode testar e entender é muito
// menos arriscada que um módulo inteiro que você aceitou "no vibe"

💡 Dica: A melhor forma de tornar vibe coding mais seguro é "dominar um nível acima". Se você não entende cada linha, entenda cada função. Se não entende cada função, entenda cada módulo. Se não entende cada módulo, entenda a arquitetura geral. Quanto mais alto o nível de compreensão que você mantém, menor o risco do vibe coding nas partes inferiores.


Cursor-first Development

O Cursor-first Development é um workflow que coloca o editor Cursor (um editor de código construído sobre VS Code com IA nativa) como o hub central do processo de desenvolvimento, construindo um fluxo que vai do design visual até o deploy passando pelo Cursor.

Design → v0/Bolt → Cursor → deploy

O workflow típico do Cursor-first Development:

Fase 1: Design Visual (v0 ou Bolt)
Você usa ferramentas como v0.dev (da Vercel) ou Bolt.new para gerar um protótipo visual da interface a partir de uma descrição em linguagem natural. Em minutos, você tem um componente React ou uma página completa que você pode ver no browser. O objetivo aqui não é código de produção — é alinhamento visual rápido.

Fase 2: Importação e refinamento no Cursor
O código gerado pelo v0 ou Bolt é importado para o Cursor. No Cursor, você usa o Composer (modo de chat do Cursor) para refinar, adicionar lógica de negócio, integrar com APIs e corrigir problemas de acessibilidade ou responsividade.

Fase 3: Backend e integrações
No Cursor, você usa o Composer para gerar endpoints de API, integrar com banco de dados, adicionar autenticação. O Cursor tem acesso a todo o codebase e consegue manter consistência melhor do que uma sessão de chat sem contexto de código.

Fase 4: Deploy
Com o código pronto no Cursor, o deploy pode ser para Vercel, Railway, Fly.io — plataformas que têm deploy em um comando.

// Exemplo de workflow Cursor-first para uma landing page com formulário

// Passo 1: v0.dev gera o componente visual
// Prompt no v0: "Landing page moderna com hero, features e formulário de contato"
// Output: componente React com Tailwind

// Passo 2: No Cursor Composer, você refina
// "Adicione validação no formulário de contato usando zod e react-hook-form.
//  Ao submeter, deve chamar POST /api/contact.
//  Mostre loading state durante o envio e mensagem de sucesso/erro."

// Passo 3: Cursor gera o endpoint de API
// "Crie o endpoint POST /api/contact que:
//  1. Valida o body com o schema zod do formulário
//  2. Envia email via Resend API
//  3. Salva o contato no banco PostgreSQL
//  4. Retorna 200 ou erro adequado"

// Passo 4: Deploy automático via Vercel
// git push origin main → deploy automático

O Cursor-first tem um apelo enorme para produtos B2C onde o design é crítico e o time-to-market é o fator mais importante. É menos adequado para sistemas backend complexos, APIs de alto tráfego, ou projetos onde a consistência arquitetural em larga escala é crítica.

⚠️ Armadilha: O código gerado por v0/Bolt é otimizado para demonstração visual, não para manutenibilidade ou performance. É comum ter componentes gigantes com lógica misturada com apresentação, CSS hardcoded, e ausência de testes. Trate o código do v0 como rascunho, não como base — refatore no Cursor antes de chegar em produção.


DORA Metrics na era IA

As DORA Metrics (métricas DORA) vêm do programa DORA (DevOps Research and Assessment — Pesquisa e Avaliação de DevOps) e são as quatro métricas mais validadas empiricamente para medir a saúde de times de engenharia de software. Com IA no processo, essas métricas se comportam de formas interessantes e por vezes contraintuitivas.

Deployment Frequency (Frequência de Deploy): aumenta com IA

A Deployment Frequency mede quantas vezes por unidade de tempo você faz deploy em produção. É um indicador de quão ágil o time é na entrega de valor.

Com IA, a tendência é de aumento significativo. O tempo de implementação cai, o tempo de geração de testes cai, e o pipeline fica mais rápido de configurar. Times que antes faziam deploy uma vez por semana passam a fazer uma vez por dia. Times que faziam uma vez por dia passam para múltiplos deploys diários.

O cuidado aqui é não confundir frequência de deploy com frequência de features valiosas entregues. É possível aumentar drasticamente a frequência de deploy sem entregar mais valor real — especialmente se você começa a fazer deploys de features pequenas e pouco impactantes só porque a IA facilita a implementação.

Lead Time for Changes (Tempo de Ciclo): diminui drasticamente

Lead Time for Changes mede o tempo desde o commit (ou a decisão de implementar uma mudança) até esse código estar em produção. É uma medida da eficiência do pipeline de entrega.

Com IA, essa métrica tende a melhorar muito. A implementação é mais rápida, os testes são gerados junto com o código, e o review pode ser parcialmente assistido por IA. Times reportam reduções de 40-70% no lead time quando adotam IA de forma séria.

Mean Time to Recovery (MTTR — Tempo Médio de Recuperação): IA ajuda no debug

O MTTR mede quanto tempo leva para recuperar de um incidente em produção. É uma medida de resiliência operacional.

A IA pode reduzir o MTTR de formas concretas:

  • Análise de logs: Jogar um stack trace para uma IA e pedir análise da causa raiz é muitas vezes mais rápido do que investigação manual.
  • Geração de hotfix: Uma vez identificado o problema, a IA pode gerar o fix rapidamente.
  • Análise de impacto: A IA pode ajudar a identificar quais outras partes do sistema podem ser afetadas por um bug específico.
// Exemplo: prompt para análise de incidente com IA
const incidentAnalysisPrompt = `
Estamos com um incidente em produção. Analise:

Stack trace:
${stackTrace}

Logs relevantes dos últimos 5 minutos:
${recentLogs}

Contexto do sistema:
- Deploy feito às 14h32 (30 minutos atrás)
- Mudança implementada: ${lastDeployDescription}
- Impacto: ${incidentImpact}

Preciso de:
1. Causa raiz provável (top 3 hipóteses com probabilidade)
2. Como confirmar cada hipótese rapidamente
3. Solução imediata para restaurar o serviço
4. Fix permanente para o problema raiz
`;

Change Failure Rate (Taxa de Falha de Mudança): CUIDADO! Pode aumentar

Esta é a métrica que mais surpreende. O Change Failure Rate mede o percentual de deploys que causam falhas em produção que requerem rollback ou hotfix. Em times maduros, fica abaixo de 15%.

Com IA, especialmente se o review humano for enfraquecido para ganhar velocidade, essa métrica pode aumentar. O motivo é que a IA gera código funcionalmente correto com alta frequência, mas pode introduzir problemas sutis que só aparecem em produção:

  • Race conditions que não aparecem em testes com baixa concorrência
  • Memory leaks que só aparecem depois de horas de execução
  • Comportamento incorreto em edge cases de dados reais vs dados de teste
  • Problemas de performance que só aparecem com carga real

O risco é especialmente alto quando o aumento de velocidade de deploy não é acompanhado de melhoria proporcional no rigor de review.

Métrica DORA Impacto da IA Condição
Deployment Frequency Aumenta (+++) Quase sempre
Lead Time for Changes Diminui (--) Quase sempre
MTTR Diminui (-) Com uso ativo de IA em incidentes
Change Failure Rate Aumenta (+) Se review for enfraquecido
Change Failure Rate Diminui (-) Se review for mantido/fortalecido

Tabela comparativa: metodologias AI-first

Metodologia Melhor cenário Risco principal Ferramentas chave Maturidade necessária
BMAD Greenfield, MVP, refactoring grande Artefatos viram burocracia Claude Code, Cursor Média-alta
Agentic Scrum Time estabelecido, produto em crescimento Agente sem review adequado GitHub Actions + IA, Claude Code Alta
AI-Augmented XP Time com cultura de qualidade Over-engineering guiado por IA Cursor, GitHub Copilot Média
PDD Compliance, auditoria, equipes grandes Falsa reprodutibilidade Qualquer LLM + git Média
Vibe Coding Prototipagem, ferramentas internas Código sem entendimento em produção Qualquer LLM, Bolt, v0 Baixa
Cursor-first Produtos B2C, landing pages, MVPs visuais Código de demonstração em produção Cursor, v0, Bolt, Vercel Baixa-média
Agentic Scrum Times remotos assíncronos Desconexão humano-agente Claude Code, automações CI Alta

Decision tree: qual metodologia usar

Use este fluxo de decisão para escolher a metodologia mais adequada ao seu contexto:

Você está começando do zero (greenfield)?
├── SIM → É um projeto sério (vai para produção com usuários)?
│         ├── SIM → Use BMAD (completo ou versão lite)
│         └── NÃO → Use Vibe Coding ou Cursor-first
│
└── NÃO → É uma feature em produto existente?
          ├── SIM → O time já usa IA de forma madura?
          │         ├── SIM → Agentic Scrum ou AI-Augmented XP
          │         └── NÃO → Comece com AI-Augmented XP (menor mudança de processo)
          │
          └── NÃO → É um bug fix ou hotfix?
                    ├── Hotfix urgente → Sem metodologia, use IA diretamente
                    └── Bug fix comum → Developer persona do BMAD (só essa parte)

Você tem requisitos de compliance ou auditoria?
└── SIM → Adicione PDD ao processo escolhido

Seu produto é visualmente intenso (landing page, dashboard)?
└── SIM → Cursor-first pode ser mais eficiente, mesmo com produto existente

🔧 Na prática: Na dúvida, comece com o menor processo possível. Se você nunca usou metodologias AI-first, começar pelo Agentic Scrum completo é provavelmente demais. Comece usando o Developer persona do BMAD para uma feature de cada vez. Depois evolua para incluir o Scrum Master para planejamento. Depois o Architect para decisões técnicas. Evolução incremental funciona melhor do que adoção completa de uma vez.


Resumo de bolso

  • Agentic Scrum é Scrum com agentes IA como membros formais do time — funciona bem em times maduros com stories bem definidas.
  • AI-Augmented XP maximiza qualidade: TDD com IA gerando testes, pair programming com IA como driver ou navigator.
  • PDD versiona prompts junto com código — ideal para compliance e auditoria, mas não garante reprodutibilidade.
  • Vibe Coding tem seu lugar (prototipagem, ferramentas internas), mas é perigoso em produção com usuários reais.
  • DORA Metrics se comportam de formas contraintuitivas: frequência de deploy e lead time melhoram, mas change failure rate pode piorar se o review humano for sacrificado por velocidade.


Capítulo 4: Adaptando Scrum, Kanban e Shape Up para IA


Scrum + IA

O Scrum é o framework ágil mais usado no mundo. Adaptá-lo para funcionar com IA não é uma revolução — é uma série de ajustes cirúrgicos que respeitam os princípios do Scrum enquanto aproveitam o que a IA oferece.

Sprint Planning: IA gera stories a partir de épico, dev refina

O Sprint Planning tradicional começa com o Product Owner apresentando itens do backlog, o time discutindo e decompondo, e depois estimando. Com IA, a fase de decomposição pode ser acelerada significativamente.

Um workflow adaptado:

Antes do planning (assíncrono):

  1. PO seleciona épicos/features candidatas para o sprint
  2. IA analisa cada épico e gera uma proposta de decomposição em stories
  3. O Dev Lead revisa as stories propostas e faz ajustes antes da cerimônia
  4. Stories revisadas chegam ao planning como material de partida
// Prompt para decomposição de épico em stories
const epicDecompositionPrompt = `
Você é o Scrum Master do projeto ${projectName}.

Analise o épico abaixo e decomponha em stories implementáveis.

Épico: ${epicTitle}
Descrição: ${epicDescription}
Contexto técnico: ${technicalContext}

Para cada story:
1. Escreva no formato "Como [persona], quero [ação] para [benefício]"
2. Identifique os critérios de aceite principais (máximo 3-4 por story)
3. Identifique dependências entre as stories
4. Sinalize stories com alta incerteza técnica

Restrições:
- Cada story deve ser implementável em 1-3 dias
- Stories devem ser independentes quando possível
- Mantenha o escopo do épico: ${epicScope}
`;

Durante o planning:

  • Time revisa as stories propostas pela IA (não começa do zero)
  • Discussão foca em clarificações, ajustes de escopo e decisões técnicas — não em "o que vamos fazer"
  • Estimativa mais rápida porque o material de partida já está estruturado

O planning que antes durava 2-3 horas pode ser feito em 45-60 minutos com essa preparação assistida por IA.

Daily Standup: incluir "o que a IA fez" no update?

Essa é uma das questões mais debatidas em times que adotam IA: como a IA entra no daily? Há três abordagens que vejo sendo adotadas:

Abordagem 1: IA é ferramenta, não aparecer no daily
"Ontem: implementei autenticação. Hoje: vou fazer o módulo de perfil."
A IA é tratada como IDE — ninguém menciona "usei o VS Code".

Abordagem 2: IA como contexto relevante
"Ontem: implementei autenticação com ajuda de IA — a parte de refresh token foi gerada e revisada, a parte de rate limiting precisou de intervenção manual porque tinha um bug na lógica. Hoje: perfil de usuário."
A IA entra quando há algo relevante a dizer — um bloqueio, um insight, uma mudança de velocidade.

Abordagem 3: Métricas de IA no daily
Times mais avançados incluem um "termômetro de IA" no daily: "Ontem: 70% do código gerado por IA, 30% escrito/reescrito manualmente. Bloqueio: IA não conseguia entender o contexto do sistema legado de pagamentos."

A abordagem mais pragmática para times que estão começando é a 2 — inclua a IA quando é relevante para o time entender sua velocidade ou seus bloqueios, não como obrigação ritual.

Sprint Review: demo de features geradas com IA

A Sprint Review não muda fundamentalmente com IA. O que muda é a conversa nos bastidores: quando o PO pergunta "como vocês conseguiram entregar tudo isso?", a resposta honesta inclui a IA. Isso é importante para gerenciar expectativas — o PO não deve assumir que a velocidade vai se manter indefinidamente independente do contexto das features.

Uma prática útil: no final da Sprint Review, o time faz um "IA Retrospective" de 5 minutos: "Onde a IA ajudou mais? Onde atrapalhou? O que vamos fazer diferente no próximo sprint?"

Retrospectiva: métricas de IA

A Retrospectiva é onde o aprendizado sobre IA no processo deve ser sistematizado. Métricas concretas para levar à retro:

// Dashboard de métricas IA para retrospectiva
interface AISprintMetrics {
  // Velocidade
  storiesCompleted: number;
  storiesWithHighAIAssist: number;   // >60% código gerado por IA
  storiesWithLowAIAssist: number;    // <30% código gerado por IA
  avgCycleTimeDays: number;

  // Qualidade
  bugsFoundInReview: number;         // Bugs achados em code review
  bugsFoundInQA: number;             // Bugs achados em QA
  bugsFoundInProduction: number;     // Bugs chegaram em prod

  // Processo
  storiesReturnedFromReview: number; // Stories que voltaram pro dev após review
  avgReviewTimeHours: number;        // Tempo médio de code review

  // Satisfação (escala 1-5)
  devSatisfactionWithAI: number;     // Dev gostou de trabalhar com IA?
  devConfidenceInOutput: number;     // Dev confia no código gerado?
}

Sprint mais curto? Argumento para 1 semana com IA

Conforme discutimos no Capítulo 1, há um argumento sólido para sprints de 1 semana quando o time usa IA intensivamente. Os argumentos específicos para o Scrum com IA:

  1. Feedback loop mais apertado: Com ciclos mais curtos, você valida hipóteses de produto mais rapidamente.
  2. Menor WIP (Work In Progress — Trabalho em Andamento): Sprints menores forçam foco em menos coisas simultaneamente.
  3. Cerimônias mais leves: Um planning de 30 minutos, daily de 10 minutos, review de 20 minutos e retro de 20 minutos — 80 minutos por semana de cerimônia total. É sustentável.
  4. Adaptação mais rápida: Se uma prioridade muda, você só "perde" meio sprint de contexto, não uma semana inteira.

A contra-indicação principal: se o negócio tem stakeholders com expectativas de "o que vem no próximo sprint", sprints de 1 semana podem criar overhead de comunicação. Avalie o contexto antes de mudar.


Kanban + IA

O Kanban é naturalmente mais adaptável à IA do que o Scrum, porque não tem a rigidez dos sprints. A filosofia Kanban de visualizar o trabalho, limitar WIP e maximizar fluxo se encaixa bem com o ritmo variável que a IA introduz.

WIP limits: IA gera rápido, review vira gargalo → ajustar limites

O principal impacto da IA no fluxo Kanban é criar um desequilíbrio: a coluna "In Development" vira muito mais rápido, enquanto a coluna "In Review" fica constipada. O WIP limit do Desenvolvimento pode ser maior (a IA acelera), mas o WIP limit do Review precisa ser respeitado rigorosamente — senão o trabalho se acumula esperando review e o fluxo para.

Um board Kanban adaptado para IA:

Backlog | Ready | AI-Dev | Human Review | QA | Done
   ∞   |   3   |    2   |      2       |  2  |  ∞

Note a distinção entre "AI-Dev" e "Human Review": a IA pode trabalhar em 2 coisas simultaneamente (ou mais, dependendo de como você organiza as sessões), mas humanos só conseguem revisar 2 coisas com qualidade antes de perder atenção.

Fluxo contínuo: IA como buffer de throughput

No modelo de fluxo contínuo, a IA serve como um buffer de produção que mantém o backlog de review sempre cheio mas nunca excessivo. O objetivo não é a IA trabalhar o mais rápido possível — é a IA trabalhar no ritmo que os revisores humanos conseguem absorver.

Isso é análogo a um pipeline de manufatura: não adianta a estação 1 produzir a 300 unidades/hora se a estação 2 só processa 100. O buffer entre elas vai saturar e o ganho se perde.

Métricas: cycle time, throughput com IA

As métricas mais relevantes para Kanban com IA:

Cycle Time (Tempo de Ciclo): Tempo de quando uma task entra em "In Dev" até quando sai de "Done". Com IA, o cycle time do desenvolvimento cai, mas o cycle time total (incluindo review) pode permanecer parecido se o review for o gargalo. Medir o cycle time por coluna revela onde o gargalo está.

Throughput (Vazão): Número de items completados por unidade de tempo. Com IA bem integrada, o throughput aumenta — mas monitore se o aumento é em features de valor ou em tasks pequenas e pouco impactantes.

Flow Efficiency (Eficiência de Fluxo): Proporção do tempo que um item fica "ativo" (alguém trabalhando) vs "esperando". Com IA, o tempo ativo no desenvolvimento cai, mas o tempo esperando review pode aumentar. Uma Flow Efficiency abaixo de 30% indica que os itens passam mais de 70% do tempo esperando.

🔧 Na prática: Use um cumulative flow diagram (diagrama de fluxo cumulativo) para visualizar onde os itens se acumulam no seu board Kanban. Se você vê uma "barriga" acumulando na coluna de review, está na hora de ajustar WIP limits ou redistribuir a capacidade de review.


Shape Up + IA

O Shape Up é a metodologia de desenvolvimento da Basecamp, descrita no livro homônimo de Ryan Singer. Ele opera com ciclos de 6 semanas ("bets" — apostas), seguidos de "cool-downs" de 2 semanas. A ideia central é trabalhar com "appetite" (apetite): ao invés de estimar quanto tempo uma feature vai levar, você decide quanto tempo está disposto a gastar — e a feature é entregue dentro desse appetite ou não é entregue.

Appetite: quando IA entrega em 1 dia o que era appetite de 6 semanas

O Shape Up é particularmente interessante com IA porque a compressão de tempo que a IA oferece colide diretamente com o conceito de appetite. Se você define um appetite de 6 semanas para uma feature e a IA entrega em 2 semanas, o que você faz com as 4 semanas restantes?

Há duas perspectivas:

Perspectiva conservadora: Use o appetite completo para fazer a feature melhor — mais testes, mais polish, mais casos de borda. Isso é especialmente válido se a feature é central para o produto.

Perspectiva expansionista: Se a IA entregou o core em 2 semanas, use as 4 semanas restantes para explorar a próxima aposta com mais liberdade. Isso aumenta a quantidade de ciclos de aprendizado por período.

A melhor escolha depende do contexto, mas a pergunta certa é: "O que mais agrega valor agora — polir essa feature ou explorar a próxima?"

Betting Table: apostar em features mais ambiciosas?

A Betting Table (Mesa de Apostas) é a cerimônia do Shape Up onde os líderes decidem em quais pitches (propostas de feature) vão apostar no próximo ciclo. Com IA, a tabela de apostas muda de formas interessantes:

Features antes consideradas muito grandes agora podem caber num appetite menor. Uma feature que estimada no manual levaria 6 semanas pode ser viável em 2-3 semanas com IA. Isso expande o menu de apostas possíveis.

Risco técnico diminui em certos tipos de feature: Features que envolvem implementação de algo existente (CRUD, integrações de API conhecidas, formulários) têm risco técnico significativamente menor com IA. O Shape Up considera risco técnico na avaliação das apostas — isso precisa ser recalibrado.

Risco de qualidade pode aumentar: Por outro lado, features de alta complexidade de domínio (algoritmos de negócio específicos, integrações com sistemas legados) não se beneficiam tão uniformemente da IA. Isso precisa ser considerado nas apostas.

Cool-down: usar para IA explorar tech debt

O cool-down de 2 semanas no Shape Up é um período de liberdade para os desenvolvedores explorarem ideias, fazerem manutenção, e se recuperarem da intensidade do ciclo anterior. Com IA, o cool-down ganha uma dimensão nova: é uma oportunidade para deixar a IA explorar tech debt de forma estruturada.

// Exemplo de sessão de tech debt exploratório no cool-down

const techDebtExplorationPrompt = `
Você é um engenheiro sênior em modo de exploração de tech debt.
Analise o codebase e identifique:

1. Duplicação de código que pode ser refatorada
2. Funções/módulos com alta complexidade ciclomática
3. Dependências desatualizadas com impacto de segurança
4. Testes ausentes em código crítico
5. Padrões inconsistentes que podem ser padronizados

Para cada item, forneça:
- Localização (arquivo, linha aproximada)
- Impacto estimado (Alto/Médio/Baixo)
- Esforço estimado de resolução (horas)
- Recomendação: resolver agora, planejar para próximo ciclo, ou aceitar

Codebase: [contexto relevante]
`;

O output dessa exploração pode alimentar a próxima Betting Table com propostas concretas de melhoria técnica baseadas em evidências.


Como medir produtividade real

Esta é a seção mais importante do capítulo, e talvez do livro inteiro. A tentação de medir produtividade de formas simplistas é enorme, e a IA exacerba isso: quando a IA pode gerar mil linhas de código em uma hora, medir produtividade por linhas de código produz números impressionantes e completamente sem sentido.

NÃO medir: as métricas de vaidade

Linhas de código: Mais código não é mais valor. Com IA, mais código pode ser mais dívida técnica.

Número de commits: Com IA gerando incrementos pequenos de código, o número de commits pode explodir sem indicar nada sobre valor entregue.

Número de PRs: Similar ao commits — volume não indica qualidade ou valor.

Velocidade em story points: Como discutido no Capítulo 1, story points ficam voláteis com IA. Usar velocity como métrica primária em times com IA leva a comportamentos perversos.

Tokens de IA consumidos: Gastar mais tokens não indica mais produtividade — pode indicar prompts ineficientes ou retrabalho.

SIM medir: métricas que importam

Features entregues e em produção: Quantas features chegaram a usuários reais por período? Esse é o output real do time.

Bugs em produção (Change Failure Rate): A qualidade do output está sendo mantida? Um time que entrega mais features mas com mais bugs está regredindo, não progredindo.

Cycle time: De quando a decisão de implementar uma feature é tomada até quando ela está em produção, quanto tempo passa? Isso captura a eficiência do pipeline completo.

Customer-facing metrics: As features entregues estão movendo métricas de negócio? Retenção, conversão, NPS, uso de feature — esses são os indicadores finais de valor.

Developer satisfaction (satisfação dos devs): Times que usam IA de forma saudável tendem a ter devs mais satisfeitos. Times que usam IA de forma estressante (volume impossível, review superficial, pressão constante) têm devs que "trabalham com IA" mas não gostam do processo.

Framework de métricas sugerido

// Framework de métricas de produtividade para times com IA

interface TeamProductivityMetrics {
  // Nível 1: Output (o que entregamos?)
  output: {
    featuresDeployed: number;           // Features em produção por sprint/semana
    storiesCompleted: number;           // Stories completadas (para capacidade)
    bugFixesDeployed: number;           // Bugs corrigidos em produção
  };

  // Nível 2: Qualidade (o que entregamos é bom?)
  quality: {
    changeFailureRate: number;          // % deploys com problema
    bugEscapeRate: number;              // Bugs encontrados em prod vs QA
    codeReviewRejectionRate: number;    // % PRs que voltam pro autor
    testCoverage: number;               // Cobertura de testes (tendência, não absoluto)
  };

  // Nível 3: Velocidade (quão rápido entregamos?)
  speed: {
    cycleTimeP50Days: number;           // Mediana do cycle time
    cycleTimeP90Days: number;           // P90 do cycle time (detecta outliers)
    deploymentFrequency: number;        // Deploys por semana
    leadTimeToProductionDays: number;   // Do commit ao deploy em prod
  };

  // Nível 4: Valor (estamos entregando o que importa?)
  value: {
    featureAdoptionRate: number;        // % usuários usando features entregues
    businessMetricImpact: number;       // Impacto em KPI principal do produto
    customerSatisfactionScore: number;  // NPS ou CSAT
  };

  // Nível 5: Saúde do time (conseguimos continuar?)
  teamHealth: {
    developerSatisfaction: number;      // Escala 1-5, medido mensalmente
    developerConfidenceInAIOutput: number; // Confia no que a IA entrega?
    burnoutRisk: number;                // Horas extras, férias atrasadas
    learningVelocity: number;           // Time está ficando mais hábil com IA?
  };
}

// Métricas para monitorar especificamente o uso de IA
interface AIUsageMetrics {
  aiAssistLevel: 'low' | 'medium' | 'high'; // Por story
  humanInterventionsPerStory: number;         // Quantas vezes dev corrigiu IA
  reviewTimeWithAI: number;                   // Review de código IA vs humano
  reworkRateForAICode: number;                // Código IA que precisou reescrever
}

O objetivo desse framework não é coletar todos esses dados de uma vez — é escolher 2-3 métricas por nível que façam sentido para o contexto do seu time e acompanhá-las consistentemente ao longo do tempo.

A pergunta-chave para cada retrospectiva: "Nossas métricas de qualidade e valor estão acompanhando nossas métricas de velocidade?" Se a velocidade está subindo mas a qualidade está caindo ou o valor não está crescendo, há algo errado no uso de IA — e você tem os dados para diagnosticar.

💡 Dica: Comece pequeno. Se o seu time não mede nada hoje, comece com cycle time e change failure rate. Essas duas métricas juntas contam a história mais importante: quão rápido entregamos e com que qualidade. Todo o resto é refinamento.

⚠️ Armadilha: Cuidado com o paradoxo da medição: se você mede cicle time e não quality, o time vai otimizar para cycle time (entregas rápidas e superficiais). Se mede só quality e não value, vai fazer código perfeito que ninguém usa. Um framework equilibrado previne a otimização local às custas do objetivo global.


Resumo de bolso

  • Scrum com IA: Planning assistido por IA acelera a decomposição; daily pode incluir IA quando relevante; retros devem ter métricas específicas de IA; sprints de 1 semana valem a pena em muitos contextos.
  • Kanban com IA: IA gera rápido mas review é gargalo — ajuste WIP limits para equilibrar; cycle time por coluna revela o real gargalo; flow efficiency abaixo de 30% é sinal de alarme.
  • Shape Up com IA: Appetite precisa ser recalibrado; Betting Table pode apostar em features mais ambiciosas; cool-down é oportunidade de ouro para exploração de tech debt com IA.
  • Métricas de vaidade a evitar: Linhas de código, commits, PRs, velocity em story points — nenhum desses captura valor real na era da IA.
  • Framework de métricas real: Output (features entregues) + Qualidade (change failure rate) + Velocidade (cycle time) + Valor (métricas de negócio) + Saúde do time (satisfação) — meça pelo menos uma por nível.

Fim da Parte I — Fundamentos e Metodologias


Próximo: Parte II — Ferramentas, Prompting Avançado e Fluxos de Trabalho

  • Capítulo 5: O ecossistema de ferramentas IA para devs
  • Capítulo 6: Prompting avançado para desenvolvimento de software
  • Capítulo 7: Construindo seu workflow pessoal com IA
  • Capítulo 8: IA em código legado — estratégias e armadilhas

Parte II — Ferramentas, Plataformas e Protocolos


Capítulo 5: Panorama de Ferramentas de IA para Desenvolvimento

O ecossistema de ferramentas de IA para desenvolvimento explodiu em 2024–2025. Se você tentar avaliar tudo que aparece no seu feed do Twitter/X, vai ficar paralisado. Este capítulo serve como mapa: onde cada ferramenta vive, para que serve, e como escolher sem enlouquecer.


5.1 Categorias de Ferramentas

Antes de listar produtos, é útil entender as categorias arquiteturais. Cada categoria tem um modelo mental diferente de como a IA se integra ao seu trabalho.

Mapa Mental: Ecossistema Completo

Ferramentas de IA para Desenvolvimento
│
├── 1. IDE-Integrated (IA dentro do editor)
│   ├── Assistência inline (autocompletar, chat)
│   │   ├── GitHub Copilot (VS Code, JetBrains, Vim)
│   │   ├── Cursor (fork do VS Code com IA nativa)
│   │   └── Windsurf (Codeium, fork do VS Code)
│   └── Plugins em IDEs existentes
│       ├── Continue.dev (VS Code + JetBrains, open-source)
│       └── Codeium Extension (VS Code, JetBrains)
│
├── 2. CLI/Terminal (IA no terminal, fora do editor)
│   ├── Agentivas (lê, edita, executa, faz commit)
│   │   ├── Claude Code (Anthropic)
│   │   └── Aider (open-source, multi-modelo)
│   └── Assistentes de terminal
│       └── GitHub Copilot CLI
│
├── 3. API/SDK (IA como componente programático)
│   ├── LLM APIs
│   │   ├── Anthropic API (Claude Sonnet, Haiku, Opus)
│   │   └── OpenAI API (GPT-4o, o3, o4-mini)
│   └── Agent SDKs
│       ├── @anthropic-ai/claude-code (TypeScript/Python)
│       └── OpenAI Agents SDK (Python)
│
├── 4. CI/CD (IA no pipeline de integração)
│   ├── Claude Code Headless (--headless -p "prompt")
│   ├── GitHub Actions + LLM (via API calls)
│   └── Aider em CI (aider --yes --no-auto-commits)
│
└── 5. Geradores de Aplicação (do zero ao app funcional)
    ├── Full-stack com UI
    │   ├── v0 (Vercel) — componentes React/Next
    │   ├── Bolt (StackBlitz) — app full-stack no browser
    │   ├── Lovable — produto completo com Supabase
    │   └── Replit Agent — ambiente + deploy integrado
    └── Especialistas em nicho
        └── Tempo (Flutter/mobile)

5.2 Tabela Comparativa Completa

⚠️ Armadilha: Preços e modelos mudam rápido. Use esta tabela como referência de posicionamento, não como cotação. Verifique os sites oficiais antes de contratar.

Ferramenta Preço (referência) Modelo IA principal Melhor para Limitação principal
Claude Code $20/mês (Pro) ou API pay-per-use Claude Sonnet 4 / Opus Tarefas agentivas longas, refatoração, CLI, CI Requer terminal; curva de configuração
Cursor $20/mês (Pro) GPT-4o, Claude, Gemini Devs que vivem no VS Code; chat contextual Vendor lock parcial; caro em uso intenso
Windsurf $15/mês (Pro) Claude, GPT-4o (Codeium) VS Code + IA sem migrar editor Ecossistema menor que Cursor
GitHub Copilot $10–19/mês GPT-4o, Claude 3.5 Times corporativos; integração GitHub nativa Autocompletar reativo, menos agentivo
Aider Gratuito (open-source) + custo de API Qualquer (Claude, GPT, local) Controle total, pipelines customizados Exige configuração manual; UX técnica
Continue.dev Gratuito (open-source) Qualquer (local ou API) Self-hosted, privacidade, modelos locais Sem cloud próprio; você gerencia infra
v0 (Vercel) Gratuito limitado / $20+ mês GPT-4o + Claude Geração de componentes React/Tailwind Foco em UI; não faz backend complexo
Bolt (StackBlitz) Gratuito limitado / $20/mês Claude Sonnet Protótipos full-stack rápidos no browser Apps simples; escala limitada
Lovable $20–50/mês Claude + GPT-4o MVPs com Supabase; não-devs e devs Menos controle sobre infra
Replit Agent $25/mês (Core) Modelos próprios + GPT Ambiente + deploy integrado em um lugar Ambiente Replit tem limites de recursos
Anthropic API Pay-per-token Claude Haiku/Sonnet/Opus Integrações customizadas, agents, CI Sem IDE; você monta tudo
OpenAI API Pay-per-token GPT-4o, o3, o4-mini Ecossistema grande, RAG, fine-tuning Custo em uso intenso; sem agent SDK nativo

5.3 Como Escolher: Árvore de Decisão

Você quer ficar no seu editor atual?
├── SIM → Continue.dev (open-source) ou GitHub Copilot
│         Quer trocar para editor melhor?
│         ├── SIM → Cursor (maior ecossistema) ou Windsurf (mais barato)
│         └── NÃO → Continue.dev com modelo local (privacidade máxima)
│
└── NÃO → Você quer uma ferramenta de terminal/agentiva?
           ├── SIM → Claude Code (melhor agente) ou Aider (open-source)
           │         Precisa de controle total/pipelines?
           │         ├── SIM → Aider + API direta
           │         └── NÃO → Claude Code
           │
           └── NÃO → Você quer gerar um app do zero?
                      ├── Componentes React/UI → v0 (Vercel)
                      ├── Protótipo full-stack → Bolt
                      ├── MVP com banco de dados → Lovable
                      └── Ambiente + deploy integrado → Replit Agent

💡 Dica: Para times de produto, a combinação mais produtiva costuma ser: Claude Code (agente principal) + Cursor ou Continue.dev (assistência no editor) + Anthropic API (integrações e CI). Você não precisa escolher apenas uma.


5.4 Posicionamento por Maturidade de Uso de IA

Perfil Ferramenta recomendada Por quê
Iniciante em IA, dev experiente GitHub Copilot ou Cursor Menos configuração, feedback imediato
Dev pleno querendo produtividade Claude Code + Cursor Agente para tarefas grandes, IDE para dia a dia
Sênior/arquiteto Claude Code + Continue.dev local Controle, integração com pipelines existentes
Tech lead de time Claude Code headless em CI Automatizar tarefas repetitivas do time
Startups com MVP urgente Lovable ou Bolt → Claude Code Bootstrapping rápido, depois controle real

Resumo de bolso

  • Ferramentas se dividem em cinco categorias: IDE-integrated, CLI/terminal, API/SDK, CI/CD e geradores de app
  • Cursor e Windsurf são forks do VS Code; Continue.dev é plugin open-source — todos competem pelo mesmo dev que vive no editor
  • Claude Code e Aider são as opções CLI agentivas; Claude Code tem melhor integração nativa com ferramentas Anthropic
  • v0, Bolt, Lovable e Replit Agent são "geradores de app" — ótimos para bootstrapping, mas você precisará de uma ferramenta real logo depois
  • Não existe ferramenta única; o meta-jogo é compor 2–3 ferramentas que cobrem fases diferentes do trabalho

Capítulo 6: Claude Code — O Canivete Suíço

Claude Code é diferente de autocompletar e diferente de chat. É um agente de linha de comando que lê seu código, edita arquivos, executa comandos e faz commit — tudo em um loop autônomo guiado pelo seu prompt. Este capítulo vai de zero ao workflow real de uma feature completa.


6.1 O Que É Claude Code

Claude Code é uma CLI (Command-Line Interface) agentiva desenvolvida pela Anthropic. Diferente de ferramentas que apenas sugerem código, Claude Code age: ele usa ferramentas (Read, Grep, Edit, Bash, WebFetch) para entender o contexto do seu projeto e executar tarefas complexas com múltiplos passos.

O modelo mental correto é:

Você é o gerente de produto.
Claude Code é o dev sênior que executa.
Você descreve o que quer. Ele descobre o como.

Internamente, cada resposta do Claude Code é uma sequência de tool calls (chamadas de ferramenta):

Prompt do usuário
     │
     ▼
Claude pensa: "Preciso entender a estrutura do projeto"
     │
     ▼
Tool call: Bash("ls -la src/")
     │
     ▼
Tool call: Read("src/services/userService.ts")
     │
     ▼
Tool call: Grep("createUser", "src/")
     │
     ▼
Tool call: Edit("src/services/userService.ts", ...)
     │
     ▼
Tool call: Bash("npm test")
     │
     ▼
Tool call: Bash("git add -p && git commit -m '...'")
     │
     ▼
Resposta final ao usuário

6.2 Instalação e Configuração Inicial

Requisitos

  • Node.js 18+ (LTS recomendado)
  • npm 9+
  • Conta Anthropic com créditos ou assinatura Claude Pro/Team/Enterprise
  • Git configurado (para operações de commit)

Instalação

# Instalar globalmente
npm install -g @anthropic-ai/claude-code

# Verificar instalação
claude --version

# Autenticar (abre browser para OAuth)
claude auth login

# Ou usar API key diretamente
export ANTHROPIC_API_KEY="sk-ant-..."
claude auth login --api-key

Verificando a Instalação

# Teste rápido
claude -p "liste os arquivos do diretório atual e descreva a estrutura"

# Ver comandos disponíveis
claude --help

6.3 Anatomia de uma Sessão

Uma sessão interativa do Claude Code começa com claude no terminal dentro do seu projeto:

cd meu-projeto
claude

O que você vê é um REPL (Read-Eval-Print Loop) onde cada prompt dispara um ciclo de raciocínio + tool calls + resposta.

Exemplo de Sessão Real

> adicione validação de email no endpoint POST /users

● Vou analisar o código existente antes de fazer alterações.

  Tool call: Read("src/routes/users.ts")
  Tool call: Read("src/models/User.ts")
  Tool call: Grep("validation", "src/")
  Tool call: Read("src/middleware/validate.ts")

● Encontrei a estrutura. Vou adicionar validação usando a biblioteca
  zod que já está no projeto.

  Tool call: Edit("src/routes/users.ts")
  [edita arquivo com schema zod]

  Tool call: Edit("src/routes/users.ts")
  [adiciona middleware de validação na rota]

  Tool call: Bash("npm test -- --testPathPattern=users")
  [todos os 12 testes passaram]

● Adicionei validação de email no endpoint POST /users usando zod.
  O schema verifica formato RFC 5321 e retorna erro 400 com mensagem
  clara se o email for inválido. Todos os testes existentes continuam
  passando.

  Quer que eu adicione testes unitários para os casos de email inválido?

Comandos Especiais na Sessão

Comando O que faz
/help Lista todos os comandos disponíveis
/plan Entra em modo planejamento (não executa)
/memory Abre editor de memória persistente
/clear Limpa contexto da conversa atual
/exit ou Ctrl+C Encerra a sessão
/cost Mostra custo de tokens da sessão
/model Troca o modelo (sonnet, opus, haiku)

6.4 CLAUDE.md: O Arquivo Mágico

CLAUDE.md é o arquivo de contexto que o Claude Code lê automaticamente ao iniciar. É onde você codifica o conhecimento do projeto para que o agente não precise descobrir tudo do zero a cada sessão.

Por Que Isso Importa

Sem CLAUDE.md, o agente gasta tokens (e tempo) descobrindo coisas que você já sabe: qual framework usa, quais convenções seguir, quais pastas ignorar, como rodar os testes. Com um bom CLAUDE.md, ele chega ao trabalho real mais rápido.

Hierarquia de CLAUDE.md

Claude Code lê múltiplos arquivos CLAUDE.md em ordem crescente de especificidade:

~/.claude/CLAUDE.md          ← preferências globais suas (todos os projetos)
     │
     ▼ (sobrescreve/complementa)
~/projeto/CLAUDE.md          ← contexto do projeto
     │
     ▼ (sobrescreve/complementa)
~/projeto/src/CLAUDE.md      ← contexto específico de subpasta
~/projeto/packages/api/CLAUDE.md

💡 Dica: Use o ~/.claude/CLAUDE.md global para preferências pessoais (idioma de resposta, estilo de commit, ferramentas preferidas). Use o CLAUDE.md do projeto para convenções do time.

O Que Colocar no CLAUDE.md

Sim, inclua:

  • Stack tecnológica e versões
  • Comandos para rodar testes, build, lint
  • Convenções de código (naming, estrutura de pastas)
  • Regras de negócio críticas que afetam o código
  • O que NÃO fazer (antipadrões do projeto)
  • Como fazer deploy / configuração de ambiente
  • Links para decisões arquiteturais (ADRs)

Não inclua:

  • Segredos, tokens, senhas
  • Documentação genérica (o Claude já sabe)
  • Coisas que mudam a cada commit (use Git para isso)

Exemplo Completo: CLAUDE.md para Node.js + React

# Projeto: Plataforma de Gestão de Pedidos

## Stack
- **Backend**: Node.js 20 LTS, Express 4, TypeScript 5.3
- **Frontend**: React 18, Vite 5, TailwindCSS 3.4
- **Banco**: PostgreSQL 16 via Prisma 5.x
- **Testes**: Vitest (unitários), Playwright (E2E)
- **Infra**: Docker Compose local, AWS ECS em produção

## Comandos Essenciais

```bash
# Desenvolvimento
npm run dev          # Inicia backend (porta 3001) + frontend (porta 5173)
npm run dev:backend  # Só o backend
npm run dev:frontend # Só o frontend

# Testes
npm test             # Todos os testes unitários
npm run test:watch   # Modo watch
npm run test:e2e     # Playwright (requer npm run dev rodando)
npm run test:coverage # Coverage com threshold 80%

# Qualidade
npm run lint         # ESLint + Prettier check
npm run lint:fix     # Corrige automaticamente
npm run typecheck    # tsc --noEmit

# Banco de dados
npm run db:migrate   # Aplica migrations pendentes
npm run db:seed      # Popula banco de dev com dados de exemplo
npm run db:reset     # Drop + migrate + seed (APENAS desenvolvimento)

# Build
npm run build        # Build de produção (backend + frontend)
docker-compose up -d # Sobe PostgreSQL + Redis localmente

Estrutura de Pastas

src/
├── api/             # Rotas Express organizadas por recurso
│   ├── orders/      # routes.ts, controller.ts, schema.ts
│   ├── users/
│   └── products/
├── services/        # Lógica de negócio (sem Express)
├── repositories/    # Acesso ao banco via Prisma
├── middleware/      # Auth, logging, error handling
├── lib/             # Utilitários compartilhados
└── types/           # Tipos TypeScript globais

frontend/src/
├── pages/           # Páginas (React Router v6)
├── components/      # Componentes reutilizáveis
│   ├── ui/          # Primitivos (Button, Input, Modal)
│   └── domain/      # Componentes de negócio (OrderCard, etc.)
├── hooks/           # Custom hooks
├── stores/          # Zustand stores
└── api/             # React Query + fetch wrappers

Convenções de Código

Naming

  • Arquivos: kebab-case.ts para utilitários, PascalCase.tsx para componentes React
  • Funções: camelCase; Classes: PascalCase; Constantes globais: UPPER_SNAKE_CASE
  • Tabelas Prisma: snake_case; Interfaces TypeScript: prefixo I não é usado — use type quando possível

TypeScript

  • Sem any — use unknown e faça narrowing
  • Prefira type sobre interface para tipos de dados; use interface para contratos de classe
  • Toda função pública deve ter tipo de retorno explícito
  • Use Zod para validação de entrada em todos os endpoints

React

  • Componentes como arrow functions: const MyComponent: React.FC<Props> = ({ prop }) => ...
  • Estado global no Zustand; estado local com useState
  • React Query para todo acesso a dados assíncronos (não use useEffect para fetch)
  • Sem prop drilling além de 2 níveis — use contexto ou store

Git

  • Commits no padrão Conventional Commits: feat:, fix:, refactor:, test:, docs:
  • Um commit por unidade lógica de mudança
  • PRs sempre com descrição explicando o "porquê", não o "o quê"
  • Branch naming: feat/TICKET-123-descricao-curta

Regras de Negócio Críticas

  1. Pedidos confirmados (status: 'confirmed') nunca podem ser deletados — apenas cancelados
  2. Estoque é decrementado no momento da confirmação, não da criação do pedido
  3. Preços são sempre armazenados em centavos (integer) — nunca em float
  4. O campo customerId é obrigatório para pedidos acima de R$ 500,00
  5. Logs de auditoria são obrigatórios para qualquer mudança de status de pedido

O Que NÃO Fazer

  • NÃO usar console.log em produção — use logger.info/error/warn do src/lib/logger.ts
  • NÃO fazer queries Prisma diretamente em controllers — use o repository correspondente
  • NÃO importar de ../../../ mais de 2 níveis — use path aliases (@/services/...)
  • NÃO commitar migrations sem revisar o SQL gerado
  • NÃO usar Date.now() para timestamps — use new Date() e deixe o Prisma gerenciar

Ambiente de Desenvolvimento

# Copie e preencha com seus valores
cp .env.example .env.local

# Variáveis necessárias para desenvolvimento
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/pedidos_dev"
REDIS_URL="redis://localhost:6379"
JWT_SECRET="dev-secret-mude-em-producao"

Decisões Arquiteturais


---

## 6.5 Modos de Operação

### Modo Normal (Interativo)

```bash
claude
# Abre o REPL interativo

O modo padrão. Você digita prompts, o Claude executa e você confirma ações ou pede ajustes. Ideal para trabalho explorativo.

Plan Mode (/plan)

# Dentro da sessão
> /plan implemente autenticação JWT completa com refresh token

No modo planejamento, Claude não executa nenhuma ferramenta. Ele analisa o contexto e descreve detalhadamente o que vai fazer antes de agir. Use quando:

  • A tarefa é grande e você quer revisar a abordagem antes
  • Você suspeita que o Claude pode escolher a estratégia errada
  • Quer entender o impacto antes de deixar executar
> /plan

● PLANO: Autenticação JWT com Refresh Token

  Fase 1 — Análise (read-only):
  - Ler src/middleware/auth.ts (middleware atual)
  - Ler src/models/User.ts (campos disponíveis)
  - Verificar se jsonwebtoken já está nas dependências

  Fase 2 — Banco de dados:
  - Criar migration: adicionar tabela refresh_tokens
    (id, userId, token hash, expiresAt, createdAt)
  - Atualizar Prisma schema

  Fase 3 — Backend:
  - Criar src/services/tokenService.ts
    • generateAccessToken(userId) → JWT 15min
    • generateRefreshToken(userId) → opaque token 30 dias
    • verifyRefreshToken(token) → userId | null
    • revokeRefreshToken(token) → void
  - Atualizar src/api/auth/routes.ts
    • POST /auth/login → retorna { accessToken, refreshToken }
    • POST /auth/refresh → troca refresh por novo access token
    • POST /auth/logout → revoga refresh token
  - Atualizar middleware de autenticação

  Fase 4 — Testes:
  - Unitários para tokenService
  - Integração para os 3 endpoints

  Quer que eu execute este plano? (s/n)

Fast Mode

Ativado com a flag --dangerously-skip-permissions ou nas configurações. Reduz confirmações intermediárias. Útil em sessões onde você já confia no fluxo.

⚠️ Armadilha: Fast mode pode executar operações destrutivas sem confirmação. Use apenas em projetos onde você tem backup/git configurado e entende o que está pedindo.


6.6 Hooks: Automações no Ciclo do Agente

Hooks são scripts que o Claude Code executa automaticamente em pontos específicos do seu ciclo de vida. Pense neles como os git hooks do mundo dos agentes.

Tipos de Hooks

Tipo Quando dispara Caso de uso
PreToolUse Antes de executar qualquer tool call Validar, logar, bloquear ações específicas
PostToolUse Após executar qualquer tool call Rodar lint após edit, notificar, registrar
Notification Quando Claude envia uma notificação Slack, desktop notification, logging
Stop Quando o agente termina uma tarefa Notificar conclusão, rodar CI, atualizar ticket

Configuração em settings.json

O arquivo de configuração fica em ~/.claude/settings.json (global) ou .claude/settings.json (projeto):

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npm run lint:fix -- ${file}"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/usr/local/bin/notify-slack.sh"
          }
        ]
      }
    ]
  }
}

Exemplo Completo: Hook de Lint Após Edit

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "node -e \"const f='${file}'; if(f.match(/\\.(ts|tsx|js|jsx)$/)) { require('child_process').execSync('npx eslint --fix ' + f, {stdio:'inherit'}); }\""
          }
        ]
      },
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "node -e \"const f='${file}'; if(f.match(/\\.(ts|tsx|js|jsx|json|css|md)$/)) { require('child_process').execSync('npx prettier --write ' + f, {stdio:'inherit'}); }\""
          }
        ]
      }
    ]
  }
}

Exemplo Completo: Hook de Notificação no Slack

Crie o script ~/.claude/hooks/notify-slack.sh:

#!/bin/bash

# ~/.claude/hooks/notify-slack.sh
# Notifica no Slack quando Claude Code termina uma tarefa

SLACK_WEBHOOK="${SLACK_WEBHOOK_URL}"
PROJECT=$(basename "$PWD")
TIMESTAMP=$(date '+%H:%M:%S')
USER=$(whoami)

if [ -z "$SLACK_WEBHOOK" ]; then
  echo "SLACK_WEBHOOK_URL não configurado, pulando notificação"
  exit 0
fi

PAYLOAD=$(cat <<EOF
{
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": ":white_check_mark: *Claude Code terminou* às ${TIMESTAMP}\n*Projeto:* ${PROJECT}\n*Dev:* ${USER}"
      }
    }
  ]
}
EOF
)

curl -s -X POST -H 'Content-type: application/json' \
  --data "$PAYLOAD" \
  "$SLACK_WEBHOOK"
chmod +x ~/.claude/hooks/notify-slack.sh

Configure no settings.json:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/hooks/notify-slack.sh"
          }
        ]
      }
    ]
  }
}

6.7 Memory: Sistema de Memória Persistente

Claude Code tem um sistema de memória que persiste entre sessões. Ao contrário do contexto da conversa (que é descartado ao fechar), a memória fica salva em arquivos e é carregada automaticamente.

Como Funciona

# Dentro de uma sessão, use /memory para criar/editar memórias
> /memory

O comando abre um editor para você escrever o que quer que o Claude lembre. O conteúdo é salvo em .claude/memory/ (ou ~/.claude/projects/[hash]/memory/ para memórias de projeto).

Você também pode pedir ao Claude que salve algo:

> lembre que neste projeto preferimos usar fetch nativo em vez de axios,
  e que os testes de integração precisam do banco rodando antes

Estrutura de Arquivos de Memória

.claude/
└── memory/
    ├── MEMORY.md        ← índice das memórias (gerado automaticamente)
    ├── stack.md         ← decisões de stack
    ├── conventions.md   ← convenções descobertas durante o trabalho
    └── decisions.md     ← decisões tomadas em sessões anteriores

Casos de Uso Práticos

# Memória de preferência pessoal (global)
> /memory
Prefiro respostas em português do Brasil.
Sempre use conventional commits.
Minha conta AWS padrão é a de staging, nunca a de prod.

# Memória de projeto (local)
> lembre: a API de terceiros do fornecedor X tem rate limit de
  100 req/min — sempre adicione retry com backoff exponencial
  quando integrar com ela

6.8 Headless Mode: Claude Code em Scripts e CI

O modo headless (sem interface interativa) permite usar Claude Code em automações, scripts shell e pipelines de CI/CD.

Sintaxe Básica

# -p ou --prompt: modo não-interativo com prompt direto
claude --headless -p "descreva o que este código faz"

# Com formato de saída JSON (para parsear em scripts)
claude --headless -p "liste todos os endpoints da API" \
  --output-format json

# Limitar número de turnos do agente (segurança em CI)
claude --headless -p "adicione docstrings em todos os métodos públicos" \
  --max-turns 20

# Especificar diretório de trabalho
claude --headless -p "refatore os testes" \
  --cwd /path/to/projeto

Flags Úteis

Flag Descrição
--headless Modo não-interativo
-p "prompt" Prompt inicial
--output-format json Saída em JSON estruturado
--max-turns N Máximo de turnos do agente
--model Especificar modelo (sonnet/opus/haiku)
--cwd /path Diretório de trabalho
--no-color Sem cores ANSI (útil em logs de CI)

Exemplo: Script de Changelog Automático

#!/bin/bash
# scripts/generate-changelog.sh
# Gera changelog baseado nos commits desde a última tag

set -euo pipefail

LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "início")
COMMITS=$(git log "${LAST_TAG}..HEAD" --oneline --no-merges)

if [ -z "$COMMITS" ]; then
  echo "Nenhum commit novo desde $LAST_TAG"
  exit 0
fi

PROMPT="Analise estes commits do Git e gere um CHANGELOG.md no formato Keep a Changelog.
Agrupe por: Added, Changed, Fixed, Deprecated, Removed, Security.
Use linguagem clara para usuários finais, não jargão técnico interno.

Commits:
$COMMITS

Retorne apenas o markdown do changelog, sem explicações adicionais."

echo "Gerando changelog para commits desde $LAST_TAG..."

claude --headless \
  --no-color \
  --output-format text \
  --max-turns 5 \
  -p "$PROMPT" > CHANGELOG_DRAFT.md

echo "Rascunho gerado em CHANGELOG_DRAFT.md"
echo "Revise e mova para CHANGELOG.md quando aprovar."

Exemplo: CI com GitHub Actions

# .github/workflows/ai-review.yml
name: AI Code Review

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  ai-review:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write

    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Instalar Claude Code
        run: npm install -g @anthropic-ai/claude-code

      - name: Gerar review do diff
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          DIFF=$(git diff origin/main...HEAD -- '*.ts' '*.tsx' | head -200)
          
          REVIEW=$(claude --headless \
            --no-color \
            --max-turns 3 \
            --output-format text \
            -p "Faça um code review focado em: 
            1. Bugs potenciais ou edge cases não tratados
            2. Problemas de performance óbvios
            3. Violações das convenções (Conventional Commits, sem any TypeScript)
            4. Segurança (XSS, SQL injection, dados sensíveis expostos)
            
            Seja conciso. Só aponte problemas reais, não sugestões cosméticas.
            
            Diff:
            $DIFF")
          
          echo "$REVIEW" > review.md

      - name: Postar review no PR
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const review = fs.readFileSync('review.md', 'utf8');
            
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: `## 🤖 AI Code Review\n\n${review}`
            });

6.9 Multi-Model: Quando Usar Cada Modelo

Claude Code suporta troca de modelo mid-session com /model. Entender quando usar cada um economiza custo sem sacrificar qualidade.

# Trocar modelo na sessão
> /model opus      # Muda para claude-opus-4
> /model sonnet    # Muda para claude-sonnet-4 (padrão)
> /model haiku     # Muda para claude-haiku-3-5

Guia de Seleção de Modelo

Modelo Velocidade Custo Melhor para
Claude Opus 4 Lento Alto Arquitetura complexa, debugging difícil, decisões críticas
Claude Sonnet 4 Médio Médio Trabalho diário, features, refatorações, code review
Claude Haiku 3.5 Rápido Baixo Formatação, classificação simples, tarefas mecânicas

Estratégia Prática

# Inicie com Sonnet (padrão) para a maioria das tarefas

# Mude para Opus quando:
# - O agente está "preso" e refazendo a mesma coisa
# - A tarefa envolve múltiplos sistemas interconectados
# - Você precisa de análise de causa raiz em bug difícil
> /model opus
> por que o sistema de cache está causando inconsistência nos dados
  do usuário após login — analise todos os arquivos relacionados

# Volte para Sonnet após o diagnóstico
> /model sonnet
> implemente a correção que você planejou

# Use Haiku para tarefas repetitivas em CI
claude --headless --model haiku -p "formate este JSON"

💡 Dica: O custo do Opus pode ser 15–20x maior que o Haiku. Para pipelines de CI que rodam centenas de vezes por mês, escolher o modelo certo faz diferença real na conta.


6.10 Workflow Real: Feature Completa do Prompt ao PR

Vamos narrar um workflow completo e realista de implementação de uma feature — adição de paginação cursor-based em uma API REST.

Contexto

Projeto: API de pedidos em Node.js + TypeScript + Prisma. A rota GET /orders retorna todos os pedidos sem paginação. Precisamos adicionar paginação cursor-based eficiente.

Passo 1: Abrir Sessão e Entender o Contexto

cd ~/projetos/orders-api
claude
> analise o endpoint GET /orders e me diga o que precisaria mudar
  para adicionar paginação cursor-based. Não implemente ainda.

Claude lê os arquivos relevantes e explica a abordagem. Você valida a estratégia.

Passo 2: Planejar

> /plan adicione paginação cursor-based no GET /orders usando
  o campo createdAt como cursor. Limite padrão de 20 itens,
  máximo de 100. Retorne hasNextPage e nextCursor no response.

Você revisa o plano proposto. Se concordar:

> execute o plano

Passo 3: Implementação Acontece Automaticamente

O Claude executa algo parecido com:

● Executando plano de paginação cursor-based...

  Tool call: Read("src/api/orders/routes.ts")
  Tool call: Read("src/repositories/orderRepository.ts")
  Tool call: Read("src/api/orders/schema.ts")

● Atualizando schema de validação da query...

  Tool call: Edit("src/api/orders/schema.ts")
  [adiciona campos: cursor?, limit? com defaults e máximos]

● Atualizando repository com query paginada...

  Tool call: Edit("src/repositories/orderRepository.ts")
  [adiciona método findWithCursor usando Prisma cursor pagination]

● Atualizando controller...

  Tool call: Edit("src/api/orders/controller.ts")
  [usa novo método do repository, monta response com metadata]

● Adicionando testes...

  Tool call: Edit("src/api/orders/routes.test.ts")
  [testes: sem cursor, com cursor, limite máximo, cursor inválido]

● Rodando testes...

  Tool call: Bash("npm test -- --testPathPattern=orders")
  ✓ 16 testes passaram

● Verificando types...

  Tool call: Bash("npm run typecheck")
  ✓ Sem erros de tipo

● Rodando lint...

  Tool call: Bash("npm run lint")
  ✓ Sem warnings

Passo 4: Revisão

> mostre um resumo das mudanças feitas e como testar manualmente

O Claude lista os arquivos modificados e dá exemplos de curl para testar.

Passo 5: Commit e PR

> faça commit com mensagem conventional commits e depois crie um PR
  descrevendo a mudança e como testar
  Tool call: Bash("git add src/api/orders/ src/repositories/")
  Tool call: Bash("git commit -m 'feat(orders): adiciona paginação cursor-based em GET /orders\n\nUtiliza campo createdAt como cursor para paginação eficiente.\nLimite padrão de 20 itens, máximo configurável de 100.\nResponse inclui hasNextPage e nextCursor para iteração.'")
  Tool call: Bash("gh pr create --title 'feat(orders): paginação cursor-based' --body '...'")

● PR criado: https://github.com/org/orders-api/pull/247

Resumo de bolso

  • Claude Code é uma CLI agentiva: ele lê, edita, executa e faz commit em loops autônomos
  • CLAUDE.md é o arquivo de contexto central — invista tempo nele e todos os agentes do time ficam mais produtivos
  • Hooks automatizam ações recorrentes: lint pós-edit, notificações, validações
  • Modo headless (--headless -p) integra Claude Code em CI/CD e scripts shell
  • Escolha o modelo conforme a complexidade: Haiku para tarefas mecânicas, Sonnet para o dia a dia, Opus para problemas complexos

Capítulo 7: Skills — Extensões de Comportamento

Skills transformam Claude Code de um assistente genérico em um especialista do seu projeto. Este capítulo mostra como as skills funcionam internamente e como criar as suas próprias.


7.1 O Que São Skills

Skills são instruções especializadas ativadas por um comando /nome dentro de uma sessão do Claude Code. Quando você digita /review, o Claude não apenas "sabe que você quer um review" — ele carrega um conjunto específico de instruções, contexto e comportamentos definidos no arquivo da skill.

O modelo mental é:

Skill = persona especialista + instruções de comportamento + tools disponíveis

Sem skill: "Claude, faça um code review"
→ Review genérico, padrões de qualquer projeto

Com skill /review customizada: "Claude, faça um code review"
→ Review seguindo as convenções específicas do seu projeto, verificando as regras de segurança da sua empresa, no formato exato que seu time usa


7.2 Como o Claude Descobre Skills

Quando você executa claude, o agente faz um scan automático em ordem:

1. Skills built-in (embutidas no Claude Code)
2. ~/.claude/skills/           ← skills globais (todos os seus projetos)
3. .claude/skills/             ← skills do projeto atual
4. Plugins instalados          ← via npm/pip com prefix @claude-skill/

Todas as skills encontradas ficam disponíveis como /nome-do-arquivo (sem extensão .md).

# Ver todas as skills disponíveis na sessão
> /help

# Listar arquivos de skill
ls ~/.claude/skills/
ls .claude/skills/

7.3 Anatomia de uma Skill

Cada skill é um arquivo Markdown com frontmatter YAML que define o comportamento, seguido pelo prompt que será injetado quando a skill for ativada.

Estrutura Completa

---
name: nome-da-skill
description: "Descrição curta para o /help e autocompletar"
version: "1.0.0"
author: "seu-nome"
triggers:
  - /nome-da-skill
  - /alias-alternativo
tools:
  - Read
  - Grep
  - Edit
  - Bash
  - WebFetch
model: sonnet          # sonnet | opus | haiku
maxTurns: 30
temperature: 0         # 0 = mais determinístico
---

# [Nome da Skill]

[Aqui vai o system prompt que define o comportamento da skill]

## Instruções

[Instruções detalhadas de como o Claude deve se comportar]

## Formato de Output

[Como o resultado deve ser estruturado]

## Exemplos

[Exemplos de input/output para calibrar o comportamento]

7.4 Skills Built-in Úteis

Claude Code vem com um conjunto de skills nativas. Aqui estão as mais úteis para devs pleno/sênior:

/init — Inicializa CLAUDE.md

> /init

Analisa seu projeto e gera um CLAUDE.md inicial com stack detectada, estrutura de pastas e comandos comuns. Ótimo ponto de partida para um projeto novo.

/review — Code Review de PR

> /review

Faz review do diff atual (staged ou unstaged) ou de um PR específico. Aponta bugs, code smells e violações de convenções.

> /review PR#247
> /review src/services/paymentService.ts

/security-review — Revisão de Segurança

> /security-review

Review focado em vulnerabilidades: injeção SQL, XSS, CSRF, secrets expostos, problemas de autenticação/autorização, dados sensíveis em logs.

/simplify — Simplifica Código

> /simplify
> /simplify src/utils/dateHelpers.ts

Identifica código desnecessariamente complexo e propõe versões mais simples sem mudar o comportamento.

/plan — Modo Planejamento

> /plan [descrição da tarefa]

Força o agente a planejar completamente antes de executar qualquer ação. (Coberto em detalhes no capítulo anterior.)


7.5 Criando Skills Custom

Usando /skill-creator

A forma mais fácil de criar uma skill nova é usar a skill built-in /skill-creator:

> /skill-creator

● Olá! Vou te ajudar a criar uma skill personalizada.
  
  Descreva em linguagem natural o que você quer que a skill faça:

> quero uma skill que analise queries SQL no projeto e identifique
  problemas de performance: N+1, falta de índice, queries sem WHERE,
  joins com tabelas grandes sem filtro

● Entendido. Vou criar uma skill "DBA Review" para você.
  [gera o arquivo .claude/skills/dba-review.md]
  
  Skill criada! Use /dba-review para ativá-la.

Estrutura de Diretório

# Criar estrutura de skills do projeto
mkdir -p .claude/skills

# Skills globais (todos os projetos)
ls ~/.claude/skills/
# dba-review.md
# api-designer.md
# security-checklist.md

# Skills do projeto atual
ls .claude/skills/
# business-rules-check.md
# migration-reviewer.md

7.6 Exemplo Completo: Skill de DBA Review

---
name: dba-review
description: "Analisa queries SQL e Prisma em busca de problemas de performance"
version: "1.2.0"
triggers:
  - /dba-review
  - /sql-review
tools:
  - Read
  - Grep
  - Bash
model: sonnet
maxTurns: 20
---

# DBA Review — Análise de Performance de Queries

Você é um DBA sênior especializado em PostgreSQL e ORMs (especialmente Prisma).
Sua tarefa é revisar queries e identificar problemas de performance antes que
cheguem à produção.

## O Que Analisar

### Problemas Críticos (sempre reportar)
1. **N+1 queries**: loop que faz query dentro de loop — sempre grave
2. **Full table scan**: query sem WHERE em tabela grande (>10k linhas estimadas)
3. **Missing index**: filtros por campos não indexados (email, status, userId, etc.)
4. **SELECT ***: em tabelas com colunas grandes (TEXT, JSONB, BYTEA)
5. **Cursor sem limite**: query que pode retornar milhões de linhas

### Problemas Importantes (reportar com contexto)
1. **Joins em cascata**: mais de 3 JOINs sem índices confirmados
2. **ORDER BY sem índice**: em queries paginadas
3. **Subquery correlacionada**: pode ser reescrita como JOIN
4. **LIKE '%termo'**: não usa índice (aceito apenas para buscas textuais explícitas)

### Boas Práticas (reportar como sugestão)
1. Usar `select` específico no Prisma em vez de `findMany` sem campos
2. Preferir `include` com limites a eager loading irrestrito
3. Usar transações para operações multi-tabela

## Como Executar

1. Use Grep para encontrar todas as queries Prisma e SQL raw no projeto
2. Para cada query encontrada, analise o contexto (loops? tamanho estimado? índices?)
3. Verifique o schema Prisma para confirmar índices existentes
4. Produza relatório estruturado

## Formato de Output

DBA Review — [data]

❌ Crítico (N problemas)

[Arquivo:linha] — [Tipo do problema]
código problemático
Impacto: [o que acontece em produção]
Solução: [código corrigido]

⚠️ Importante (N problemas)

[mesmo formato]

💡 Sugestões (N itens)

[mesmo formato]

✅ Sem problemas

[arquivos que foram analisados e estão OK]


## Exemplos

### Exemplo de N+1 (CRÍTICO)
```typescript
// ❌ N+1 — 1 query para orders + N queries para cada user
const orders = await prisma.order.findMany();
for (const order of orders) {
  const user = await prisma.user.findUnique({ where: { id: order.userId } });
}

// ✅ Correto — 1 query com include
const orders = await prisma.order.findMany({
  include: { user: true }
});

Exemplo de Missing Index (CRÍTICO)

// ❌ Campo 'status' provavelmente não tem índice
const pending = await prisma.order.findMany({
  where: { status: 'pending' }
});

// Verificar no schema: @@index([status]) existe?

Inicie a análise lendo o schema Prisma e depois buscando queries no projeto.


---

## 7.7 Exemplo Completo: Skill de API Designer

```markdown
---
name: api-designer
description: "Gera especificações OpenAPI 3.1 a partir de descrições em linguagem natural"
version: "2.0.0"
triggers:
  - /api-designer
  - /openapi
tools:
  - Read
  - Edit
  - Bash
model: sonnet
maxTurns: 15
---

# API Designer — Gerador de OpenAPI Specs

Você é um arquiteto de APIs REST especializado em OpenAPI 3.1.
Seu objetivo é criar especificações completas, corretas e seguindo
as melhores práticas de design de API.

## Princípios de Design que Você Segue

1. **Recursos em plural e substantivos**: `/users`, `/orders`, não `/getUsers`
2. **HTTP verbs corretos**: GET=leitura, POST=criação, PUT=substituição completa,
   PATCH=atualização parcial, DELETE=remoção
3. **Status codes precisos**: 200/201/204/400/401/403/404/409/422/500
4. **Paginação cursor-based** para listas grandes (cursor + limit + hasNextPage)
5. **Versionamento na URL**: `/v1/users`
6. **Erros no formato RFC 7807** (Problem Details)

## Formato de Erro Padrão (RFC 7807)
```json
{
  "type": "https://api.exemplo.com/errors/validation-error",
  "title": "Validation Error",
  "status": 422,
  "detail": "O campo email é inválido",
  "instance": "/v1/users/123",
  "errors": [
    { "field": "email", "message": "Formato de email inválido" }
  ]
}

Processo

  1. Leia o CLAUDE.md para entender o stack e convenções existentes
  2. Se existir uma spec OpenAPI já, leia-a para manter consistência
  3. Gere a spec completa em YAML
  4. Salve em docs/openapi.yaml (ou no path indicado)
  5. Valide com npx @redocly/cli lint docs/openapi.yaml se disponível

Output

Gere sempre a spec OpenAPI 3.1 completa em YAML, incluindo:

  • Info block com versão, title, description
  • Servers (dev + prod)
  • SecuritySchemes (Bearer JWT por padrão)
  • Tags com descrição
  • Todos os paths com parâmetros, request bodies e responses
  • Components/schemas para todos os tipos
  • Exemplos em todos os schemas

Após gerar, explique as decisões de design mais importantes.


---

## 7.8 Skills como "Personas" — O Padrão BMAD

BMAD (*Business, Market, Architecture, Development*) é um pattern de orquestração onde diferentes "personas" de agente cuidam de fases diferentes do desenvolvimento. Com skills, você implementa isso nativamente no Claude Code.

### Mapeamento de Personas para Skills

| Persona BMAD | Skill Correspondente | Responsabilidade |
|---|---|---|
| Business Analyst | `/analyst` | Refinamento de requisitos, critérios de aceite |
| Product Manager | `/pm` | Priorização, impacto de negócio |
| Architect | `/architect` | Design de sistema, ADRs, decisões técnicas |
| Developer | `/dev` (padrão) | Implementação, testes, refatoração |
| QA Engineer | `/qa-review` | Casos de teste, edge cases, cobertura |
| Security | `/security-review` | Vulnerabilidades, compliance |

### Exemplo: Skill de Architect

```markdown
---
name: architect
description: "Persona de arquiteto — analisa e propõe design de sistemas"
triggers:
  - /architect
tools:
  - Read
  - Grep
  - WebFetch
model: opus
maxTurns: 10
---

# Architect — Design e Decisões Técnicas

Você é um arquiteto de software sênior com 15+ anos de experiência.
Seu papel é pensar em sistemas, não em código.

## Seu Foco
- Trade-offs entre abordagens (não existe "melhor" abstrato)
- Implicações de escala, manutenibilidade e custo
- Alinhamento com o contexto do negócio
- Documentação de decisões via ADRs

## O Que Você NÃO Faz
- Você não escreve código de implementação
- Você não revisa style ou formatação
- Você não faz code review de detalhe

## Formato de Output
Quando propuser uma arquitetura, sempre inclua:
1. Diagrama ASCII da solução
2. Trade-offs: por que esta abordagem? o que ela sacrifica?
3. Riscos identificados
4. ADR draft (Architecture Decision Record)
5. Próximos passos para o dev implementar

Pense alto. Questione premissas. Proponha alternativas.

Orquestração de Personas em um Projeto Real

# Fluxo completo de uma feature nova

# 1. Analyst refina os requisitos
claude
> /analyst precisamos de um sistema de notificações push para mobile

# Claude como Analyst: pergunta, refina, documenta requisitos

# 2. Architect projeta a solução
> /architect baseado nos requisitos documentados, proponha a
  arquitetura do sistema de notificações

# Claude como Architect: diagrama, trade-offs, ADR

# 3. Dev implementa
> /dev implemente a primeira fase: cadastro de device tokens

# Claude como Dev: código, testes, commit

# 4. QA revisa
> /qa-review revise o que foi implementado e adicione casos de teste
  que podem estar faltando

7.9 Exemplo Prático Completo: Criar e Iterar uma Skill de Code Review

Vamos criar do zero uma skill de code review customizada para um projeto específico.

Passo 1: Definir o Problema

Nosso time tem algumas convenções muito específicas que review manuais frequentemente deixam passar:

  • Nunca usar console.log (usar logger)
  • Todos os endpoints precisam de autenticação explícita
  • Queries Prisma com findMany precisam de take explícito
  • Mensagens de erro para o usuário devem estar em português

Passo 2: Criar a Skill com /skill-creator

> /skill-creator

> Quero uma skill de code review para nosso projeto específico que verifique:
  1. Uso de console.log (proibido, use logger do src/lib/logger.ts)
  2. Endpoints Express sem middleware de auth (requireAuth ou requireAdmin)
  3. Prisma findMany sem campo take (risco de retornar tudo)
  4. Mensagens de erro em inglês para o usuário (devem ser em português)
  5. Funções assíncronas sem try/catch em routes

Passo 3: Revisar e Editar o Arquivo Gerado

.claude/skills/project-review.md:

---
name: project-review
description: "Code review com as regras específicas do nosso projeto"
version: "1.0.0"
triggers:
  - /project-review
  - /pr
tools:
  - Read
  - Grep
  - Bash
model: sonnet
maxTurns: 25
---

# Project Review — Regras Específicas do Projeto

Você é um tech lead revisando código para o projeto de pedidos.
Você conhece profundamente as convenções do time e não aceita exceções.

## Checklist Obrigatório

### 1. Logger (CRÍTICO)
- **NUNCA** `console.log/error/warn` em código de produção
- **SEMPRE** usar `import { logger } from '@/lib/logger'`
- Exceção: scripts de seed e migration (avisar mas não bloquear)

Grep por: `console\.(log|error|warn|info|debug)`

### 2. Autenticação em Endpoints (CRÍTICO)
- Todo handler de rota precisa de `requireAuth` ou `requireAdmin` como middleware
- Exceção permitida: rotas públicas documentadas com comentário `// PUBLIC ROUTE`

Grep por: `router\.(get|post|put|patch|delete)\(` e verificar se tem middleware

### 3. Prisma sem Limite (IMPORTANTE)
- `findMany` sem `take` em tabelas de dados de usuário é proibido
- Tabelas de configuração (< 1000 rows) podem ser exceção documentada

Grep por: `\.findMany\(` e verificar se tem `take:` no mesmo bloco

### 4. Idioma das Mensagens de Erro (IMPORTANTE)
- Mensagens que chegam ao usuário FINAL devem ser em português
- Mensagens de log interno podem ser em inglês
- Identificar por: campos `message`, `error`, respostas 4xx

### 5. Error Handling em Rotas (IMPORTANTE)
- Funções `async` em route handlers precisam de try/catch OU uso do wrapper `asyncHandler`
- Verificar: `router.get('/', async (req, res) => {` sem try/catch e sem asyncHandler

## Processo de Review

1. `git diff main...HEAD` para ver o diff (ou analisar arquivos indicados)
2. Para cada arquivo modificado, aplicar o checklist
3. Grep global para padrões proibidos nos arquivos alterados

## Formato de Output

🔍 Project Review

Arquivos Revisados

  • src/api/orders/routes.ts (modificado)
  • src/services/orderService.ts (modificado)

❌ Bloqueadores (devem ser corrigidos antes do merge)

src/api/orders/routes.ts:45 — console.log detectado
```typescript
console.log('Order created:', order.id); // ❌
```
Correção:
```typescript
logger.info('Order created', { orderId: order.id }); // ✅
```


⚠️ Avisos (fortemente recomendado corrigir)

[itens importantes mas não bloqueadores]


✅ OK

[convenções que foram seguidas corretamente]


📊 Resumo

  • Bloqueadores: N
  • Avisos: N
  • Status: APROVADO / REQUER MUDANÇAS

Seja direto e específico. Cite linha e arquivo. Sempre mostre a correção.

Passo 4: Testar a Skill

# Em uma sessão Claude Code
> /project-review

● Iniciando review com regras do projeto...

  Tool call: Bash("git diff main...HEAD --name-only")
  Tool call: Read("src/api/orders/routes.ts")
  Tool call: Grep("console\.(log|error|warn)", "src/")
  ...

## 🔍 Project Review

### ❌ Bloqueadores (2)

**src/api/orders/routes.ts:34** — console.log detectado
...

**src/api/payments/routes.ts:12** — Endpoint sem autenticação
...

### Status: REQUER MUDANÇAS

Passo 5: Iterar

Após usar a skill algumas vezes, você percebe que ela está tendo falsos positivos em arquivos de teste. Edite a skill:

## Exceções Conhecidas
- Arquivos `*.test.ts` e `*.spec.ts`: console.log é permitido
- Arquivos em `src/scripts/`: avisar mas não bloquear
- Rotas com comentário `// PUBLIC ROUTE`: auth não é obrigatória

Resumo de bolso

  • Skills são arquivos Markdown com frontmatter YAML que definem personas especializadas ativadas via /nome
  • Claude Code escaneia ~/.claude/skills/ (global) e .claude/skills/ (projeto) automaticamente
  • O frontmatter define modelo, tools disponíveis, max turns e triggers — use opus apenas para skills de design/arquitetura
  • O padrão BMAD mapeia personas (Analyst, Architect, Dev, QA) para skills separadas, criando um workflow estruturado
  • Itere suas skills como código: versione no Git, melhore baseado em feedback real de uso

Capítulo 8: Agents e Agent SDK

Claude Code pode ser usado como biblioteca programática — sem terminal interativo, sem humano no loop. Este capítulo mostra como construir agentes que trabalham sozinhos em tarefas de desenvolvimento.


8.1 O Conceito: Agentes Programáticos

Um agente é uma instância do Claude Code que recebe um prompt, executa um conjunto de tool calls em autonomia e retorna um resultado — tudo via código, sem intervenção humana.

CLI vs Agent SDK

Aspecto Claude Code CLI Agent SDK
Ativação Terminal interativo Código (TypeScript/Python)
Supervisão Humano presente Totalmente autônomo
Integração Manual Parte de um sistema maior
Caso de uso Trabalho diário do dev Pipelines, CI/CD, automações
Output Terminal (texto) Estruturado (JSON/objetos)
CLI: dev abre o terminal, conversa com Claude, valida cada passo

Agent SDK: script inicia agente, agente trabalha, script usa o resultado

8.2 Agent SDK em TypeScript

Instalação

npm install @anthropic-ai/claude-code

# O SDK requer Node.js 18+
node --version  # v18.0.0+

# Configure a API key
export ANTHROPIC_API_KEY="sk-ant-..."

API Básica

import { claude } from '@anthropic-ai/claude-code';

// Forma mais simples
const result = await claude({
  prompt: 'liste todos os arquivos TypeScript no projeto',
});

console.log(result.text);

Opções Disponíveis

import { claude, ClaudeOptions } from '@anthropic-ai/claude-code';

const options: ClaudeOptions = {
  // Modelo a usar
  model: 'claude-sonnet-4-5',  // ou 'claude-opus-4', 'claude-haiku-3-5'
  
  // Diretório de trabalho do agente
  cwd: '/path/to/project',
  
  // Máximo de turnos do agente (proteção contra loops infinitos)
  maxTurns: 50,
  
  // Quais tools o agente pode usar
  allowedTools: ['Read', 'Grep', 'Edit', 'Bash'],
  
  // Tools que nunca serão usadas (lista de exclusão)
  disallowedTools: ['WebFetch'],
  
  // Arquivo CLAUDE.md a carregar (além do padrão)
  systemPrompt: 'Você é um especialista em migração de código...',
  
  // Callbacks de progresso
  onProgress: (message) => {
    console.log('[agente]', message.type, message.content);
  },
};

const result = await claude({
  prompt: 'migre todos os require() para import/export ES Modules',
  ...options,
});

Exemplo Completo: Agente de Migração CommonJS → ESM

// scripts/migrate-to-esm.ts
import { claude } from '@anthropic-ai/claude-code';
import path from 'path';
import fs from 'fs';

interface MigrationResult {
  filesChanged: string[];
  errors: string[];
  summary: string;
}

async function migrateToESM(projectPath: string): Promise<MigrationResult> {
  console.log(`Iniciando migração para ESM em: ${projectPath}`);
  
  // Verificar se o projeto existe
  if (!fs.existsSync(projectPath)) {
    throw new Error(`Projeto não encontrado: ${projectPath}`);
  }

  const prompt = `
Você é um especialista em JavaScript moderno. Sua tarefa é migrar este projeto
de CommonJS (require/module.exports) para ES Modules (import/export).

## Passos a seguir:

1. Encontre todos os arquivos .js/.ts que usam require() ou module.exports
2. Para cada arquivo, converta a sintaxe:
   - require('x') → import x from 'x' (ou import { x } from 'x')
   - module.exports = x → export default x
   - module.exports = { a, b } → export { a, b }
3. Atualize o package.json para adicionar "type": "module"
4. Ajuste tsconfig.json se existir (module: "ESNext", moduleResolution: "bundler")
5. Verifique se há __dirname ou __filename (não existem em ESM) e substitua por:
   import { fileURLToPath } from 'url'
   const __filename = fileURLToPath(import.meta.url)
   const __dirname = path.dirname(__filename)

## Importante:
- NÃO modifique arquivos em node_modules/
- NÃO modifique arquivos .json (exceto package.json e tsconfig.json)
- Faça um commit por arquivo migrado para facilitar revisão
- Se encontrar padrão ambíguo, prefira a conversão mais conservadora

Ao final, liste todos os arquivos modificados.
  `.trim();

  const result = await claude({
    prompt,
    cwd: projectPath,
    model: 'claude-sonnet-4-5',
    maxTurns: 100,
    allowedTools: ['Read', 'Grep', 'Edit', 'Bash'],
    onProgress: (msg) => {
      if (msg.type === 'tool_use') {
        process.stdout.write(`  [${msg.tool}] ${msg.input?.path || ''}\n`);
      }
    },
  });

  // Parsear resultado
  const filesChanged = extractFileList(result.text);
  
  return {
    filesChanged,
    errors: [],
    summary: result.text,
  };
}

function extractFileList(text: string): string[] {
  const lines = text.split('\n');
  return lines
    .filter(line => line.match(/^\s*[-*]\s+\S+\.(ts|js)/))
    .map(line => line.replace(/^\s*[-*]\s+/, '').trim());
}

// Execução
const projectPath = process.argv[2] || process.cwd();

migrateToESM(projectPath)
  .then(result => {
    console.log('\n✅ Migração concluída!');
    console.log(`Arquivos modificados: ${result.filesChanged.length}`);
    result.filesChanged.forEach(f => console.log(`  - ${f}`));
  })
  .catch(err => {
    console.error('❌ Erro na migração:', err.message);
    process.exit(1);
  });
# Executar
npx ts-node scripts/migrate-to-esm.ts /path/to/project

8.3 Agent SDK em Python

Instalação

pip install claude-code-sdk

# Python 3.9+ requerido
python --version

export ANTHROPIC_API_KEY="sk-ant-..."

API Básica

import asyncio
from claude_code_sdk import ClaudeCode, ClaudeCodeOptions

async def main():
    # Forma simples
    result = await ClaudeCode.query(
        prompt="liste todos os arquivos sem cobertura de testes"
    )
    print(result.text)

asyncio.run(main())

Exemplo Completo: Agente de Geração de Testes

# scripts/generate_tests.py
import asyncio
import subprocess
import json
from pathlib import Path
from claude_code_sdk import ClaudeCode, ClaudeCodeOptions

async def find_uncovered_files(project_path: str) -> list[str]:
    """Identifica arquivos com cobertura de teste abaixo de 80%."""
    
    result = subprocess.run(
        ['npm', 'run', 'test:coverage', '--', '--json', '--silent'],
        capture_output=True,
        text=True,
        cwd=project_path
    )
    
    try:
        coverage_data = json.loads(result.stdout)
        uncovered = []
        
        for file_path, data in coverage_data.get('coverageMap', {}).items():
            if 'node_modules' in file_path:
                continue
            
            statements = data.get('s', {})
            if not statements:
                continue
                
            covered = sum(1 for v in statements.values() if v > 0)
            total = len(statements)
            coverage_pct = (covered / total * 100) if total > 0 else 100
            
            if coverage_pct < 80:
                uncovered.append({
                    'path': file_path,
                    'coverage': round(coverage_pct, 1)
                })
        
        return sorted(uncovered, key=lambda x: x['coverage'])
    
    except json.JSONDecodeError:
        print("Aviso: não foi possível parsear cobertura. Usando análise manual.")
        return []


async def generate_tests_for_file(
    file_path: str,
    project_path: str
) -> str:
    """Gera testes unitários para um arquivo específico."""
    
    relative_path = Path(file_path).relative_to(project_path)
    
    options = ClaudeCodeOptions(
        cwd=project_path,
        model='claude-sonnet-4-5',
        max_turns=20,
        allowed_tools=['Read', 'Grep', 'Edit', 'Bash'],
    )
    
    prompt = f"""
Analise o arquivo `{relative_path}` e gere testes unitários completos.

Siga estas regras:
1. Use o mesmo framework de testes já presente no projeto (Vitest ou Jest)
2. Salve os testes em arquivo adjacente com sufixo .test.ts
3. Cubra: happy path, edge cases, erros esperados
4. Mock dependências externas (banco, APIs, etc.)
5. Cada test deve ser independente (sem estado compartilhado)
6. Nomes de teste em português do Brasil, descritivos

Meta de cobertura: ≥ 90% de statements e branches.

Após criar os testes, execute-os para confirmar que passam.
    """.strip()
    
    result = await ClaudeCode.query(prompt=prompt, options=options)
    return result.text


async def main():
    project_path = '/home/dev/meu-projeto'
    
    print("🔍 Buscando arquivos com cobertura insuficiente...")
    uncovered = await find_uncovered_files(project_path)
    
    if not uncovered:
        print("✅ Todos os arquivos têm cobertura adequada!")
        return
    
    print(f"📋 Encontrados {len(uncovered)} arquivos para cobrir:\n")
    for item in uncovered:
        print(f"  {item['coverage']}% — {item['path']}")
    
    print("\n🤖 Gerando testes...\n")
    
    # Processar um por vez para evitar conflitos de arquivo
    for item in uncovered[:5]:  # Limitar a 5 por execução
        print(f"  Gerando testes para: {Path(item['path']).name}")
        
        try:
            result = await generate_tests_for_file(
                item['path'],
                project_path
            )
            print(f"  ✅ Testes criados\n")
        except Exception as e:
            print(f"  ❌ Erro: {e}\n")
    
    print("✨ Geração de testes concluída!")


if __name__ == '__main__':
    asyncio.run(main())

8.4 Subagent Types no Claude Code

Internamente, o Claude Code usa diferentes "tipos" de subagentes para diferentes propósitos. Você pode indicar qual tipo quer ao criar agentes programáticos:

Explore (Somente Leitura)

const exploreAgent = await claude({
  prompt: 'mapeie toda a lógica de autenticação do projeto',
  allowedTools: ['Read', 'Grep', 'Bash'],
  // Sem 'Edit' = agente somente leitura
  model: 'claude-haiku-3-5', // Rápido, só precisa ler
});

Uso: Descoberta de código, análise, geração de relatórios, busca de padrões. Seguro para rodar em qualquer branch.

Plan (Planejamento)

const planAgent = await claude({
  prompt: `/plan implemente o módulo de notificações push`,
  allowedTools: ['Read', 'Grep', 'WebFetch'],
  model: 'claude-opus-4', // Opus para raciocínio complexo
  maxTurns: 10,
});

// result.text contém o plano estruturado
// Você revisa antes de passar para o implement agent

Uso: Arquitetura, planejamento de refatorações grandes, análise de impacto.

General Purpose (Lê e Escreve)

const implementAgent = await claude({
  prompt: plan, // Alimenta com output do plan agent
  allowedTools: ['Read', 'Grep', 'Edit', 'Bash'],
  model: 'claude-sonnet-4-5',
  maxTurns: 100,
});

Uso: Implementação real, refatoração, geração de testes.


8.5 Orquestração de Agentes

Execução Sequencial: Pipeline

// agents/pipeline.ts
import { claude } from '@anthropic-ai/claude-code';

async function runPipeline(feature: string, cwd: string) {
  console.log('🔍 Fase 1: Exploração');
  const exploreResult = await claude({
    prompt: `Mapeie todo o código relacionado a "${feature}". 
             Liste arquivos, funções e dependências.`,
    cwd,
    allowedTools: ['Read', 'Grep'],
    model: 'claude-haiku-3-5',
    maxTurns: 15,
  });

  console.log('📐 Fase 2: Planejamento');
  const planResult = await claude({
    prompt: `/plan Baseado nesta análise:

${exploreResult.text}

Proponha como implementar: ${feature}
Seja específico: quais arquivos criar/editar e em que ordem.`,
    cwd,
    allowedTools: ['Read', 'Grep'],
    model: 'claude-opus-4',
    maxTurns: 10,
  });

  console.log('⚙️ Fase 3: Implementação');
  const implementResult = await claude({
    prompt: `Execute este plano de implementação:

${planResult.text}

Implemente completamente. Faça um commit por mudança lógica.
Rode os testes ao final e corrija se necessário.`,
    cwd,
    allowedTools: ['Read', 'Grep', 'Edit', 'Bash'],
    model: 'claude-sonnet-4-5',
    maxTurns: 80,
  });

  return {
    exploration: exploreResult.text,
    plan: planResult.text,
    implementation: implementResult.text,
  };
}

// Uso
runPipeline(
  'sistema de webhooks para notificar eventos de pedido',
  '/home/dev/orders-api'
).then(result => {
  console.log('\n✅ Pipeline concluído!');
  console.log(result.implementation);
});

Execução Paralela: Fan-out/Fan-in

// agents/parallel-review.ts
import { claude } from '@anthropic-ai/claude-code';

async function parallelCodeReview(prDiff: string, cwd: string) {
  console.log('Iniciando review paralelo...');
  
  // Três agentes rodando ao mesmo tempo, cada um com foco diferente
  const [securityReview, performanceReview, testsReview] = await Promise.all([
    
    // Agente 1: Segurança
    claude({
      prompt: `Faça um security review deste diff. Foque em:
- Injeção SQL/NoSQL
- XSS e CSRF
- Secrets expostos
- Problemas de auth/authz
- Dados sensíveis em logs

Diff:
${prDiff}`,
      cwd,
      allowedTools: ['Read', 'Grep'],
      model: 'claude-sonnet-4-5',
      maxTurns: 15,
    }),
    
    // Agente 2: Performance
    claude({
      prompt: `Analise o impacto de performance deste diff:
- N+1 queries
- Loops desnecessários
- Memória e garbage collection
- Chamadas síncronas bloqueantes

Diff:
${prDiff}`,
      cwd,
      allowedTools: ['Read', 'Grep'],
      model: 'claude-sonnet-4-5',
      maxTurns: 15,
    }),
    
    // Agente 3: Qualidade de Testes
    claude({
      prompt: `Revise a cobertura de testes deste diff:
- Edge cases não testados
- Mocks incorretos
- Testes frágeis (dependem de ordem de execução)
- Asserções fracas

Diff:
${prDiff}`,
      cwd,
      allowedTools: ['Read', 'Grep'],
      model: 'claude-sonnet-4-5',
      maxTurns: 15,
    }),
  ]);

  // Fan-in: consolidar os três reviews em um
  console.log('Consolidando reviews...');
  const consolidatedReview = await claude({
    prompt: `Consolide estes três reviews em um relatório único e priorizado.
Elimine duplicações. Ordene por severidade (crítico → importante → sugestão).

## Review de Segurança:
${securityReview.text}

## Review de Performance:
${performanceReview.text}

## Review de Testes:
${testsReview.text}`,
    model: 'claude-haiku-3-5',
    maxTurns: 5,
  });

  return consolidatedReview.text;
}

Worktree Isolation: Agentes em Branches Separadas

// agents/worktree-agents.ts
import { claude } from '@anthropic-ai/claude-code';
import { execSync } from 'child_process';
import path from 'path';
import fs from 'fs';
import os from 'os';

async function runAgentInWorktree(
  feature: string,
  baseBranch: string = 'main'
): Promise<{ branch: string; success: boolean; output: string }> {
  
  const branchName = `feat/auto-${Date.now()}-${feature.slice(0, 20).replace(/\s/g, '-')}`;
  const worktreePath = path.join(os.tmpdir(), `claude-worktree-${Date.now()}`);
  
  try {
    // Criar worktree em pasta temporária
    execSync(`git worktree add ${worktreePath} -b ${branchName} ${baseBranch}`, {
      stdio: 'pipe'
    });
    
    console.log(`Agente trabalhando em: ${branchName}`);
    
    // Agente trabalha no worktree isolado
    const result = await claude({
      prompt: feature,
      cwd: worktreePath,
      allowedTools: ['Read', 'Grep', 'Edit', 'Bash'],
      model: 'claude-sonnet-4-5',
      maxTurns: 60,
    });
    
    return {
      branch: branchName,
      success: true,
      output: result.text,
    };
    
  } finally {
    // Limpar worktree (mas manter a branch)
    try {
      execSync(`git worktree remove ${worktreePath} --force`, { stdio: 'pipe' });
    } catch {
      // Ignorar erros de cleanup
    }
  }
}

// Exemplo: dois agentes em paralelo, cada um em sua branch
async function parallelFeatures() {
  const features = [
    'Implemente endpoint GET /users/:id/orders com paginação',
    'Implemente rate limiting de 100 req/min por IP usando Redis',
  ];

  const results = await Promise.all(
    features.map(f => runAgentInWorktree(f))
  );

  results.forEach(r => {
    console.log(`\nBranch: ${r.branch}`);
    console.log(`Status: ${r.success ? '✅' : '❌'}`);
    console.log(`Criar PR: gh pr create --head ${r.branch}`);
  });
}

8.6 Multi-Agent Patterns

Supervisor Pattern

// agents/supervisor.ts
import { claude } from '@anthropic-ai/claude-code';

interface Task {
  id: string;
  description: string;
  type: 'explore' | 'implement' | 'test' | 'review';
}

async function supervisorAgent(goal: string, cwd: string) {
  // Supervisor planeja e delega
  const planResult = await claude({
    prompt: `Você é um agente supervisor. Analise este objetivo e divida em tarefas:
    
Objetivo: ${goal}

Retorne um JSON array de tarefas, onde cada tarefa tem:
- id: string único
- description: o que fazer
- type: "explore" | "implement" | "test" | "review"
- dependsOn: array de IDs de tarefas que devem completar antes desta

Responda APENAS com o JSON, sem markdown.`,
    model: 'claude-opus-4',
    allowedTools: ['Read', 'Grep'],
    cwd,
    maxTurns: 5,
  });

  let tasks: Task[] = [];
  try {
    tasks = JSON.parse(planResult.text);
  } catch {
    throw new Error('Supervisor não retornou JSON válido');
  }

  console.log(`Supervisor criou ${tasks.length} tarefas:`);
  tasks.forEach(t => console.log(`  [${t.type}] ${t.id}: ${t.description}`));

  // Executar tarefas respeitando dependências
  const completed = new Set<string>();
  const results: Record<string, string> = {};

  while (completed.size < tasks.length) {
    // Encontrar tarefas cujas dependências estão completas
    const ready = tasks.filter(t => 
      !completed.has(t.id) &&
      (t as any).dependsOn?.every((dep: string) => completed.has(dep)) !== false
    );

    if (ready.length === 0) break; // Sem progresso possível

    // Executar tarefas prontas em paralelo
    await Promise.all(ready.map(async (task) => {
      console.log(`  Executando [${task.type}]: ${task.id}`);
      
      const allowedTools = task.type === 'explore' 
        ? ['Read', 'Grep'] 
        : ['Read', 'Grep', 'Edit', 'Bash'];

      const result = await claude({
        prompt: task.description,
        cwd,
        allowedTools,
        model: task.type === 'explore' ? 'claude-haiku-3-5' : 'claude-sonnet-4-5',
        maxTurns: task.type === 'explore' ? 10 : 40,
      });

      results[task.id] = result.text;
      completed.add(task.id);
    }));
  }

  return results;
}

8.7 Exemplos Práticos de Agentes

Agente de Triagem de Issues do GitHub

// agents/issue-triage.ts
import { claude } from '@anthropic-ai/claude-code';
import { Octokit } from '@octokit/rest';

const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });

async function triageIssue(
  owner: string,
  repo: string,
  issueNumber: number,
  cwd: string
) {
  // Buscar issue
  const { data: issue } = await octokit.issues.get({
    owner, repo, issue_number: issueNumber
  });

  const result = await claude({
    prompt: `Analise este bug report do GitHub e faça a triagem:

**Issue #${issue.number}: ${issue.title}**

${issue.body}

Tarefa:
1. Busque no código onde o bug pode estar (use Grep e Read)
2. Classifique severidade: crítico | importante | menor
3. Estime complexidade: simples | médio | complexo
4. Identifique arquivos afetados
5. Sugira próximos passos

Responda em formato estruturado.`,
    cwd,
    allowedTools: ['Read', 'Grep'],
    model: 'claude-sonnet-4-5',
    maxTurns: 20,
  });

  // Postar análise no issue
  await octokit.issues.createComment({
    owner, repo,
    issue_number: issueNumber,
    body: `## 🤖 Triagem Automática\n\n${result.text}`,
  });

  // Adicionar labels baseado na análise
  const labels = [];
  if (result.text.includes('crítico')) labels.push('priority: critical');
  if (result.text.includes('simples')) labels.push('complexity: simple');
  
  if (labels.length > 0) {
    await octokit.issues.addLabels({
      owner, repo, issue_number: issueNumber, labels
    });
  }

  console.log(`Issue #${issueNumber} triado. Labels: ${labels.join(', ')}`);
}

// Processar issues sem label de triagem
async function processUntriaged(owner: string, repo: string, cwd: string) {
  const { data: issues } = await octokit.issues.listForRepo({
    owner, repo,
    state: 'open',
    labels: 'needs-triage',
    per_page: 10,
  });

  for (const issue of issues) {
    console.log(`Triando issue #${issue.number}...`);
    await triageIssue(owner, repo, issue.number, cwd);
    // Rate limiting básico
    await new Promise(r => setTimeout(r, 2000));
  }
}

Agente de Geração de Documentação

// agents/doc-generator.ts
import { claude } from '@anthropic-ai/claude-code';
import { glob } from 'glob';

async function generateDocs(cwd: string) {
  // Encontrar arquivos sem documentação JSDoc
  const files = await glob('src/**/*.ts', { 
    cwd,
    ignore: ['**/*.test.ts', '**/*.spec.ts', '**/node_modules/**']
  });

  console.log(`Gerando documentação para ${files.length} arquivos...`);

  const result = await claude({
    prompt: `Você é um technical writer especializado em TypeScript.

Adicione JSDoc completo em todos os arquivos públicos do projeto:
- Funções e métodos: @param, @returns, @throws, @example
- Classes e interfaces: descrição do propósito
- Módulos: @module com descrição do que o módulo faz
- Funções complexas: @description com algoritmo explicado

Regras:
- Escreva em inglês (padrão para documentação técnica)
- Seja conciso mas completo
- Use @example com código real do contexto do projeto
- NÃO documente código óbvio demais (getters triviais, etc.)
- Preserve código existente, apenas adicione documentação

Comece pelos arquivos de service e repository, depois controllers.`,
    cwd,
    allowedTools: ['Read', 'Grep', 'Edit', 'Bash'],
    model: 'claude-sonnet-4-5',
    maxTurns: 100,
  });

  return result.text;
}

Resumo de bolso

  • O Agent SDK permite usar Claude Code programaticamente — sem terminal, integrado em sistemas maiores
  • TypeScript usa @anthropic-ai/claude-code com claude({ prompt, options }); Python usa claude-code-sdk com ClaudeCode.query()
  • Tres tipos de subagente: Explore (read-only, rápido), Plan (raciocínio, sem edição), General Purpose (lê e escreve)
  • Paralelize com Promise.all para tarefas independentes; use worktrees Git para isolamento real entre agentes
  • Fan-out/fan-in, pipeline e supervisor são os três padrões principais de orquestração — escolha baseado em se as tarefas são independentes, sequenciais ou hierárquicas

Capítulo 9: MCP (Model Context Protocol)

O MCP resolve o "problema de integração" do mundo de IA: cada ferramenta precisava de integração proprietária com cada modelo. O MCP cria uma interface padrão.


9.1 O Que É MCP e Por Que Existe

O MCP (Model Context Protocol) é um protocolo aberto criado pela Anthropic para padronizar a comunicação entre modelos de IA e ferramentas externas.

O Problema Antes do MCP

Sem MCP:
  Cursor ←→ integração proprietária A ←→ GitHub
  Cursor ←→ integração proprietária B ←→ PostgreSQL
  Cursor ←→ integração proprietária C ←→ Slack
  
  Claude Code ←→ integração diferente A' ←→ GitHub
  Claude Code ←→ integração diferente B' ←→ PostgreSQL
  (Slack não suportado)
  
  Resultado: N ferramentas × M integrações = caos

Com MCP

Com MCP:
  Qualquer Host (Claude Code, Cursor, VS Code, etc.)
       ↓ protocolo padrão
  Qualquer MCP Server (GitHub, PostgreSQL, Slack, etc.)
  
  Resultado: 1 protocolo unifica tudo

💡 Dica: Pense no MCP como o "USB" do mundo de IA. Antes do USB, cada fabricante tinha seu conector. O MCP cria o conector padrão para que qualquer host de IA se conecte a qualquer ferramenta.


9.2 Arquitetura do MCP

┌─────────────────────────────────────────────────────────┐
│  HOST (Claude Code, Cursor, VS Code + Continue, etc.)    │
│                                                           │
│  ┌──────────────┐     ┌──────────────┐                   │
│  │   LLM Engine │     │  MCP Client  │                   │
│  │   (Claude)   │────▶│  (gerencia   │                   │
│  │              │◀────│  conexões)   │                   │
│  └──────────────┘     └──────┬───────┘                   │
└─────────────────────────────┼───────────────────────────┘
                               │ JSON-RPC 2.0
              ┌────────────────┼────────────────┐
              │                │                │
              ▼                ▼                ▼
   ┌──────────────┐  ┌──────────────┐  ┌──────────────┐
   │  MCP Server  │  │  MCP Server  │  │  MCP Server  │
   │   GitHub     │  │  PostgreSQL  │  │    Custom    │
   │              │  │              │  │    (sua      │
   │ tools:       │  │ tools:       │  │   empresa)   │
   │ - list_prs   │  │ - query      │  │              │
   │ - create_pr  │  │ - schema     │  │ tools:       │
   │ resources:   │  │ resources:   │  │ - get_order  │
   │ - repo info  │  │ - tables     │  │ - update_inv │
   └──────────────┘  └──────────────┘  └──────────────┘

Três Papéis

Papel O que é Exemplo
Host Aplicação que roda o modelo Claude Code, Cursor, VS Code
Client Componente dentro do host que gerencia conexões MCP Integrado no Claude Code
Server Processo separado que expõe capabilities @modelcontextprotocol/server-github

9.3 Tipos de Capability

Tools (Ações)

São funções que o modelo pode chamar. O modelo decide quando chamar, com quais parâmetros.

{
  "name": "create_github_issue",
  "description": "Cria um novo issue no repositório GitHub especificado",
  "inputSchema": {
    "type": "object",
    "properties": {
      "owner": { "type": "string", "description": "Dono do repositório" },
      "repo": { "type": "string", "description": "Nome do repositório" },
      "title": { "type": "string", "description": "Título do issue" },
      "body": { "type": "string", "description": "Corpo do issue em Markdown" },
      "labels": {
        "type": "array",
        "items": { "type": "string" },
        "description": "Labels a aplicar"
      }
    },
    "required": ["owner", "repo", "title"]
  }
}

Resources (Dados)

São fontes de dados que o modelo pode ler. Identificados por URI.

{
  "uri": "postgres://db/schema",
  "name": "Schema do Banco de Dados",
  "description": "Estrutura de todas as tabelas e índices",
  "mimeType": "application/json"
}

Prompts (Templates)

São templates de prompt reutilizáveis que o usuário pode invocar.

{
  "name": "debug_sql_query",
  "description": "Template para debugar uma query SQL lenta",
  "arguments": [
    {
      "name": "query",
      "description": "A query SQL a analisar",
      "required": true
    }
  ]
}

9.4 MCP Servers Úteis

filesystem — Leitura/Escrita de Arquivos

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/home/dev/projetos",
        "/tmp/claude-work"
      ]
    }
  }
}

O que faz: Expõe operações de arquivo (read, write, list, search) em diretórios autorizados. Útil quando você quer que o agente acesse arquivos fora do projeto atual.

Tools expostas: read_file, write_file, list_directory, search_files, get_file_info


git — Operações Git Avançadas

{
  "mcpServers": {
    "git": {
      "command": "uvx",
      "args": ["mcp-server-git", "--repository", "/home/dev/meu-projeto"]
    }
  }
}

O que faz: Expõe operações git além do básico: histórico detalhado, blame, diff entre branches, stash.

Tools expostas: git_log, git_diff, git_blame, git_show, git_status, git_branch, git_stash


browser — Automação Web (Puppeteer)

{
  "mcpServers": {
    "puppeteer": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-puppeteer"]
    }
  }
}

O que faz: Permite que o agente controle um browser: navegar, clicar, capturar screenshot, extrair dados de páginas.

Tools expostas: puppeteer_navigate, puppeteer_click, puppeteer_screenshot, puppeteer_evaluate, puppeteer_fill

Caso de uso: Testar fluxos E2E, extrair dados de sistemas sem API, validar UI.


postgres — Consultas em Banco

{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": {
        "POSTGRES_CONNECTION_STRING": "postgresql://user:pass@localhost:5432/mydb"
      }
    }
  }
}

O que faz: Permite que o agente execute queries SQL, inspecione schema e analise dados.

Tools expostas: query, list_tables, describe_table, list_indexes

⚠️ Armadilha: Configure permissões de banco corretamente. Para agentes em CI ou produção, use usuário read-only. Nunca conecte um agente a banco de produção com permissão de escrita sem revisão humana no loop.


slack — Enviar Mensagens e Ler Canais

{
  "mcpServers": {
    "slack": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-slack"],
      "env": {
        "SLACK_BOT_TOKEN": "xoxb-...",
        "SLACK_TEAM_ID": "T..."
      }
    }
  }
}

O que faz: Envia mensagens, lê canais, reage a mensagens, cria posts.

Tools expostas: slack_post_message, slack_reply_to_thread, slack_add_reaction, slack_get_channel_history, slack_list_channels

Caso de uso: Agente que notifica o time quando termina uma tarefa, ou que busca contexto de discussões passadas.


github — Issues, PRs, Actions

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_..."
      }
    }
  }
}

O que faz: Operações completas no GitHub via API: criar/listar issues e PRs, verificar status de checks, ler código de repositórios.

Tools expostas: create_issue, list_issues, create_pull_request, list_pull_requests, get_file_contents, search_code, list_commits


sentry — Monitorar Erros

{
  "mcpServers": {
    "sentry": {
      "command": "uvx",
      "args": ["mcp-server-sentry"],
      "env": {
        "SENTRY_AUTH_TOKEN": "sntryu_...",
        "SENTRY_ORGANIZATION": "minha-org"
      }
    }
  }
}

O que faz: Lê erros do Sentry, rastreia issues, busca stack traces.

Tools expostas: list_issues, get_issue_details, list_events, get_stacktrace

Caso de uso: Agente que recebe descrição de bug, busca no Sentry o erro correspondente, analisa o stack trace e sugere a correção.


9.5 Criando um MCP Server Custom

Quando nenhum server público atende sua necessidade, você cria o seu. Caso típico: integrar com APIs internas da empresa.

Setup

mkdir meu-mcp-server
cd meu-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node ts-node
// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "outDir": "dist",
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src/**/*"]
}

Exemplo Completo: MCP Server para API REST Interna

Cenário: nossa empresa tem uma API interna de catálogo de produtos. Queremos que o Claude Code possa consultar preços, estoque e especificações sem precisar abrir documentação.

// src/index.ts
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
  ListResourcesRequestSchema,
  ReadResourceRequestSchema,
  ErrorCode,
  McpError,
} from '@modelcontextprotocol/sdk/types.js';
import { z } from 'zod';

const API_BASE = process.env.CATALOG_API_URL || 'https://catalog.interno.empresa.com';
const API_KEY = process.env.CATALOG_API_KEY;

if (!API_KEY) {
  throw new Error('CATALOG_API_KEY não configurada');
}

// Helper para chamadas à API interna
async function apiCall<T>(path: string, options?: RequestInit): Promise<T> {
  const response = await fetch(`${API_BASE}${path}`, {
    ...options,
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
      ...options?.headers,
    },
  });

  if (!response.ok) {
    const error = await response.text();
    throw new McpError(
      ErrorCode.InternalError,
      `API retornou ${response.status}: ${error}`
    );
  }

  return response.json();
}

// Schemas de validação com Zod
const SearchProductsSchema = z.object({
  query: z.string().describe('Termo de busca (nome, SKU, categoria)'),
  category: z.string().optional().describe('Filtrar por categoria'),
  inStock: z.boolean().optional().describe('Apenas produtos em estoque'),
  limit: z.number().min(1).max(50).optional().default(10),
});

const GetProductSchema = z.object({
  productId: z.string().describe('ID ou SKU do produto'),
});

const UpdateStockSchema = z.object({
  productId: z.string().describe('ID do produto'),
  quantity: z.number().int().describe('Nova quantidade em estoque'),
  reason: z.string().describe('Motivo da atualização (para auditoria)'),
});

// Criar o servidor MCP
const server = new Server(
  {
    name: 'catalog-api',
    version: '1.0.0',
  },
  {
    capabilities: {
      tools: {},
      resources: {},
    },
  }
);

// Listar tools disponíveis
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
    {
      name: 'search_products',
      description: 'Busca produtos no catálogo por nome, SKU ou categoria',
      inputSchema: {
        type: 'object',
        properties: {
          query: {
            type: 'string',
            description: 'Termo de busca',
          },
          category: {
            type: 'string',
            description: 'Categoria para filtrar (opcional)',
          },
          inStock: {
            type: 'boolean',
            description: 'Se true, retorna apenas produtos com estoque > 0',
          },
          limit: {
            type: 'number',
            description: 'Máximo de resultados (1-50, padrão 10)',
          },
        },
        required: ['query'],
      },
    },
    {
      name: 'get_product',
      description: 'Obtém detalhes completos de um produto (preço, estoque, specs)',
      inputSchema: {
        type: 'object',
        properties: {
          productId: {
            type: 'string',
            description: 'ID ou SKU do produto',
          },
        },
        required: ['productId'],
      },
    },
    {
      name: 'update_stock',
      description: 'Atualiza quantidade em estoque de um produto',
      inputSchema: {
        type: 'object',
        properties: {
          productId: { type: 'string' },
          quantity: { type: 'number' },
          reason: { type: 'string' },
        },
        required: ['productId', 'quantity', 'reason'],
      },
    },
  ],
}));

// Implementar handlers das tools
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  try {
    switch (name) {
      case 'search_products': {
        const params = SearchProductsSchema.parse(args);
        const queryString = new URLSearchParams({
          q: params.query,
          limit: String(params.limit),
          ...(params.category && { category: params.category }),
          ...(params.inStock !== undefined && { inStock: String(params.inStock) }),
        });

        const data = await apiCall<{
          products: Array<{
            id: string;
            sku: string;
            name: string;
            price: number;
            stock: number;
            category: string;
          }>;
          total: number;
        }>(`/v1/products?${queryString}`);

        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(data, null, 2),
            },
          ],
        };
      }

      case 'get_product': {
        const { productId } = GetProductSchema.parse(args);
        const product = await apiCall(`/v1/products/${productId}`);

        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(product, null, 2),
            },
          ],
        };
      }

      case 'update_stock': {
        const params = UpdateStockSchema.parse(args);
        const result = await apiCall(`/v1/products/${params.productId}/stock`, {
          method: 'PATCH',
          body: JSON.stringify({
            quantity: params.quantity,
            reason: params.reason,
          }),
        });

        return {
          content: [
            {
              type: 'text',
              text: `Estoque atualizado com sucesso:\n${JSON.stringify(result, null, 2)}`,
            },
          ],
        };
      }

      default:
        throw new McpError(ErrorCode.MethodNotFound, `Tool "${name}" não encontrada`);
    }
  } catch (error) {
    if (error instanceof z.ZodError) {
      throw new McpError(
        ErrorCode.InvalidParams,
        `Parâmetros inválidos: ${error.errors.map(e => e.message).join(', ')}`
      );
    }
    throw error;
  }
});

// Resources: dados estáticos ou semi-estáticos
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
  resources: [
    {
      uri: 'catalog://categories',
      name: 'Categorias do Catálogo',
      description: 'Lista de todas as categorias disponíveis',
      mimeType: 'application/json',
    },
    {
      uri: 'catalog://price-rules',
      name: 'Regras de Preço',
      description: 'Tabela de descontos e regras de precificação',
      mimeType: 'application/json',
    },
  ],
}));

server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  const { uri } = request.params;

  switch (uri) {
    case 'catalog://categories': {
      const data = await apiCall('/v1/categories');
      return {
        contents: [
          {
            uri,
            mimeType: 'application/json',
            text: JSON.stringify(data, null, 2),
          },
        ],
      };
    }

    case 'catalog://price-rules': {
      const data = await apiCall('/v1/pricing/rules');
      return {
        contents: [
          {
            uri,
            mimeType: 'application/json',
            text: JSON.stringify(data, null, 2),
          },
        ],
      };
    }

    default:
      throw new McpError(ErrorCode.InvalidRequest, `Resource "${uri}" não encontrado`);
  }
});

// Inicializar e rodar
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('Catalog MCP Server rodando...');

Build e Teste Local

// package.json
{
  "name": "catalog-mcp-server",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "ts-node --esm src/index.ts"
  }
}
# Testar localmente (MCP Inspector)
npx @modelcontextprotocol/inspector node dist/index.js

O MCP Inspector abre uma interface web onde você testa as tools antes de integrar.


9.6 MCP Registry: Descobrindo Servers da Comunidade

O MCP Registry é o catálogo público de servers disponíveis:

# Buscar servers disponíveis
npx @modelcontextprotocol/registry search "database"
npx @modelcontextprotocol/registry search "github"
npx @modelcontextprotocol/registry info @modelcontextprotocol/server-postgres

# Ver todos os servers oficiais
npx @modelcontextprotocol/registry list --official

Sites úteis para descobrir servers:

  • https://github.com/modelcontextprotocol/servers — Repositório oficial com servers da Anthropic
  • https://mcp.so — Diretório da comunidade
  • https://smithery.ai — Marketplace de MCP servers

9.7 Configuração Completa no Claude Code

O arquivo settings.json do Claude Code aceita a seção mcpServers:

// ~/.claude/settings.json (global) ou .claude/settings.json (projeto)
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_..."
      }
    },

    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": {
        "POSTGRES_CONNECTION_STRING": "postgresql://user:pass@localhost:5432/dev_db"
      }
    },

    "catalog": {
      "command": "node",
      "args": ["/home/dev/tools/catalog-mcp-server/dist/index.js"],
      "env": {
        "CATALOG_API_URL": "https://catalog.interno.empresa.com",
        "CATALOG_API_KEY": "..."
      }
    },

    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/home/dev/projetos",
        "/tmp"
      ]
    },

    "slack": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-slack"],
      "env": {
        "SLACK_BOT_TOKEN": "xoxb-...",
        "SLACK_TEAM_ID": "T..."
      }
    }
  },

  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npm run lint:fix -- ${file} 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}

⚠️ Armadilha: Não coloque tokens e senhas diretamente no settings.json se o arquivo for commitado. Use variáveis de ambiente ou um gerenciador de segredos, e adicione .claude/settings.json ao .gitignore do projeto.

Usando Variáveis de Ambiente no Settings

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  }
}
# No seu shell profile (~/.bashrc ou ~/.zshrc)
export GITHUB_TOKEN="ghp_..."
export CATALOG_API_KEY="..."

9.8 MCP em Cursor e Outras IDEs

Cursor: mcp.json na raiz do projeto

// .cursor/mcp.json
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${env:GITHUB_TOKEN}"
      }
    },
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": {
        "POSTGRES_CONNECTION_STRING": "postgresql://localhost/dev"
      }
    }
  }
}

Após criar o arquivo, abra Command Palette no Cursor e execute MCP: Reload Servers.

VS Code + Continue.dev: config.json

// ~/.continue/config.json
{
  "models": [
    {
      "title": "Claude Sonnet",
      "provider": "anthropic",
      "model": "claude-sonnet-4-5",
      "apiKey": "sk-ant-..."
    }
  ],
  "experimental": {
    "modelContextProtocolServers": [
      {
        "transport": {
          "type": "stdio",
          "command": "npx",
          "args": ["-y", "@modelcontextprotocol/server-github"],
          "env": {
            "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_..."
          }
        }
      },
      {
        "transport": {
          "type": "stdio",
          "command": "node",
          "args": ["/home/dev/tools/catalog-mcp-server/dist/index.js"],
          "env": {
            "CATALOG_API_URL": "https://catalog.interno.empresa.com",
            "CATALOG_API_KEY": "sua-chave"
          }
        }
      }
    ]
  }
}

Windsurf

// ~/.codeium/windsurf/mcp_settings.json
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_..."
      }
    }
  }
}

9.9 Padrões de Uso Avançado

MCP + Claude Code Headless

# Script que usa MCP server para buscar dados e gerar relatório
export ANTHROPIC_API_KEY="sk-ant-..."

claude --headless \
  --no-color \
  --max-turns 10 \
  -p "Use o servidor MCP do PostgreSQL para analisar as queries
      mais lentas do último dia (tabela slow_query_log) e gere
      um relatório com as top 10 queries para otimizar." \
  2>/dev/null > relatorio-queries-lentas.md

echo "Relatório salvo em relatorio-queries-lentas.md"

MCP em Agente Programático

import { claude } from '@anthropic-ai/claude-code';

// O Agent SDK respeita os MCP servers configurados no settings.json
// mas você pode especificar configuração adicional:
const result = await claude({
  prompt: `Verifique se há issues abertos com a label 'bug' no repositório.
           Para cada bug, verifique se existe código relacionado ao erro
           no projeto. Gere um relatório de bugs e código afetado.`,
  cwd: '/home/dev/meu-projeto',
  model: 'claude-sonnet-4-5',
  maxTurns: 30,
  // As tools do MCP ficam disponíveis automaticamente
  // se configuradas no settings.json
});

Criando MCP Server com Autenticação OAuth

Para MCP servers que precisam de OAuth (como integrações com Google, Salesforce, etc.):

// src/oauth-mcp-server.ts
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

// Carregar tokens salvos (após fluxo OAuth inicial)
const getAccessToken = (): string => {
  const token = process.env.OAUTH_ACCESS_TOKEN;
  if (!token) {
    throw new Error(
      'Execute: node scripts/oauth-setup.js para autenticar'
    );
  }
  return token;
};

const server = new Server(
  { name: 'oauth-service', version: '1.0.0' },
  { capabilities: { tools: {} } }
);

// Tools que usam o token OAuth
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const token = getAccessToken();
  // usar token nas chamadas de API...
});

Resumo de bolso

  • MCP é um protocolo aberto que padroniza a comunicação entre hosts de IA (Claude Code, Cursor) e ferramentas externas (GitHub, banco de dados, APIs)
  • Três tipos de capability: Tools (ações), Resources (dados) e Prompts (templates) — cada um com caso de uso diferente
  • Servers oficiais cobrem os casos mais comuns: filesystem, git, browser, postgres, slack, github, sentry
  • Para APIs internas, crie seu próprio MCP server com @modelcontextprotocol/sdk — o exemplo do catálogo é um template reaproveitável
  • A configuração é uniforme em settings.json para Claude Code, mcp.json para Cursor e config.json para Continue.dev; o mesmo server funciona em todos

Capítulo 10: Cursor, Windsurf e GitHub Copilot

O ecossistema de editores e extensões com IA evoluiu rapidamente. Não existe mais "o melhor para tudo" — cada ferramenta tem um ponto forte, e profissionais seniores aprendem a combiná-las. Este capítulo cobre as três principais opções do mercado com profundidade suficiente para você tomar decisões técnicas informadas.


Cursor: O Editor com IA Nativa

O Cursor é um fork (bifurcação) do VS Code mantido pela Anysphere. Ele herda todo o ecossistema de extensões do VS Code, mas reescreve a camada de IA de forma nativa — não como extensão, mas como parte do editor em si.

A diferença prática: enquanto extensões como o Copilot se comunicam com o editor via APIs públicas limitadas, o Cursor tem acesso direto ao grafo de sintaxe, ao índice do projeto e ao estado do editor. Isso permite funcionalidades que extensões simplesmente não conseguem replicar.

.cursorrules: Definindo o Contexto do Projeto

O arquivo .cursorrules é o equivalente do CLAUDE.md para o Cursor. Ele é injetado automaticamente no contexto de toda conversa iniciada dentro do projeto.

# .cursorrules
# Exemplo completo para projeto React + Fastify
Você é um desenvolvedor sênior trabalhando em um monorepo com:
- Frontend: React 18 + TypeScript + Vite + TailwindCSS
- Backend: Fastify 4 + Prisma + PostgreSQL
- Testes: Vitest (unit), Playwright (e2e)
- Package manager: pnpm workspaces

## Convenções de Código

### TypeScript
- Sempre use tipos explícitos em funções públicas (nunca `any`)
- Prefira `type` a `interface` para objetos simples
- Use `satisfies` para validar objetos literais com tipos
- Enums são proibidos; use `const` objects com `as const`

### React
- Componentes: function components com arrow functions
- Props: sempre desestruture no parâmetro
- Estado global: Zustand (não Redux, não Context para estado global)
- Fetching: TanStack Query (não useEffect para fetching)
- Formulários: React Hook Form + Zod

### Fastify
- Sempre declare schema de input/output nas rotas (validação automática)
- Plugins usam `fastify-plugin` para não encapsular escopo
- Erros: use `fastify.httpErrors` (plugin `@fastify/sensible`)
- Nunca use `req.body` sem validação de schema

### Banco de Dados
- Migrations: sempre via `prisma migrate dev`, nunca manual
- Nunca use `prisma.$queryRaw` sem parametrização
- Transações complexas: use `prisma.$transaction` com array

## Estrutura de Arquivos

src/
├── features/         # Feature-first, não layer-first
│   └── <feature>/
│       ├── components/
│       ├── hooks/
│       ├── api.ts    # React Query hooks
│       └── schema.ts # Zod schemas compartilhados
├── lib/              # Utilitários genéricos
└── server/
    ├── routes/
    ├── plugins/
    └── db/

## Regras de Geração

- Sempre gere testes junto com o código de produção
- Nomes de variáveis: inglês. Comentários: português
- Commits devem seguir Conventional Commits
- Nunca gere `console.log` em código de produção (use o logger do Fastify)

💡 Dica: O .cursorrules suporta até ~8.000 tokens. Use-o para codificar decisões arquiteturais que você não quer repetir em cada prompt. Versione o arquivo junto com o projeto — ele é documentação viva.

Composer: Edição Multi-Arquivo

O Composer (atalho Cmd+Shift+I no Mac, Ctrl+Shift+I no Windows) é onde o Cursor brilha. Diferente do chat tradicional, o Composer pode editar múltiplos arquivos simultaneamente com contexto completo entre eles.

Fluxo típico:

  1. Abra o Composer
  2. Descreva a feature em linguagem natural
  3. O Cursor mostra um diff de todos os arquivos que serão modificados
  4. Você revisa e aplica (ou rejeita arquivo por arquivo)
Exemplo de prompt eficaz no Composer:

"Adicione autenticação JWT ao endpoint POST /api/orders.
Use o plugin @fastify/jwt já instalado.
Middleware de autenticação deve ficar em src/server/plugins/auth.ts.
Rotas protegidas devem usar o decorator `fastify.authenticate`.
Atualize os testes em tests/orders.test.ts para incluir o header Authorization."

O Composer vai criar/modificar: auth.ts, orders.ts (rota), orders.test.ts — tudo de uma vez, com consistência entre os arquivos.

⚠️ Armadilha: O Composer tem um limite de contexto. Em projetos grandes, arquivos que não estão abertos ou mencionados via @ podem não ser incluídos. Sempre mencione explicitamente os arquivos críticos usando @-mentions.

Agent Mode: O Cursor Executa

O Agent Mode (Cmd+I) vai além da edição — o Cursor pode executar comandos no terminal, ler outputs e iterar.

Exemplo de sessão no Agent Mode:

Você: "Os testes de integração estão falhando. Descubra o motivo e corrija."

Cursor Agent:
→ Executa: pnpm test --reporter=verbose
→ Lê o output de erro
→ Identifica: "PrismaClientKnownRequestError: Foreign key constraint failed"
→ Examina a migration pendente
→ Edita o arquivo de seed de testes
→ Executa os testes novamente
→ Confirma: "Testes passando. O problema era um registro orphan no seed."

🔧 Na prática: Use o Agent Mode para tarefas de diagnóstico, refatorações que envolvem build/test, e qualquer fluxo onde você precisaria alternar entre editor e terminal várias vezes.

@-mentions: Dando Contexto Preciso

Mention O que faz
@file src/routes/orders.ts Inclui arquivo específico no contexto
@folder src/features/auth Inclui pasta inteira
@web https://docs.fastify.io Lê página web e inclui como contexto
@docs Acessa documentação indexada pelo Cursor
@git Inclui diff do git no contexto
@codebase Busca semântica em todo o projeto
Exemplo de prompt com @-mentions:

"Veja @file src/features/payments/api.ts e @web https://docs.stripe.com/api/payment_intents/create.
Atualize o tipo `CreatePaymentDTO` para incluir os campos obrigatórios da Stripe que estamos usando."

Modelos Disponíveis no Cursor

O Cursor permite selecionar o modelo por conversa:

Modelo Melhor para
claude-3-5-sonnet Edições complexas, arquitetura
claude-3-5-haiku Completions rápidas, perguntas simples
gpt-4o Alternativa geral, multimodal
o1-mini Raciocínio passo a passo
Modelo customizado Ollama local, APIs privadas

💡 Dica: Configure um modelo "rápido" para completions e um modelo "poderoso" para o Composer nas configurações do Cursor. Isso equilibra custo e qualidade.


Windsurf: Cascade e o Contexto Global

O Windsurf (anteriormente Codeium) é um editor similar ao Cursor, mas com uma filosofia diferente. Seu diferencial é o Cascade, um sistema de IA que tenta entender o projeto inteiro antes de agir.

Cascade: Entendendo Impacto de Mudanças

Enquanto o Cursor trabalha com o que você dá explicitamente via @-mentions, o Cascade analisa proativamente as dependências do projeto.

Exemplo do diferencial do Cascade:

Você: "Renomeie o campo `userId` para `accountId` no modelo User."

Cascade:
→ Analisa schema do Prisma
→ Identifica: 14 arquivos referenciam `userId`
→ Mapeia: 3 são testes, 2 são migrations, 9 são código de produção
→ Atualiza todos de forma consistente
→ Alerta: "A migration existente não pode ser alterada. Criei uma nova migration de renomeação."

O Cursor também faz isso com @codebase, mas o Cascade é mais agressivo em buscar dependências automaticamente.

Quando Escolher Windsurf vs Cursor

Critério Windsurf Cursor
Refatorações grandes (renomear, mover) ✅ Melhor ⚠️ Requer @mentions
Entender impacto de mudanças ✅ Melhor ⚠️ Manual
Customização de modelos ⚠️ Limitada ✅ Melhor
.cursorrules equivalente ⚠️ Menos maduro ✅ Melhor
Velocidade de completions ✅ Muito rápido ✅ Rápido
Plano gratuito ✅ Generoso ⚠️ Limitado
Controle granular de contexto ⚠️ Automático ✅ Explícito

🔧 Na prática: Se você tem um projeto legacy com muitas dependências implícitas e precisa fazer refatorações seguras, o Windsurf tende a errar menos. Se você quer controle total do contexto e um ecossistema mais maduro de regras, prefira o Cursor.


GitHub Copilot: O Autocomplete Mais Maduro

O GitHub Copilot existe desde 2021 e é o mais maduro em termos de completions inline. Seu modelo de linguagem foi treinado com dados do GitHub, o que dá a ele vantagem em código que segue padrões comuns de repositórios públicos.

Completions Inline: O Melhor do Mercado

O autocomplete do Copilot é consensualmente o mais fluido do mercado. Ele completa linha a linha, mas também sugere blocos inteiros com base no nome da função e comentários acima.

// Exemplo: você escreve apenas o comentário e o nome da função
// Valida se um CPF brasileiro é válido
function validateCPF(cpf: string): boolean {
  // Copilot completa todo o bloco abaixo automaticamente
  const cleaned = cpf.replace(/\D/g, '');
  if (cleaned.length !== 11) return false;
  if (/^(\d)\1+$/.test(cleaned)) return false;

  const calcDigit = (slice: string, factor: number) =>
    slice.split('').reduce((sum, digit, i) =>
      sum + parseInt(digit) * (factor - i), 0);

  const remainder = (sum: number) => {
    const r = (sum * 10) % 11;
    return r >= 10 ? 0 : r;
  };

  const d1 = remainder(calcDigit(cleaned.slice(0, 9), 10));
  const d2 = remainder(calcDigit(cleaned.slice(0, 10), 11));

  return d1 === parseInt(cleaned[9]) && d2 === parseInt(cleaned[10]);
}

Copilot Chat e Workspace Agent

O Copilot Chat no VS Code tem acesso ao workspace completo via o Workspace Agent (@workspace):

Exemplos de prompts no Copilot Chat:

"@workspace Onde está a lógica de autenticação?"
→ Copilot busca no índice do workspace e aponta os arquivos

"@workspace Explique como o fluxo de pagamento funciona de ponta a ponta"
→ Copilot rastreia o fluxo entre arquivos e explica

"/fix Esse código tem um race condition?"
→ Analisa o arquivo aberto e sugere correção

Copilot CLI: IA no Terminal

# Instalar
npm install -g @githubnext/github-copilot-cli

# Explicar um comando
gh copilot explain "git rebase -i HEAD~3"

# Sugerir comando para uma tarefa
gh copilot suggest "encontrar todos os arquivos .ts maiores que 1MB modificados na última semana"

# Output:
# find . -name "*.ts" -size +1M -mtime -7

💡 Dica: O gh copilot suggest é especialmente útil para comandos de shell complexos (awk, sed, jq) que você não usa com frequência suficiente para memorizar a sintaxe.


Tabela Comparativa: Cursor × Windsurf × Copilot

Feature Cursor Windsurf GitHub Copilot
Completions inline ✅ Bom ✅ Bom ✅✅ Melhor
Edição multi-arquivo ✅✅ Composer ✅ Cascade ⚠️ Limitado
Entendimento de dependências ⚠️ Manual ✅✅ Automático ⚠️ Manual
Regras de projeto ✅✅ .cursorrules ⚠️ Básico ⚠️ Básico
Escolha de modelo ✅✅ Múltiplos ⚠️ Limitado ⚠️ GPT-4o
Agent mode ✅ Bom ✅ Bom ⚠️ Beta
CLI integrada ⚠️ Não ⚠️ Não gh copilot
Integração GitHub ⚠️ Básica ⚠️ Básica ✅✅ Nativa
Preço/mês $20 Pro $15 Pro $10 Individual
Plano gratuito Limitado Generoso Gratuito para OSS
Privacidade (Enterprise)

Usando em Conjunto: O Workflow Combinado

Profissionais seniores não escolhem apenas uma ferramenta — eles combinam os pontos fortes de cada uma.

Workflow típico de uma feature nova:

1. PLANEJAMENTO (Claude Code no terminal)
   claude "Analise o projeto e proponha a arquitetura para o módulo de notificações.
           Considere o padrão atual em src/features/"

2. IMPLEMENTAÇÃO (Cursor Composer)
   → Abre o Composer com o plano gerado
   → Usa @folder src/features/payments como referência de padrão
   → Gera os arquivos da feature

3. COMPLETIONS RÁPIDAS (Copilot inline)
   → Durante a edição de detalhes, deixa o Copilot completar
   → Mais rápido que abrir o chat para cada linha

4. REFATORAÇÃO DE IMPACTO (Windsurf Cascade)
   → Quando precisa renomear/mover com segurança
   → Cascade garante que nada quebra

5. REVISÃO E TESTES (Claude Code)
   claude "Revise o código em src/features/notifications/
           e sugira melhorias de segurança e performance"

🔧 Na prática: Mantenha o Cursor como editor principal (com .cursorrules bem configurado), o Copilot ativo para completions inline, e o Claude Code no terminal para tarefas que exigem mais raciocínio ou que envolvem todo o repositório. O Windsurf entra quando você precisa de refatorações grandes e seguras.

Exemplo de Workflow Combinado no Dia a Dia

# Manhã: chegou uma issue de bug crítico

# 1. Use Claude Code para diagnóstico rápido
claude "Leia os últimos 50 erros em logs/error.log e identifique o padrão"

# 2. Abra o Cursor, use @git para ver o que mudou
# Prompt no Composer:
# "Veja @git (últimos 3 commits) e @file src/services/payment.ts
#  O bug de timeout em pagamentos começou após qual mudança?"

# 3. Cursor encontra a mudança, você pede o fix
# "Corrija o problema e adicione um teste que reproduz o bug antes do fix"

# 4. Copilot preenche os detalhes do teste enquanto você refina

# 5. Claude Code valida
claude "Revise o fix em src/services/payment.ts. 
       O teste cobre edge cases suficientes?"

Resumo de bolso

  • Cursor é o melhor editor all-around com IA: use .cursorrules para codificar convenções do projeto e o Composer para edições multi-arquivo
  • Windsurf brilha em refatorações de impacto amplo, pois o Cascade mapeia dependências automaticamente
  • GitHub Copilot tem as melhores completions inline e integração nativa com o ecossistema GitHub
  • A combinação Cursor (editor) + Copilot (completions) + Claude Code (terminal) cobre praticamente todos os cenários de desenvolvimento
  • Invista tempo no .cursorrules — é documentação que também pilota a IA

Capítulo 11: Aider e Continue.dev (Open-Source)

Ferramentas proprietárias são convenientes, mas há cenários onde open-source não é opcional: dados sensíveis, compliance, redes isoladas (air-gapped), ou simplesmente controle total sobre o que vai para onde. Este capítulo cobre as duas principais opções open-source com profundidade de produção.


Aider: Pair Programming em CLI

O Aider é uma ferramenta de linha de comando para pair programming com IA. Diferente dos editores com IA, o Aider roda no terminal e usa qualquer editor que você já tenha. Ele lê e edita arquivos diretamente no filesystem, faz commits automáticos e entende a estrutura do projeto via um mapa de repositório.

Instalação e Setup

# Instalar via pip (recomendado: em virtualenv ou pipx)
pip install aider-chat

# Ou via pipx (isolado do sistema)
pipx install aider-chat

# Verificar instalação
aider --version

# Iniciar com Claude (recomendado)
export ANTHROPIC_API_KEY="sk-ant-..."
aider --model claude-3-5-sonnet-20241022

# Iniciar com GPT-4
export OPENAI_API_KEY="sk-..."
aider --model gpt-4o

# Iniciar com modelo local via Ollama
aider --model ollama/codellama:13b

Architect Mode: Planejar com Modelo Forte, Editar com Modelo Rápido

O Architect mode é uma das features mais inteligentes do Aider. Você usa um modelo poderoso (como Claude 3.5 Sonnet) para planejar e um modelo rápido e barato para executar as edições.

# Architect mode: Sonnet planeja, Haiku edita
aider --architect \
  --model claude-3-5-sonnet-20241022 \
  --editor-model claude-3-5-haiku-20241022

# Alternativa: Sonnet planeja, GPT-4o-mini edita
aider --architect \
  --model claude-3-5-sonnet-20241022 \
  --editor-model gpt-4o-mini

O fluxo interno:

  1. Você descreve a task
  2. O modelo "arquiteto" analisa e produz um plano de alto nível com instruções precisas de edição
  3. O modelo "editor" recebe o plano e faz as edições reais nos arquivos
  4. O resultado é revisado pelo arquiteto antes de ser aplicado

Isso reduz custo em até 60% mantendo a qualidade de planejamento.

💡 Dica: Use Architect mode para features que envolvem múltiplos arquivos. Para edições simples em um arquivo, o modo padrão é mais rápido.

/commands: O Vocabulário do Aider

O Aider tem um conjunto rico de comandos para controlar a sessão:

# Gerenciamento de contexto
/add src/routes/orders.ts          # Adiciona arquivo ao contexto
/add src/features/auth/            # Adiciona pasta inteira
/drop src/old-file.ts              # Remove do contexto
/ls                                # Lista arquivos no contexto atual

# Inspeção e controle
/diff                              # Mostra diff de todas as mudanças na sessão
/undo                              # Desfaz o último commit do Aider
/commit                            # Faz commit manual com mensagem gerada por IA

# Execução
/run pnpm test                     # Executa comando e inclui output no contexto
/test                              # Executa o comando de teste configurado

# Informação
/ask Como funciona o fluxo de auth?  # Pergunta sem editar arquivos
/ask @src/auth.ts O que esse middleware faz?

# Controle do modelo
/model claude-3-5-sonnet-20241022  # Troca de modelo na sessão
/models                            # Lista modelos disponíveis

⚠️ Armadilha: Adicionar arquivos demais ao contexto (/add) degrada a qualidade. O Aider já tem o repo map para entender a estrutura — adicione ao contexto apenas os arquivos que serão editados, não todos os relacionados.

Repo Map: Como o Aider Entende o Projeto

O Repo Map é uma das tecnologias centrais do Aider. Em vez de carregar o projeto inteiro no contexto (impossível para projetos grandes), o Aider usa ctags e análise estática para criar um mapa comprimido de todo o repositório.

O mapa inclui:

  • Assinaturas de todas as funções e classes
  • Relacionamentos de importação entre módulos
  • Nomes de variáveis e constantes exportadas
Exemplo de repo map gerado pelo Aider:

src/routes/orders.ts:
  createOrder(req, reply)
  updateOrder(req, reply)
  deleteOrder(req, reply)

src/services/payment.ts:
  PaymentService
    processPayment(amount, currency, customerId): Promise<PaymentResult>
    refund(paymentId): Promise<void>

src/models/order.ts:
  Order { id, customerId, items, total, status }
  OrderStatus: 'pending' | 'paid' | 'cancelled'

O modelo recebe esse mapa junto com o contexto dos arquivos adicionados via /add, o que permite que ele entenda dependências sem precisar ler cada arquivo inteiro.

Exemplo Completo: Uma Feature com Aider

# Iniciando uma sessão
$ aider --architect --model claude-3-5-sonnet-20241022 --editor-model claude-3-5-haiku-20241022

# Aider mostra o repo map e aguarda
# ─────────────────────────────────────────────────────────
# Adicionando os arquivos relevantes ao contexto
/add src/routes/orders.ts
/add src/services/orders.ts

# Descrevendo a feature
> Adicione paginação ao endpoint GET /api/orders.
  Parâmetros: page (default 1) e limit (default 20, máximo 100).
  Retorne também totalCount e totalPages na resposta.
  Use o padrão de paginação já existente em src/routes/products.ts como referência.

# Aider lê products.ts via repo map, planeja e edita
# [Architect]: Analisando padrão em products.ts...
# [Editor]: Modificando orders.ts...

# Verificando as mudanças
/diff

# Rodando os testes
/run pnpm test src/routes/orders.test.ts

# Se passou, commitar
/commit

# Resultado: commit automático com mensagem "feat: add pagination to GET /api/orders"

🔧 Na prática: O /run é poderoso porque o output do comando vai direto para o contexto do modelo. Se os testes falharem, você pode pedir /ask Por que o teste falhou? e o Aider já tem o output do erro disponível.

Configuração ~/.aider.conf.yml

# ~/.aider.conf.yml
# Configurações globais do Aider

# Modelo padrão
model: claude-3-5-sonnet-20241022

# Architect mode habilitado por padrão
architect: true
editor-model: claude-3-5-haiku-20241022

# Commits automáticos após cada edição
auto-commits: true

# Mensagens de commit em português
commit-prompt: |
  Gere uma mensagem de commit no formato Conventional Commits em português.
  Tipos: feat, fix, refactor, test, docs, chore
  Exemplo: "feat: adicionar paginação ao endpoint de pedidos"

# Não perguntar confirmação para edições
yes: false  # manter false para revisão manual

# Mostrar diff antes de aplicar
show-diffs: true

# Formato de output
pretty: true
stream: true

# Lint automático após edições
lint-cmd: pnpm eslint --fix

# Teste automático após commits
test-cmd: pnpm test --run

# Ignorar arquivos (além do .gitignore)
read: .aiderignore
# .aiderignore
# Arquivos que o Aider não deve editar
*.lock
dist/
build/
node_modules/
.env*
*.min.js
coverage/

Modelos Suportados

# Anthropic (recomendado para qualidade)
aider --model claude-3-5-sonnet-20241022

# OpenAI
aider --model gpt-4o
aider --model gpt-4o-mini  # mais barato

# Groq (rápido e gratuito com limites)
export GROQ_API_KEY="..."
aider --model groq/llama-3.1-70b-versatile

# Ollama (100% local, sem custo de API)
# Primeiro: ollama pull codellama:13b
aider --model ollama/codellama:13b
aider --model ollama/deepseek-coder:6.7b

# DeepSeek (muito barato, boa qualidade)
export DEEPSEEK_API_KEY="..."
aider --model deepseek/deepseek-coder

Continue.dev: IA Open-Source dentro do VS Code

O Continue.dev é uma extensão open-source para VS Code e JetBrains que replica as features dos editores com IA (Copilot, Cursor) mas com controle total sobre os modelos e dados.

Instalação e Setup Básico

# No VS Code: instalar a extensão "Continue" da marketplace
# Ou via linha de comando:
code --install-extension Continue.continue

# A configuração fica em:
# ~/.continue/config.json  (global)
# .continue/config.json    (por projeto, tem precedência)

config.json Completo

{
  "models": [
    {
      "title": "Claude 3.5 Sonnet",
      "provider": "anthropic",
      "model": "claude-3-5-sonnet-20241022",
      "apiKey": "$ANTHROPIC_API_KEY",
      "contextLength": 200000,
      "completionOptions": {
        "temperature": 0.1,
        "maxTokens": 8192
      }
    },
    {
      "title": "GPT-4o Mini (rápido)",
      "provider": "openai",
      "model": "gpt-4o-mini",
      "apiKey": "$OPENAI_API_KEY"
    },
    {
      "title": "Llama 3.1 Local (Ollama)",
      "provider": "ollama",
      "model": "llama3.1:8b",
      "apiBase": "http://localhost:11434"
    },
    {
      "title": "DeepSeek Coder Local",
      "provider": "ollama",
      "model": "deepseek-coder:6.7b",
      "apiBase": "http://localhost:11434"
    }
  ],
  "tabAutocompleteModel": {
    "title": "Autocomplete Local",
    "provider": "ollama",
    "model": "starcoder2:3b",
    "apiBase": "http://localhost:11434"
  },
  "embeddingsProvider": {
    "provider": "ollama",
    "model": "nomic-embed-text",
    "apiBase": "http://localhost:11434"
  },
  "contextProviders": [
    {
      "name": "code",
      "params": {}
    },
    {
      "name": "docs",
      "params": {}
    },
    {
      "name": "diff",
      "params": {}
    },
    {
      "name": "folder",
      "params": {}
    },
    {
      "name": "search",
      "params": {}
    },
    {
      "name": "url",
      "params": {}
    },
    {
      "name": "problems",
      "params": {}
    }
  ],
  "slashCommands": [
    {
      "name": "edit",
      "description": "Editar código selecionado"
    },
    {
      "name": "comment",
      "description": "Adicionar comentários ao código"
    },
    {
      "name": "share",
      "description": "Exportar conversa"
    },
    {
      "name": "cmd",
      "description": "Gerar comando de terminal"
    },
    {
      "name": "commit",
      "description": "Gerar mensagem de commit"
    }
  ],
  "customCommands": [
    {
      "name": "review",
      "prompt": "Revise este código considerando: segurança, performance, legibilidade e cobertura de casos extremos. Use português.",
      "description": "Code review completo"
    },
    {
      "name": "test",
      "prompt": "Gere testes unitários completos para este código usando Vitest. Inclua casos felizes e edge cases.",
      "description": "Gerar testes unitários"
    },
    {
      "name": "doc",
      "prompt": "Documente esta função com JSDoc em português, incluindo parâmetros, retorno e exemplos de uso.",
      "description": "Documentar com JSDoc"
    }
  ],
  "allowAnonymousTelemetry": false
}

Autocomplete com Modelos Locais

O Continue.dev suporta completions inline com modelos locais via Ollama, eliminando qualquer envio de código para servidores externos:

# Instalar Ollama
curl -fsSL https://ollama.ai/install.sh | sh

# Modelos recomendados para autocomplete (pequenos e rápidos)
ollama pull starcoder2:3b       # 1.7GB, ótimo para completions
ollama pull deepseek-coder:1.3b # 776MB, mais leve ainda
ollama pull codellama:7b        # 3.8GB, melhor qualidade

# Para embeddings (busca semântica no codebase)
ollama pull nomic-embed-text    # 274MB, essencial

⚠️ Armadilha: Modelos muito grandes (>13B parâmetros) para autocomplete tornam a experiência lenta demais. Para completions inline, priorize velocidade: modelos de 1B a 7B são o ponto ideal.

@-mentions no Continue.dev

No chat do Continue.dev:

@file src/services/auth.ts          → inclui o arquivo
@folder src/features/               → inclui pasta
@code UserService.authenticate      → busca símbolo no código
@docs https://fastify.dev           → indexa documentação externa
@diff                               → diff atual do git
@problems                           → erros do painel Problems do VS Code
@url https://api.example.com/spec   → lê URL e inclui

Vantagens do Open-Source: O Que Você Ganha

Critério Open-Source (Aider/Continue) Closed-Source (Cursor/Copilot)
Privacidade de código ✅ Total (com Ollama) ⚠️ Envia para servidores
Compliance (LGPD, HIPAA) ✅ Controlável ⚠️ Depende do plano
Air-gapped networks ✅ Funciona offline ❌ Requer internet
Custo de API ✅ Zero com modelos locais ⚠️ Plano mensal obrigatório
Customização ✅ Ilimitada ⚠️ Limitada
Vendor lock-in ✅ Sem lock-in ⚠️ Dependente do fornecedor
Qualidade com modelos cloud ✅ Igual (mesma API) ✅ Igual
Qualidade offline ⚠️ Menor que cloud N/A
UX/polish ⚠️ Mais bruto ✅ Mais polido
Setup inicial ⚠️ Mais trabalhoso ✅ Plug-and-play

Quando Preferir Open-Source

✅ Use Aider/Continue quando:

1. DADOS SENSÍVEIS
   → PII, código de sistema financeiro, saúde, governo
   → Qualquer código que não pode sair da rede corporativa

2. AIR-GAPPED
   → Redes sem acesso à internet
   → Desenvolvimento em ambientes de segurança máxima

3. COMPLIANCE REGULATÓRIO
   → LGPD: dados pessoais não podem ir para terceiros
   → HIPAA: dados de saúde
   → PCI DSS: dados de cartão de crédito

4. ORÇAMENTO LIMITADO
   → Com Ollama local: custo zero de API
   → Projetos open-source sem budget para ferramentas

5. EXPERIMENTAÇÃO DE MODELOS
   → Testar modelos novos (DeepSeek, Qwen, Mistral) antes de adotar
   → Fine-tuning de modelos para domínio específico

🔧 Na prática: Em projetos corporativos, considere uma estratégia híbrida: Continue.dev com Ollama para código do produto (fica na máquina local), e Cursor/Copilot para código de ferramentas internas sem dados sensíveis.

Resumo de bolso

  • Aider é o melhor CLI open-source para pair programming: Architect mode, repo map e /commands são diferenciais de produção real
  • Continue.dev replica a experiência do Cursor/Copilot dentro do VS Code com controle total sobre modelos e dados
  • Modelos locais via Ollama eliminam completamente o custo de API e o envio de código para servidores externos
  • Open-source é a escolha técnica correta para dados sensíveis, compliance e ambientes air-gapped — não apenas uma questão ideológica
  • O arquivo ~/.aider.conf.yml e .continue/config.json merecem tanto cuidado quanto o .cursorrules

Capítulo 12: APIs de LLM para Automação Custom

Usar IA via editor é ótimo para desenvolvimento interativo, mas a automação real — pipelines de CI, scripts de manutenção, geração de documentação em lote — exige integração direta com as APIs. Este capítulo cobre os SDKs com exemplos prontos para produção.


Anthropic SDK (TypeScript)

Instalação e Setup

npm install @anthropic-ai/sdk
# ou
pnpm add @anthropic-ai/sdk
// src/lib/anthropic.ts
import Anthropic from '@anthropic-ai/sdk';

export const anthropic = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY, // default: process.env.ANTHROPIC_API_KEY
  maxRetries: 3,
  timeout: 60_000, // 60 segundos
});

Messages API: Exemplo Completo

// src/scripts/review-code.ts
import Anthropic from '@anthropic-ai/sdk';
import { readFileSync } from 'fs';

const anthropic = new Anthropic();

async function reviewCode(filePath: string): Promise<string> {
  const code = readFileSync(filePath, 'utf-8');

  const message = await anthropic.messages.create({
    model: 'claude-3-5-sonnet-20241022',
    max_tokens: 2048,
    system: `Você é um revisor de código sênior especializado em TypeScript e Node.js.
Analise o código e forneça feedback em português sobre:
1. Bugs potenciais e edge cases
2. Problemas de segurança
3. Performance
4. Legibilidade e manutenibilidade
Seja específico e cite linhas quando relevante.`,
    messages: [
      {
        role: 'user',
        content: `Revise este código:\n\n\`\`\`typescript\n${code}\n\`\`\``,
      },
    ],
  });

  const content = message.content[0];
  if (content.type !== 'text') throw new Error('Resposta inesperada');

  return content.text;
}

// Uso
const review = await reviewCode('./src/services/payment.ts');
console.log(review);

Tool Use: Exemplo Completo

O (Tool Use) é o mecanismo pelo qual o modelo chama funções que você define:

// src/scripts/analyze-repo.ts
import Anthropic from '@anthropic-ai/sdk';
import { execSync } from 'child_process';
import { readFileSync, existsSync } from 'fs';

const anthropic = new Anthropic();

// Definição das tools disponíveis para o modelo
const tools: Anthropic.Tool[] = [
  {
    name: 'run_command',
    description: 'Executa um comando shell e retorna o output',
    input_schema: {
      type: 'object',
      properties: {
        command: {
          type: 'string',
          description: 'Comando a executar (ex: git log, ls, cat)',
        },
      },
      required: ['command'],
    },
  },
  {
    name: 'read_file',
    description: 'Lê o conteúdo de um arquivo',
    input_schema: {
      type: 'object',
      properties: {
        path: {
          type: 'string',
          description: 'Caminho do arquivo a ler',
        },
      },
      required: ['path'],
    },
  },
];

// Executor das tools
function executeTool(name: string, input: Record<string, string>): string {
  switch (name) {
    case 'run_command': {
      try {
        return execSync(input.command, {
          encoding: 'utf-8',
          timeout: 10_000,
          cwd: process.cwd(),
        });
      } catch (err) {
        return `Erro: ${err instanceof Error ? err.message : String(err)}`;
      }
    }
    case 'read_file': {
      if (!existsSync(input.path)) return `Arquivo não encontrado: ${input.path}`;
      return readFileSync(input.path, 'utf-8');
    }
    default:
      return `Tool desconhecida: ${name}`;
  }
}

// Loop de agentic
async function analyzeRepository(question: string): Promise<string> {
  const messages: Anthropic.MessageParam[] = [
    { role: 'user', content: question },
  ];

  while (true) {
    const response = await anthropic.messages.create({
      model: 'claude-3-5-sonnet-20241022',
      max_tokens: 4096,
      tools,
      messages,
    });

    // Adiciona resposta do assistente ao histórico
    messages.push({ role: 'assistant', content: response.content });

    // Se parou por tool_use, execute as tools
    if (response.stop_reason === 'tool_use') {
      const toolResults: Anthropic.ToolResultBlockParam[] = [];

      for (const block of response.content) {
        if (block.type === 'tool_use') {
          console.log(`Executando tool: ${block.name}`, block.input);
          const result = executeTool(block.name, block.input as Record<string, string>);
          toolResults.push({
            type: 'tool_result',
            tool_use_id: block.id,
            content: result,
          });
        }
      }

      // Adiciona resultados ao histórico e continua
      messages.push({ role: 'user', content: toolResults });
      continue;
    }

    // Se parou por end_turn, retorna a resposta final
    if (response.stop_reason === 'end_turn') {
      const textBlock = response.content.find(b => b.type === 'text');
      return textBlock?.type === 'text' ? textBlock.text : '';
    }

    break;
  }

  return '';
}

// Uso
const analysis = await analyzeRepository(
  'Analise este repositório: quais são os principais módulos, ' +
  'qual a cobertura de testes atual, e há algum arquivo sem testes?'
);
console.log(analysis);

Prompt Caching: Economizando em System Prompts Grandes

O (Prompt Caching) é essencial quando você tem um system prompt longo (documentação, regras de projeto) que se repete em muitas chamadas:

// src/lib/cached-client.ts
import Anthropic from '@anthropic-ai/sdk';
import { readFileSync } from 'fs';

const anthropic = new Anthropic();

// System prompt grande que será cacheado
const projectContext = readFileSync('./docs/architecture.md', 'utf-8');
const codeConventions = readFileSync('./docs/conventions.md', 'utf-8');

async function askWithCache(question: string): Promise<string> {
  const response = await anthropic.messages.create({
    model: 'claude-3-5-sonnet-20241022',
    max_tokens: 2048,
    system: [
      {
        type: 'text',
        text: `# Contexto do Projeto\n${projectContext}\n\n# Convenções\n${codeConventions}`,
        // Este bloco será cacheado após a primeira chamada
        cache_control: { type: 'ephemeral' },
      },
    ],
    messages: [{ role: 'user', content: question }],
  });

  // Inspecionar uso de cache no response
  const usage = response.usage as Anthropic.Usage & {
    cache_creation_input_tokens?: number;
    cache_read_input_tokens?: number;
  };

  console.log({
    inputTokens: usage.input_tokens,
    cacheCreation: usage.cache_creation_input_tokens ?? 0,  // primeira vez
    cacheRead: usage.cache_read_input_tokens ?? 0,          // chamadas subsequentes
    outputTokens: usage.output_tokens,
  });

  const content = response.content[0];
  return content.type === 'text' ? content.text : '';
}

// Primeira chamada: cria o cache (custo 1.25x)
// Chamadas seguintes: lê do cache (custo 0.1x = 90% de economia)

💡 Dica: O cache tem duração de 5 minutos e é invalidado se o conteúdo mudar. Para system prompts estáticos (documentação, regras), a economia é imediata a partir da segunda chamada na mesma sessão.

Batch API: 50% de Desconto para Processamento em Lote

// src/scripts/batch-review.ts
import Anthropic from '@anthropic-ai/sdk';
import { readdirSync, readFileSync } from 'fs';
import path from 'path';

const anthropic = new Anthropic();

async function batchReviewFiles(directory: string) {
  // Pega todos os arquivos .ts do diretório
  const files = readdirSync(directory)
    .filter(f => f.endsWith('.ts') && !f.endsWith('.test.ts'))
    .map(f => path.join(directory, f));

  // Cria requests em batch
  const requests: Anthropic.Batch.Request[] = files.map((filePath, index) => ({
    custom_id: `review-${index}-${path.basename(filePath)}`,
    params: {
      model: 'claude-3-5-haiku-20241022', // modelo mais barato para volume
      max_tokens: 1024,
      messages: [
        {
          role: 'user' as const,
          content: `Revise brevemente este arquivo TypeScript. Aponte apenas issues críticos:\n\n${readFileSync(filePath, 'utf-8')}`,
        },
      ],
    },
  }));

  console.log(`Enviando batch com ${requests.length} requests...`);

  // Submete o batch
  const batch = await anthropic.batches.create({ requests });
  console.log(`Batch criado: ${batch.id}`);
  console.log('Aguardando processamento (pode levar minutos a horas)...');

  // Poll até completar
  let currentBatch = batch;
  while (currentBatch.processing_status === 'in_progress') {
    await new Promise(resolve => setTimeout(resolve, 30_000)); // poll a cada 30s
    currentBatch = await anthropic.batches.retrieve(batch.id);
    console.log(`Status: ${currentBatch.processing_status} | ` +
      `Sucesso: ${currentBatch.request_counts.succeeded} | ` +
      `Erro: ${currentBatch.request_counts.errored}`);
  }

  // Processar resultados
  for await (const result of await anthropic.batches.results(batch.id)) {
    if (result.result.type === 'succeeded') {
      const content = result.result.message.content[0];
      if (content.type === 'text') {
        console.log(`\n=== ${result.custom_id} ===\n${content.text}`);
      }
    }
  }
}

await batchReviewFiles('./src/services');

Anthropic SDK (Python)

pip install anthropic

Script Completo: Changelog a partir do Git Log

#!/usr/bin/env python3
# scripts/generate_changelog.py

import subprocess
import sys
from datetime import datetime
import anthropic


def get_git_log(since: str = "1 week ago") -> str:
    """Obtém o git log formatado desde uma data."""
    result = subprocess.run(
        [
            "git", "log",
            f"--since={since}",
            "--pretty=format:%H|%an|%ae|%ad|%s|%b",
            "--date=short",
            "--no-merges",
        ],
        capture_output=True,
        text=True,
        check=True,
    )
    return result.stdout


def get_diff_stats(since: str = "1 week ago") -> str:
    """Obtém estatísticas de arquivos alterados."""
    result = subprocess.run(
        ["git", "diff", f"HEAD@{{1 week ago}}", "--stat"],
        capture_output=True,
        text=True,
    )
    return result.stdout


def generate_changelog(since: str = "1 week ago") -> str:
    client = anthropic.Anthropic()

    git_log = get_git_log(since)
    diff_stats = get_diff_stats(since)

    if not git_log.strip():
        return "Nenhum commit encontrado no período especificado."

    prompt = f"""Baseado no seguinte git log, gere um CHANGELOG profissional em português.

GIT LOG (formato: hash|autor|email|data|assunto|corpo):
{git_log}

ARQUIVOS ALTERADOS:
{diff_stats}

Formate o changelog assim:
## [Unreleased] - {datetime.now().strftime('%Y-%m-%d')}

### Novas Funcionalidades
- Item

### Correções de Bugs  
- Item

### Melhorias
- Item

### Mudanças Técnicas
- Item

Regras:
- Agrupe commits relacionados
- Use linguagem clara para usuários finais (não técnica demais)
- Ignore commits de merge e chore triviais
- Se um commit menciona um ticket (ex: GVR-123), inclua entre colchetes
"""

    message = client.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=2048,
        system="Você é um especialista em documentação de software. Gere changelogs claros e úteis.",
        messages=[{"role": "user", "content": prompt}],
    )

    return message.content[0].text


def main():
    since = sys.argv[1] if len(sys.argv) > 1 else "1 week ago"
    print(f"Gerando changelog desde: {since}\n")

    changelog = generate_changelog(since)
    print(changelog)

    # Salvar em arquivo
    output_file = f"CHANGELOG-{datetime.now().strftime('%Y-%m-%d')}.md"
    with open(output_file, "w", encoding="utf-8") as f:
        f.write(changelog)

    print(f"\nChangelog salvo em: {output_file}")


if __name__ == "__main__":
    main()
# Uso
python scripts/generate_changelog.py "2 weeks ago"
python scripts/generate_changelog.py "last monday"

OpenAI SDK: Diferenças Principais

Aspecto Anthropic SDK OpenAI SDK
Formato de system prompt Campo system separado Dentro de messages com role: "system"
Tool calling tools + tool_use blocks tools + function_call
Streaming stream=True, eventos content_block_delta stream=True, eventos delta
Prompt caching cache_control nos content blocks Automático (sem controle explícito)
Batch API anthropic.batches.create() openai.batches.create() (formato diferente)
Max tokens param max_tokens (obrigatório) max_tokens (opcional)
Contagem de tokens anthropic.messages.count_tokens() tiktoken library separada

Padrões de Automação para Devs

Geração de Testes Automatizada

// scripts/generate-tests.ts
import Anthropic from '@anthropic-ai/sdk';
import { readFileSync, writeFileSync, existsSync } from 'fs';

const anthropic = new Anthropic();

async function generateTests(sourceFile: string): Promise<void> {
  const testFile = sourceFile.replace('.ts', '.test.ts');

  if (existsSync(testFile)) {
    console.log(`Testes já existem: ${testFile}`);
    return;
  }

  const sourceCode = readFileSync(sourceFile, 'utf-8');

  const response = await anthropic.messages.create({
    model: 'claude-3-5-sonnet-20241022',
    max_tokens: 4096,
    system: `Você gera testes unitários com Vitest e TypeScript.
Regras:
- Import do Vitest: import { describe, it, expect, vi } from 'vitest'
- Mocks com vi.mock() e vi.fn()
- Teste casos felizes E edge cases E erros
- Nomes de testes em português
- Sem imports desnecessários`,
    messages: [
      {
        role: 'user',
        content: `Gere testes para este arquivo:\n\`\`\`typescript\n${sourceCode}\n\`\`\`\n\nRetorne APENAS o código TypeScript do arquivo de testes, sem explicações.`,
      },
    ],
  });

  const content = response.content[0];
  if (content.type !== 'text') return;

  // Extrai o código do markdown se necessário
  const code = content.text
    .replace(/```typescript\n?/g, '')
    .replace(/```\n?/g, '')
    .trim();

  writeFileSync(testFile, code, 'utf-8');
  console.log(`Testes gerados: ${testFile}`);
}

Documentação Automática

// scripts/document-functions.ts
async function documentFunction(
  code: string,
  functionName: string
): Promise<string> {
  const response = await anthropic.messages.create({
    model: 'claude-3-5-haiku-20241022', // modelo mais barato para task simples
    max_tokens: 512,
    messages: [
      {
        role: 'user',
        content: `Gere JSDoc em português para esta função. Retorne apenas o bloco JSDoc, sem o código.\n\n${code}`,
      },
    ],
  });

  const content = response.content[0];
  return content.type === 'text' ? content.text : '';
}

Custo e Otimização

Tabela de Preços (referência — verificar pricing atual)

Modelo Input ($/1M tokens) Output ($/1M tokens) Cache Read
claude-3-5-sonnet $3.00 $15.00 $0.30
claude-3-5-haiku $0.80 $4.00 $0.08
gpt-4o $2.50 $10.00 Automático
gpt-4o-mini $0.15 $0.60 Automático

Estratégias de Otimização

// 1. Modelo certo para a task certa
const model = taskComplexity === 'high'
  ? 'claude-3-5-sonnet-20241022'  // $3/1M input
  : 'claude-3-5-haiku-20241022';  // $0.80/1M input — 73% mais barato

// 2. Prompt caching para contexto repetitivo
// System prompt de 10k tokens = $0.03 por chamada sem cache
// Com cache: $0.003 por chamada (90% economia)

// 3. Batch API para processamento em lote
// 1000 reviews de código: $X normal → $X/2 com Batch API

// 4. Limitar output tokens
// max_tokens: 256  // para respostas curtas (labels, booleans, etc)
// max_tokens: 2048 // para análises médias
// max_tokens: 8192 // apenas quando realmente necessário

Estimativa de Custo por Task

Task Modelo recomendado Custo estimado/100 execuções
Classificar issue (bug/feature) Haiku ~$0.05
Gerar mensagem de commit Haiku ~$0.10
Review de função (~200 linhas) Sonnet ~$0.80
Gerar testes para módulo Sonnet ~$1.50
Analisar PR completo (~500 linhas) Sonnet + Cache ~$1.20
Gerar documentação de projeto Sonnet + Batch ~$2.00

💡 Dica: Use anthropic.messages.count_tokens() para estimar o custo antes de processar em lote. Evite surpresas com arquivos grandes ou contextos inesperadamente longos.

Resumo de bolso

  • A Anthropic SDK tem Tool Use para automação agentic, Prompt Caching para 90% de economia em contextos repetitivos, e Batch API para 50% de desconto em volume
  • O script de changelog automático é um exemplo direto de automação de valor imediato: conecta git log com Claude via Python
  • Use modelos menores (Haiku, GPT-4o-mini) para tasks simples — a diferença de qualidade é irrelevante para classificação e geração de textos curtos, mas o custo é 5-10x menor
  • Prompt caching é a otimização de maior impacto: qualquer system prompt acima de 1024 tokens que se repete deve usar cache_control
  • A escolha de modelo deve ser parte do design da automação, não uma decisão posterior

Capítulo 13: GitHub Actions + IA

Integrar IA nas Actions do GitHub transforma o CI/CD de um pipeline de verificação passivo em um sistema que ativamente melhora o código. Este capítulo cobre workflows prontos para produção.


Claude Code Headless em Actions

Antes dos exemplos específicos, o setup base que todos os workflows usarão:

# Configuração base reutilizável em todos os exemplos

# 1. No repositório do GitHub:
# Settings → Secrets and variables → Actions → New repository secret
# Nome: ANTHROPIC_API_KEY
# Valor: sk-ant-...

# 2. Instalação do Claude Code no runner Ubuntu
- name: Instalar Claude Code
  run: npm install -g @anthropic-ai/claude-code

# 3. Flags úteis para uso headless
# --headless              → Modo não-interativo (obrigatório em CI)
# --output-format json    → Output estruturado para parsing
# --max-turns 10          → Limite de iterações do agente
# --no-color              → Remove cores ANSI dos logs

# Exemplo de step completo
- name: Analisar código com Claude
  env:
    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
  run: |
    claude --headless \
           --output-format json \
           --max-turns 5 \
           "Analise os arquivos alterados neste PR e identifique problemas" \
    | jq -r '.result'

PR Review Automático com Claude Code

# .github/workflows/ai-pr-review.yml
name: AI PR Review

on:
  pull_request:
    types: [opened, synchronize]
    branches: [main, develop]

permissions:
  contents: read
  pull-requests: write

jobs:
  ai-review:
    name: Revisão com IA
    runs-on: ubuntu-latest
    # Não rodar em PRs de dependabot
    if: github.actor != 'dependabot[bot]'

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0  # histórico completo para diff correto

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Instalar Claude Code
        run: npm install -g @anthropic-ai/claude-code

      - name: Obter diff do PR
        id: diff
        run: |
          # Diff entre a branch base e a branch do PR
          git diff origin/${{ github.base_ref }}...HEAD > /tmp/pr.diff
          echo "diff_size=$(wc -l < /tmp/pr.diff)" >> $GITHUB_OUTPUT

      - name: Revisar PR com Claude
        id: review
        if: steps.diff.outputs.diff_size != '0'
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          DIFF=$(cat /tmp/pr.diff)

          REVIEW=$(claude --headless --output-format json --max-turns 3 \
            "Revise o seguinte diff de um Pull Request.

          TÍTULO DO PR: ${{ github.event.pull_request.title }}
          DESCRIÇÃO: ${{ github.event.pull_request.body }}

          DIFF:
          ${DIFF}

          Forneça uma revisão estruturada em PORTUGUÊS com:
          1. **Resumo das mudanças** (2-3 frases)
          2. **Problemas críticos** (bugs, segurança, race conditions) — se houver
          3. **Sugestões de melhoria** (performance, legibilidade, testes)
          4. **Pontos positivos** — reconheça boas práticas
          5. **Veredicto**: APROVADO, APROVADO COM SUGESTÕES, ou MUDANÇAS NECESSÁRIAS

          Seja construtivo e específico. Cite números de linha quando relevante." \
          | jq -r '.result')

          # Salvar review em arquivo para o próximo step
          echo "$REVIEW" > /tmp/review.md

      - name: Postar comentário no PR
        if: steps.diff.outputs.diff_size != '0'
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const review = fs.readFileSync('/tmp/review.md', 'utf8');

            const body = `## 🤖 Revisão Automática com IA

            ${review}

            ---
            *Gerado por Claude via GitHub Actions. Esta é uma revisão auxiliar — a aprovação humana ainda é necessária.*`;

            // Deletar comentário anterior se existir (evita spam)
            const comments = await github.rest.issues.listComments({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
            });

            const botComment = comments.data.find(c =>
              c.user.type === 'Bot' &&
              c.body.includes('Revisão Automática com IA')
            );

            if (botComment) {
              await github.rest.issues.updateComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                comment_id: botComment.id,
                body,
              });
            } else {
              await github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: context.issue.number,
                body,
              });
            }

💡 Dica: Note o padrão de deletar e recriar o comentário em vez de acumular múltiplos comentários a cada push. Em PRs iterativos, o desenvolvedor quer ver a revisão mais recente, não um histórico de revisões.


Geração de Testes em CI

# .github/workflows/generate-tests.yml
name: Gerar Testes Automaticamente

on:
  pull_request:
    types: [opened, synchronize]

permissions:
  contents: write
  pull-requests: write

jobs:
  generate-tests:
    name: Detectar e Gerar Testes
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          # Token com permissão de push para commitar os testes gerados
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Setup Node.js e dependências
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'pnpm'

      - name: Instalar dependências
        run: pnpm install

      - name: Instalar Claude Code
        run: npm install -g @anthropic-ai/claude-code

      - name: Detectar arquivos sem testes
        id: detect
        run: |
          # Arquivos .ts alterados no PR (exceto testes e configs)
          CHANGED=$(git diff origin/${{ github.base_ref }}...HEAD \
            --name-only \
            --diff-filter=AM \
            | grep '\.ts$' \
            | grep -v '\.test\.ts$' \
            | grep -v '\.spec\.ts$' \
            | grep -v 'd\.ts$' \
            | grep 'src/' \
            | head -10)  # limitar a 10 arquivos por PR

          echo "files<<EOF" >> $GITHUB_OUTPUT
          echo "$CHANGED" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

          COUNT=$(echo "$CHANGED" | grep -c . || echo 0)
          echo "count=$COUNT" >> $GITHUB_OUTPUT

      - name: Gerar testes para arquivos sem cobertura
        if: steps.detect.outputs.count != '0'
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          FILES="${{ steps.detect.outputs.files }}"

          while IFS= read -r file; do
            [ -z "$file" ] && continue

            TEST_FILE="${file%.ts}.test.ts"

            # Pular se o teste já existe
            if [ -f "$TEST_FILE" ]; then
              echo "Teste já existe: $TEST_FILE"
              continue
            fi

            echo "Gerando testes para: $file"

            claude --headless --output-format json --max-turns 2 \
              "Leia o arquivo $file e gere testes unitários completos com Vitest.

            Regras obrigatórias:
            - Import: import { describe, it, expect, vi, beforeEach } from 'vitest'
            - Mocks com vi.mock() para dependências externas
            - Teste casos felizes, edge cases e erros
            - Nomes dos describes e its em português
            - Retorne APENAS o código TypeScript sem blocos markdown
            - Salve o resultado em $TEST_FILE" \
            | jq -r '.result'

          done <<< "$FILES"

      - name: Commitar testes gerados
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"

          # Adicionar apenas arquivos de teste novos
          git add "*.test.ts" 2>/dev/null || true

          if git diff --staged --quiet; then
            echo "Nenhum teste novo gerado"
          else
            git commit -m "test: gerar testes automáticos para arquivos do PR

            Gerado automaticamente por Claude via GitHub Actions.
            Os testes devem ser revisados e ajustados se necessário."

            git push origin HEAD:${{ github.head_ref }}
          fi

⚠️ Armadilha: Testes gerados por IA devem ser tratados como ponto de partida, não como verdade final. Adicione um comentário no workflow informando isso e considere marcar o commit com [generated] para fácil identificação.


Lint Semântico com IA

# .github/workflows/semantic-lint.yml
name: Lint Semântico com IA

on:
  pull_request:
    types: [opened, synchronize]

permissions:
  pull-requests: write

jobs:
  semantic-lint:
    name: Análise Semântica
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Instalar Claude Code
        run: npm install -g @anthropic-ai/claude-code

      - name: Análise semântica com IA
        id: lint
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          DIFF=$(git diff origin/${{ github.base_ref }}...HEAD)

          RESULT=$(claude --headless --output-format json --max-turns 2 \
            "Analise este diff de código TypeScript/JavaScript como um linter semântico avançado.

          DIFF:
          ${DIFF}

          Verifique especificamente:

          **SEGURANÇA**
          - SQL/NoSQL injection (concatenação de strings em queries)
          - XSS (interpolação sem escape em HTML)
          - Exposição de dados sensíveis em logs
          - Credenciais hardcoded

          **PERFORMANCE**
          - N+1 queries (loop com await dentro)
          - Operações síncronas desnecessárias em código async
          - Re-renders desnecessários em React (dependências incorretas no useEffect)
          - Objetos grandes sendo copiados desnecessariamente

          **LÓGICA**
          - Race conditions (múltiplos awaits sem Promise.all quando independentes)
          - Off-by-one errors em arrays e paginação
          - Condições que nunca serão verdadeiras
          - Casos de null/undefined não tratados

          Formato de resposta JSON:
          {
            \"severity\": \"ok\" | \"warning\" | \"error\",
            \"issues\": [
              {
                \"type\": \"security\" | \"performance\" | \"logic\",
                \"severity\": \"warning\" | \"error\",
                \"line\": \"número ou range\",
                \"description\": \"descrição em português\",
                \"suggestion\": \"como corrigir\"
              }
            ],
            \"summary\": \"resumo geral\"
          }

          Retorne APENAS o JSON, sem markdown." \
          | jq -r '.result')

          echo "$RESULT" > /tmp/lint-result.json

          # Determinar se há erros críticos
          SEVERITY=$(echo "$RESULT" | jq -r '.severity')
          echo "severity=$SEVERITY" >> $GITHUB_OUTPUT

      - name: Postar resultado no PR
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const result = JSON.parse(fs.readFileSync('/tmp/lint-result.json', 'utf8'));

            if (result.issues.length === 0) {
              console.log('Nenhum problema encontrado pelo lint semântico');
              return;
            }

            const severityEmoji = { error: '🔴', warning: '🟡' };
            const typeLabel = {
              security: '🔒 Segurança',
              performance: '⚡ Performance',
              logic: '🧠 Lógica'
            };

            const issuesList = result.issues.map(issue =>
              `#### ${severityEmoji[issue.severity]} ${typeLabel[issue.type]} — Linha ${issue.line}\n` +
              `**Problema:** ${issue.description}\n` +
              `**Sugestão:** ${issue.suggestion}`
            ).join('\n\n');

            const body = `## 🔍 Lint Semântico com IA

            **Status:** ${result.severity === 'error' ? '🔴 Problemas críticos encontrados' : result.severity === 'warning' ? '🟡 Avisos encontrados' : '✅ Sem problemas'}

            ${issuesList}

            **Resumo:** ${result.summary}

            ---
            *Esta análise complementa (não substitui) o ESLint/TypeScript. Valide cada ponto manualmente.*`;

            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body,
            });

      - name: Falhar se houver erros críticos
        if: steps.lint.outputs.severity == 'error'
        run: |
          echo "Lint semântico encontrou erros críticos. Verifique os comentários no PR."
          exit 1

Auto-labeling e Triagem de Issues

# .github/workflows/triage-issues.yml
name: Triagem Automática de Issues

on:
  issues:
    types: [opened]
  issue_comment:
    types: [created]

permissions:
  issues: write

jobs:
  triage:
    name: Classificar e Rotular Issue
    runs-on: ubuntu-latest
    if: github.event_name == 'issues' && github.event.action == 'opened'

    steps:
      - name: Instalar Claude Code
        run: npm install -g @anthropic-ai/claude-code

      - name: Classificar issue com IA
        id: classify
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          TITLE="${{ github.event.issue.title }}"
          BODY="${{ github.event.issue.body }}"

          RESULT=$(claude --headless --output-format json --max-turns 1 \
            "Classifique esta issue do GitHub.

          TÍTULO: ${TITLE}
          CORPO: ${BODY}

          Retorne APENAS um JSON válido (sem markdown):
          {
            \"type\": \"bug\" | \"feature\" | \"question\" | \"docs\" | \"performance\" | \"security\",
            \"priority\": \"low\" | \"medium\" | \"high\" | \"critical\",
            \"component\": \"backend\" | \"frontend\" | \"database\" | \"ci\" | \"docs\" | \"unknown\",
            \"needs_more_info\": true | false,
            \"auto_response\": \"mensagem curta de boas-vindas em português, máximo 2 frases\"
          }" \
          | jq -r '.result')

          echo "result=$RESULT" >> $GITHUB_OUTPUT

          # Extrair campos individuais
          echo "type=$(echo $RESULT | jq -r '.type')" >> $GITHUB_OUTPUT
          echo "priority=$(echo $RESULT | jq -r '.priority')" >> $GITHUB_OUTPUT
          echo "component=$(echo $RESULT | jq -r '.component')" >> $GITHUB_OUTPUT
          echo "needs_info=$(echo $RESULT | jq -r '.needs_more_info')" >> $GITHUB_OUTPUT

      - name: Aplicar labels
        uses: actions/github-script@v7
        with:
          script: |
            const type = '${{ steps.classify.outputs.type }}';
            const priority = '${{ steps.classify.outputs.priority }}';
            const component = '${{ steps.classify.outputs.component }}';
            const needsInfo = '${{ steps.classify.outputs.needs_info }}' === 'true';

            // Mapear para labels existentes no repositório
            const labels = [];

            const typeLabels = {
              bug: 'bug',
              feature: 'enhancement',
              question: 'question',
              docs: 'documentation',
              performance: 'performance',
              security: 'security',
            };

            const priorityLabels = {
              low: 'priority: low',
              medium: 'priority: medium',
              high: 'priority: high',
              critical: 'priority: critical',
            };

            if (typeLabels[type]) labels.push(typeLabels[type]);
            if (priorityLabels[priority]) labels.push(priorityLabels[priority]);
            if (component !== 'unknown') labels.push(`component: ${component}`);
            if (needsInfo) labels.push('needs more info');

            if (labels.length > 0) {
              await github.rest.issues.addLabels({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: context.issue.number,
                labels,
              });
            }

      - name: Postar resposta automática
        uses: actions/github-script@v7
        with:
          script: |
            const result = JSON.parse('${{ steps.classify.outputs.result }}');

            let response = result.auto_response + '\n\n';

            if (result.needs_more_info) {
              response += '> **Informações adicionais necessárias:** Para agilizar a triagem, por favor forneça: versão do sistema, passos para reproduzir e comportamento esperado vs atual.';
            }

            if (result.type === 'security') {
              response = '🔒 **Issue de segurança detectada.** Obrigado por reportar! Por favor, evite incluir detalhes de exploração publicamente. Um mantenedor entrará em contato em particular.';
            }

            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: response,
            });

Workflow Completo: PR do Início ao Fim

# .github/workflows/ai-full-pipeline.yml
name: Pipeline IA Completo

on:
  pull_request:
    types: [opened, synchronize, ready_for_review]
    branches: [main, develop]

permissions:
  contents: write
  pull-requests: write
  checks: write

concurrency:
  group: ai-pipeline-${{ github.event.pull_request.number }}
  cancel-in-progress: true  # cancela run anterior ao fazer novo push

jobs:
  # ──────────────────────────────────────────────
  # JOB 1: Setup e lint tradicional (rápido)
  # ──────────────────────────────────────────────
  lint-and-typecheck:
    name: Lint e Tipagem
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'pnpm'
      - run: pnpm install --frozen-lockfile
      - run: pnpm lint
      - run: pnpm typecheck

  # ──────────────────────────────────────────────
  # JOB 2: Testes unitários
  # ──────────────────────────────────────────────
  unit-tests:
    name: Testes Unitários
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'pnpm'
      - run: pnpm install --frozen-lockfile
      - run: pnpm test --coverage
      - name: Upload coverage
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}

  # ──────────────────────────────────────────────
  # JOB 3: Review IA (em paralelo com testes)
  # ──────────────────────────────────────────────
  ai-review:
    name: Review com IA
    runs-on: ubuntu-latest
    if: github.event.pull_request.draft == false
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Instalar Claude Code
        run: npm install -g @anthropic-ai/claude-code

      - name: Obter diff
        run: git diff origin/${{ github.base_ref }}...HEAD > /tmp/pr.diff

      - name: Review com Claude
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          claude --headless --output-format json --max-turns 3 \
            "$(cat <<'PROMPT'
          Revise este PR em português. Seja direto e útil.

          PR: ${{ github.event.pull_request.title }}

          DIFF:
          $(cat /tmp/pr.diff)

          Analise: bugs, segurança, performance, testes, legibilidade.
          Veredicto final: APROVADO | APROVADO COM SUGESTÕES | MUDANÇAS NECESSÁRIAS
          PROMPT
          )" | jq -r '.result' > /tmp/review.md

      - name: Postar review
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const review = fs.readFileSync('/tmp/review.md', 'utf8');
            const isApproved = review.includes('APROVADO') && !review.includes('MUDANÇAS NECESSÁRIAS');

            // Postar como review (não apenas comentário)
            await github.rest.pulls.createReview({
              owner: context.repo.owner,
              repo: context.repo.repo,
              pull_number: context.issue.number,
              body: `## 🤖 Revisão Automática\n\n${review}`,
              event: isApproved ? 'COMMENT' : 'COMMENT',
              // Nota: aprovação automática requer permissão adicional
              // Use 'APPROVE' apenas em ambientes controlados
            });

  # ──────────────────────────────────────────────
  # JOB 4: Lint semântico IA
  # ──────────────────────────────────────────────
  semantic-lint:
    name: Lint Semântico
    runs-on: ubuntu-latest
    if: github.event.pull_request.draft == false
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Instalar Claude Code
        run: npm install -g @anthropic-ai/claude-code

      - name: Lint semântico
        id: lint
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          DIFF=$(git diff origin/${{ github.base_ref }}...HEAD)

          SEVERITY=$(claude --headless --output-format json --max-turns 2 \
            "Analise este diff por bugs de segurança e lógica críticos apenas.
            Retorne JSON: {\"severity\": \"ok\"|\"warning\"|\"error\", \"summary\": \"string\"}
            DIFF: ${DIFF}" \
          | jq -r '.result | fromjson | .severity')

          echo "severity=$SEVERITY" >> $GITHUB_OUTPUT

      - name: Falhar se crítico
        if: steps.lint.outputs.severity == 'error'
        run: exit 1

  # ──────────────────────────────────────────────
  # JOB 5: Geração de testes (só em PRs novos)
  # ──────────────────────────────────────────────
  generate-tests:
    name: Gerar Testes Faltantes
    runs-on: ubuntu-latest
    needs: [lint-and-typecheck]  # aguardar lint antes de commitar
    if: github.event.action == 'opened'  # apenas no primeiro push
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
          token: ${{ secrets.GITHUB_TOKEN }}

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'pnpm'

      - run: pnpm install --frozen-lockfile

      - name: Instalar Claude Code
        run: npm install -g @anthropic-ai/claude-code

      - name: Gerar testes para arquivos novos
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          # Apenas arquivos ADICIONADOS (A), não modificados
          ADDED=$(git diff origin/${{ github.base_ref }}...HEAD \
            --name-only --diff-filter=A \
            | grep 'src/.*\.ts$' \
            | grep -v '\.test\.' \
            | head -5)

          for file in $ADDED; do
            TEST="${file%.ts}.test.ts"
            [ -f "$TEST" ] && continue

            echo "Gerando: $TEST"
            claude --headless --output-format json --max-turns 2 \
              "Leia $file e gere testes Vitest completos. Salve em $TEST. Retorne apenas 'done'." \
            | jq -r '.result'
          done

      - name: Commitar testes gerados
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add "**/*.test.ts" 2>/dev/null || true
          if ! git diff --staged --quiet; then
            git commit -m "test: [generated] adicionar testes para arquivos novos do PR"
            git push origin HEAD:${{ github.head_ref }}
          fi

  # ──────────────────────────────────────────────
  # JOB 6: Status final
  # ──────────────────────────────────────────────
  pipeline-status:
    name: Status do Pipeline
    runs-on: ubuntu-latest
    needs: [lint-and-typecheck, unit-tests, ai-review, semantic-lint]
    if: always()
    steps:
      - name: Verificar resultado geral
        uses: actions/github-script@v7
        with:
          script: |
            const jobs = {
              lint: '${{ needs.lint-and-typecheck.result }}',
              tests: '${{ needs.unit-tests.result }}',
              aiReview: '${{ needs.ai-review.result }}',
              semanticLint: '${{ needs.semantic-lint.result }}',
            };

            const failed = Object.entries(jobs)
              .filter(([, r]) => r === 'failure')
              .map(([name]) => name);

            if (failed.length > 0) {
              core.setFailed(`Pipeline falhou em: ${failed.join(', ')}`);
            } else {
              console.log('✅ Pipeline completo com sucesso');
            }

🔧 Na prática: O job generate-tests roda apenas em action == 'opened' (primeiro push do PR). Isso evita reescrever testes a cada atualização, mas ainda garante que PRs novos tenham cobertura básica desde o início.

⚠️ Armadilha: O uso de GITHUB_TOKEN para push requer que "Allow GitHub Actions to create and approve pull requests" esteja habilitado nas configurações do repositório (Settings → Actions → General).

Resumo de bolso

  • O flag --headless é obrigatório para Claude Code em CI; combine com --output-format json e jq para parsing estruturado
  • O padrão de atualizar comentário existente (em vez de criar novos) mantém o PR limpo em iterações múltiplas
  • O workflow de lint semântico captura classes de bugs (race conditions, N+1 queries, XSS) que ferramentas estáticas tradicionais ignoram
  • Use concurrency com cancel-in-progress: true para evitar runs paralelas do mesmo pipeline ao fazer múltiplos pushes rápidos
  • O job de geração de testes deve rodar apenas em PRs novos (action == 'opened') para não sobrescrever testes existentes
  • Trate outputs de IA em CI como sugestões auditáveis, não como decisões finais: sempre deixe um humano com o poder de override

PARTE III — Integrando Tudo no Seu Fluxo


Capítulo 14: Montando Seu Stack de IA para Desenvolvimento

Não existe stack universal de IA para desenvolvimento. O que funciona para um dev solo num produto SaaS não é o mesmo que faz sentido para uma equipe de engenharia numa fintech. Neste capítulo vamos destrinchar as opções por perfil, com custos reais e um guia de decisão para você saber qual ferramenta pegar em cada situação.


Stack por perfil de dev

Solo Dev — o kit essencial (~$40/mês)

Se você trabalha sozinho — seja como freelancer, indie hacker ou num projeto pessoal —, a combinação mais eficiente hoje é:

Ferramenta Função no workflow Custo mensal
Claude Code (Pro) Agente principal: plan, implement, debug $20
Cursor (Pro) IDE com autocomplete contextual e edição pontual $20
GitHub Actions CI/CD + reviews automáticos via Claude headless $0–5 (incluso no free tier para repos públicos)
Total ~$40–45

O que cada ferramenta faz no seu dia a dia:

Claude Code é o centro de gravidade. Você o usa para tarefas que exigem raciocínio mais longo: planejamento de feature, refactoring de módulo inteiro, debugging de problema complexo, geração de testes. Em plan mode, ele propõe o que vai fazer antes de tocar em qualquer arquivo — isso é crítico para não perder trabalho.

# Fluxo típico no terminal
$ claude
> /plan Adicionar autenticação JWT com refresh token na API Express
# Claude descreve os arquivos que vai criar/modificar
# Você revisa, aprova ou ajusta
> Aprovado. Pode implementar.

Cursor entra para as tarefas mais táticas: completar uma linha específica, navegar entre arquivos relacionados, fazer uma edição cirúrgica sem abrir uma sessão de agente completa. O Cmd+K para edição inline e o Cmd+L para chat contextual com o arquivo aberto são os dois atalhos que você vai usar centenas de vezes por dia.

💡 Dica: Use Claude Code para o "pensar" e o Cursor para o "escrever". Quando você sabe exatamente o que quer mudar em 3 linhas, o Cursor é mais rápido. Quando você não sabe por onde começar, o Claude Code é melhor.

GitHub Actions fecha o ciclo. Para solo dev, o mínimo viável é um workflow que roda lint, testes e — opcionalmente — um review automático via Claude API. Você empurra o código, a action comenta no PR com issues encontrados, você corrige antes de mergear para main.

# .github/workflows/ai-review.yml
name: AI Code Review
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Get diff
        id: diff
        run: |
          git diff origin/main...HEAD > diff.txt
          echo "diff_size=$(wc -c < diff.txt)" >> $GITHUB_OUTPUT

      - name: AI Review
        if: steps.diff.outputs.diff_size < 50000
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          npx tsx scripts/ai-review.ts

Custo detalhado para solo dev:

  • Claude Pro: $20/mês fixo, uso ilimitado com rate limits generosos
  • Cursor Pro: $20/mês fixo
  • GitHub Actions: gratuito para repos públicos; para repos privados, 2.000 minutos/mês no free tier (suficiente para a maioria dos projetos solo)
  • Claude API (para Actions): $1–5/mês dependendo de quantos PRs você abre

⚠️ Armadilha: Não tente usar só a API do Claude sem o Claude Code. Você vai acabar escrevendo scripts de integração e perdendo mais tempo do que ganha. O Claude Code já tem toda a camada de ferramentas (file system, bash, git) integrada.


Equipe Pequena (2–5 devs) — colaboração sem atrito (~$100–200/mês total)

Com múltiplos devs, surgem dois problemas novos: consistência (cada dev usando IA de forma diferente produz código inconsistente) e custo (cada pessoa pagando separado fica caro e desorganizado).

Ferramenta Função Custo mensal
Claude Code (Pro, por dev) Agente principal individual $20 × nº devs
Cursor (Pro, por dev) IDE contextual individual $20 × nº devs
Aider (open source) CLI para devs que preferem terminal puro $0 (só API)
Claude API (compartilhada) MCP servers, Actions, Aider $20–50
Total (3 devs) ~$150–170

Aider para quem prefere CLI:

Nem todo dev gosta de IDE. O Aider (aider.chat) é uma alternativa excelente via terminal: você abre um repositório, ele mapeia a estrutura e você programa em linguagem natural com um loop de edit/commit automático.

# Instalação
pip install aider-chat

# Uso básico com Claude
aider --model claude-opus-4-5 --file src/auth/jwt.service.ts

# Modo /ask para explorar sem modificar
/ask Como funciona o fluxo de refresh token aqui?

# Modo /code para implementar
Adiciona validação de expiração no método validateToken

O Aider é especialmente útil para devs que já têm um terminal sempre aberto e acham o overhead de uma IDE pesada demais para algumas tarefas.

MCP Servers compartilhados:

Em equipes pequenas, vale configurar MCP servers (Model Context Protocol) que todos usam. Um servidor MCP centraliza ferramentas que os agentes podem chamar — acesso a Jira, Confluence, banco de dados de staging, etc.

// .claude/mcp-servers.json (commitado no repo)
{
  "mcpServers": {
    "jira": {
      "command": "npx",
      "args": ["@company/mcp-jira"],
      "env": {
        "JIRA_URL": "https://company.atlassian.net",
        "JIRA_TOKEN": "${JIRA_TOKEN}"
      }
    },
    "postgres-staging": {
      "command": "npx",
      "args": ["@modelcontextprotocol/server-postgres"],
      "env": {
        "DATABASE_URL": "${STAGING_DB_URL}"
      }
    }
  }
}

Cada dev define as variáveis de ambiente localmente. O arquivo de configuração vai no repo, mas os secrets ficam em .env.local (no .gitignore).

CLAUDE.md por repositório como política de equipe:

Este é o ponto mais importante para equipes: o CLAUDE.md funciona como um contrato com o agente de IA que todos compartilham. Quando está no repo, todo mundo trabalha com as mesmas instruções, os mesmos padrões, as mesmas restrições.

<!-- CLAUDE.md na raiz do repo -->
# Guia para o Agente de IA — Projeto Checkout

## Stack
- Node.js 20 + TypeScript 5.4
- NestJS para o backend
- PostgreSQL com Prisma ORM
- Jest para testes (mínimo 80% de cobertura)
- Docker Compose para dev local

## Convenções obrigatórias
- Usar `Result<T, E>` para operações que podem falhar (ver src/core/result.ts)
- NUNCA usar `any` — use `unknown` e type guards
- Serviços são injetáveis via DI do NestJS — sem instanciação manual
- Migrations do Prisma: criar sempre, nunca editar as existentes

## O que NÃO fazer
- Não instalar dependências sem perguntar
- Não modificar arquivos em src/core/ sem aprovação explícita
- Não commitar código com `console.log` (use o logger injetado)

## Contexto do domínio
Este é o serviço de checkout de um e-commerce B2B.
Clientes são empresas (CNPJ), não pessoas físicas.
Preços são sempre em centavos (integer), nunca float.

🔧 Na prática: Faça uma sessão de 30 minutos com a equipe para escrever o CLAUDE.md juntos. Esse documento vai evitar que a IA introduza padrões inconsistentes e vai reduzir o tempo de review de PRs gerados por IA.

Custo detalhado para equipe de 3 devs:

  • Claude Pro × 3: $60
  • Cursor Pro × 3: $60
  • Claude API compartilhada (Actions + MCP): ~$30
  • Aider para 1 dev CLI: $0 (usa API compartilhada)
  • Total: ~$150/mês (~$50/dev)

Enterprise (10+ devs) — governança, segurança e escala

Em empresas maiores, o problema não é só custo — é controle, auditoria, segurança de dados e padronização em escala. O stack muda significativamente.

Ferramenta Função Custo mensal estimado
GitHub Copilot Business Autocomplete integrado ao GitHub $19/dev × nº devs
Claude API (via AWS Bedrock ou GCP Vertex) Agentes customizados, sem dados saindo para Anthropic diretamente $500–2000 (uso)
Custom Agents (Agent SDK) Workflows específicos da empresa Dev interno
Observabilidade (Langfuse/Helicone) Tracking de uso, custos, qualidade $100–500
Total (20 devs) ~$1.500–3.000/mês

Por que GitHub Copilot Business em vez de Cursor?

Em enterprise, integração com políticas existentes importa. O Copilot Business se integra nativamente com GitHub Enterprise, respeita políticas de segurança existentes, tem painel de administração centralizado e auditoria de uso. Para times que já vivem no ecossistema GitHub, é o caminho de menor atrito.

Claude via AWS Bedrock — dados e compliance:

Para empresas com requisitos de compliance (LGPD, SOC 2, HIPAA), usar Claude diretamente via Anthropic.com pode ser problemático porque os dados trafegam pelos servidores da Anthropic. Via AWS Bedrock, o processamento acontece dentro da sua conta AWS, com as políticas de retenção e segurança que você já tem.

// src/agents/claude-bedrock.client.ts
import { BedrockRuntimeClient, InvokeModelCommand } from '@aws-sdk/client-bedrock-runtime';

export class ClaudeBedrockClient {
  private client: BedrockRuntimeClient;

  constructor() {
    this.client = new BedrockRuntimeClient({
      region: process.env.AWS_REGION ?? 'us-east-1',
      // Credenciais via IAM Role — sem keys no código
    });
  }

  async complete(prompt: string, options?: { maxTokens?: number }): Promise<string> {
    const command = new InvokeModelCommand({
      modelId: 'anthropic.claude-opus-4-5-20251101-v1:0',
      body: JSON.stringify({
        anthropic_version: 'bedrock-2023-05-31',
        max_tokens: options?.maxTokens ?? 4096,
        messages: [{ role: 'user', content: prompt }],
      }),
    });

    const response = await this.client.send(command);
    const body = JSON.parse(new TextDecoder().decode(response.body));
    return body.content[0].text;
  }
}

Custom Agents para workflows corporativos:

Em vez de cada dev configurar seus próprios agentes, a equipe de plataforma constrói agentes padronizados que todos usam:

// agents/code-reviewer.agent.ts
import Anthropic from '@anthropic-ai/sdk';

export class CodeReviewerAgent {
  private client: Anthropic;
  private systemPrompt: string;

  constructor() {
    this.client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
    this.systemPrompt = `
      Você é um reviewer de código sênior especializado em segurança e performance.
      Foque especialmente em: OWASP Top 10, N+1 queries, vazamento de dados sensíveis.
      Retorne issues em formato JSON estruturado para integração com nosso sistema.
      Severidade: critical | high | medium | low | info
    `;
  }

  async review(diff: string, context: { repo: string; pr: number }): Promise<ReviewResult[]> {
    const message = await this.client.messages.create({
      model: 'claude-opus-4-5-20251101',
      max_tokens: 8192,
      system: this.systemPrompt,
      messages: [{
        role: 'user',
        content: `
          Repositório: ${context.repo}
          PR: #${context.pr}
          
          Diff para review:
          \`\`\`diff
          ${diff}
          \`\`\`
          
          Retorne um array JSON de issues encontrados.
        `,
      }],
    });

    return JSON.parse(message.content[0].type === 'text' ? message.content[0].text : '[]');
  }
}

Observabilidade — você precisa saber o que está acontecendo:

Com 10+ devs usando IA, você precisa monitorar: quanto está custando por dev, por projeto, por tipo de tarefa. E também: a qualidade está melhorando? Os agentes estão seguindo as políticas?

// Integração com Langfuse para rastreamento
import { Langfuse } from 'langfuse';

const langfuse = new Langfuse({
  publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
  secretKey: process.env.LANGFUSE_SECRET_KEY!,
});

// Em cada chamada de agente
const trace = langfuse.trace({
  name: 'code-review',
  userId: dev.email,
  metadata: { repo, pr, team },
});

const generation = trace.generation({
  name: 'claude-review',
  model: 'claude-opus-4-5-20251101',
  input: { diff },
});

const result = await agent.review(diff, { repo, pr });

generation.end({ output: result });
await langfuse.flushAsync();

Governança e Compliance em enterprise:

Política Implementação
Dados sensíveis não saem da empresa Usar AWS Bedrock ou GCP Vertex em vez de Anthropic direto
Auditoria de uso Langfuse ou Helicone com retenção de 90 dias
Aprovação de IA em PRs críticos Branch protection: review humano obrigatório além do AI review
Limites de custo por equipe Budget alerts no Bedrock/Vertex por tag de projeto
Proibição de colar dados de clientes DLP no API gateway que intercepta requests com PII
Política de CLAUDE.md padronizada Template corporativo versionado em repo central

⚠️ Armadilha: Em enterprises, o maior erro é deixar cada dev ou equipe configurar sua IA do jeito que quiser. Isso gera inconsistência de qualidade, custo descontrolado e riscos de segurança. A equipe de plataforma precisa liderar a adoção.


Decision Tree — "Preciso de X, uso Y"

Qual é a tarefa?
│
├── Feature nova e complexa (múltiplos arquivos, domínio novo)
│   └── → Claude Code em plan mode + revisão do plano + implementação
│       └── Cursor para ajustes pontuais durante o desenvolvimento
│
├── Bug fix urgente (produção está falhando)
│   ├── Contexto claro do erro → Claude Code direto com stack trace
│   └── Sem certeza da causa → Copilot Chat para explorar hipóteses rápido
│
├── Code review (antes de mergear)
│   ├── PR pequeno (<300 linhas) → /review skill no Claude Code
│   └── PR grande ou crítico → GitHub Action com Claude headless + review humano
│
├── Documentação
│   ├── Docstrings/JSDoc → Cursor inline (Cmd+K)
│   ├── README de módulo → Claude Code com context de arquivos
│   └── Docs técnica em batch → Agent SDK com múltiplos arquivos
│
├── Refactoring grande (ex: migrar de callbacks para async/await)
│   └── → BMAD para planejamento + Agent SDK multi-agent para execução
│       └── Worktree isolation para não quebrar main
│
├── Migração (ex: PostgreSQL → MongoDB, Express → NestJS)
│   └── → Agente custom com worktree isolation
│       └── Claude Code para validar cada etapa
│
├── Explorar código desconhecido (onboarding, código legado)
│   ├── Exploração ampla → Subagente Explore ou Aider /ask
│   └── Entender um arquivo específico → Cursor (Cmd+L com arquivo aberto)
│
├── Geração de testes
│   ├── Testes de uma função → Claude Code ou Cursor inline
│   └── Suíte completa de módulo → Agent SDK batch
│
└── Setup de CI/CD e automações
    └── → Claude Code (tem acesso a bash e pode testar o workflow)

Tabela consolidada de custos mensais

Perfil Ferramenta Preço unitário Quantidade Total
Solo Dev Claude Pro $20 1 dev $20
Cursor Pro $20 1 dev $20
Claude API (Actions) ~$3 $3
Subtotal $43
Equipe (3 devs) Claude Pro $20 3 devs $60
Cursor Pro $20 3 devs $60
Claude API compartilhada ~$30 $30
Subtotal $150
Enterprise (20 devs) Copilot Business $19 20 devs $380
Claude API (Bedrock) ~$1.500 alto volume $1.500
Observabilidade (Langfuse Cloud) $200 $200
Custom agents (infra) ~$300 $300
Subtotal ~$2.380

💡 Dica: Para enterprise, o ROI de IA é calculado em horas economizadas, não em custo de ferramenta. Se 20 devs economizam 1h/dia em média, são 400h/mês. A $100/h de custo de dev, isso é $40.000 de valor gerado para um investimento de ~$2.400. O debate não é se vale — é como implementar bem.


Resumo de bolso

  • Solo dev: Claude Code + Cursor + GitHub Actions por ~$43/mês cobre 95% dos casos
  • Equipe pequena: adicione MCP servers compartilhados e um CLAUDE.md por repo como política de equipe — isso resolve a inconsistência
  • Enterprise: a camada de governança (Bedrock/Vertex, observabilidade, políticas centralizadas) é mais importante que a escolha de ferramenta em si
  • Use o decision tree para saber qual ferramenta acionar em cada situação — misturar ferramentas sem critério gera confusão e retrabalho
  • O custo de IA para desenvolvimento é marginal comparado ao valor gerado; o problema real é adoção consistente e políticas claras

Capítulo 15: Workflow Diário AI-First (Do Zero ao PR)

O que realmente muda quando você adota IA como parte central do seu workflow? Não é só "usar autocomplete mais inteligente". É uma reorganização de como você pensa sobre cada hora do seu dia. Vamos acompanhar um dia real de um dev sênior — chamemos de Rafael — trabalhando num produto SaaS de gestão financeira.


8:00 — Morning planning com IA

Rafael chega, abre o café, olha o board. Tem um épico de "Módulo de conciliação bancária" que precisa ser quebrado em stories para a sprint que começa amanhã. Em vez de gastar 1h escrevendo stories do zero, ele copia a descrição do épico e abre o Claude Code.

O épico original (do Jira/Linear):

Épico: Conciliação bancária automática
Descrição: O sistema deve comparar automaticamente os lançamentos do nosso 
sistema com os extratos bancários importados via OFX, identificar matches 
automáticos, sinalizar divergências e permitir conciliação manual das não-matches.
Integração: Banco do Brasil e Itaú inicialmente.
Regras: Tolerância de R$0,01 por arredondamento. Match por data ± 2 dias úteis
e valor. Lançamentos parcelados devem ser agrupados.

O prompt de Rafael:

Tenho esse épico de conciliação bancária. Nossa stack é Node.js + TypeScript + 
NestJS + PostgreSQL + Prisma. Temos ~3 devs trabalhando em paralelo.

Gere stories com critérios de aceite no formato Gherkin (Given/When/Then) 
para esse épico. Quebre em stories que caibam em 1-3 dias de desenvolvimento cada.
Inclua: story de setup de infraestrutura, parsing de OFX, lógica de matching,
UI de revisão e story de testes de integração.

Priorize na ordem que faz mais sentido tecnicamente (dependências primeiro).

Output do Claude (resumido):

## Stories geradas — Módulo de Conciliação Bancária

**Prioridade 1 (bloco tudo mais):**

### CONC-01: Setup da estrutura de dados para conciliação
**Estimativa:** 1 dia

**Critérios de aceite:**
```gherkin
Given que o schema do banco está sendo migrado
When a migration CONC-001 é executada
Then as tabelas bank_statements, bank_transactions e reconciliation_matches 
  existem com os campos corretos
And os índices de performance estão criados (date, amount, status)
And o rollback da migration funciona sem erros

Prioridade 2 (paralelo após CONC-01):

CONC-02: Parser de arquivo OFX

Estimativa: 2 dias
...

CONC-03: Engine de matching automático

Estimativa: 3 dias
...


Rafael revisa, ajusta algumas estimativas (a CONC-03 vai precisar de 4 dias, não 3), copia para o Linear e distribui para o time. Tempo total: 20 minutos em vez de 1h30.

> 🔧 **Na prática:** Peça para a IA gerar as stories em formato que você pode copiar direto para o seu board. Markdown com headers e critérios em Gherkin costuma importar bem na maioria das ferramentas. Se você usa Jira, pode pedir para gerar no formato de template do Jira.

**O que Rafael anotou para si:**
- A IA agrupou corretamente as dependências técnicas
- Sugeriu uma story de "testes de integração" que ele teria esquecido
- Estimativas vieram conservadoras — bom ponto de partida

---

### 9:00 — Development loop

Rafael pega a CONC-03 (engine de matching) — a mais complexa. Abre o Claude Code no terminal.

**Fase 1: Plan mode**

```bash
$ claude

> /plan Implementar engine de matching automático para conciliação bancária.

Regras de negócio:
- Match por valor exato (tolerância ±R$0,01 = 1 centavo)
- Match por data ± 2 dias úteis (ignorar fins de semana e feriados brasileiros)
- Lançamentos do mesmo valor na mesma janela de data = candidatos
- Score de confiança: valor exato + data exata = 100, variações reduzem
- Lançamentos parcelados: identificar pelo padrão "X/Y" na descrição e agrupar

Contexto:
- Tabelas já existem (CONC-01 está feita): bank_statements, bank_transactions
- Usar Prisma para queries
- Módulo NestJS com injeção de dependência
- Jest para testes (TDD)

Plano proposto pelo Claude:

## Plano de implementação: Matching Engine

### Arquivos a criar:
1. src/reconciliation/matching/matching.engine.ts
   - Classe principal MatchingEngine
   - Método findCandidates(transaction) → Candidate[]
   - Método calculateScore(transaction, statement) → number
   - Método applyMatches(matches) → ReconciliationResult

2. src/reconciliation/matching/date-utils.ts
   - Função addBusinessDays(date, days, holidays)
   - Função isBusinessDay(date, holidays)
   - Lista de feriados nacionais 2024-2025

3. src/reconciliation/matching/matching.engine.spec.ts
   - Testes unitários com cenários: match perfeito, match por proximidade,
     sem match, lançamento parcelado, feriado na janela

4. src/reconciliation/matching/matching.module.ts
   - Módulo NestJS registrando engine e serviços

### Estratégia de query:
- Primeiro filtrar por janela de data (índice de data)
- Depois filtrar por range de valor (± 1 centavo)
- Calcular score e ordenar candidatos
- Evitar N+1: buscar todos os candidatos em batch

### Ordem de implementação:
1. date-utils.ts (sem dependências, testável isolado)
2. matching.engine.ts esqueleto com tipos
3. Testes primeiro (TDD)
4. Implementação da lógica

Posso prosseguir?

Rafael lê o plano. Está bom, mas ele nota um problema: o plano não menciona feriados estaduais, e o sistema precisa suportar clientes de SP e RJ. Ele ajusta:

> Bom plano. Ajuste: os feriados precisam ser por estado (SP e RJ por enquanto).
  O constructor do engine vai receber o estado como parâmetro.
  Pode implementar.

Fase 2: Implementação em ciclos

O Claude começa a implementar. Rafael acompanha no terminal enquanto toma o café. O agente cria arquivos, escreve testes, implementa a lógica, roda os testes, corrige erros:

✓ Criando src/reconciliation/matching/date-utils.ts
✓ Criando src/reconciliation/matching/date-utils.spec.ts
→ Rodando testes: date-utils.spec.ts
  ✓ 8 testes passando

✓ Criando src/reconciliation/matching/matching.engine.ts
✓ Criando src/reconciliation/matching/matching.engine.spec.ts
→ Rodando testes: matching.engine.spec.ts
  ✗ 2 testes falhando:
    - "deve ignorar match quando valor difere mais de 1 centavo"
    - "deve calcular janela de data corretamente com feriado estadual"

→ Analisando falhas...
→ Corrigindo lógica de comparação de centavos (problema com floating point)
→ Corrigindo cálculo de janela com feriados estaduais

→ Rodando testes novamente:
  ✓ 14 testes passando

Enquanto o Claude trabalha no matching engine, Rafael abre o Cursor para fazer uma edição pontual num arquivo relacionado: quer adicionar um campo reconciliation_status na query do endpoint de listagem de transações.

💡 Dica: Alternar entre Claude Code e Cursor é natural e esperado. Claude Code para o trabalho autônomo e de maior escopo; Cursor para edições cirúrgicas onde você sabe exatamente o que quer. Não force uma ferramenta para o que a outra faz melhor.

Fase 3: Cursor para ajustes pontuais

No Cursor, Rafael abre src/transactions/transactions.service.ts, pressiona Cmd+L e digita:

Adiciona o campo reconciliationStatus na query do método findAll.
O status vem de uma join com a tabela reconciliation_matches.
Se não houver match, retorna 'pending'. Se houver, retorna o status do match.

O Cursor aplica a mudança inline, Rafael revisa, aprova. 30 segundos.

Exemplo do loop completo com comandos reais:

# Terminal 1: Claude Code rodando o desenvolvimento principal
$ claude
> /plan [...]
> [aprovação do plano]
> [Claude implementa autonomamente]

# Terminal 2: Rafael monitora, faz ajustes pontuais via Cursor
# Cursor aberto com o projeto

# Quando Claude termina um ciclo:
> Commit as mudanças com mensagem descritiva
# Claude roda: git add, git commit com mensagem formatada

# Rafael verifica:
$ git log --oneline -5
a3f2b1c feat(reconciliation): add matching engine with business day support
b2e1a0d feat(reconciliation): add date utils with state-specific holidays  
c1d0f9e feat(reconciliation): add schema migrations for reconciliation tables

12:00 — Review e qualidade

Antes do almoço, Rafael roda o review do que foi implementado pela manhã.

Review do código gerado:

# No Claude Code
> /review src/reconciliation/matching/

# Output (resumido):
## Code Review — src/reconciliation/matching/

### 🔴 Issues críticos (2)

**1. Floating point para valores monetários**
Arquivo: matching.engine.ts, linha 47
```typescript
// ❌ Código gerado
const withinTolerance = Math.abs(transaction.amount - statement.amount) <= 0.01;

// ⚠️ Problema: floating point pode causar falsos negativos
// Ex: 10.10 - 10.09 = 0.009999999999999787 (passa)
//     100.30 - 100.29 = 0.009999999999998934 (pode falhar)

// ✅ Correto: trabalhar com centavos (integers)
const withinTolerance = Math.abs(transaction.amountCents - statement.amountCents) <= 1;

2. Query sem limite pode causar timeout
Arquivo: matching.engine.ts, linha 89
Método findCandidates faz query sem LIMIT quando a janela de data é grande.
Em bases com muitas transações, isso pode demorar ou causar OOM.
Sugestão: adicionar LIMIT 100 com paginação ou índice composto.

🟡 Issues médios (3)

...

🟢 Pontos positivos

  • Testes bem estruturados com casos edge
  • Injeção de dependência correta (NestJS pattern)
  • Tipos TypeScript sem uso de any

Rafael lê o review. O problema de floating point é real — ele já viu esse bug em produção antes em outro projeto. Pede para o Claude corrigir:

```bash
> Corrija os dois issues críticos do review. Para o floating point, 
  garanta que todos os valores monetários são tratados como inteiros (centavos).
  Para o limite da query, adicione paginação com cursor (não offset).

Review de segurança nas mudanças sensíveis:

> /security-review src/reconciliation/

# Output relevante:
### 🔴 Vulnerabilidade: Exposição de dados de extrato bancário

O endpoint GET /reconciliation/statements não verifica se o statement 
pertence ao tenant do usuário autenticado.

Código atual:
async findStatement(id: string) {
  return this.prisma.bankStatement.findUnique({ where: { id } });
}

Risco: Usuário autenticado pode acessar extratos de outros clientes 
passando um UUID válido.

Correção necessária:
async findStatement(id: string, tenantId: string) {
  return this.prisma.bankStatement.findUnique({
    where: { id, tenantId }, // ← filtro por tenant obrigatório
  });
}

⚠️ Armadilha: Este tipo de bug de autorização é exatamente o que a IA gera com frequência. O código funciona e passa testes — mas os testes também foram gerados pela IA e não testaram o cenário de acesso cross-tenant. Review de segurança manual ou por agente especializado é não-negociável.

Rafael corrige o bug de autorização, commita e vai almoçar.


14:00 — Testes

Voltando do almoço, Rafael quer aumentar a cobertura de testes. O matching engine tem 14 testes unitários, mas ainda falta testes de integração e os edge cases do parsing de OFX.

Gerando testes com Agent SDK:

// scripts/generate-tests.ts
import Anthropic from '@anthropic-ai/sdk';
import fs from 'fs/promises';
import path from 'path';

const client = new Anthropic();

async function generateIntegrationTests(modulePath: string): Promise<void> {
  const files = await fs.readdir(modulePath);
  const sourceFiles = files.filter(f => f.endsWith('.ts') && !f.endsWith('.spec.ts'));

  for (const file of sourceFiles) {
    const content = await fs.readFile(path.join(modulePath, file), 'utf-8');
    const specFile = file.replace('.ts', '.integration.spec.ts');

    console.log(`Gerando testes de integração para ${file}...`);

    const message = await client.messages.create({
      model: 'claude-opus-4-5-20251101',
      max_tokens: 4096,
      messages: [{
        role: 'user',
        content: `
          Gere testes de integração Jest para este arquivo TypeScript/NestJS.
          Foque em:
          - Testes com banco de dados real (use testcontainers para PostgreSQL)
          - Cenários de concorrência (dois matches simultâneos para o mesmo statement)
          - Rollback em caso de erro parcial
          - Dados de teste realistas (use faker-js)
          
          Código fonte:
          \`\`\`typescript
          ${content}
          \`\`\`
          
          Retorne APENAS o código TypeScript do arquivo de teste, sem explicação.
        `,
      }],
    });

    const testCode = message.content[0].type === 'text' ? message.content[0].text : '';
    await fs.writeFile(path.join(modulePath, specFile), testCode);
    console.log(`✓ ${specFile} criado`);
  }
}

generateIntegrationTests('./src/reconciliation/matching');
$ npx tsx scripts/generate-tests.ts
Gerando testes de integração para matching.engine.ts...
✓ matching.engine.integration.spec.ts criado
Gerando testes de integração para date-utils.ts...
✓ date-utils.integration.spec.ts criado

Rodando a suíte completa:

$ npm test -- --coverage

PASS src/reconciliation/matching/date-utils.spec.ts
PASS src/reconciliation/matching/matching.engine.spec.ts
FAIL src/reconciliation/matching/matching.engine.integration.spec.ts
  ● deve fazer rollback quando segundo match falha
    Expected: state "rolled_back"
    Received: state "partial_match"

Coverage: 73% → meta é 80%

Rafael pede para o Claude corrigir o teste falhando:

$ claude
> O teste "deve fazer rollback quando segundo match falha" está falhando.
  Veja o output: [cola o erro]
  
  O problema pode ser no teste ou na implementação. Analise e corrija
  o que estiver errado.

O Claude analisa, identifica que a transação do Prisma não estava envolvendo os dois matches numa única transação atômica, e corrige tanto o teste quanto a implementação.

$ npm test -- --coverage

All tests: ✓ 28 passing (0 failing)
Coverage: 84% ✓

16:00 — PR e Deploy

Chegou a hora de empacotar o trabalho do dia.

Claude gera o PR:

$ claude
> Gera um PR para tudo que foi implementado hoje. Branch atual: feat/conc-03-matching-engine.
  Use gh pr create. Inclua na descrição:
  - O que foi implementado
  - As decisões técnicas importantes (floating point com centavos, paginação com cursor)
  - Screenshot não tem, mas mencione que os testes cobrem os cenários principais
  - Checklist de review para o revisor humano
# Claude executa:
$ gh pr create \
  --title "feat(reconciliation): add automatic matching engine" \
  --body "$(cat pr-body.md)" \
  --base main \
  --draft

# Output:
https://github.com/company/finapp/pull/247

A descrição gerada pelo Claude:

## O que foi implementado

Engine de matching automático para conciliação bancária (CONC-03).

## Mudanças principais

- `MatchingEngine`: lógica de matching por valor e proximidade de data
- `DateUtils`: cálculo de dias úteis com feriados nacionais e estaduais (SP/RJ)
- Testes unitários (14) e de integração (14): cobertura 84%

## Decisões técnicas

**Valores monetários como inteiros (centavos)**
Todos os valores são armazenados e comparados como `number` de centavos, 
nunca como float. Evita bugs de precisão de ponto flutuante.

**Paginação com cursor em vez de offset**
O método `findCandidates` usa cursor-based pagination para suportar
bases com grande volume de transações sem degradação de performance.

**Feriados por estado**
O `MatchingEngine` recebe o estado do cliente no constructor. Suporta SP e RJ.
Novos estados podem ser adicionados em `date-utils.ts`.

## Checklist para o revisor

- [ ] Validar a lógica de tolerância de ±1 centavo está correta
- [ ] Confirmar que o filtro por tenantId está em todos os endpoints
- [ ] Verificar se os índices de banco estão otimizados para o padrão de query
- [ ] Testar manualmente com um OFX real do BB e Itaú

GitHub Actions roda o review automático:

✓ Lint: passed
✓ Type check: passed  
✓ Tests: 28/28 passed
✓ Coverage: 84% (meta: 80%)
✓ AI Security Review: 0 critical issues
⚠️  AI Code Review: 2 suggestions (non-blocking)
   - matching.engine.ts:127 — considere adicionar log de auditoria nos matches
   - date-utils.ts:45 — lista de feriados pode ficar desatualizada; sugestão: API IBGE

Tudo verde (os warnings são sugestões, não bloqueios). Rafael remove o draft e pede review ao colega.

$ gh pr ready 247
$ gh pr request-review 247 --reviewer @ana @carlos

🔧 Na prática: Configure seu GitHub Actions para bloquear merge se houver issues críticos do security review automatizado. Issues de severidade média para baixo ficam como comentários não-bloqueantes — o revisor humano decide se são relevantes.


17:00 — Retro rápida (5 minutos)

Rafael tem um template simples que preenche todo dia antes de fechar o laptop:

# Retro Diária — 2026-05-04

## Métricas
- Tokens usados (estimativa): ~180k input, ~45k output
- Custo estimado: ~$4.20 (Claude Pro, incluso no plano)
- Features entregues: CONC-03 (matching engine) — completa
- Testes escritos: 28 (14 unitários + 14 integração)
- Bugs encontrados pelo AI review: 3 (2 críticos corrigidos, 1 médio pendente)

## O que a IA fez bem hoje
- Gerou o plano de implementação com dependências corretas
- Identificou o bug de floating point no review (eu poderia ter passado)
- Gerou testes de integração realistas com cenários de concorrência
- A descrição do PR ficou melhor do que eu escreveria manualmente

## Onde precisei mais supervisão
- O plano inicial esqueceu feriados estaduais — eu peguei
- O bug de autorização (cross-tenant) só apareceu no /security-review
- Um dos testes de integração gerados estava testando o cenário errado

## Para amanhã
- Fazer CONC-04 (UI de revisão manual) — estimar 2 dias
- Revisar PR do Carlos (CONC-02)
- Verificar se a lista de feriados estaduais está completa para 2026

💡 Dica: A retro diária de 5 minutos é o momento mais importante para calibrar sua relação com a IA. Você vai perceber padrões ao longo das semanas: quais tipos de tarefa a IA faz melhor, onde ela sistematicamente erra, quanto custou vs quanto valor gerou. Esses dados informam como você ajusta seu workflow.


Resumo de bolso

  • Morning planning com IA transforma épicos em stories priorizadas em minutos — mas você precisa revisar as estimativas, que tendem a ser otimistas
  • O development loop alterna entre Claude Code (autônomo, escopo maior) e Cursor (cirúrgico, edições pontuais) — não force uma ferramenta para o papel da outra
  • Review e security review são etapas não-negociáveis: a IA escreve código que compila e testa, mas bugs de autorização e segurança passam despercebidos nos testes gerados pela própria IA
  • GitHub Actions com AI review automatiza a primeira camada de qualidade — configure para bloquear issues críticos e comentar os não-críticos
  • A retro diária de 5 minutos é o que transforma uso casual de IA em melhoria contínua do workflow

Capítulo 16: Prompt Engineering para Devs

Prompt engineering não é mágica nem arte obscura. Para desenvolvedores, é uma habilidade como qualquer outra: tem princípios, padrões e anti-padrões. O problema é que a maioria dos guias de prompt engineering foi escrito para criação de conteúdo ou chat geral. Aqui vamos focar especificamente em prompts para código, com exemplos concretos do que funciona e do que não funciona.


Anatomia de um bom prompt para coding

Um prompt de coding eficiente tem quatro componentes. Quando um deles está faltando, a qualidade da resposta cai.

Os quatro componentes:

1. CONTEXTO — o que é o projeto, stack, constraints existentes
2. OBJETIVO — o que você quer que aconteça (específico e mensurável)
3. CONSTRAINTS — limitações, padrões a seguir, o que NÃO fazer
4. OUTPUT FORMAT — como você quer a resposta


Exemplo lado a lado — prompt ruim vs bom:

Tarefa: Implementar paginação numa API REST

❌ PROMPT RUIM:

"faz paginação na minha API"
✅ PROMPT BOM:

CONTEXTO:
API REST em Node.js + TypeScript com Express e Prisma (PostgreSQL).
Endpoint atual: GET /api/products — retorna todos os produtos sem paginação.
Média de produtos: 50.000 registros. Clientes reclamando de lentidão.

OBJETIVO:
Implementar cursor-based pagination no endpoint GET /api/products.
Retornar máximo 50 items por página. Suportar ordenação por createdAt e name.

CONSTRAINTS:
- NÃO usar offset pagination (performance ruim com volume alto)
- Manter compatibilidade com clientes existentes (adicionar parâmetros opcionais)
- Seguir o padrão de resposta existente: { data: [], meta: { nextCursor, total } }
- Não usar bibliotecas externas para isso — implementar na mão com Prisma

OUTPUT FORMAT:
1. O código modificado do endpoint (apenas o que mudou)
2. Exemplo de request e response da paginação
3. Um teste Jest cobrindo os casos: primeira página, página do meio, última página

A diferença no output é significativa. O prompt ruim vai gerar código genérico que provavelmente usa offset, pode usar uma biblioteca que você não quer, e não vai incluir testes. O prompt bom vai gerar exatamente o que você precisa.

💡 Dica: Você não precisa escrever esses quatro componentes em ordem ou com esses títulos. O importante é que a informação esteja lá. Com o tempo, eles se tornam instintivos.


System prompts e CLAUDE.md como "prompt persistente"

Por que funciona

Toda vez que você começa uma nova sessão de Claude Code e explica o contexto do projeto do zero, você está perdendo tempo e tokens. O CLAUDE.md resolve isso: ele é carregado automaticamente em todas as sessões dentro do repositório, funcionando como um system prompt persistente.

Isso tem um efeito profundo: você não precisa mais repetir "nós usamos TypeScript com strict mode" ou "nunca use any" toda vez. O modelo já sabe.

Como escrever um CLAUDE.md eficiente

Princípios:

  1. Seja específico, não genérico — "use TypeScript strict" é melhor que "escreva código de qualidade"
  2. Inclua exemplos concretos — se tem um padrão, mostre o código do padrão
  3. Documente o domínio — o modelo não conhece seus conceitos de negócio
  4. Especifique o que NÃO fazer — proibições explícitas são mais eficazes que regras positivas
  5. Mantenha curto e denso — CLAUDE.md longo dilui a atenção; prefira links para docs detalhadas
<!-- CLAUDE.md — exemplo bem estruturado -->

# Contexto do Projeto

API de gestão financeira para PMEs brasileiras. Stack: NestJS + TypeScript 5 + 
PostgreSQL (Prisma) + Redis (Bull queues) + Jest.

## Domínio — termos importantes
- **Conta**: entidade financeira de um cliente (não confundir com user account)
- **Lançamento**: qualquer débito ou crédito numa Conta
- **Conciliação**: processo de comparar lançamentos com extrato bancário
- Valores monetários são SEMPRE em centavos (integer). Nunca float.
- Datas fiscais usam fuso de Brasília (America/Sao_Paulo)

## Padrões de código obrigatórios

### Tratamento de erros
Usamos o padrão Result<T, E> (ver src/core/result.ts):
```typescript
// ✅ Correto
const result = await lancamentoService.create(dto);
if (result.isErr()) return left(new ValidationError(result.error));
return right(result.value);

// ❌ Errado — não lançar exceções para erros de negócio
throw new Error('Saldo insuficiente');

Autorização

TODO acesso a dados deve filtrar por tenantId:

// ✅ Obrigatório
prisma.conta.findMany({ where: { tenantId, ...filters } })

// ❌ Nunca
prisma.conta.findMany({ where: { ...filters } })

O que NÃO fazer

  • Não instalar dependências sem perguntar
  • Não usar any — use unknown com type guards
  • Não commitar console.log — use o LoggerService injetado
  • Não criar migrations que alterem colunas existentes sem plano de rollback

#### CLAUDE.md como "contrato" com o agente

Pense no CLAUDE.md não como documentação, mas como um contrato. Quando está no repo, você tem a garantia (quase) de que o agente vai seguir aquelas regras. Isso é importante para equipes: é a diferença entre ter IA que reforça os padrões da equipe e IA que cria inconsistência.

> ⚠️ **Armadilha:** Não copie o CLAUDE.md de um projeto para outro sem adaptar. Regras específicas de domínio de um projeto podem confundir o modelo em outro. Cada repositório precisa do seu próprio CLAUDE.md.

---

### Técnicas de prompting para código

#### Few-shot: mostrar o padrão antes de pedir

O few-shot (poucos exemplos) é a técnica mais eficaz para ensinar padrões específicos do projeto. Em vez de descrever o padrão, você mostra exemplos.

```typescript
// ❌ Sem few-shot — resultado genérico
"Cria um serviço NestJS para gerenciar usuários"

// ✅ Com few-shot — resultado que segue seu padrão
`
Cria um serviço NestJS para gerenciar Contas (conta.service.ts).
Siga o mesmo padrão dos exemplos abaixo:

Exemplo 1 — LancamentoService:
\`\`\`typescript
@Injectable()
export class LancamentoService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly logger: LoggerService,
  ) {}

  async create(dto: CreateLancamentoDto, tenantId: string): Promise<Result<Lancamento, DomainError>> {
    try {
      const lancamento = await this.prisma.lancamento.create({
        data: { ...dto, tenantId },
      });
      this.logger.log('lancamento.created', { id: lancamento.id, tenantId });
      return right(lancamento);
    } catch (error) {
      return left(new DatabaseError(error));
    }
  }
}
\`\`\`

Exemplo 2 — ConciliacaoService:
[segundo exemplo]

Agora crie ContaService com os métodos: create, findById, findAll, update, softDelete.
`

Com dois exemplos, o modelo vai seguir o padrão de Result<T,E>, logger, tenantId e error handling sem que você precise explicar cada um.


Chain-of-thought: pensar antes de implementar

Para problemas complexos, pedir para o modelo "pensar em voz alta" antes de implementar produz resultados significativamente melhores. O modelo ativa um modo de raciocínio mais cuidadoso.

// ❌ Sem chain-of-thought — pula para código imediatamente
"Implementa o algoritmo de matching de conciliação bancária"

// ✅ Com chain-of-thought
"Antes de implementar, pense passo a passo:
1. Quais são os casos edge que podem quebrar o algoritmo?
2. Qual estrutura de dados é mais eficiente para o lookup de candidatos?
3. Como garantir que um statement não seja matched duas vezes em concorrência?

Depois de pensar, implemente a solução considerando esses pontos."

O output vai incluir a análise e depois o código. A análise frequentemente revela trade-offs que o modelo teria ignorado se fosse direto para a implementação.

💡 Dica: Para Claude especificamente, "pense passo a passo" e "antes de implementar, analise" são frases que ativam raciocínio mais cuidadoso. Use-as sempre que a tarefa envolver lógica de negócio complexa ou trade-offs de design.


Tree-of-thought: explorar antes de decidir

Para decisões de arquitetura onde não há uma resposta óbvia, peça para o modelo explorar múltiplas abordagens antes de recomendar:

"Preciso implementar rate limiting na minha API NestJS.

Explore 3 abordagens diferentes (ex: in-memory, Redis, middleware externo),
descrevendo para cada uma:
- Como funciona tecnicamente
- Prós e contras no nosso contexto (NestJS + PostgreSQL, ~10k req/min)
- Custo de implementação e manutenção

Depois das 3 análises, recomende a melhor opção com justificativa."

Output esperado:

## Abordagem 1: In-memory com Map/LRU Cache
**Como funciona:** Armazena contadores por IP/API key em memória no processo Node.js
**Prós:** Zero dependências, implementação simples, latência mínima
**Contras:** Não funciona com múltiplas instâncias (cada instância tem seu estado),
dados perdidos no restart, memória cresce com volume de IPs únicos
**Custo:** Baixo para implementar, problemático em produção com escala horizontal

## Abordagem 2: Redis com Sliding Window
[análise]

## Abordagem 3: API Gateway externo (Kong/Nginx)
[análise]

## Recomendação
Para o contexto descrito (NestJS, 10k req/min, assumindo múltiplas instâncias em prod):
**Redis com Sliding Window** é a melhor opção porque...

Role prompting: especialista no domínio certo

O modelo responde de forma diferente dependendo do papel que você define. Para código, seja específico sobre a expertise que você quer:

// ❌ Role genérico
"Você é um assistente de programação"

// ✅ Role específico
"Você é um engenheiro de backend sênior especializado em sistemas financeiros,
com experiência específica em conciliação bancária e integração com APIs de bancos
brasileiros (BB, Itaú, Bradesco). Você conhece bem os formatos OFX e CNAB240.
Seu código sempre trata valores monetários como inteiros (centavos) e
considera edge cases de fuso horário e feriados brasileiros."

O role prompt especializado produz código mais alinhado ao domínio e evita erros comuns específicos da área (como usar float para dinheiro).


Constrained output: só o que você precisa

Quando você sabe exatamente o que quer, remova o ruído:

// ❌ Gera explicação longa + código + conclusão
"Como implemento debounce em TypeScript?"

// ✅ Retorna só o código
"Implemente uma função debounce genérica em TypeScript.
Retorne APENAS o código TypeScript (sem explicação, sem comentários,
sem imports desnecessários). Tipo genérico, suporte a cancel()."
// Output direto:
function debounce<T extends (...args: unknown[]) => unknown>(
  fn: T,
  delay: number
): T & { cancel: () => void } {
  let timer: ReturnType<typeof setTimeout> | null = null;

  const debounced = (...args: Parameters<T>) => {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };

  debounced.cancel = () => {
    if (timer) {
      clearTimeout(timer);
      timer = null;
    }
  };

  return debounced as T & { cancel: () => void };
}

Anti-padrões de prompt (com antes/depois)

Anti-padrão 1: Prompt vago

// ❌ Antes — vago demais
"faz um CRUD"

// ✅ Depois — especificado
"Implementa CRUD REST para a entidade Produto com NestJS.
Schema Prisma (já existe): Product { id, name, sku, priceInCents, stock, tenantId, createdAt }
Endpoints: POST /products, GET /products (com paginação cursor), 
GET /products/:id, PATCH /products/:id, DELETE /products/:id (soft delete via deletedAt).
Validação com class-validator. DTOs separados para create e update.
Não incluir autenticação — assume que o tenantId vem do middleware (req.user.tenantId)."

Anti-padrão 2: Contexto ausente

// ❌ Antes — sem contexto de stack
"como faço paginação?"

// ✅ Depois — contexto completo
"Como implemento cursor-based pagination num endpoint GET /orders?
Stack: Express + TypeScript + Prisma + PostgreSQL.
Modelo Order tem: id (uuid), createdAt, customerId, totalInCents, status.
Quero paginar por createdAt DESC, 25 items por página.
Response esperado: { data: Order[], nextCursor: string | null }"

Anti-padrão 3: Expectativa irreal

// ❌ Antes — escopo impossível
"faz o sistema de pagamento completo para o meu app"

// ✅ Depois — dividido em incrementos
"Implementa a primeira etapa do sistema de pagamento: 
integração com Stripe para checkout único (não assinatura).
Escopo desta etapa: 
1. Endpoint POST /payments/intent — cria PaymentIntent no Stripe
2. Endpoint POST /payments/confirm — confirma pagamento e registra no banco
3. Webhook handler para eventos payment.succeeded e payment.failed

Stack: NestJS + TypeScript. Chaves Stripe via ConfigService.
Não incluir UI, email de confirmação ou lógica de reembolso — essas serão próximas etapas."

Anti-padrão 4: Prompt parede de texto

// ❌ Antes — bloco de texto corrido
"preciso que você crie um serviço de autenticação com jwt usando nestjs que
suporte login com email e senha e também com google oauth e que gere access token
e refresh token sendo que o access token expira em 15 minutos e o refresh em 7 dias
e que o refresh token seja rotacionado a cada uso e invalidado no logout e que tenha
proteção contra brute force bloqueando após 5 tentativas por 15 minutos e que use
bcrypt com salt rounds 12 para as senhas e que salve os refresh tokens no redis..."

// ✅ Depois — estruturado
"Cria AuthService em NestJS com as seguintes especificações:

**Métodos de login:**
- Email/senha
- Google OAuth (passport-google-oauth20)

**Tokens:**
- Access token: JWT, expira em 15min
- Refresh token: JWT, expira em 7 dias, rotacionado a cada uso
- Refresh tokens invalidados no logout

**Segurança:**
- Bcrypt com salt rounds 12
- Brute force protection: bloquear IP após 5 tentativas por 15min (Redis)
- Refresh tokens armazenados no Redis (não no banco)

**NÃO incluir nesta etapa:**
- 2FA, magic links, SSO corporativo

**Dependências já instaladas:**
@nestjs/passport, passport-google-oauth20, @nestjs/jwt, bcrypt, ioredis"

Anti-padrão 5: Prompt contraditório

// ❌ Antes — regras conflitantes
"faz rápido e simples mas com todos os testes e documentação completa 
e seguindo todas as melhores práticas de segurança e performance"

// ✅ Depois — prioridade explícita
"Implementa um endpoint de busca de produtos.

Prioridade 1 (não-negociável): segurança — filtro por tenantId obrigatório.
Prioridade 2 (desejável): performance — índice no campo name para LIKE queries.
Prioridade 3 (se sobrar tempo): documentação — Swagger decorators.

Se houver trade-off entre velocidade de implementação e performance,
prefira a implementação mais simples que funcione corretamente.
Testes: apenas os casos críticos (sem tenant, busca vazia, resultado paginado)."

💡 Dica: Regras conflitantes fazem o modelo tentar agradar a todos e produzir resultados mediocres em todas as dimensões. Seja explícito sobre o que é prioridade quando não dá para ter tudo.


Templates reutilizáveis

Copie e adapte esses templates para suas necessidades.

Template para nova feature

## Feature: [Nome da Feature]

**Contexto do projeto:**
Stack: [Node.js/Python/etc] + [Framework] + [Banco]
Módulo relacionado: [caminho do módulo existente]
Padrões do projeto: [link ou referência ao CLAUDE.md]

**O que precisa ser implementado:**
[Descrição objetiva do comportamento esperado]

**Inputs esperados:**
- [campo]: [tipo] — [descrição]

**Outputs esperados:**
- [campo]: [tipo] — [descrição]

**Regras de negócio:**
1. [regra]
2. [regra]

**Casos edge para tratar:**
- [caso]
- [caso]

**NÃO implementar nesta etapa:**
- [o que fica de fora]

**Testes esperados:**
- Caso feliz: [descrição]
- Caso de erro: [descrição]
- Caso edge: [descrição]

Template para bug fix

## Bug Fix

**Comportamento atual (incorreto):**
[O que está acontecendo]

**Comportamento esperado:**
[O que deveria acontecer]

**Como reproduzir:**
1. [passo]
2. [passo]
3. Resultado: [erro/comportamento incorreto]

**Contexto técnico:**
- Arquivo suspeito: [caminho]
- Stack trace (se houver):
\`\`\`
[stack trace]
\`\`\`
- Logs relevantes:
\`\`\`
[logs]
\`\`\`

**Hipótese inicial (se tiver):**
[Sua hipótese do que pode estar causando]

**Pedido:**
1. Analise o problema e confirme (ou corrija) minha hipótese
2. Implemente a correção
3. Adicione um teste que reproduz o bug (para evitar regressão)

Template para refactoring

## Refactoring: [Objetivo]

**Código atual:**
[caminho do arquivo ou cole o código]

**Problema com o código atual:**
[Por que precisa ser refatorado — complexidade, performance, manutenibilidade]

**Objetivo do refactoring:**
[O que deve melhorar ao final]

**Constraints:**
- Comportamento externo deve ser IDÊNTICO (sem breaking changes)
- Testes existentes devem continuar passando
- [outras constraints]

**NÃO refatorar:**
- [o que não deve mudar]

**Critério de sucesso:**
[Como saber que o refactoring ficou bom]

Template para geração de testes

## Gerar testes para: [arquivo/função/módulo]

**Código a testar:**
[cole o código ou informe o caminho]

**Framework de testes:** Jest + [TypeScript/etc]
**Tipo de testes:** [unitário | integração | e2e]

**Casos que DEVEM ser cobertos:**
1. Caminho feliz: [descrição]
2. Validação de input inválido: [descrição]
3. Erro de infraestrutura (ex: DB offline): [descrição]
4. [caso específico do domínio]

**Mocks disponíveis:**
- [serviço]: usar jest.mock()
- [banco]: [PrismaService mockado | testcontainers | etc]

**NÃO testar:**
- [o que está fora do escopo]

**Formato do output:**
Apenas o código TypeScript do arquivo de teste.
Um describe por função/método, it() para cada caso.

Template para documentação

## Documentação para: [módulo/função/API]

**Código a documentar:**
[caminho do arquivo]

**Audiência:**
[Dev do time | Dev externo integrando a API | Usuário final]

**Formato:**
[JSDoc inline | README.md | Swagger/OpenAPI | ADR]

**Incluir:**
- [o que deve estar na doc]
- Exemplos de uso com código real
- Casos de erro e como tratá-los

**NÃO incluir:**
- Detalhes de implementação interna
- [outras exclusões]

**Nível de detalhe:** [básico | intermediário | completo]

Resumo de bolso

  • Todo prompt de coding eficiente tem 4 componentes: Contexto, Objetivo, Constraints e Output Format — quando um falta, a qualidade cai
  • CLAUDE.md é o prompt persistente do time: escreva-o como um contrato, não como documentação
  • Few-shot (exemplos do seu padrão) é a técnica mais eficaz para gerar código consistente com o projeto
  • Anti-padrões mais comuns: prompt vago, contexto ausente e regras conflitantes — todos têm solução simples
  • Templates reutilizáveis economizam tempo e garantem que você não vai esquecer informações críticas na hora de prompting

Capítulo 17: Qualidade e Segurança no Código Gerado por IA

Existe uma armadilha sutil no desenvolvimento com IA que pega desenvolvedores experientes desprevenidos: o código gerado parece correto. Ele compila, o TypeScript não reclama, os testes básicos passam, a lógica faz sentido quando você lê. E então vai para produção.

O problema é que "parece correto" e "é seguro" são categorias completamente diferentes.


O problema real

Os modelos de linguagem foram treinados para produzir código que satisfaz a especificação imediata do prompt. Eles são excepcionais em gerar código que faz o que você pediu. O que eles não fazem de forma confiável é antecipar o que você não pediu: o atacante que vai explorar aquele endpoint, os dados de outros clientes que vão vazar, o erro que vai ser silenciosamente engolido em produção.

Vamos ver os problemas mais comuns com exemplos reais.


SQL Injection via template literals

// ❌ Código gerado por IA — parece inofensivo

// Prompt: "cria endpoint de busca de produtos por nome"
app.get('/products/search', async (req, res) => {
  const { name } = req.query;

  // IA frequentemente gera raw queries quando Prisma não é mencionado
  const query = `SELECT * FROM products WHERE name LIKE '%${name}%'`;
  const products = await db.query(query);

  res.json(products);
});

O problema: se name vier como '; DROP TABLE products; --, a tabela some. Template literals com input de usuário em queries SQL é a vulnerabilidade mais clássica e ainda é gerada regularmente por modelos de IA quando o contexto não especifica o uso de ORM ou prepared statements.

// ✅ Correto — parametrizado

// Com Prisma (recomendado)
app.get('/products/search', async (req, res) => {
  const { name } = req.query as { name: string };

  const products = await prisma.product.findMany({
    where: {
      name: { contains: name, mode: 'insensitive' },
    },
  });

  res.json(products);
});

// Com pg (raw) — quando necessário, use $1 parametrizado
app.get('/products/search', async (req, res) => {
  const { name } = req.query as { name: string };

  const result = await pool.query(
    'SELECT * FROM products WHERE name ILIKE $1',
    [`%${name}%`] // ← parâmetro separado, nunca interpolado
  );

  res.json(result.rows);
});

⚠️ Armadilha: A IA gera SQL injection com mais frequência quando você usa banco raw sem ORM, quando o prompt não menciona segurança e quando o exemplo de código no contexto usa template literals. Sempre especifique no CLAUDE.md que queries devem ser parametrizadas.


Secrets hardcoded ou logados

// ❌ Código gerado por IA — dois problemas num arquivo só

// Problema 1: secret hardcoded (comum quando IA "preenche o exemplo")
const stripeClient = new Stripe('sk_live_abc123xyz...'); // ← secret no código

// Problema 2: dados sensíveis no log (muito comum)
async function processPayment(cardData: CardData) {
  console.log('Processing payment:', cardData); // ← número de cartão no log!
  
  const result = await stripeClient.charges.create({
    amount: cardData.amount,
    source: cardData.token,
  });

  console.log('Payment result:', result); // ← response do Stripe no log (tem dados sensíveis)
  return result;
}
// ✅ Correto

// Secret via variável de ambiente, nunca no código
const stripeClient = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2024-12-18.acacia',
});

async function processPayment(cardData: CardData) {
  // Log sem dados sensíveis — apenas o que é necessário para debug
  logger.info('payment.processing', {
    amount: cardData.amount,
    currency: cardData.currency,
    // NÃO logar: cardNumber, cvv, token, customerId, email
  });

  const result = await stripeClient.charges.create({
    amount: cardData.amount,
    source: cardData.token,
  });

  // Log de resultado sem dados sensíveis do Stripe
  logger.info('payment.completed', {
    chargeId: result.id,
    status: result.status,
    // NÃO logar: result inteiro (tem dados do cartão)
  });

  return result;
}

🔧 Na prática: Adicione um hook de pre-commit com detect-secrets (open source da Yelp) para bloquear commits com secrets. Em projetos com IA gerando código, isso é especialmente importante porque a IA tende a colocar valores de exemplo que parecem keys reais.


Autorização esquecida — qualquer usuário acessa qualquer recurso

Este é o problema mais perigoso e o mais comum em código gerado por IA. O motivo é que autorização raramente está no prompt imediato ("cria um endpoint que retorna os pedidos do usuário"), mas é um requisito implícito de segurança.

// ❌ Código gerado por IA — funcionalmente correto, mas perigoso

// Prompt: "cria endpoint GET /orders/:id que retorna um pedido"
router.get('/orders/:id', authMiddleware, async (req, res) => {
  const { id } = req.params;

  // A IA busca pelo ID — mas não verifica se pertence ao usuário autenticado
  const order = await prisma.order.findUnique({
    where: { id },
  });

  if (!order) {
    return res.status(404).json({ error: 'Order not found' });
  }

  res.json(order);
});

O ataque: Um usuário malicioso autentica com sua própria conta, pega o ID de um pedido de outro cliente (IDs são sequenciais ou UUIDs previsíveis em alguns sistemas) e acessa dados que não são dele. É um ataque chamado IDOR (Insecure Direct Object Reference — Referência Direta a Objeto Insegura).

// ✅ Correto — autorização por ownership

router.get('/orders/:id', authMiddleware, async (req, res) => {
  const { id } = req.params;
  const userId = req.user.id; // vem do authMiddleware

  const order = await prisma.order.findUnique({
    where: {
      id,
      userId, // ← filtro obrigatório: só retorna se o pedido pertence ao usuário
    },
  });

  // Retorna 404 (não 403) para não revelar que o recurso existe
  if (!order) {
    return res.status(404).json({ error: 'Order not found' });
  }

  res.json(order);
});

⚠️ Armadilha: Retornar 403 (Forbidden) em vez de 404 para recursos que existem mas não pertencem ao usuário confirma para um atacante que o recurso existe. Sempre retorne 404 em casos de IDOR para não vazar informação sobre a existência do recurso.


Error handling que engole erros silenciosamente

// ❌ Código gerado por IA — errors desaparecem sem deixar rastro

async function sendNotification(userId: string, message: string) {
  try {
    const user = await userService.findById(userId);
    await emailService.send(user.email, message);
    await smsService.send(user.phone, message);
    await pushService.send(user.deviceToken, message);
  } catch (error) {
    // IA frequentemente gera catch vazio ou com console.log
    console.log('Notification failed'); // ← sem contexto, sem stack trace, sem userId
    // Nenhum re-throw, nenhum return de erro — a função retorna undefined silenciosamente
  }
}

// No chamador:
await sendNotification(userId, 'Seu pedido foi aprovado');
// Retornou? Funcionou? Não tem como saber.
// ✅ Correto — errors tratados com contexto e propagação adequada

import { logger } from '@/core/logger';
import { NotificationError } from '@/core/errors';

async function sendNotification(userId: string, message: string): Promise<void> {
  const channels = [
    { name: 'email', fn: () => emailService.send(userId, message) },
    { name: 'sms', fn: () => smsService.send(userId, message) },
    { name: 'push', fn: () => pushService.send(userId, message) },
  ];

  const results = await Promise.allSettled(channels.map(c => c.fn()));

  const failures = results
    .map((result, i) => ({ ...channels[i], result }))
    .filter(({ result }) => result.status === 'rejected');

  if (failures.length > 0) {
    // Log com contexto suficiente para debugar
    failures.forEach(({ name, result }) => {
      logger.error('notification.channel.failed', {
        userId,
        channel: name,
        error: (result as PromiseRejectedResult).reason,
      });
    });

    // Se TODOS falharam, é erro crítico — propaga
    if (failures.length === channels.length) {
      throw new NotificationError(
        `All notification channels failed for user ${userId}`,
        { userId, failures: failures.map(f => f.name) }
      );
    }
    // Se alguns falharam mas não todos — decide por contexto de negócio
    // (neste caso, logar e continuar)
  }
}

N+1 queries escondidas em loops

// ❌ Código gerado por IA — N+1 queries oculto

// Prompt: "lista todos os pedidos com informações do cliente e produtos"
async function getOrdersWithDetails(): Promise<OrderWithDetails[]> {
  const orders = await prisma.order.findMany(); // 1 query

  // IA gera o map sem perceber que está fazendo queries dentro do loop
  const ordersWithDetails = await Promise.all(
    orders.map(async (order) => {
      const customer = await prisma.customer.findUnique({ // N queries
        where: { id: order.customerId },
      });

      const items = await prisma.orderItem.findMany({ // N queries
        where: { orderId: order.id },
      });

      return { ...order, customer, items };
    })
  );

  return ordersWithDetails;
}

// Com 1.000 pedidos: 1 + 1.000 + 1.000 = 2.001 queries
// ✅ Correto — uma única query com includes

async function getOrdersWithDetails(): Promise<OrderWithDetails[]> {
  const orders = await prisma.order.findMany({
    include: {
      customer: true,  // JOIN automático pelo Prisma
      items: {
        include: {
          product: true, // JOIN aninhado
        },
      },
    },
  });

  return orders;
}

// Com qualquer volume de pedidos: sempre 1 query (ou 3 em batch, no Prisma)

Identificando N+1 gerado por IA:

O padrão mais comum é findMany() seguido de .map(async order => findUnique/findMany dentro). Qualquer vez que você ver uma query dentro de um loop ou map, questione.

// Detector simples: procure por este padrão no código gerado
const items = await repository.findMany();
const withDetails = await Promise.all(
  items.map(async (item) => {
    // ← se houver qualquer query aqui, é N+1
    const related = await otherRepository.findById(item.relatedId);
    return { ...item, related };
  })
);

💡 Dica: Em desenvolvimento com Prisma, habilite o logging de queries (log: ['query']) durante code review. Você vai ver claramente se há dezenas de queries repetidas. Em produção, use APM (Application Performance Monitoring) como Datadog ou New Relic para detectar N+1 por padrão de latência.


Por que esses problemas ocorrem sistematicamente:

Os modelos de IA otimizam para satisfazer o prompt, não para antecipar requisitos implícitos de segurança. Os problemas acima acontecem porque:

  1. SQL injection: o prompt não pede "use queries parametrizadas"
  2. Secrets hardcoded: o modelo preenche valores de exemplo que parecem reais
  3. IDOR: o prompt diz "busca o pedido por ID", não "busca o pedido do usuário autenticado"
  4. Error handling ruim: o modelo assume que erros são raros e não critica o tratamento deles
  5. N+1: o modelo pensa em termos de lógica, não em termos de I/O de banco de dados

A resposta não é parar de usar IA para código — é combinar geração com revisão estruturada. O código gerado por IA precisa de um processo de review que compensa sistematicamente os pontos cegos dos modelos.

🔧 Na prática: Crie um checklist de review específico para código gerado por IA. Itens que você revisa mecanicamente em todo PR que contém código de IA — não por desconfiança, mas porque os padrões de erro são previsíveis e o checklist torna o review mais rápido e confiável.


Resumo de bolso

  • IA gera código que compila e passa testes básicos — mas isso não é evidência de segurança; os problemas mais críticos são invisíveis para testes gerados pela mesma IA
  • Os cinco problemas mais comuns em código de IA: SQL injection por template literals, secrets hardcoded, IDOR (autorização ausente), error handling silencioso e N+1 queries em loops
  • Esses problemas são previsíveis e sistemáticos — o que permite mitigá-los com checklist de review estruturado e ferramentas automatizadas
  • IDOR é o mais perigoso: retorne sempre 404 (não 403) para não vazar existência de recursos
  • N+1 queries são detectáveis habilitando logging de queries no ORM em ambiente de desenvolvimento — faça isso durante review de código com IA

Checklist de review para código de IA

Imprima, coloque no Notion, adicione ao CONTRIBUTING.md — use antes de todo PR com código gerado por IA:

## Checklist de Review — Código Gerado por IA

### Segurança
- [ ] Todas as queries ao banco usam parametrização (sem interpolação de string)
- [ ] Dados sensíveis (CPF, cartão, senha) nunca aparecem em logs
- [ ] Cada endpoint verifica que o recurso pertence ao usuário autenticado
- [ ] Middleware de autenticação aplicado em todas as rotas protegidas
- [ ] Input validado e sanitizado antes de qualquer uso
- [ ] Sem secrets hardcoded no código (use process.env)
- [ ] Respostas de erro não expõem stack traces ou detalhes internos

### Lógica
- [ ] Edge cases tratados: null, undefined, lista vazia, valor zero
- [ ] Condições de corrida em operações assíncronas consideradas
- [ ] Transações de banco para operações que tocam múltiplas tabelas
- [ ] Rollback correto em caso de erro no meio de uma transação
- [ ] Limites de paginação definidos (sem endpoint que retorna todos os registros)

### Performance
- [ ] Sem N+1 queries (loop fazendo query individual por item)
- [ ] Índices necessários criados na migration
- [ ] Sem operações síncronas bloqueantes no caminho principal
- [ ] Tamanho de payload de resposta razoável

### Qualidade
- [ ] Nomenclatura segue as convenções do projeto
- [ ] Código morto removido (imports não usados, variáveis não usadas)
- [ ] Sem console.log de debug esquecido
- [ ] Erros tratados — não swallowed silenciosamente
- [ ] Cobertura de testes ≥ 80% para código novo

### Manutenibilidade
- [ ] Lógica complexa tem comentário explicando o "porquê" (não o "o quê")
- [ ] Sem duplicação com código já existente (verificar antes de criar)
- [ ] Dependências circulares não introduzidas

OWASP Top 10 aplicado ao código de IA

A01: Broken Access Control

// IA frequentemente esquece verificação de ownership
// Padrão seguro obrigatório:
async function verifyOwnership<T extends { userId: string }>(
  resource: T | null,
  requestingUserId: string
): Promise<T> {
  if (!resource) throw new NotFoundError();
  if (resource.userId !== requestingUserId) throw new ForbiddenError();
  return resource;
}

// Uso:
const order = await verifyOwnership(
  await orderRepo.findById(orderId),
  req.user.id
);

A02: Cryptographic Failures

// IA pode gerar hashing fraco
// ERRADO (MD5 ou SHA1 para senhas):
const hash = crypto.createHash('md5').update(password).digest('hex');

// CERTO (bcrypt ou argon2):
import bcrypt from 'bcrypt';
const hash = await bcrypt.hash(password, 12); // cost factor 12

A03: Injection

// Template literal em query = SQL injection
// NUNCA:
const result = await db.query(
  `SELECT * FROM orders WHERE status = '${status}'`
);

// SEMPRE com Drizzle (ou qualquer ORM parametrizado):
const result = await db.select()
  .from(orders)
  .where(eq(orders.status, status));

A07: Identification and Authentication Failures

// IA pode gerar JWT sem validação adequada
// ERRADO — aceitar qualquer token sem verificar expiração:
const decoded = jwt.decode(token); // sem verificar assinatura!

// CERTO:
const decoded = jwt.verify(token, process.env.JWT_SECRET!, {
  algorithms: ['HS256'],
  issuer: 'minha-api',
});

A09: Security Logging and Monitoring Failures

// IA raramente adiciona logs de segurança adequados
// Adicione sempre:
logger.warn({
  event: 'failed_login_attempt',
  email: maskedEmail,
  ip: req.ip,
  userAgent: req.headers['user-agent'],
}, 'Failed login attempt');

// Rate limiting para endpoints sensíveis
fastify.register(require('@fastify/rate-limit'), {
  routeConfig: {
    rateLimit: {
      max: 5,
      timeWindow: '15 minutes',
    }
  }
});

Testes como rede de segurança

Coverage mínimo para código de IA

// vitest.config.ts
import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    coverage: {
      provider: 'v8',
      reporter: ['text', 'lcov'],
      thresholds: {
        // Mais rigoroso para código gerado por IA
        lines: 80,
        functions: 80,
        branches: 75,
        statements: 80,
      },
      // Excluir arquivos de config e tipos
      exclude: [
        'src/db/migrations/**',
        'src/**/*.dto.ts',
        'src/types/**',
      ],
    },
  },
});

Property-based testing para edge cases

import { fc } from '@fast-check/vitest';

// Testa a função com centenas de inputs aleatórios
it.prop([fc.string(), fc.string()])(
  'deve sanitizar qualquer input de usuário sem quebrar',
  (name, email) => {
    const result = sanitizeUserInput({ name, email });
    // Invariantes que sempre devem ser verdadeiras
    expect(result.name).not.toContain('<script>');
    expect(result.name.length).toBeLessThanOrEqual(255);
    expect(result).toBeDefined();
  }
);

// Para funções numéricas
it.prop([fc.integer({ min: 1 }), fc.integer({ min: 1, max: 120 })])(
  'cálculo de parcelas sempre retorna valor positivo',
  (total, months) => {
    const installment = calculateInstallment(total, months);
    expect(installment).toBeGreaterThan(0);
    expect(installment * months).toBeGreaterThanOrEqual(total);
  }
);

Licenciamento e IP

O código gerado por IA tem copyright?

No Brasil e nos EUA, o entendimento atual (2025) é que código gerado inteiramente por IA sem criatividade humana significativa pode não ter proteção de copyright. Na prática:

  • Código que você gerou com IA e modificou substancialmente: protegido (sua criatividade)
  • Código gerado por IA e aceito sem modificação: zona cinzenta legal
  • Código que reproduz trechos de projetos open-source memorados pelo modelo: risco real

Políticas de empresa sugeridas

# ai-code-policy.yml — política para equipe

uso_aceitavel:
  - Geração de boilerplate e código estrutural
  - Testes unitários e de integração
  - Documentação técnica
  - Refactoring de código existente
  - Debugging e análise de problemas

revisao_obrigatoria:
  - Todo código gerado por IA passa por review humano antes de merge
  - Reviewer verifica se o código é original (não parece copiado de OSS)
  - Para código em áreas críticas (pagamento, auth): dois revisores

proibido:
  - Código de IA em produção sem review
  - Aceitar sugestões de código em sistemas com dados de pacientes sem revisão adicional
  - Usar código gerado sem verificar licença de dependências sugeridas

auditoria:
  - Registrar uso de IA no template de PR
  - Manter log de ferramentas usadas por sprint
  - Revisar política a cada 6 meses

Resumo de bolso

  • IA gera código funcional, não necessariamente seguro — a lacuna é real e sistemática, não ocasional
  • O checklist de review de 20 pontos é mais eficiente do que reviews ad-hoc — institucionalize-o como etapa do fluxo de PR
  • Os pontos mais críticos do OWASP que a IA erra com frequência: A01 (ownership), A03 (injection via template literal), A02 (crypto fraca) — revise especificamente esses
  • Property-based testing é a ferramenta mais eficiente para encontrar edge cases que a IA não gerou testes explícitos — adote @fast-check/vitest em módulos críticos
  • Documente o uso de IA nos PRs — é boa prática de governança e facilita auditorias futuras

Capítulo 18: O futuro próximo (2025-2027)

Prever o futuro em tecnologia é arriscado. Prever o futuro em IA é duas vezes mais arriscado. Mas existem tendências já em curso que, com alta probabilidade, vão moldar como desenvolvemos software nos próximos dois anos. Entendê-las ajuda a escolher onde investir energia agora.


Agentes autônomos de longa duração

Os agentes atuais — Claude Code, Aider, Cursor Agent — trabalham em sessões. Você dá uma tarefa, eles executam, terminam. O próximo passo já está em desenvolvimento nos principais labs: agentes que mantêm contexto por dias ou semanas, executam tarefas em background, e entregam resultados quando prontos.

Hoje (2025):
"Claude, implemente esta feature" → resultado em minutos

Próximos 2 anos:
"Agente, monitore os issues com label 'bug' e implemente correções 
para os de baixa complexidade. Quando tiver um PR pronto, me notifique 
no Slack para revisão."
→ Agente roda continuamente, entrega PRs ao longo da semana

As implicações práticas:

  • Review humano se torna o gargalo principal (não a implementação)
  • Fluxos de aprovação precisam ser redesenhados para escala
  • A habilidade de escrever specs claras vira competência central

Coding agents em CI/CD

A tendência já visível com GitHub Actions + Claude vai se tornar mainstream: agentes integrados ao pipeline que não só detectam problemas, mas os corrigem automaticamente.

# O que está vindo:
on:
  push:
    branches: [main]

jobs:
  auto-fix:
    steps:
      - name: Detectar regressões
        run: npm test
      - name: Auto-fix com agente
        if: failure()
        run: |
          agent fix-regression \
            --test-output "$TEST_OUTPUT" \
            --create-pr \
            --assign-reviewer "@team-lead"

Casos de uso que já estão emergindo em 2025:

  • Auto-refactoring: deprecações de biblioteca detectadas e corrigidas automaticamente
  • Security patches: CVEs aplicados automaticamente em dependências
  • Performance regression: identificar e reverter commits que degradaram performance
  • Dead code elimination: remover código não utilizado em PRs automáticos

Natural language como interface primária

O shift mais profundo não é técnico — é ergonômico. A interface de linha de comando e o editor de texto são 50 anos de convenção. Estamos no início de uma transição onde linguagem natural se torna a interface primária para uma parcela crescente de tarefas de desenvolvimento.

Hoje: você escreve código, IA sugere
Amanhã: você descreve intenção, IA escreve código, você verifica
Depois: você define outcomes, IA propõe e implementa, você aprova

O que isso não significa: que devs deixarão de ler e entender código. Verificar, auditar e tomar decisões sobre código gerado exige leitura proficiente. A habilidade de ler código com velocidade e precisão se tornará mais valiosa, não menos.


O dev como orquestrador de agentes

O papel está mudando de "escritor de código" para "orquestrador de sistemas de agentes". As habilidades que distinguem o dev excelente do mediano vão mudar:

Hoje valorizado:                  Amanhã mais valorizado:
├── Velocidade de digitação    →  ├── Clareza de especificação
├── Memorizar APIs             →  ├── Avaliação crítica de output
├── Conhecer sintaxe           →  ├── Design de sistemas
├── Debug linha a linha        →  ├── Definição de critérios de aceite
└── Implementar features       →  └── Coordenação de agentes

Isso não é diminuição do papel do dev. É elevação. As partes mais mecânicas da implementação serão delegadas. As partes que exigem julgamento, contexto de negócio e criatividade continuarão sendo humanas.


O que NÃO vai mudar

Independente de onde a tecnologia for, algumas coisas permanecem constantes:

Pensamento crítico e ceticismo técnico. IA gera código convincente que está errado. A habilidade de questionar, verificar e pensar "isso faz sentido?" não vai ser automatizada.

Design e arquitetura de sistemas. Decidir como dividir um sistema em partes, quais trade-offs aceitar, como um sistema vai evoluir ao longo de anos — isso exige julgamento sobre contexto de negócio, restrições de time, skills da equipe. IA pode sugerir, mas não pode decidir.

Empatia com o usuário. Entender o que o usuário realmente precisa (que frequentemente não é o que pediu), priorizar features que geram valor real, reconhecer quando uma feature "completa" ainda é uma experiência ruim — isso é profundamente humano.

Responsabilidade. Quando um sistema falha em produção, alguém precisa tomar decisões difíceis, comunicar com clareza, e consertar. Responsabilidade não é delegável para IA.


Preparando-se: onde investir agora

Skills técnicas com alto retorno (2025-2027)

Alta prioridade:
├── Prompt engineering para código (Capítulo 16)
├── Arquitetura de sistemas de agentes
├── Segurança: review de código gerado por IA
├── Observabilidade: entender sistemas que a IA construiu
└── Testes: property-based testing, mutation testing

Média prioridade:
├── MLOps básico: entender como modelos funcionam
├── RAG (Retrieval-Augmented Generation): sistemas que buscam contexto
├── Avaliação de LLMs: como medir qualidade de outputs
└── APIs de embedding e busca semântica

Monitorar:
├── Agent protocols (MCP e seus sucessores)
├── Modelos de código especializados (pequenos, velozes, offline)
└── Frameworks de orquestração multi-agente

Hábitos a cultivar agora

1. Revise todo código de IA com ceticismo ativo
   → Pergunte "o que pode estar errado aqui?"

2. Escreva specs antes de prompts
   → A qualidade do output é proporcional à clareza da spec

3. Mantenha o "músculo" de código manual
   → Reserve tempo para implementar coisas sem IA
   → Você precisa saber se o output de IA é bom

4. Documente o que a IA fez bem e mal no seu contexto
   → Seu retro de 5min diário (Capítulo 15) compila isso

5. Experimente ferramentas novas com projetos reais, não tutoriais
   → A produtividade real aparece em contextos reais

Resumo de bolso

  • Agentes de longa duração vão tornar review humano o gargalo — a habilidade de avaliar código rapidamente e com precisão será o principal diferencial
  • O CI/CD com auto-fix é a tendência mais próxima (alguns projetos já têm) — comece experimentando com GitHub Actions + Claude headless hoje
  • O dev como orquestrador valoriza especificação clara, pensamento sistêmico e avaliação crítica acima de velocidade de digitação
  • Pensamento crítico, design e empatia com usuário são as habilidades mais à prova de automação — invista nelas
  • A melhor preparação para o futuro é usar as ferramentas existentes com profundidade real em projetos reais agora

APÊNDICES


Apêndice A: Glossário

Agent (Agente): Sistema de IA que percebe o ambiente, toma decisões e executa ações de forma semi-autônoma. Diferente de um chatbot que só responde, um agente pode chamar ferramentas, escrever arquivos, executar comandos e iterar sobre os resultados.

Anthropic SDK: Biblioteca oficial da Anthropic para Python e TypeScript que facilita o acesso à API Claude. Oferece tipos, retry automático, streaming e suporte a Tool Use e Batch API.

Architect Mode (Aider): Modo do Aider onde um modelo mais capaz planeja a implementação e um modelo mais rápido executa. Divide raciocínio e codificação para melhor custo-benefício.

Autocomplete inline: Sugestão de código gerada em tempo real enquanto o dev digita, apresentada em cinza antes do cursor. Implementado pelo Copilot, Cursor e Continue.dev.

Batch API: Funcionalidade da Anthropic que processa múltiplas requests de forma assíncrona com 50% de desconto no custo. Ideal para processamento em massa (gerar docs, reviews, testes) com SLA de até 24h.

BMAD (Business Model and Architecture Document): Metodologia de prompt para planejamento de sistemas complexos com IA. Define papéis (Analyst, Architect, Dev) e fases de desenvolvimento antes de escrever código.

Cache hit: Quando uma request usa contexto já cacheado na Anthropic, reduzindo o custo em ~90% para os tokens cacheados.

Chain-of-thought (Cadeia de pensamento): Técnica de prompting que instrui o modelo a raciocinar passo a passo antes de responder, melhorando a qualidade em tarefas complexas.

CI/CD (Continuous Integration/Continuous Delivery): Prática de integrar código frequentemente (CI) e automatizar o processo de entrega (CD). GitHub Actions é o orquestrador mais comum.

CLAUDE.md: Arquivo na raiz do projeto que funciona como system prompt persistente para Claude Code. Define convenções, stack, regras de comportamento e contexto do projeto.

Claude Code: CLI oficial da Anthropic para desenvolvimento assistido por IA. Roda no terminal, tem acesso ao filesystem, executa comandos e suporta modo headless para automação em CI/CD.

Composer (Cursor): Funcionalidade do Cursor para edição simultânea de múltiplos arquivos com contexto do projeto. Ativado com Cmd+Shift+I.

Context window (Janela de contexto): Quantidade máxima de tokens que um modelo processa de uma vez. Determina quanto código/texto pode ser passado em uma única interação.

Continue.dev: Extensão open-source para VS Code e JetBrains que adiciona chat e autocomplete de IA configurável com qualquer modelo (local ou cloud).

Cursor: Editor de código baseado em VS Code com IA nativa. Inclui Composer (multi-arquivo), Agent Mode e suporte a múltiplos modelos. Configurável via .cursorrules.

.cursorrules: Arquivo de configuração do Cursor equivalente ao CLAUDE.md. Define regras de projeto, convenções de código e comportamento esperado do agente.

DORA Metrics: Quatro métricas de performance de engenharia: Deployment Frequency, Lead Time for Changes, Change Failure Rate e Time to Restore Service.

Drizzle ORM: ORM TypeScript type-safe para Node.js, alternativa ao Prisma com foco em performance e SQL próximo ao literal.

Embedding: Representação vetorial de texto que captura significado semântico. Usado em sistemas RAG para busca por similaridade.

Few-shot prompting: Técnica de incluir 2-3 exemplos do resultado desejado no prompt, antes de fazer o pedido principal. Muito eficaz para ensinar padrões de código.

Fastify: Framework web Node.js de alta performance, alternativa ao Express com validação de schema nativa e ecossistema de plugins.

Headless: Modo de execução sem interface interativa. Claude Code --headless roda em CI/CD sem input manual do usuário.

Hook (Git hook): Script executado automaticamente em eventos do Git (pre-commit, pre-push). Claude Code usa hooks para automação e controle de qualidade.

LLM (Large Language Model): Modelo de linguagem grande, como Claude, GPT-4 e Gemini. Treinado em vastas quantidades de texto para gerar linguagem e código.

MCP (Model Context Protocol): Protocolo aberto da Anthropic para conectar agentes de IA a fontes de dados e ferramentas externas (banco de dados, APIs, filesystem, etc.).

MCP Server: Servidor que implementa o protocolo MCP, expondo tools e resources para agentes de IA. Pode ser local (stdio) ou remoto (HTTP/SSE).

Neverthrow: Biblioteca TypeScript para modelar erros como valores usando o padrão Result<T, E>, evitando exceptions não tratadas.

Ollama: Ferramenta para rodar modelos de linguagem localmente. Suporta Llama, Qwen, Mistral e outros. Expõe API compatível com OpenAI.

OWASP Top 10: Lista das 10 vulnerabilidades de segurança web mais críticas, mantida pelo Open Web Application Security Project.

Plan mode: Modo do Claude Code onde o agente analisa o problema e gera um plano antes de escrever código. Permite revisão humana antes da execução.

Prompt caching: Funcionalidade da Anthropic que cacheia partes do prompt por 5 minutos, reduzindo custo em ~90% para o conteúdo cacheado em requests subsequentes.

Property-based testing: Abordagem de teste onde você define propriedades invariantes e a biblioteca (fast-check) gera centenas de inputs aleatórios para tentar violá-las.

RAG (Retrieval-Augmented Generation): Padrão arquitetural onde o modelo busca informação relevante (via embedding) antes de gerar a resposta, reduzindo alucinações.

Repo map: Representação compacta da estrutura do repositório (classes, funções, assinaturas) gerada pelo Aider para dar contexto ao modelo sem injetar todos os arquivos.

Result type: Padrão de modelagem de erros onde funções retornam Ok(value) | Err(error) em vez de usar exceptions. Implementado pelo neverthrow em TypeScript.

Skill (Claude Code): Comando customizável do tipo /nome definido em .claude/commands/. Encapsula prompts reutilizáveis para tarefas específicas do projeto.

Slash command: Comando iniciado com / no Claude Code (/review, /test, /fix) ou em ferramentas como Aider (/add, /commit).

Token: Unidade de texto processada pelo modelo. Aproximadamente 4 caracteres em inglês, 2-3 em português. Preço de API é calculado por tokens de input e output.

Tool Use (Function calling): Funcionalidade onde o modelo pode solicitar a execução de funções definidas pelo desenvolvedor, receber o resultado e continuar o raciocínio.

Tree-of-thought: Técnica de prompting que instrui o modelo a explorar múltiplos caminhos de raciocínio antes de convergir para uma resposta.

Vibe coding: Abordagem informal de desenvolvimento onde o dev descreve em linguagem natural o que quer e aceita o resultado sem revisão rigorosa. Funciona para protótipos, perigoso para produção.

vLLM: Framework de alta performance para servir modelos de linguagem self-hosted. Suporta quantização e batching eficiente.

Vitest: Framework de testes para projetos Vite/TypeScript. API compatível com Jest, mas mais rápido e integrado ao ecossistema moderno.

Windsurf: Editor de código (ex-Codeium) com foco em entender dependências do projeto via Cascade, seu sistema de IA que analisa impacto de mudanças.

WIP (Work in Progress): Trabalho em andamento. Contexto relevante em workflows ágeis para limitar trabalho simultâneo e reduzir context switching.

Worktree (Git worktree): Funcionalidade do Git que permite ter múltiplos branches em diretórios diferentes simultaneamente. Usado em workflows multi-agente para paralelizar trabalho.

Zero-retention policy: Política da Anthropic onde dados enviados via API não são usados para treinar modelos futuros, desde que ativada na conta.

Zod: Biblioteca TypeScript de validação de schema com inferência automática de tipos. Padrão para validação de input em APIs Fastify/Express modernas.


Apêndice B: Cheat Sheets

Cheat Sheet 1: Claude Code

Comandos do terminal

Comando Descrição
claude Inicia sessão interativa
claude "mensagem" Executa uma tarefa diretamente
claude --plan "tarefa" Planeja sem executar
claude --headless "tarefa" Modo não-interativo (CI/CD)
claude --output-format json Saída em JSON estruturado
claude --output-format text Saída em texto plano
claude --max-turns N Limita iterações do agente
claude --model MODEL Sobrescreve modelo padrão
claude --system-prompt FILE Lê system prompt de arquivo
claude --no-auto-approve Pede confirmação antes de ações
claude --resume SESSION_ID Retoma sessão anterior
claude config Gerencia configurações

Slash commands nativos

Comando Descrição
/help Lista todos os comandos disponíveis
/review Revisa código atual ou especificado
/test Gera ou roda testes
/fix Corrige problemas identificados
/explain Explica código selecionado
/ask "pergunta" Pergunta sem modificar arquivos
/add FILE Adiciona arquivo ao contexto
/clear Limpa o histórico da sessão
/cost Mostra custo da sessão atual
/model MODEL Troca modelo em tempo de execução
/compact Comprime o histórico para economizar tokens

Slash commands customizados (.claude/commands/)

# Criar skill custom
mkdir -p .claude/commands/
cat > .claude/commands/security-review.md << 'EOF'
Faça uma análise de segurança focada em OWASP Top 10.
Foque em: injeção, autenticação, exposição de dados, autorização.
Retorne lista priorizada de issues com severidade e correção sugerida.
EOF

# Usar a skill
claude /security-review src/modules/payment/

Estrutura do CLAUDE.md

# CLAUDE.md
## Stack e contexto
## Convenções de código  
## O que fazer / não fazer
## Estrutura de módulos
## Regras de segurança
## Padrões de teste

Flags mais úteis em CI/CD

claude \
  --headless \
  --output-format json \
  --max-turns 10 \
  --no-auto-approve \
  "sua tarefa"

Cheat Sheet 2: Cursor

Atalhos essenciais

Atalho (Mac) Atalho (Win/Linux) Ação
Cmd+K Ctrl+K Edição inline (arquivo atual)
Cmd+L Ctrl+L Abrir chat lateral
Cmd+Shift+I Ctrl+Shift+I Abrir Composer (multi-arquivo)
Cmd+I Ctrl+I Agent Mode
Tab Tab Aceitar autocomplete
Esc Esc Rejeitar autocomplete
Cmd+Shift+L Ctrl+Shift+L Adicionar seleção ao chat

@-mentions: injetar contexto

Mention Injeta
@file nome.ts Conteúdo do arquivo
@folder src/modules/ Estrutura da pasta
@web query Resultado de busca web
@docs biblioteca Documentação indexada
@git Histórico de commits
@codebase query Busca semântica no projeto
@terminal Output do terminal atual
@problems Erros/warnings do LSP

.cursorrules: diretivas úteis

# Diretivas que funcionam bem no .cursorrules

## Stack (seja explícito)
Use sempre TypeScript strict, nunca JavaScript puro.
Use Fastify, nunca Express.
Use Vitest, nunca Jest.

## Proibições (use "nunca" / "não")
Nunca use any sem comentário justificando.
Não gere console.log de debug.
Não crie arquivos fora de src/.

## Padrão de referência (use "como em")
Siga o padrão do módulo payment como referência para novos módulos.

## Output
Retorne apenas código. Sem explicações a menos que pedido.
Comentários JSDoc apenas em funções públicas de API.

Modelos e quando usar

Modelo Quando usar
cursor-small Autocomplete inline (rápido, barato)
claude-sonnet-4-5 Composer e chat (equilíbrio)
claude-opus-4-5 Problemas complexos, arquitetura
gpt-4o Multimodal, análise de imagens

Cheat Sheet 3: Aider

Comandos de sessão

Comando Descrição
/add FILE Adiciona arquivo editável ao contexto
/drop FILE Remove arquivo do contexto
/read FILE Adiciona arquivo somente-leitura
/ls Lista arquivos no contexto
/diff Mostra mudanças feitas na sessão
/commit Commit com mensagem gerada por IA
/undo Desfaz último commit do Aider
/test Roda comando de testes configurado
/run CMD Executa comando e injeta output
/ask "msg" Pergunta sem editar arquivos
/clear Limpa histórico do chat
/tokens Mostra uso de tokens
/model MODEL Troca modelo
/editor Abre editor externo para prompt
/map Mostra o repo map atual
/quit Sai do Aider

Flags de linha de comando

aider --model claude-sonnet-4-5    # modelo principal
aider --editor-model claude-haiku  # modelo para edição (architect mode)
aider --architect                  # ativa architect mode
aider --no-auto-commits            # não commitar automaticamente
aider --dirty-commits              # commitar mesmo com dirty working tree
aider --read FILE                  # arquivo somente-leitura inicial
aider --show-repo-map              # mostrar repo map e sair
aider --dark-mode                  # tema escuro
aider --vim                        # modo vim para edição
aider --yes                        # confirmar todas as ações
aider --no-stream                  # sem streaming (útil para logs)

Configuração ~/.aider.conf.yml

model: claude-sonnet-4-5
auto-commits: true
git: true
show-diff: true
dark-mode: true
stream: true
read:
  - CONVENTIONS.md

Modelos suportados

# Anthropic
aider --model claude-sonnet-4-5
aider --model claude-opus-4-5

# OpenAI  
aider --model gpt-4o
aider --model o3-mini

# Local via Ollama
aider --model ollama/qwen2.5-coder:32b
aider --model ollama/deepseek-coder-v2

# Groq (rápido)
aider --model groq/llama-3.1-70b-versatile

Cheat Sheet 4: MCP

Formato de configuração (claude_desktop_config.json)

{
  "mcpServers": {
    "nome-do-server": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-nome"],
      "env": {
        "VARIAVEL": "valor"
      }
    },
    "server-local": {
      "command": "node",
      "args": ["/caminho/absoluto/meu-server/index.js"]
    },
    "server-python": {
      "command": "python",
      "args": ["-m", "meu_server"]
    }
  }
}

Servidores MCP comuns

Server Package Para que serve
Filesystem @modelcontextprotocol/server-filesystem Ler/escrever arquivos locais
PostgreSQL @modelcontextprotocol/server-postgres Queries no banco
GitHub @modelcontextprotocol/server-github Issues, PRs, repos
Slack @modelcontextprotocol/server-slack Mensagens e canais
Brave Search @modelcontextprotocol/server-brave-search Busca na web
Memory @modelcontextprotocol/server-memory Memória persistente entre sessões
Puppeteer @modelcontextprotocol/server-puppeteer Automação de browser
SQLite @modelcontextprotocol/server-sqlite Banco SQLite local

Estrutura mínima de MCP server em TypeScript

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const server = new Server(
  { name: "meu-server", version: "1.0.0" },
  { capabilities: { tools: {} } }
);

server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [{ name: "minha-tool", description: "...", inputSchema: {...} }]
}));

server.setRequestHandler(CallToolRequestSchema, async (request) => ({
  content: [{ type: "text", text: "resultado" }]
}));

const transport = new StdioServerTransport();
await server.connect(transport);

Troubleshooting MCP

Problema Causa provável Solução
Server não aparece no Claude JSON inválido no config Validar JSON com jq . config.json
"Command not found" Path incorreto ou npx não instalado Usar caminho absoluto do node/npx
Server conecta mas tools falham Erro no handler Verificar logs em ~/Library/Logs/Claude/
Timeout na conexão Server demora a iniciar Adicionar delay ou verificar dependências
Variáveis de ambiente não chegam env não configurado Adicionar no campo env do config

Apêndice C: Templates

Template 1: CLAUDE.md para Node.js + React + PostgreSQL

# CLAUDE.md — [Nome do Projeto]

## Visão geral
[Descrição de 2-3 linhas do que o projeto faz]

Repositório: [URL]
Ambiente de desenvolvimento: Node.js 20 + React 18 + PostgreSQL 15

## Stack completa

### Backend (src/server/)
- Runtime: Node.js 20 LTS
- Framework: Fastify 4.x
- Linguagem: TypeScript 5.x (strict mode obrigatório)
- ORM: Drizzle ORM
- Validação: Zod
- Testes: Vitest + Supertest
- Auth: JWT via @fastify/jwt
- Erros: neverthrow (Result types, sem throw em lógica de negócio)

### Frontend (src/client/)
- Framework: React 18 com hooks (sem class components)
- Build: Vite
- State: Zustand (sem Redux)
- Formulários: React Hook Form + Zod
- HTTP: TanStack Query (sem fetch manual em componentes)
- Testes: Vitest + Testing Library
- Estilos: Tailwind CSS (sem CSS modules, sem styled-components)

### Banco de dados
- PostgreSQL 15
- Migrações: Drizzle Kit
- Schema: src/server/db/schema.ts
- Migrações: src/server/db/migrations/
- Convenção: tabelas em snake_case, sem plural (user, não users)

### Infraestrutura
- Docker Compose para ambiente local
- CI/CD: GitHub Actions
- Deploy: [plataforma]

## Estrutura de diretórios

src/
├── server/
│ ├── modules/ # Um subdiretório por domínio
│ │ └── {modulo}/
│ │ ├── {modulo}.controller.ts
│ │ ├── {modulo}.service.ts
│ │ ├── {modulo}.repository.ts
│ │ ├── {modulo}.dto.ts # Schemas Zod
│ │ └── tests/
│ ├── db/
│ │ ├── schema.ts
│ │ ├── migrations/
│ │ └── index.ts
│ ├── plugins/ # Plugins Fastify globais
│ └── app.ts
└── client/
├── features/ # Um subdiretório por feature
│ └── {feature}/
│ ├── components/
│ ├── hooks/
│ ├── store.ts
│ └── api.ts # TanStack Query hooks
├── components/ # Componentes compartilhados
└── main.tsx


## Convenções de código

### Nomenclatura
- Arquivos TypeScript: kebab-case (`payment-service.ts`)
- Componentes React: PascalCase (`PaymentForm.tsx`)
- Variáveis e funções: camelCase
- Constantes: SCREAMING_SNAKE_CASE
- Interfaces: prefixo I (`IPaymentRepository`)
- Types alias: sem prefixo (`PaymentStatus`)
- Enums: PascalCase (`PaymentStatus.PENDING`)

### Padrões obrigatórios

```typescript
// ✅ CERTO — Result type para erros de negócio
async function createUser(dto: CreateUserDto): Promise<Result<User, AppError>> {
  if (await this.userRepo.existsByEmail(dto.email)) {
    return err(new AppError('EMAIL_ALREADY_EXISTS'));
  }
  const user = await this.userRepo.save(dto);
  return ok(user);
}

// ❌ ERRADO — throw em lógica de negócio
async function createUser(dto: CreateUserDto): Promise<User> {
  throw new Error('Email already exists'); // NUNCA
}

// ✅ CERTO — Query parametrizada com Drizzle
const user = await db.select().from(users).where(eq(users.email, email));

// ❌ ERRADO — Interpolação de string em query
const user = await db.query(`SELECT * FROM users WHERE email = '${email}'`);

Frontend

// ✅ CERTO — TanStack Query para data fetching
function useUser(id: string) {
  return useQuery({
    queryKey: ['user', id],
    queryFn: () => api.users.getById(id),
  });
}

// ❌ ERRADO — useEffect para data fetching
useEffect(() => {
  fetch(`/api/users/${id}`).then(/* ... */);
}, [id]);

Segurança — regras invioláveis

  1. NUNCA interpoler input do usuário em queries SQL
  2. NUNCA logar dados pessoais (CPF, email em prod, cartão)
  3. SEMPRE verificar ownership antes de retornar/modificar recurso
  4. SEMPRE validar input com Zod no controller (nunca confiar no cliente)
  5. NUNCA expor stack traces em responses de produção
  6. SEMPRE usar HTTPS em URLs de redirect
  7. NUNCA commitar secrets — usar variáveis de ambiente

Testes

  • Framework: Vitest
  • Cobertura mínima: 80% para código novo
  • Factories: src/server/__tests__/factories/
  • Fixtures: src/server/__tests__/fixtures/
  • Mocks de banco: usar test database real (não mock do Drizzle)
  • Frontend: Testing Library, sem enzyme
# Rodar testes
npm test                          # todos os testes
npm test -- --coverage            # com relatório de coverage
npm test -- src/modules/payment/  # módulo específico
npm run test:e2e                  # testes end-to-end

Comandos úteis

npm run dev              # desenvolvimento (nodemon + vite)
npm run build            # build de produção
npm run db:generate      # gerar migration após mudança no schema
npm run db:migrate       # aplicar migrations
npm run db:studio        # abrir Drizzle Studio
npm run lint             # ESLint
npm run typecheck        # TypeScript sem emitir

O que você NÃO deve fazer

  • Instalar dependências sem perguntar primeiro
  • Criar arquivos fora da estrutura documentada acima
  • Usar any sem comentário explicando por quê
  • Gerar console.log de debug
  • Sugerir Express, Prisma, Redux ou Jest como alternativas
  • Criar migrations manualmente — use npm run db:generate
  • Modificar arquivos em src/server/db/migrations/ gerados automaticamente

---

## Template 2: Skill custom de code review

```markdown
<!-- .claude/commands/review.md -->
# Code Review — [Projeto]

Faça uma code review do código especificado seguindo os padrões deste projeto.

## Estrutura da review

### 1. Resumo (2-3 linhas)
O que o código faz e qual é a impressão geral de qualidade.

### 2. Issues críticos (DEVE ser corrigido antes do merge)
Para cada issue crítico:
- **Arquivo:linha** — descrição clara do problema
- Por que é um problema
- Como corrigir (com exemplo de código se relevante)

Categorias de issues críticos: segurança, bugs, dados incorretos, auth ausente.

### 3. Issues médios (DEVERIA ser corrigido)
Mesmo formato. Categorias: performance, manutenibilidade, falta de testes.

### 4. Sugestões (pode ignorar com justificativa)
Melhorias de código que não são obrigatórias.

### 5. Pontos positivos
O que foi bem feito (brevemente).

### 6. Veredicto final
- ✅ **APROVADO**: pode fazer merge
- ⚠️ **APROVADO COM RESSALVAS**: merge ok, mas corrigir issues médios logo
- ❌ **SOLICITAR MUDANÇAS**: corrigir issues críticos antes do merge

## Checklist de segurança (verificar sempre)
- [ ] Queries parametrizadas (sem interpolação de string)
- [ ] Ownership verificado antes de retornar recursos
- [ ] Autenticação aplicada em rotas protegidas
- [ ] Input validado com Zod antes de usar
- [ ] Sem dados sensíveis em logs
- [ ] Sem secrets hardcoded
- [ ] Respostas de erro não expõem internos

## Padrões do projeto a verificar
- Result types (neverthrow) em vez de throw
- Estrutura de módulos correta
- Nomenclatura seguindo as convenções
- Testes com cobertura ≥ 80%
- JSDoc apenas em funções públicas de API

Template 3: MCP server básico em TypeScript

// src/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

// Definir as tools disponíveis
const TOOLS = [
  {
    name: "get_project_status",
    description: "Retorna o status atual do projeto: PRs abertos, issues críticos, deploy status",
    inputSchema: {
      type: "object",
      properties: {
        include_details: {
          type: "boolean",
          description: "Se true, inclui detalhes de cada item",
        },
      },
      required: [],
    },
  },
  {
    name: "search_codebase",
    description: "Busca por padrões no código fonte do projeto",
    inputSchema: {
      type: "object",
      properties: {
        query: {
          type: "string",
          description: "Termo ou padrão regex para buscar",
        },
        file_pattern: {
          type: "string",
          description: "Padrão glob para filtrar arquivos (ex: *.ts)",
        },
      },
      required: ["query"],
    },
  },
] as const;

// Implementações das tools
async function getProjectStatus(includeDetails: boolean): Promise<string> {
  // Implementar aqui: buscar do GitHub API, Jira, etc.
  return JSON.stringify({
    open_prs: 3,
    critical_issues: 1,
    deploy_status: "healthy",
    last_deploy: new Date().toISOString(),
  });
}

async function searchCodebase(query: string, filePattern?: string): Promise<string> {
  const { execSync } = await import("child_process");
  const grepCmd = filePattern
    ? `grep -r "${query}" --include="${filePattern}" . 2>/dev/null | head -20`
    : `grep -r "${query}" . 2>/dev/null | head -20`;
  
  try {
    return execSync(grepCmd, { encoding: "utf-8" });
  } catch {
    return "Nenhum resultado encontrado";
  }
}

// Criar e configurar o server
const server = new Server(
  {
    name: "meu-projeto-mcp",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// Handler: listar tools disponíveis
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: TOOLS,
}));

// Handler: executar tool
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  try {
    let result: string;

    switch (name) {
      case "get_project_status":
        result = await getProjectStatus(args?.include_details as boolean ?? false);
        break;

      case "search_codebase":
        result = await searchCodebase(
          args?.query as string,
          args?.file_pattern as string | undefined
        );
        break;

      default:
        throw new Error(`Tool desconhecida: ${name}`);
    }

    return {
      content: [
        {
          type: "text",
          text: result,
        },
      ],
    };
  } catch (error) {
    return {
      content: [
        {
          type: "text",
          text: `Erro: ${error instanceof Error ? error.message : String(error)}`,
        },
      ],
      isError: true,
    };
  }
});

// Iniciar server
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP Server iniciado");
// package.json
{
  "name": "meu-projeto-mcp",
  "version": "1.0.0",
  "type": "module",
  "main": "dist/index.js",
  "scripts": {
    "build": "tsc",
    "dev": "tsx src/index.ts",
    "start": "node dist/index.js"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.0.0"
  },
  "devDependencies": {
    "typescript": "^5.0.0",
    "tsx": "^4.0.0",
    "@types/node": "^20.0.0"
  }
}
// Adicionar ao claude_desktop_config.json
{
  "mcpServers": {
    "meu-projeto": {
      "command": "node",
      "args": ["/caminho/absoluto/meu-projeto-mcp/dist/index.js"],
      "env": {
        "PROJECT_ROOT": "/caminho/do/projeto"
      }
    }
  }
}

Template 4: GitHub Action com Claude Code headless

# .github/workflows/claude-agent.yml
name: Claude Code Agent

on:
  pull_request:
    types: [opened, synchronize, labeled]
  workflow_dispatch:
    inputs:
      task:
        description: 'Tarefa para o agente executar'
        required: true
        type: string

concurrency:
  group: claude-agent-${{ github.event.pull_request.number || github.run_id }}
  cancel-in-progress: true

jobs:
  run-agent:
    name: Executar agente Claude
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
      issues: write

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          ref: ${{ github.head_ref || github.ref }}
          fetch-depth: 0
          # Token com permissão para push no branch do PR
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Instalar dependências do projeto
        run: npm ci

      - name: Instalar Claude Code
        run: npm install -g @anthropic-ai/claude-code@latest

      - name: Determinar tarefa
        id: task
        run: |
          if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
            echo "task=${{ github.event.inputs.task }}" >> $GITHUB_OUTPUT
          elif echo "${{ github.event.label.name }}" | grep -q "ai-fix"; then
            echo "task=Analise o PR e corrija todos os issues identificados na review" >> $GITHUB_OUTPUT
          elif echo "${{ github.event.label.name }}" | grep -q "ai-test"; then
            echo "task=Gere testes unitários para todos os arquivos modificados neste PR" >> $GITHUB_OUTPUT
          else
            echo "task=Faça uma review de código deste PR e poste os resultados" >> $GITHUB_OUTPUT
          fi

      - name: Executar agente Claude
        id: agent
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
          BASE_BRANCH: ${{ github.base_ref }}
        run: |
          # Configurar identidade git para commits do agente
          git config user.name "claude-agent[bot]"
          git config user.email "claude-agent[bot]@users.noreply.github.com"
          
          # Capturar contexto do PR
          DIFF=$(git diff origin/$BASE_BRANCH...HEAD 2>/dev/null | head -c 30000)
          
          # Executar o agente com a tarefa determinada
          RESULT=$(claude \
            --headless \
            --output-format json \
            --max-turns 15 \
            --no-auto-approve \
            "${{ steps.task.outputs.task }}
            
          Contexto adicional:
          - PR número: $PR_NUMBER
          - Branch base: $BASE_BRANCH
          - Diff disponível para análise (primeiros 30k chars):
          $(echo "$DIFF" | head -c 5000)
          
          Se gerar arquivos ou fazer mudanças no código:
          1. Commite com mensagem descritiva começando com 'bot: '
          2. Faça push para o branch atual
          ")
          
          echo "result<<EOF" >> $GITHUB_OUTPUT
          echo "$RESULT" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

      - name: Push mudanças (se houver)
        run: |
          if git diff --staged --quiet && git diff HEAD --quiet; then
            echo "Sem mudanças para fazer push"
          else
            git push origin HEAD:${{ github.head_ref }}
            echo "Mudanças enviadas para o branch"
          fi

      - name: Postar resultado no PR
        if: github.event.pull_request.number != ''
        uses: actions/github-script@v7
        env:
          AGENT_RESULT: ${{ steps.agent.outputs.result }}
        with:
          script: |
            const result = process.env.AGENT_RESULT;
            
            let body;
            try {
              const parsed = JSON.parse(result);
              body = parsed.result || result;
            } catch {
              body = result;
            }
            
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: `## Resultado do Agente Claude\n\n${body}\n\n---\n_Executado automaticamente via GitHub Actions_`,
            });

      - name: Atualizar status do check
        if: always()
        uses: actions/github-script@v7
        with:
          script: |
            const conclusion = '${{ steps.agent.outcome }}' === 'success' ? 'success' : 'failure';
            // Status já é atualizado pelo workflow status automaticamente
            console.log(`Agente finalizado com status: ${conclusion}`);

Apêndice D: Leituras e recursos

Documentação oficial

Recurso URL Para que serve
Anthropic Docs docs.anthropic.com API, modelos, guias de prompt
Claude Code Docs docs.anthropic.com/claude-code CLI, configuração, CLAUDE.md
MCP Specification modelcontextprotocol.io Protocolo, SDK, servers
Cursor Docs docs.cursor.com Editor, .cursorrules, features
Aider Docs aider.chat CLI, comandos, configuração
Continue.dev Docs docs.continue.dev Extensão, config.json, modelos
GitHub Copilot Docs docs.github.com/copilot Features, configuração, CLI

Blogs e newsletters

Nome URL Foco
Anthropic Blog anthropic.com/news Updates de modelos, research
Simon Willison's Blog simonwillison.net IA aplicada, ferramentas, experimentos
The Pragmatic Engineer newsletter.pragmaticengineer.com Engenharia de software + IA
AI Breakfast aibreakfast.beehiiv.com Notícias diárias de IA
Latent Space latent.space Podcast + newsletter de AI eng

Vídeos e cursos

Recurso Plataforma Conteúdo
Anthropic YouTube youtube.com/@anthropic-ai Demos, tutoriais, webinars
Cursor YouTube youtube.com/@cursor-ai Tutoriais de features
Aider YouTube (Paul Gauthier) youtube.com Demos e novidades do Aider
DeepLearning.AI — Prompt Engineering deeplearning.ai Fundamentos de prompt engineering
Full Stack LLM Bootcamp fullstackdeeplearning.com LLMs para engenheiros

Comunidades

Comunidade Plataforma Para quem
Anthropic Discord discord.gg/anthropic Usuários Claude e devs
Cursor Discord discord.gg/cursor-so Usuários do Cursor
Aider Discord discord.gg/aider Usuários do Aider
r/LocalLLaMA reddit.com/r/LocalLLaMA Modelos locais e open-source
r/ClaudeAI reddit.com/r/ClaudeAI Uso do Claude
Hugging Face Forums discuss.huggingface.co Open-source, modelos, datasets

Ferramentas complementares

Ferramenta Para que serve
Ollama (ollama.ai) Rodar modelos localmente
LM Studio (lmstudio.ai) Interface GUI para modelos locais
vLLM (github.com/vllm-project) Servir modelos em produção
Langfuse (langfuse.com) Observabilidade e tracing de LLMs
Helicone (helicone.ai) Proxy com cache e analytics para APIs LLM
PromptLayer (promptlayer.com) Versionamento e teste de prompts
Braintrust (braintrustdata.com) Avaliação de qualidade de outputs

Papers e research (para quem quer ir fundo)

Paper Onde encontrar Sobre
"Constitutional AI" (Anthropic) arxiv.org Como o Claude foi treinado
"Toolformer" (Meta) arxiv.org Fundamentos de tool use
"ReAct" arxiv.org Raciocínio + ação em agentes
"Tree of Thoughts" arxiv.org Exploração de múltiplos caminhos
"Chain-of-Thought Prompting" arxiv.org Raciocínio passo a passo

Recursos em português

Recurso URL Conteúdo
Escola de IA (Turing) escoladeia.com.br Cursos em português
Pizza de Dados pizzadedados.com Podcast sobre dados e IA
AI para Devs BR Comunidade no Discord Discussões em português sobre IA para devs

Comentários