---
title: "Como garantir que projetos muito grandes continuem evoluindo com Claude"
description: "O que aprendi quando um jogo feito por diversão passou de 40 mil linhas em dois dias, e as regras que impedem o projeto de andar para trás."
date: 2026-10-31
url: https://joaodavisn.pages.dev/projetos-grandes-com-claude/
author: joaodavisn
---

# Como garantir que projetos muito grandes continuem evoluindo com Claude

O que aprendi quando um jogo feito por diversão passou de 40 mil linhas em dois dias, e as regras que impedem o projeto de andar para trás.

![Globo de hexágonos e um astro menor gravados em linhas finas, como numa cédula, sobre papel claro](https://joaodavisn.pages.dev/projetos-grandes-com-claude/img/capa.webp)

Comecei o TERRADOME numa quinta à noite, por diversão. O primeiro pedido foi uma frase: "cria, em Rust, usando WebGPU, um minimundinho… isométrico, minimalista, meio pixelado". Dezoito minutos depois havia um globo de hexágonos girando na tela. Na mensagem seguinte veio a ideia que mudou o tamanho da coisa: "e aí que fica interessante. Quero que cada humano seja uma IA".

A partir daí fui somando:

- 27 espécies;
- um planeta de 92 mil células, com Sol, Lua e mais dois astros;
- mentes com LLM local;
- saves comprimidos;
- menus em dois idiomas;
- uma API de mods.

Em 48 horas, três fases de trabalho, com o Claude, o Codex e o Claude de novo, levaram o código a **41.926 linhas em 70 arquivos**. No meio do caminho percebi que o projeto ia parar de evoluir, e não por falta de capacidade do modelo.

Este post não é sobre o jogo. É sobre o que quebra quando um projeto feito com IA fica grande, o que investiguei e o que pus no lugar para ele continuar crescendo sem regredir. O jogo é o caso de estudo. Os números vêm da base de conhecimento do próprio projeto, e cada um cita o identificador do registro (`F-` para fatos, `E-` para experimentos), para quem quiser conferir.

## 01. Como o projeto cresceu

### De um pedido de uma linha a 70 arquivos em dois dias.

![Linha do tempo de 48 horas com os períodos de trabalho do Claude, do Codex e dos subagentes, o primeiro pedido, o primeiro commit e o momento em que o processo entrou](https://joaodavisn.pages.dev/projetos-grandes-com-claude/img/linha-do-tempo.webp)

O ritmo foi o de quem está brincando e vai se empolgando. Cada resposta abria uma ideia nova, e eu pedia a próxima antes de a anterior assentar.

| quando (Recife) | quem | o que entrou |
| --- | --- | --- |
| 29/10, 22:06 | Claude | globo hexagonal de 10.242 células em wgpu, dia e noite |
| 29/10, 23:25 | Claude | 20 mentes simultâneas num llama-server, com respostas por esquema JSON |
| 30/10, manhã | Claude | 27 espécies, crônica, sons sintetizados, materiais com propriedades |
| 30/10, 13:59 | Claude | planeta três vezes maior (92.162 células), Sol, Lua, Gaia e Rubra com gravidade |
| 30/10, 16:12 | Claude | nome, menu, saves com foto e codec próprio |
| 30/10, 16:36 | Codex | "quero continuar o trabalho do Claude… aprenda com os erros": saves, crashes, opções, tectônica, desempenho |
| 31/10, 00:10 | Claude | **primeiro commit**, 26 horas depois do primeiro pedido |
| 31/10, tarde | Claude e subagentes | reforma da interface, API de mods, e o processo descrito neste post |

O primeiro commit tinha 22.821 linhas em 36 arquivos. Vinte e duas horas depois eram quase o dobro (F-204). Pelas transcrições, os testes foram de 11 para 126 nas primeiras 36 horas. Hoje há 371 funções marcadas com `#[test]`, 99 delas na API de mods.

## 02. Os sinais de que ia parar de evoluir

### O projeto não quebrou de uma vez. Começou a esquecer, a repetir e a voltar atrás.

Nenhum sintoma, sozinho, parecia grave. Juntos, mostravam que cada sessão nova começava mais longe de onde a anterior tinha parado.

**O contexto acaba, e o que estava só nele some.** O Codex compactou a conversa 17 vezes numa sessão de cerca de 15 horas. Um minuto depois de uma dessas compactações, escrevi: "NÃO, CARA, VC VOLTOU ATRÁS". A resposta foi: "retomei um pedido antigo de documentação e ignorei o trabalho mais recente". A primeira sessão do Claude estourou o contexto duas vezes e bateu o limite de uso uma vez.

**Pedidos ficam pelo caminho.** "Faz as outras coisas lá que tinha dito, lembra?" e "e a parte de pensar? Que eu tinha dito, fez?" viraram frases comuns. O modelo Gemma estava no primeiro pedido e só voltou à mesa quando cobrei: "testou Gemma? Considerou, sequer?".

**A passagem de uma IA para outra perde quase tudo.** Quando o Codex assumiu, o primeiro documento dele registrava: "o repositório estava em main, sem nenhum commit… o histórico disponível é a transcrição". E o exportador da transcrição "trunca comandos e resultados". O que não estava em arquivo precisou ser redescoberto.

**O código se repete.** A interface parecia prolixa, e a contagem confirmou (F-074):

- 352 posições fixas na tela;
- o botão "voltar (Esc)" feito de 5 jeitos;
- 3 implementações de quebra de linha;
- 13 cortes de texto no meio da palavra;
- cerca de 634 frases soltas no código.

Cada tela nova copiava a vizinha e mudava um detalhe.

**Os experimentos se repetem.** A pasta de rodadas de teste chegou a 1.314 arquivos e 4,32 GiB (F-204), com dezenas de cópias do código salvas antes de cada tentativa. Várias rodadas de otimização mediram ganhos de 1% a 5% e foram desfeitas. Sem registro, a sessão seguinte tentaria de novo.

**Decisões antigas viram paredes.** Quando pedi que outros planetas pudessem ter vida tão complexa quanto a da Terra, a medição mostrou que o código tratava a Terra como caso especial: 70 chamadas a um raio de planeta global em 14 arquivos, 26 decisões por `== EARTH` e um motor paralelo simplificado para Gaia (F-205).

> [!NOTE]
> Nenhum desses problemas é de capacidade do modelo. São de memória e de organização. Uma sessão de IA é um trabalhador competente que chega sem lembrar de nada. O que não está escrito no repositório não existe para ela.

## 03. O repositório é a memória

### O que não está num arquivo não existe na próxima sessão.

A decisão central foi parar de tratar a conversa como lugar de memória. A conversa é descartável. A continuidade mora em arquivos que a próxima sessão lê sozinha, sem eu precisar lembrar de pedir.

| arquivo | o que guarda | quando é lido |
| --- | --- | --- |
| `CLAUDE.md` | regras curtas do projeto e onde fica o resto | toda sessão, automaticamente |
| `development/planning/TODO.md` | o que está em andamento, a fila, o backlog e o registro do que foi feito | injetado no começo de toda sessão |
| `development/knowledge/` | fatos, experimentos com veredicto, teorias e ferramentas de medição | antes de medir ou tentar qualquer coisa |
| `.claude/skills/<área>/SKILL.md` | o "profissional" de cada área: regras, gosto do dono, como verificar, lições | quando a tarefa é daquela área |
| `development/retros/` | o relatório de cada tarefa | no fechamento, e vira lição na skill |

O TODO entra no contexto por um hook do Claude Code. Ele roda no começo da sessão, lê as seções "Em andamento" e "Fila" e devolve o texto como contexto adicional:

```json
{
  "hooks": {
    "SessionStart": [{
      "hooks": [{
        "type": "command",
        "command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/sessao_inicio.py\" 2>/dev/null || true",
        "timeout": 10
      }]
    }]
  }
}
```

```python
def secao(titulo):
    m = re.search(r"^## " + re.escape(titulo) + r".*?$\n(.*?)(?=^## |\Z)", texto, re.S | re.M)
    return m.group(1).strip() if m else ""

partes = ["## Em andamento", secao("Em andamento") or "(nada)",
          "## Fila", secao("Fila") or "(vazia)"]
print(json.dumps({"hookSpecificOutput": {"hookEventName": "SessionStart",
                                         "additionalContext": "\n".join(partes)}}))
```

O `|| true` importa: um hook que falha não pode impedir a sessão de abrir. E a seção "Em andamento" diz quem está mexendo em quê. Quando outro agente trabalha no mesmo checkout, a lista de arquivos dele aparece ali, e quem chega sabe que não pode tocar neles.

> [!TIP]
> O `CLAUDE.md` deve ser curto e apontar para o resto. Regras longas no arquivo de instruções viram ruído e são as primeiras a ser ignoradas. O detalhe vai para as skills, carregadas só quando a tarefa é da área.

## 04. Medir antes de afirmar, e guardar o número num lugar só

### Um número copiado em dois documentos é um número que vai ficar velho.

Para dizer quanto o código tratava a Terra como especial, contei com `grep` na mão e escrevi "91 chamadas em 13 arquivos" em dois commits. Estava errado: a busca pegava também os métodos `.radius()` de plantas, seres e partículas. Com o critério escrito numa ferramenta, o número certo era 70 em 14 arquivos. O erro não foi apagado. A correção ficou registrada na base, ao lado da medida certa (F-205).

Daí saíram quatro regras:

1. **Medição que se repete vira ferramenta.** `development/tools/dividas.sh` mede sempre com o mesmo critério e imprime cada número ao lado do identificador do registro.
2. **O número mora só na base.** Design, TODO e skills citam `F-205`, nunca o 70.
3. **Quando o número muda, entra um registro novo**, e o antigo ganha `SUPERADO em <data> por F-xxx: <o que mudou>`. A história fica.
4. **Experimento marcado `NÃO FUNCIONOU` não se repete** sem dizer o que mudou na hipótese.

![Diagrama: a ferramenta de medição alimenta a base; design, TODO e skills apontam para o registro F-205 em vez de copiar o número](https://joaodavisn.pages.dev/projetos-grandes-com-claude/img/numero-unico.webp)

Um registro da base tem data, área, veredicto, evidência e o comando que o reproduz. Este é o da compressão dos saves (E-063), resumido:

```markdown
- **E-063** · save · **FUNCIONOU** · nível de compressão dos saves (`--save-levels`, 155,3 MB cru):
  nível 22 numa thread 72,5 MB em ~70 s; … **9 com 4 threads 78,5 MB em 0,87 s** … Abrir leva
  0,1–0,2 s em todos, e todos voltam idênticos. Escolhido nível 9 … Não voltar ao 22: ganha 8% de
  disco pagando ~80× o tempo.
```

A última frase é a mais útil. Ela existe para a próxima sessão que achar que "comprimir no máximo" é óbvio.

### A própria base precisa de conferência.

Escrevendo este post, achei seis identificadores definidos duas vezes na base: F-062, F-063 e F-093 a F-096. Cada agente tinha pegado o "próximo número livre" que leu no começo da tarefa, enquanto outro agente escrevia no mesmo arquivo. Renumerei os que não eram do agente ativo, corrigi as citações pelo assunto de cada trecho e criei `development/tools/conferir_base.py`, que falha com identificador repetido e mostra o próximo livre.

A conferência pagou o próprio custo no mesmo dia. No fechamento desta tarefa, minutos depois de eu usar os números F-101 a F-108, o agente de mods escreveu os seus F-101 a F-104. A ferramenta acusou antes do commit. Como não se mexe no trabalho de um agente ativo, os meus foram para uma faixa própria, de F-201 a F-208. As regras novas: o número se pega na hora de escrever, não no começo da tarefa; e, com dois agentes escrevendo na mesma base, cada um usa uma faixa longe da sequência do outro (F-204).

## 05. O ciclo de toda tarefa

### Começo, durante e fechamento, sempre os mesmos passos.

![Ciclo em três estações ligadas por um laço: começo, durante e fechamento, cada uma com os seus passos](https://joaodavisn.pages.dev/projetos-grandes-com-claude/img/ciclo.webp)

O ciclo mora numa skill (`terradome-tarefa`), e o `CLAUDE.md` manda carregá-la no começo e no fim de toda tarefa.

**Começo:**

- ler o que está em andamento e a fila (o hook já mostrou);
- procurar o assunto na base;
- carregar a skill da área;
- descobrir se há outro agente no mesmo checkout.

**Durante:**

- medir em vez de supor;
- registrar na base na hora, com o comando que reproduz;
- anotar cada intervenção minha com as minhas palavras.

**Fechamento**, que é um checklist que não se pula:

- testes;
- conferência dos saves se mudou tipo serializado;
- nenhum aviso novo de compilação;
- capturas nos dois idiomas se mexeu em interface;
- revisão de duplicação no diff;
- base atualizada;
- TODO e registro;
- relatório da tarefa;
- lição na skill da área;
- commit só dos arquivos da tarefa.

Por que um checklist escrito? O modelo tende a pular o passo que considera feito. "Os testes devem passar" vira "os testes passaram" sem ninguém rodar. Uma lista curta numa skill carregada no fim custa poucos tokens e pega exatamente esse tipo de atalho.

> [!IMPORTANT]
> O relatório de cada tarefa diz com clareza o que **não** foi verificado. Isso pesa mais que a lista do que deu certo. Uma afirmação sem verificação, repetida por três sessões, vira fato no projeto.

## 06. Skills como profissionais

### Cada área tem um especialista que lembra o gosto do dono.

O projeto tem quatro skills, que chamo de profissionais:

- **`terradome-tarefa`:** o ciclo e o versionamento;
- **`terradome-ui`:** telas, textos e idiomas;
- **`terradome-desempenho`:** medir e otimizar;
- **`terradome-mods`:** a API de mods.

Cada uma traz quatro coisas:

- onde fica cada coisa;
- as regras de código que não se negociam;
- o meu gosto, aprendido;
- uma seção de lições, a mais nova em cima, com data e origem.

O gosto escrito poupa a mesma correção duas vezes. Na skill de interface, por exemplo:

```markdown
- **Ele confere no detalhe do pixel:** margens iguais em volta de um elemento, derivadas de uma medida
  só (tecla de atalho: margem direita = margem de cima e de baixo).
- **Texto curto e direto:** "salvando estado atual…" em vez de "salvando antes de voltar ao menu"; sem
  subtítulo que explica o óbvio.
```

Uma skill nova nasce quando:

- um tipo de pedido aparece em três ou mais relatórios;
- uma área junta cinco ou mais lições;
- eu corrijo a mesma coisa duas vezes.

A skill de mods nasceu assim, quando a API passou a ocupar sessões inteiras.

## 07. Como o Claude aprende com os erros

### Um erro só ensina quando vira regra e, se der, ferramenta.

![Quatro etapas num trilho: o erro, o relatório que registra a causa, a regra na skill e a ferramenta que impede a repetição](https://joaodavisn.pages.dev/projetos-grandes-com-claude/img/erro-vira-regra.webp)

O exemplo da figura aconteceu nesta mesma sessão. Num checkout com dois agentes, um commit levou o arquivo da base inteiro, com quatro fatos que eram do outro agente e ainda não estavam prontos. A conferência antes do commit tinha impresso `False`, e o commit saiu mesmo assim.

O relatório registrou a causa real, que não era "esqueci de olhar", e sim "a conferência falhou e eu segui". Disso saíram duas coisas:

- **a regra na skill:** conferência que falha barra o commit;
- **a ferramenta `preparar_trechos.py`:** põe no índice do git só os trechos de um arquivo que casam com a marca da tarefa e lista o que ficou de fora.

O modelo do relatório tem seções fixas:

- pedido;
- o que foi feito;
- verificação, inclusive o que não foi verificado;
- acertos;
- erros e correções;
- intervenções do usuário, citadas com as palavras dele;
- o que ele pediu diferente;
- o que ele incentivou;
- lições e onde ficaram.

As duas seções sobre o que eu pedi e incentivei são as que mais rendem, porque o gosto está nas palavras exatas:

| o que eu disse | no que virou |
| --- | --- |
| "o espaço na direita do botão de atalho é menor que o espaço vertical, deixa igual" | regra de margens derivadas de uma medida só, na skill de interface |
| "não precisa desse textão, pode ser só 'Salvando estado atual…'" | regra de texto curto; a tela de espera perdeu o subtítulo |
| "ficou salvando e não sai mais" | a medição de 70,2 s por save (F-073) e a troca do nível de compressão (E-063) |
| "depois de descobrir isso, já deixa anotado, pra caso outro Claude vá procurar a mesma coisa" | toda medida vai para a base na hora, com o comando, e é atualizada quando muda |
| "sempre que compilo tem vários erros e coisas estranhas; não gosto disso" | meta de zero avisos; tarefa nenhuma aumenta o número (F-206) |
| "o seu tá com muito cara de Claude" | este post segue o estilo do meu laboratório, não o visual padrão do modelo |

> [!WARNING]
> O relatório e a lição são escritos pelo mesmo modelo que errou. Ele tende a descrever o erro com gentileza e a lição de forma genérica. Vale exigir a causa concreta e o destino da lição (qual skill, qual regra, qual ferramenta). Lição sem destino não muda a próxima sessão.

## 08. Uma implementação, muitos usos

### Duplicação não é questão de estética: é o que faz a décima tela sair errada.

![Quatro painéis comparando antes e depois: posições fixas de 352 para 12, jeitos de fazer o voltar de 5 para 1, quebras de linha de 3 para 1, cortes no meio da palavra de 13 para 0](https://joaodavisn.pages.dev/projetos-grandes-com-claude/img/duplicacao.webp)

A reforma da interface trocou cópias por três lugares comuns:

- **Um kit de componentes** (`widgets.rs`): botão de voltar, ajuste de texto com reticências, quebra de linha, recorte do que passa do painel e cores por papel.
- **Catálogos de texto** (`i18n/`), com uma chave por frase e o idioma trocado na hora. O espanhol entra como mais um catálogo, sem tocar nas telas.
- **Um tema.**

A regra no `CLAUDE.md` é curta: antes de escrever, procurar se já existe; na segunda vez que a mesma lógica aparece, extrair para o lugar comum e trocar os dois usos.

| antes | depois |
| --- | --- |
| ![Lista de saves antiga: botões soltos embaixo de cada item, título pequeno, voltar em texto](https://joaodavisn.pages.dev/projetos-grandes-com-claude/img/antes-lista-de-saves.webp) | ![Lista de saves nova: botões alinhados numa coluna, título grande, voltar com a tecla em destaque, texto longo terminando em reticências](https://joaodavisn.pages.dev/projetos-grandes-com-claude/img/depois-lista-de-saves.webp) |

A diferença visível é pequena. A que importa é a seguinte: a próxima tela já nasce com o mesmo botão, o mesmo corte de texto e as mesmas margens, porque não há outro jeito de fazer.

## 09. Desempenho: medir sem se enganar

### O que parecia lento não era o que estava lento.

A meta é 120 FPS com o tempo do jogo em 30x. A intuição dizia que o gargalo era o desenho de um planeta de 92 mil células. A medição disse outra coisa (F-078).

![Barra de um quadro de 49,4 ms: simulação 40,0 ms, render e GPU 6,8 ms, o resto 2,6 ms; linhas de 8,3 ms para 120 FPS e de 16,7 ms para 60 FPS](https://joaodavisn.pages.dev/projetos-grandes-com-claude/img/quadro.webp)

O método que funcionou tem três camadas:

1. **Tempo por fase do quadro, sem janela** (`--benchmark`): separa simulação, malhas, interface e render.
2. **Tempo por trecho da simulação** (`MINIMUNDO_PROFILE=1`).
3. **Amostragem do processo rodando** (`sample` do macOS), para achar a função quente.

O amostrador atribuía quase tudo a uma única função, porque o compilador embute as menores. Para separar, valeram marcadores de tempo temporários dentro do trecho suspeito. Assim apareceu a leitura de marcas: 114 µs por chamada, 85% do trecho, porque percorria todas as marcas do mundo a cada leitura (F-079). Os marcadores saíram depois da medição.

> [!IMPORTANT]
> Meça no mundo real de quem usa, não só no de teste. O mundo de referência, no dia 93, escondia o custo das marcas, que cresce com a idade do mundo. No save mais antigo, no dia 3.846, ele era o maior custo isolado (E-064).

O save que "travava" é o mesmo tipo de lição. O jogo comprimia com zstd no nível 22, numa thread só, por padrão. No mundo maior, gravar levava 70,2 s, e a tela de espera parecia congelada (F-073). A curva de níveis mostrou o preço do máximo:

![Dois painéis: tempo para gravar e tamanho no disco por nível de compressão; o nível 9 grava em 0,87 s com 78,5 MB, o 22 em 64,6 s com 72,5 MB](https://joaodavisn.pages.dev/projetos-grandes-com-claude/img/compressao.webp)

| nível do zstd, 4 threads | tempo | tamanho |
| --- | ---: | ---: |
| 3 | 0,17 s | 84,5 MB |
| **9 (escolhido)** | **0,87 s** | **78,5 MB** |
| 15 | 6,0 s | 76,5 MB |
| 19 | 28,5 s | 73,4 MB |
| 22 | 64,6 s | 72,5 MB |

O save completo passou de 70,2 s para 3,8 s, com 8% a mais de disco (E-063).

## 10. Vários agentes no mesmo checkout

### Paralelismo acelera; sem regras, um agente desfaz o outro.

![Tela do Mac com várias janelas de terminal do Claude Code abertas ao mesmo tempo: a API de mods, o roteiro do vídeo, o custo do dia e outras conversas, com o texto pixelado](https://joaodavisn.pages.dev/projetos-grandes-com-claude/img/tela-terminais-pixelada.webp)

É assim que fica a tela quando estou fazendo mil coisas ao mesmo tempo:

- um agente na API de mods;
- outro no roteiro do vídeo de anúncio;
- outro medindo o custo do dia;
- subagentes rodando por baixo de cada um.

Vai rápido, e é exatamente aí que um passa por cima do outro.

![Dois trilhos, um por agente, com arquivos separados, que se juntam num só antes de chegar à main](https://joaodavisn.pages.dev/projetos-grandes-com-claude/img/agentes.webp)

O que funcionou:

- **Base comum pronta, testada e congelada antes de dividir.** Componente novo que dois agentes vão usar é feito antes, por um só.
- **Assinaturas combinadas e arquivos separados por agente.** A lista de arquivos de quem está trabalhando fica em "Em andamento", no TODO.
- **O relatório de cada agente salvo em arquivo assim que chega.** O resumo que um subagente devolve existe só na conversa de quem o chamou.
- **Commit só dos próprios trechos** em arquivos compartilhados como a base e o TODO, com `preparar_trechos.py` e conferência do índice antes.
- **Branch por tarefa sem trocar arquivos no checkout compartilhado:** commit na branch e avanço da main só depois dos testes.

O próximo passo são worktrees: cada agente na sua pasta e na sua branch, e a pasta principal só junta o trabalho (é onde eu jogo). Ainda não migrei, porque o motor de som mora numa pasta vizinha e o build de cada worktree dependeria dela. Esse item está na fila.

## 11. O custo de fazer algo bom

### Um teste aqui e ali sai barato. Fazer direito, e manter, não.

![Dois painéis: custo por dia do Claude Code, de US$ 25 em 29/10 a US$ 367 em 31/10, e a divisão por tipo de token, com leitura de cache em 49%](https://joaodavisn.pages.dev/projetos-grandes-com-claude/img/custo.webp)

Desenvolver um projeto grande assim não é barato. Numa sessão pedi ao Claude para puxar o custo do dia nos registros locais. Depois transformei a conta numa ferramenta do projeto (`development/tools/custo_claude.py`). Em preço de API, os três dias de Claude Code no TERRADOME somaram perto de **US$ 500** em 3.603 chamadas (F-203):

| dia | chamadas | US$ |
| --- | ---: | ---: |
| 29/10 (duas horas de trabalho) | 148 | 24,85 |
| 30/10 | 769 | 107,66 |
| 31/10, até as 22h, com subagentes | 2.685 | 367,26 |

Metade do dinheiro não foi para escrever código. Foi para **reler contexto**: 1,21 bilhão de tokens lidos do cache para 6,0 milhões escritos, cerca de 200 para 1. Cada passo de uma sessão longa relê tudo o que veio antes, e cada agente em paralelo multiplica isso. O Codex, que trabalhou no meio, fica fora da conta, e a conversa dele sozinha passou de 265 milhões de tokens.

As alavancas que a medição mostrou:

- **Sessões mais curtas** ou compactadas antes, e menos agentes ao mesmo tempo, pesam mais do que cortar a saída.
- **Modelo mais caro só onde ele faz diferença.**
- **Ler trechos de arquivo em vez de arquivos inteiros.**

O que não compensou: filtrar a saída do shell. O que as ferramentas devolvem ao contexto é quase todo leitura de código, pela ferramenta de leitura ou pelo próprio shell. `cargo` e `git` somaram menos de 1% do shell. A economia estimada era de 2% a 4%.

> [!CAUTION]
> Os valores são o equivalente em preço de API, contados nos registros locais do Claude Code desta máquina. Assinatura não cobra por token, o Bedrock tem tabela própria, e o claude.ai e outras máquinas ficam de fora.

### Gosto é a parte que não dá para delegar.

O dinheiro é a parte fácil de medir. Fazer um teste aqui e ali até vai. Agora, se aplicar a fazer algo bom demora, é caro e exige muita pesquisa, base técnica e gosto pessoal.

A IA produz coisas plausíveis em minutos. O trabalho que sobra para mim é saber dizer:

- o que é bom e entra;
- o que é lixo e sai;
- o que nem deve ser considerado.

Os sons da primeira versão estavam horríveis e a música estava perfeita, e só eu podia separar uma coisa da outra. O texto da tela de espera era longo demais. As primeiras figuras deste post estavam com cara de modelo, não de laboratório.

Cada uma dessas correções custou uma rodada inteira de trabalho. Registrar o gosto nas skills é o que faz a mesma correção não custar duas.

### A IA amplifica o que você sabe.

Ter contexto é o que separa um resultado bom de um plausível, e contexto se ganha aprendendo de fato. Tem coisa que só você, fuçando e buscando, vai aprender. A IA é muito boa em amplificar o que você sabe. Se você é muito limitado num assunto, ela amplifica essa limitação, e não necessariamente expande os seus horizontes.

Neste projeto, as melhores viradas vieram de coisas que eu já carregava:

- **A pergunta sobre o Gemma** ("testou Gemma? Considerou, sequer?") só existiu porque eu conhecia as opções de modelo local.
- **As figuras** só deixaram de ter cara de modelo quando eu apontei o meu laboratório e o shader que estava numa pasta do meu SSD.
- **A hipótese da próxima seção** veio de outro trabalho meu.

O modelo responde muito bem à pergunta que você sabe fazer.

## 12. O que vem a seguir: ler menos

### O mais importante não é como guardar a informação, e sim saber qual trazer.

Metade do custo é reler contexto (F-203). Tudo o que entra na conversa é pago de novo em cada chamada seguinte, até a próxima compactação. Antes de mudar qualquer coisa, medi de onde vem o que as ferramentas põem no contexto e quanto disso é relido (F-209):

![Barras da parte do que é relido por origem: shell de leitura 72%, ferramenta Read 11%, outros comandos do shell 11%, outras ferramentas 6%](https://joaodavisn.pages.dev/projetos-grandes-com-claude/img/leituras.webp)

| origem | resultados | caracteres | parte do que é relido |
| --- | ---: | ---: | ---: |
| shell de leitura (`sed`, `cat`, `grep`, `ls`) | 2.091 | 7,8 M | 72% |
| ferramenta `Read` | 355 | 1,8 M | 11% |
| outros comandos do shell | 1.438 | 1,7 M | 11% |
| outras ferramentas e subagentes | 308 | 0,3 M | 6% |

Três coisas saltam:

- **Os resultados de ferramenta são cerca de 23% de tudo o que se lê do cache.** O resto é o prompt do sistema, as instruções, as skills e a própria conversa. Ler menos ajuda, mas sessões mais curtas também.
- **A maior parte da leitura passa pelo shell**, aos pedaços (`sed -n`, `grep`), muitas vezes por tarefa, e não pela ferramenta de leitura.
- **112 vezes o Claude abriu um arquivo que já tinha lido na mesma conversa.**

### Um insight do meu trabalho principal.

O próximo passo veio de outro projeto, do meu trabalho principal na Supersonic Labs. Ter isso em mente me ajudou nas conjecturas daqui. Lá, uma ideia guia tudo: mais importante do que saber puxar informação é saber qual informação puxar, e puxar rápido. A inteligência está em escolher o que trazer, não em como trazer ou armazenar.

Traduzindo para um repositório:

- **Guardar tudo bruto e organizar em pedaços menores.** O código e os documentos ficam como estão. Por cima, um índice de pedaços pequenos (uma função, uma seção, um registro da base), cada um com um resumo e a origem.
- **Índice antes do texto.** A busca vai primeiro no índice e só desce ao arquivo quando precisa do detalhe. Nada de carregar a pasta inteira: o trecho certo, sob demanda.
- **Fato substituído não some.** A base deste projeto já faz isso à mão: o registro antigo ganha `SUPERADO em <data>` e aponta para o novo. Um índice que entende tempo é a versão automática disso.

Antes de qualquer modelo, há passos baratos:

- ler trechos com intervalo de linhas em vez de arquivos inteiros;
- não reabrir o que já está no contexto;
- manter nas skills o mapa de onde fica cada coisa;
- fechar a sessão quando a tarefa fecha.

### A hipótese: um classificador decide o que o Claude lê.

Antes de abrir qualquer arquivo, o Claude monta um pedido curto: o que procura e para quê. Um modelo de classificação local escolhe quais arquivos ou trechos servem, e só então o Claude lê de fato. Se funcionar, cai o que entra no contexto, e cai junto tudo o que seria relido depois.

O [Julia 1](https://huggingface.co/SupersonicLabs/Julia-1), o modelo de decisão do laboratório, foi feito para esse tipo de escolha. Ele recebe um contexto, uma pergunta e de 2 a 20 opções, escolhe uma e roda em CPU, com 144 milhões de parâmetros e cerca de 33 ms por decisão num M4, na medição publicada. Seria o porteiro do contexto.

Os riscos já aparecem nos números do próprio modelo:

- **Listas longas de opções parecidas são o ponto fraco.** Num teste de 72 categorias, com uma etapa que reduz a lista antes da escolha, ele acertou 64 de 100, contra 87 da referência. Um repositório tem centenas de arquivos, então a escolha teria de ser em degraus: pasta, arquivo, trecho.
- **O pedido inteiro cabe em 1.024 tokens.** Cada opção teria de ser um resumo curto, não o arquivo.
- **Errar custa mais do que ler.** Se o trecho certo ficar de fora, o Claude age sem a informação. Com confiança baixa, a busca normal continua valendo.

Como vou medir:

- as mesmas tarefas com e sem o classificador;
- tokens lidos do cache por tarefa;
- número de leituras e de releituras;
- se os trechos escolhidos tinham o que a tarefa precisava;
- se a tarefa saiu certa.

A linha de base é a F-209, que `custo_claude.py --leituras` refaz a qualquer momento.

> [!NOTE]
> É hipótese. Nesta seção, só a linha de base foi medida.

## 13. O que ainda não resolvi

### Limites, ditos com clareza.

- **O código acumulado ainda não está todo versionado.** São 64 entradas sem commit, que misturam três origens. O commit de base espera o agente de mods terminar.
- **Ainda há avisos de compilação:** 11 (F-206). A regra de zero avisos vale para o código novo; os antigos estão na fila.
- **A Terra ainda é caso especial** (F-205). O princípio "todo astro é um mundo completo" está escrito, e o caminho está no backlog.
- **A meta de desempenho não foi cumprida no mundo mais antigo:** o quadro está em 49 ms contra os 8,3 ms de 120 FPS. A meta de 90x ficou adiada.
- **O processo custa tokens.** Todo fechamento lê e escreve vários arquivos, e a base cresce. Ela vai precisar de poda: registros superados reunidos, áreas resumidas.
- **Relatórios e lições são escritos pelo modelo que errou.** A minha revisão continua necessária.
- **A busca local antes da leitura é hipótese.** Só a linha de base foi medida (F-209).
- **Os números do começo do projeto vêm das transcrições,** levantados por um subagente e não reconferidos um a um: as 17 compactações do Codex e a contagem de testes de 11 a 126.

## 14. Para levar para o seu projeto

### Uma lista curta, do sintoma à prática.

| sintoma | prática | onde mora |
| --- | --- | --- |
| a sessão nova não sabe o que estava em andamento | TODO fixo injetado por hook no começo da sessão | `TODO.md` e hook `SessionStart` |
| a mesma medição feita de novo, com número diferente | ferramenta com critério escrito; número só na base, citado por identificador | `knowledge/` e `tools/` |
| experimento que falhou volta a ser tentado | veredicto `NÃO FUNCIONOU` e a regra de dizer o que mudou na hipótese | `EXPERIMENTOS.md` |
| a mesma correção de gosto, de novo | o gosto escrito na skill da área, com as palavras do dono | `.claude/skills/<área>/` |
| erro que se repete | relatório com a causa concreta, a regra e, se der, uma ferramenta | `retros/` e as lições da skill |
| a décima tela sai diferente das outras | kit de componentes e catálogos de texto; extrair na segunda repetição | `widgets.rs` e `i18n/` |
| um agente desfaz o outro | base congelada, arquivos disjuntos, commit só dos próprios trechos | "Em andamento" e `preparar_trechos.py` |
| identificador repetido na base | pegar o número na hora de escrever e conferir no fechamento | `conferir_base.py` |
| a conta chega e ninguém sabe de onde | medir o custo por dia e por tipo de token | `custo_claude.py` |
| metade do custo é reler contexto | medir o que entra e é relido; ler trechos; sessões curtas; depois, escolher o que ler antes de ler | `custo_claude.py --leituras` |
