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:

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.