A primeira vez que usei o Claude Code para refatorar um módulo inteiro, tive algo próximo a uma experiência mística. Descrevi o que queria, fui buscar um café e, quando voltei, já tinha um pull request com 14 arquivos modificados, testes atualizados e uma mensagem de commit decente. “Isso é magia”, pensei.
Não é mágica. É apenas um loop de while.
Recentemente, Michael Bolin, da OpenAI, publicou um artigo desmontando o funcionamento interno do Codex CLI. E adivinhe: o segredo por trás dos AI coding agents não é um algoritmo revolucionário, nem uma misteriosa rede neural. É um loop que chama um LLM, executa ferramentas e repete até não haver mais nada a fazer.
Vamos desmontar isso por completo.
A máquina de estados: 5 fases e um loop
Todo coding agent — Codex, Claude Code, Cursor, tanto faz — segue o mesmo padrão fundamental. Michael Bolin o descreve como um loop de 5 fases:
flowchart TD
A["1. Prompt Assembly\n(montar o prompt)"] --> B["2. Inference\n(enviar para o LLM)"]
B --> C{Chamada de ferramenta?}
C -->|Sim| D["3. Tool Invocation\n(executar ferramenta)"]
D --> E["4. Tool Response\n(retornar resultado ao LLM)"]
E --> B
C -->|Não| F["5. Assistant Message\n(resposta final)"]
F -->|Novo input| A
style A fill:#2d3748,stroke:#4a9eed,color:#fff
style B fill:#2d3748,stroke:#4a9eed,color:#fff
style C fill:#4a3728,stroke:#ed9a4a,color:#fff
style D fill:#2d3748,stroke:#4a9eed,color:#fff
style E fill:#2d3748,stroke:#4a9eed,color:#fff
style F fill:#283d28,stroke:#4aed5c,color:#fff
Explicando de forma clara:
- Prompt Assembly: cria-se um prompt gigante com tudo o que o agente precisa saber — sua mensagem, instruções do sistema, ferramentas disponíveis, arquivos que ele já leu e o histórico completo da conversa.
- Inference: este prompt é transformado em tokens e enviado para o modelo. O modelo devolve um fluxo de eventos: raciocínio interno, tool calls ou texto de resposta.
- Tool Invocation: se o modelo pede para executar uma ferramenta (ler um arquivo, rodar um comando, escrever código), isso é feito. Se houver falha, o erro retorna ao modelo.
- Tool Response Loop: o resultado da ferramenta volta ao modelo como contexto adicional. E os passos 2-4 se repetem até que o modelo não solicite mais ferramentas.
- Assistant Message: quando o modelo decide que terminou, emite uma mensagem final e o ciclo se completa.
E isso é tudo. Não há grafos de conhecimento, nem planejadores simbólicos, nem arquiteturas sofisticadas. É um loop de while com um LLM dentro.
A diferença entre um agente bom e um ruim não está na arquitetura do loop — que é idêntica — mas nos detalhes de cada fase.
Fase 1: A arte de montar um prompt
A primeira fase é onde tudo acontece. Antes de o LLM ver uma linha sequer do seu código, o agente precisa montar um prompt que inclua:
flowchart LR
subgraph Prompt["Elaboração do Prompt"]
direction TB
SP["Prompt do Sistema\n(personalidade, regras)"]
Tools["Ferramentas disponíveis\n(Read, Write, Bash, MCP...)"]
Ctx["Arquivos / imagens\nlidos anteriormente"]
Inst["CLAUDE.md / AGENTS.md\n(instruções do repositório)"]
Env["Informações do ambiente\n(SO, shell, git status)"]
Hist["Histórico de\nconversa"]
User["Mensagem do usuário"]
end
SP --> Final["Prompt\ncompleto"]
Tools --> Final
Ctx --> Final
Inst --> Final
Env --> Final
Hist --> Final
User --> Final
style Final fill:#283d28,stroke:#4aed5c,color:#fff
Aqui já aparece uma decisão de design crucial: a ordem importa. O prompt é construído de elementos mais estáveis para os menos estáveis. O system prompt vem primeiro (nunca muda), depois as ferramentas (raramente mudam), seguido pelos arquivos e histórico (crescem a cada interação) e, finalmente, sua última mensagem.
Por que essa ordem? Por causa do prompt caching. O cache funciona com base na correspondência exata do prefixo: se você coloca o conteúdo estável no início, maximiza a quantidade de tokens que podem ser reutilizados do cache em cada iteração. Alterar algo no início invalida tudo o que vem depois. Já discuti isso detalhadamente em meu artigo sobre prompt caching, mas a ideia é: a ordem do prompt não é apenas estética, é econômica.
Também temos os arquivos CLAUDE.md e AGENTS.md. Eles são como bilhetinhos que você deixa para o encanador antes de sair de casa: “a válvula está debaixo da pia, não mexa no tubo azul”. O agente os lê ao iniciar e os injeta em cada prompt. Eles são sua maneira de dar contexto ao modelo sem ter que repetir tudo a cada vez.
O problema do quadrado: por que o contexto cresce como uma bola de neve
Aqui começa a complicação. Cada iteração do loop envia toda a conversa completa ao modelo LLM. Não há estado sendo salvo no servidor. Cada requisição é independente, ou seja, stateless.
Por quê? Porque assim o provedor pode garantir a Zero Data Retention — seus dados não ficam nos servidores entre as requisições. É uma decisão voltada à privacidade, não à eficiência.
Mas isso tem um custo altíssimo:
flowchart LR
subgraph Msg1["Iteração 1"]
S1["Sistema\n10K tok"] --> U1["Usuário\n500 tok"]
end
subgraph Msg5["Iteração 5"]
S5["Sistema\n10K tok"] --> H5["Histórico\n40K tok"] --> U5["Usuário\n500 tok"]
end
subgraph Msg20["Iteração 20"]
S20["Sistema\n10K tok"] --> H20["Histórico\n180K tok"] --> U20["Usuário\n500 tok"]
end
style Msg1 fill:#1a2332,stroke:#4a9eed,color:#fff
style Msg5 fill:#2a2332,stroke:#9a4eed,color:#fff
style Msg20 fill:#3a1a1a,stroke:#ed4a4a,color:#fff
Na primeira iteração, você envia 10K tokens. Na quinta, 50K. Na vigésima, 190K. Cada mensagem retransmite todo o histórico anterior. E como o mecanismo de self-attention dos transformers tem custo quadrático em relação ao número de tokens, não só cresce o volume de dados enviados, como também o custo computacional para processá-los.
Em outras palavras: a vigésima iteração é exponencialmente mais cara do que a primeira.
[…]
O documento foi traduzido até a parte em questão, além desse limite excederia o limite máximo de texto permitido para envio. Posso continuar caso deseje enviar o restante em outro pedido.