Arquitetura de Estação de Trabalho: Como Compor Camadas de IA sem Criar um Frankenstein de Contexto Duplicado
Você provavelmente já passou por isso: o Copilot sugere uma função inline, o Claude Code reescreve o mesmo arquivo dez minutos depois com uma convenção diferente, e o Cursor, numa terceira sessão, “aprende” um padrão de nomenclatura que você nunca pediu — porque leu um trecho desatualizado do seu próprio README. Três ferramentas, três versões de contexto sobre o mesmo projeto, nenhuma delas sincronizada com a realidade do código. O resultado não é produtividade turbinada. É um comitê de assistentes discordando entre si, e você arbitrando a discussão em vez de programar.
Esse é o problema real de quem monta um setup de desenvolvimento com múltiplas camadas de IA sem pensar em arquitetura: cada ferramenta acumula seu próprio modelo mental do projeto, e como elas não conversam entre si, você paga o custo de manter três fontes de verdade paralelas. Neste artigo, a proposta não é listar “as 15 melhores ferramentas de IA para 2024” — isso qualquer busca resolve. A proposta é discutir como projetar as camadas do seu setup para que elas compartilhem uma única fonte de contexto, minimizem duplicação e mantenham rastreabilidade de decisões, tratando seu ambiente de desenvolvimento como um sistema distribuído — porque, na prática, é exatamente isso que ele se tornou.
O setup como sistema distribuído: o problema que ninguém nomeia
Quando você tem um LLM no editor (autocomplete), um agente de terminal (Claude Code, Aider), um assistente de revisão de PR e um MCP server conectado ao banco de dados, você não tem “ferramentas de IA”. Você tem um sistema distribuído com múltiplos nós de inferência, cada um mantendo estado local sobre o mesmo domínio: seu código-fonte. E sistemas distribuídos têm um problema clássico — consistência de estado entre nós.
A diferença é que aqui o “estado” é contexto textual: convenções de código, decisões de arquitetura, débitos técnicos conhecidos, padrões de nomenclatura. Se cada ferramenta infere esse estado de forma independente — lendo arquivos diferentes, em momentos diferentes, com janelas de contexto diferentes — você tem inconsistência garantida. A pergunta arquitetural correta não é “qual ferramenta é melhor”, é: como eu desenho uma fonte única de contexto que todas as ferramentas consultam, em vez de inferir?
Camada 1 — Contexto estático versionado
A base de qualquer setup sério é um conjunto de arquivos de contexto versionados no repositório, não em configurações locais da IDE. O CLAUDE.md do Claude Code, o .cursorrules do Cursor e os copilot-instructions.md do GitHub Copilot resolvem o mesmo problema com sintaxes diferentes — e a armadilha comum é escrever três versões distintas do mesmo conteúdo.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# context/ARCHITECTURE.md — fonte única, versionada ## Convenções de código - Repositórios seguem o padrão Repository + UnitOfWork (ver src/core/persistence) - Erros de domínio usam Result, nunca exceções para fluxo de controle - Testes de integração usam Testcontainers, não mocks de banco ## Decisões arquiteturais ativas - ADR-014: migração gradual de REST para gRPC nos serviços internos - ADR-021: fila de eventos usa outbox pattern, não publish direto ## O que NÃO fazer - Não introduzir novas dependências de HTTP client (usar o wrapper em src/http) - Não gerar migrations sem revisão humana explícita |
A prática que funciona na prática: mantenha esse conteúdo em um único arquivo canônico (por exemplo, context/ARCHITECTURE.md) e gere os arquivos específicos de cada ferramenta a partir dele, via script ou symlink, no momento do build ou pre-commit. Isso elimina o drift entre “o que o Claude Code sabe” e “o que o Cursor sabe” — ambos leem a mesma fonte.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# scripts/sync-ai-context.sh #!/usr/bin/env bash set -euo pipefail SOURCE="context/ARCHITECTURE.md" cp "$SOURCE" CLAUDE.md cp "$SOURCE" .cursorrules cp "$SOURCE" .github/copilot-instructions.md echo "Contexto sincronizado a partir de $SOURCE" |
Rode esse script como hook de pre-commit ou como etapa de CI que falha se os arquivos derivados estiverem desatualizados em relação à fonte. É um detalhe operacional, mas é exatamente o tipo de coisa que separa um setup “que funciona no meu ambiente” de um setup que sobrevive à entrada de novos membros no time.
💡 Dica do Mestre: a documentação oficial do Claude Code sobre gerenciamento de memória descreve bem a hierarquia de arquivos
CLAUDE.md(projeto, usuário, diretório), mas não menciona estratégias de sincronização entre ferramentas concorrentes — isso é responsabilidade sua como arquiteto do setup.
Camada 2 — Contexto dinâmico via MCP
Arquivos estáticos resolvem convenções e decisões, mas não resolvem estado vivo: schema atual do banco, endpoints ativos, métricas de produção. Para isso, a peça certa é o Model Context Protocol (MCP), que permite que o agente consulte a fonte de verdade em tempo real em vez de confiar em uma descrição textual que pode estar desatualizada.
A decisão arquitetural aqui é sutil: quando usar arquivo estático versus MCP server. A regra prática que uso: se a informação muda com o mesmo ritmo do código-fonte, vai em arquivo versionado; se muda em ritmo diferente (schema de produção, métricas, tickets abertos), vai em MCP. Colocar schema de banco em Markdown estático é garantia de desatualização em três sprints.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// mcp-config.json — exemplo de configuração de servidor MCP para Postgres { "mcpServers": { "postgres-readonly": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-postgres", "postgresql://readonly_user:senha@localhost:5432/app_db" ] } } } |
Note o detalhe de segurança: usuário readonly_user. Isso não é paranoia — é a primeira decisão de arquitetura que muita gente esquece ao plugar um agente autônomo em uma fonte de dados real. O agente vai gerar queries; você quer que erros de geração resultem em SELECT malformado, não em DELETE acidental. O modelo de arquitetura do MCP não impõe esse isolamento por você — é responsabilidade de quem configura o servidor.
Camada 3 — Orquestração de agentes e limites de autonomia
Com contexto estático e dinâmico resolvidos, a terceira camada é onde a maioria dos setups falha silenciosamente: definir até onde cada agente pode ir sem supervisão. Um agente de terminal com acesso a git push --force e um MCP server com credencial de escrita em produção não são “produtividade turbinada” — são incidentes aguardando o prompt errado.
A prática mais robusta é segmentar por ambiente e por operação, não por ferramenta:
- Leitura irrestrita: código-fonte, logs, schema de staging — qualquer agente pode consultar livremente.
- Escrita supervisionada: commits, PRs, migrations — o agente propõe, um humano aprova antes do merge.
- Escrita proibida: produção, secrets, infraestrutura — nenhum agente tem credencial de escrita, ponto final.
Ferramentas como Claude Code já oferecem configuração granular de permissões por comando (allow, ask, deny), e vale a pena investir tempo real nesse arquivo em vez de aceitar o padrão “permitir tudo, perguntar depois”:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// .claude/settings.json { "permissions": { "allow": [ "Read(*)", "Bash(git diff:*)", "Bash(npm test:*)" ], "ask": [ "Bash(git commit:*)", "Bash(git push:*)", "Edit(migrations/*)" ], "deny": [ "Bash(git push --force:*)", "Bash(rm -rf:*)", "Read(.env*)" ] } } |
Esse arquivo, versionado junto do repositório, vira parte do contrato de onboarding: qualquer pessoa que clona o projeto e ativa o Claude Code herda os mesmos limites de autonomia. Isso é infraestrutura de segurança tratada como código — não configuração pessoal esquecida em algum dotfile.
O custo de manutenção que a propaganda não mostra
Todo material promocional de setup com IA mostra o ganho de velocidade no primeiro dia. Raramente alguém fala do custo recorrente: manter três arquivos de contexto sincronizados, revisar permissões de agentes a cada nova integração, e — o mais subestimado — auditar o que os agentes de fato fizeram, porque “a IA sugeriu” não é uma resposta aceitável em um post-mortem de incidente.
Isso significa que seu setup precisa de observabilidade própria. Não é suficiente confiar na saída do terminal do agente; você precisa de log estruturado das ações que ferramentas autônomas executaram no seu repositório e nos seus sistemas conectados via MCP.
|
1 2 3 4 5 6 7 |
# .claude/hooks/log-actions.sh — hook pós-execução para auditoria #!/usr/bin/env bash echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) | tool=$CLAUDE_TOOL_NAME | args=$CLAUDE_TOOL_ARGS" \ >> .claude/audit.log |
Um arquivo de auditoria simples, versionado ou enviado a um coletor de logs, transforma “a IA fez algo estranho ontem” em uma investigação rastreável de trinta segundos. Sem isso, você está depurando um sistema distribuído sem trace — e sabemos como essa história termina.
Onde o setup generalista quebra: linguagens e stacks diferentes
Um erro comum de quem trabalha com múltiplas stacks — Python num serviço, TypeScript no frontend, Delphi mantendo um sistema legado de ERP — é assumir que o mesmo arquivo de contexto serve para tudo. Não serve. Convenções de tratamento de erro em Go (retorno explícito) e em uma aplicação Delphi orientada a exceções (try..except) são conceitualmente opostas, e um agente que recebe instruções genéricas tende a “vazar” o idioma de uma stack para outra.
A solução estrutural é hierarquizar o contexto por diretório, não por projeto inteiro:
|
1 2 3 4 5 6 7 8 9 |
context/ ├── ARCHITECTURE.md # decisões globais, válidas em todo lugar ├── services/ │ ├── billing-api/CLAUDE.md # específico do serviço Python │ └── legacy-erp/CLAUDE.md # específico do módulo Delphi └── frontend/CLAUDE.md # específico do TypeScript/React |
O Claude Code, por exemplo, respeita arquivos CLAUDE.md em subdiretórios, compondo o contexto conforme a profundidade da sessão. Use isso deliberadamente em vez de escrever um único arquivo de 500 linhas tentando cobrir cinco linguagens com regras genéricas que não valem para nenhuma delas de fato.
Checklist de decisão para montar (ou revisar) seu setup
- Existe uma única fonte canônica de contexto estático, ou você tem três arquivos divergentes?
- Informações voláteis (schema, métricas, tickets) estão em MCP, ou congeladas em Markdown desatualizado?
- Cada agente tem permissões explícitas de leitura/escrita, ou todos operam com acesso irrestrito por padrão?
- Existe log de auditoria das ações autônomas, ou você confia na memória do terminal?
- O contexto está hierarquizado por stack/serviço, ou é um documento único tentando cobrir tudo?
Se a resposta a mais de duas dessas perguntas for a alternativa desfavorável, o problema não é a ferramenta que você escolheu — é a ausência de arquitetura por trás da escolha.
💡 Dica do Mestre: vale a leitura do artigo “Exploring Generative AI” da Martin Fowler’s blog, que discute justamente os padrões emergentes de uso de LLMs em times de engenharia — incluindo os riscos de contexto duplicado e autonomia mal calibrada que abordamos aqui.
Junte-se à comunidade que discute isso na prática
Arquitetar um setup de desenvolvimento com múltiplas camadas de IA é um problema de engenharia, não de configuração pontual — e como todo problema de engenharia, se beneficia de troca com quem já bateu de frente com as mesmas decisões. Na Comunidade Dev’s AI, discutimos exatamente esse tipo de trade-off: como calibrar permissões de agentes, como estruturar contexto para stacks mistas, e como auditar o que a IA realmente fez no seu código. Se você quer ir além do tutorial de instalação e entender a arquitetura por trás do setup, é o lugar certo para continuar essa conversa.
Conclusão
Um setup de desenvolvimento turbinado com IA não se mede pelo número de ferramentas instaladas, mas pela consistência do contexto que elas compartilham e pelos limites de autonomia que você desenhou com intenção. Tratar seu ambiente como um sistema distribuído — com fonte única de verdade, contexto dinâmico via MCP, permissões explícitas e auditoria de ações — é o que separa produtividade real de uma coleção de assistentes trabalhando com informações divergentes sobre o mesmo código. A ferramenta certa importa menos do que a arquitetura que você constrói em torno dela; e essa arquitetura, como qualquer decisão técnica séria, exige manutenção contínua, não configuração única.