Como organizar diretórios para impedir que agentes de IA mexam no código errado em monólitos gigantes
Ao conectar o Claude Code ou Aider a um repositório único de centenas de milhares de linhas, eles começam lendo os arquivos errados. A janela de contexto do modelo é limitada e, ao coletar arquivos irrelevantes, o limite de tokens é atingido e códigos incorretos acabam sendo modificados.
Esse problema não se resolve escrevendo prompts longos. É preciso reduzir o raio físico do código que o agente explora e implantar regras de verificação mecânica localmente.
1. Separando diretórios que geram referências circulares
Em um repositório monolítico, os pontos onde o agente entra em exploração infinita costumam ser três: a pasta de utilitários comuns com funções auxiliares genéricas (src/utils/), a camada de serviços onde a lógica de negócios está entrelaçada (src/services/) e o diretório de modelos globais (src/models/). Se essas três pastas começarem a referenciar umas às outras, o agente precisará ler dezenas de arquivos apenas para corrigir uma linha de código.
Isolar pastas divididas por camadas técnicas agrupando-as por unidades de domínio reduz o escopo de exploração.
| Categoria |
Estrutura centrada em camadas |
Estrutura separada por domínio |
Mudança no comportamento do agente |
| Critério de pastas |
Separação por camada técnica (/controllers, /services) |
Separação por domínio (/domains/order) |
Explora apenas os arquivos necessários dentro de uma única pasta |
| Conexão de dependências |
Importação direta de entidades globais |
Comunicação por limites de interface de domínio |
Bloqueia o carregamento em cadeia de arquivos irrelevantes |
| Lógica comum |
Funções misturadas em um único src/utils/ |
Separado em utilitários específicos do domínio e pacotes comuns |
Evita a poluição desnecessária do contexto global |
A ordem para mover os diretórios sem interromper o serviço em execução é a seguinte:
- Identifique as relações de dependência chamadas excessivamente pelo agente para definir o domínio a ser separado.
- Crie interfaces de limite de serviço para cortar referências diretas entre domínios.
- Mova a lógica de negócios relevante para a pasta
src/domains/{nome-do-dominio}/ e atualize os aliases de caminho no tsconfig.json.
- Insira um arquivo de configuração dedicado a esse domínio (
CLAUDE.md) dentro do subdiretório separado.
2. Convertendo regras vagas em linguagem natural para restrições numéricas
Convenções de código escritas longamente em linguagem natural são facilmente ignoradas pelo agente. Regras claras e proibições numéricas devem ser colocadas no topo do arquivo de configuração para garantir que as diretrizes sejam seguidas com precisão.
`markdown
Restrições do projeto (Posicionado no topo do CLAUDE.md)
- Segurança e tratamento de exceções
- NEVER allow raw SQL string concatenation. ALWAYS use parameterized queries with ORM.
- NEVER throw generic Exception or Error. ALWAYS throw domain-specific exceptions inheriting from BaseDomainException.
- ALWAYS enforce tenant_id filtering in all database queries under src/domains/.
- Restrições numéricas da estrutura de código
- Functions MUST NOT exceed 40 lines of code.
- Cyclomatic complexity MUST be kept under 8 per function.
- ALWAYS return Result<T, E> pattern for business layer operations instead of null.
`
Se o arquivo de configuração ultrapassar 200 linhas, as instruções finais serão frequentemente ignoradas.
- No
CLAUDE.md do diretório raiz, mantenha apenas os comandos de build e regras de commit globais em até 200 linhas.
- Distribua regras de pastas inferiores, como
src/domains/order/, para arquivos de regras dedicados dentro desses próprios diretórios.
- Escreva as configurações pessoais do desenvolvedor em
CLAUDE.local.md e adicione-o ao .gitignore para evitar conflitos.
3. Validação automática de código modificado pelo agente com ganchos locais
Erros de sintaxe ou bugs de regressão criados pelo agente devem ser capturados automaticamente no momento do commit. O uso do Lefthook, que opera como um binário único em Go, permite executar verificações paralelas de forma mais leve do que ferramentas baseadas em Node.js.
Coloque o lefthook.yml na raiz e separe as verificações estáticas leves das etapas de testes pesados.
`yaml
pre-commit:
parallel: true
commands:
linter:
glob: ".{ts,tsx}"
run: npx eslint --fix {staged_files}
stage_fixed: true
formatter:
glob: ".{ts,tsx,json,md}"
run: npx prettier --write {staged_files}
stage_fixed: true
security-scan:
run: gitleaks git --staged --no-banner
pre-push:
parallel: false
commands:
typecheck:
run: npx tsc --noEmit
unit-tests:
run: npm run test:unit -- --passWithNoTests
`
O pre-commit verifica apenas os arquivos em stage em menos de 10 segundos, enquanto a verificação de tipo completa e os testes unitários são delegados para a etapa de pre-push.
Para impedir que o agente ignore os ganchos usando a opção --no-verify, registre o interceptador .claude/hooks/block-no-verify.mjs.
`javascript
import fs from 'fs';
const input = fs.readFileSync(0, 'utf8');
const parsed = JSON.parse(input);
if (parsed.tool_input?.command?.includes('--no-verify')) {
console.error("Policy Violation: --no-verify flag is strictly prohibited.");
process.exit(1);
}
process.exit(0);
`
Se um gancho falhar, a saída de erro do console é inserida no próximo prompt, fazendo com que o agente corrija o código por conta própria.
4. Prevenção de desperdício de tokens limitando o escopo de exploração
Se o agente começar a ler resultados de build ou arquivos de lock, os tokens se esgotarão rapidamente. Bloquear o escopo de exploração de arquivos evita custos acidentais.
Crie um .ignore ou .aiderignore na raiz do projeto e registre artefatos de grande porte.
`text
node_modules/
dist/
build/
coverage/
*.min.js
*.svg
*.lock
package-lock.json
public/assets/
db/migrations/
`
Ao executar comandos no terminal, especifique também o diretório de trabalho para bloquear varreduras globais.
`bash
aider "Refactor Order validation logic" --path=src/domains/order/ --exclude=src/domains/order/tests/
`
Verificar as alterações usando o modo de planejamento antes de modificar o código, escrever testes unitários que falham e fazer com que o agente escreva apenas o código necessário para passá-los mantém o raio de ação do agente em um nível seguro.