Por que agentes de código ignoram suas instruções
A regra diz para parar, mas o agente continua. Veja como contexto ausente, regras vagas, conflitos e compactação causam isso e como diagnosticar antes de reescrever.
Por que os agentes de programação ignoram as suas instruções
Os agentes de programação ignoram as suas instruções por quatro motivos, e nenhum deles é ter sido demasiado educado. A regra nunca chegou à janela de contexto. A regra era demasiado vaga para permitir verificar uma ação em relação a ela. Havia outro conteúdo no contexto que a contradizia, normalmente o código que o agente tinha acabado de ler. Ou a regra continua carregada, mas está muito atrás do turno atual, e o agente trabalha com o que está mais próximo.
Cada causa tem a sua própria correção, por isso o primeiro passo é distingui-las. Usar letras maiúsculas e a palavra IMPORTANT não é um diagnóstico. Os mecanismos abaixo usam o Claude Code como exemplo prático, porque o seu comportamento de carregamento e compactação está documentado em detalhe em agosto de 2026. Outras ferramentas diferem nos detalhes, mas comportam-se da mesma forma em termos gerais.
Primeiro, dois termos. A janela de contexto é o bloco de texto que o modelo vê num determinado turno: o prompt do sistema, os seus ficheiros de instruções, a conversa e todos os ficheiros que o agente leu. O harness é o programa que envolve o modelo, ou seja, o componente que lê os ficheiros do disco e monta esse bloco. Quase todas as queixas neste artigo são, na realidade, queixas sobre o harness, e não sobre o modelo.
O seu ficheiro de instruções é uma mensagem, não uma definição
Um ficheiro de instruções não é configuração. Nada no runtime lê CLAUDE.md e impõe esse conteúdo. O harness lê o ficheiro do disco e cola o texto na conversa. No Claude Code, esse conteúdo é enviado como uma mensagem do utilizador depois do prompt do sistema. Isto significa que o modelo vê as suas regras da mesma forma que vê qualquer outro texto que tenha introduzido.
Isto tem uma consequência desconfortável. As suas regras competem com todos os outros textos da janela em condições de igualdade. Uma regra é uma afirmação. O ficheiro que o agente acabou de abrir é uma evidência. Quando os dois entram em conflito, a evidência muitas vezes prevalece. Não é gerado qualquer erro, porque, do ponto de vista do modelo, nada correu mal.
A documentação oficial afirma isto claramente: os ficheiros de instruções são tratados como contexto, não como configuração imposta. Para bloquear uma ação independentemente da decisão do modelo, precisa de um hook, não de uma frase. Tenha esta distinção presente. A maioria das correções no final deste artigo aplica essa distinção a um caso específico.
Quais ficheiros de instruções são carregados e quando
O Claude Code percorre a árvore de diretórios a partir do diretório onde foi iniciado. Todos os ficheiros CLAUDE.md e CLAUDE.local.md existentes desde a raiz do sistema de ficheiros até ao diretório de trabalho são carregados por completo no arranque. São concatenados nessa ordem. Assim, o ficheiro mais próximo do diretório onde o comando foi iniciado é lido por último. Dentro de cada diretório, o ficheiro .local é acrescentado depois do ficheiro principal.
Os ficheiros existentes em subdiretórios abaixo do diretório de trabalho comportam-se de forma diferente. Não são carregados no arranque. São carregados quando o agente lê um ficheiro nesse diretório. O mesmo se aplica às regras condicionadas pelo caminho em .claude/rules/ que tenham um campo de frontmatter paths:. Essas regras entram no contexto quando é lido um ficheiro correspondente, e não em cada turno.
Esta diferença explica grande parte das falhas reportadas. Coloca uma regra em packages/api/CLAUDE.md, faz uma pergunta sobre a API e o agente responde sem abrir qualquer ficheiro em packages/api/. A regra não foi ignorada. Nunca esteve presente. Se o repositório distribuir as orientações por ficheiros de instruções por pacote num monorepo, este é o primeiro aspeto a verificar, sempre.
Existe ainda outro problema de carregamento, e é a causa mais comum da mensagem "o agente ignorou as minhas instruções": o Claude Code lê CLAUDE.md, não AGENTS.md. Um repositório que tenha adotado AGENTS.md como padrão e não tenha CLAUDE.md não fornece ao Claude Code qualquer ficheiro para carregar. A integração suportada é um ficheiro CLAUDE.md cuja primeira linha seja @AGENTS.md. Essa linha importa o ficheiro no arranque, e pode incluir abaixo quaisquer notas específicas do Claude. Uma ligação simbólica também funciona quando não há nada adicional a acrescentar. Decidir o que deve pertencer a esse ficheiro é uma questão separada, abordada em separar as instruções do agente da documentação para humanos.
Confirme se o ficheiro foi carregado antes de o reescrever
Não altere o texto até ter provas de que o agente consegue ver o ficheiro. Existem duas verificações, e a mais simples vem primeiro.
Execute /context dentro da sessão. O comando mostra a janela atual dividida por categoria, e a lista Memory files apresenta o nome de todos os ficheiros de instruções efetivamente carregados. Se um ficheiro não aparecer nessa lista, ele não está na conversa e nada do que escrever dentro dele poderá ter efeito. /memory lista as localizações dos ficheiros e abre-os para edição, incluindo os que ainda não existem.
Para obter uma confirmação mais completa, registe os carregamentos. O evento de hook InstructionsLoaded é acionado sempre que um CLAUDE.md ou um ficheiro de regras entra no contexto, e o matcher indica o motivo do carregamento: session_start, nested_traversal, path_glob_match, include ou compact. Coloque isto em .claude/settings.json:
{
"hooks": {
"InstructionsLoaded": [
{
"matcher": "nested_traversal",
"hooks": [
{
"type": "command",
"command": "cat >> /tmp/instructions-loaded.log"
}
]
}
]
}
}O hook recebe os dados como JSON na entrada padrão, por isso cat acrescenta o registo completo. Monitorize-o com tail -f /tmp/instructions-loaded.log enquanto trabalha. O código de saída deste evento é ignorado, por isso o hook apenas observa e nunca bloqueia. Se o seu ficheiro aninhado nunca aparecer nesse log durante uma sessão em que esperava que fosse carregado, pare de reescrever o texto. O problema está na localização.
O que uma sessão longa faz às suas regras
Aplicam-se aqui dois efeitos distintos, e cada um exige uma resposta diferente.
Distância. Uma regra declarada no turno 1 ainda está na janela no turno 90, mas agora compete com 90 turnos de texto mais recentes e mais específicos para o que está a fazer neste momento. Não pode eliminar este efeito através da configuração, mas pode medi-lo. Execute a mesma tarefa numa sessão nova. Se a regra funcionar nessa sessão e falhar numa sessão longa, a distância é a causa.
Compactação. Quando a janela fica cheia, o harness resume a conversa até esse ponto e continua a partir desse resumo. O que permanece é o que o resumidor considerou importante, o que pode não coincidir com o que considera importante. O Claude Code documenta o resultado por mecanismo, e as diferenças são grandes. O root do projeto CLAUDE.md e as regras sem escopo são reinjetados a partir do disco depois de uma compactação. A memória automática é reinjetada a partir do disco. As regras com frontmatter paths: perdem-se até um ficheiro correspondente ser lido novamente. Os ficheiros CLAUDE.md aninhados em subdiretórios perdem-se até um ficheiro desse subdiretório ser lido novamente.
Ordene as instruções de acordo com essa tabela, e a ordem de fragilidade torna-se evidente. Uma regra que escreveu apenas no chat é o elemento mais frágil da sessão: só persiste se o resumo a tiver mantido. Uma regra em packages/api/CLAUDE.md vem a seguir, porque foi carregada uma vez, removida pelo resumo e só regressa na leitura seguinte nesse diretório. Uma regra no ficheiro root do projeto é a mais durável, porque é relida a partir do disco todas as vezes.
Por isso, se uma instrução tiver de se manter durante toda a sessão, deve ficar no ficheiro root do projeto, sem frontmatter paths:. Tudo o resto é um compromisso que deve assumir de forma deliberada. Gerir o que permanece na janela de contexto aborda /compact com um argumento de foco e /clear entre tarefas não relacionadas; ambos alteram a frequência com que o resumidor pode decidir quais eram as suas regras.
Por que o código ao redor prevalece sobre a regra
Esta é a falha que as pessoas descrevem com mais frequência e diagnosticam com menos frequência. O seu ficheiro diz que o acesso à base de dados passa pela camada de repositório. O agente escreve um handler que chama diretamente o ORM (mapeador objeto-relacional). Não foi ignorado por uma questão de estilo. As evidências tiveram mais peso.
Uma regra descreve uma preferência. O código demonstra uma preferência. Quando o agente abre três ficheiros do módulo que está prestes a editar e os três chamam diretamente o ORM, o contexto contém uma frase abstrata de um lado e três exemplos concretos, recentes e correspondentes à tarefa do outro. Copiar o padrão local é normalmente o comportamento correto. Neste caso, é errado apenas porque sabe algo que o contexto desconhece: esses ficheiros são código legado.
Por isso, escreva essa informação na regra. As regras que identificam as próprias evidências em contrário resistem ao contacto com um repositório real. As regras que expressam apenas uma preferência não resistem.
O novo acesso à base de dados passa porapp/repositories/. Os ficheiros emapp/legacy/ainda chamam diretamente o ORM. Esse é código antigo, não é o padrão. Não o copie.
A segunda frase faz o trabalho necessário. Informa o agente sobre o que está prestes a encontrar e como deve interpretar isso, antes de o encontrar. A mesma correção aplica-se a qualquer regra que o repositório contradiga visivelmente: um estilo de commit que o histórico não segue, uma estrutura de testes que metade da suite ignora, uma convenção de import que só existe no código novo. Sempre que o código discordar do ficheiro, identifique essa discordância no ficheiro.
Uma regra vaga não pode ser verificada, portanto não pode ser seguida
"Escreva código limpo." "Não complique demasiado." "Mantenha a simplicidade." "Tenha cuidado com as migrações." Nenhuma destas regras pode ser testada contra uma ação específica, pelo agente ou por si. Um agente que recebe uma regra que não consegue verificar na própria saída está a adivinhar, e você está a avaliar esse palpite com base na sua impressão.
Este é o teste a aplicar a cada linha do seu ficheiro. Escreva o comando shell que terminaria com um código diferente de zero quando a regra fosse violada. Se não conseguir escrever esse comando, a regra não é verificável. Compare estes pares:
- Não verificável: "Mantenha as funções pequenas." Verificável: "Uma função com mais de 60 linhas precisa de um comentário acima a explicar o motivo."
- Não verificável: "Teste as suas alterações." Verificável: "Execute
npm teste cole a contagem de falhas antes de considerar uma tarefa concluída." - Não verificável: "Mantenha os ficheiros organizados." Verificável: "Os handlers HTTP ficam em
src/api/handlers/. Nada mais pode ser colocado nesse diretório." - Não verificável: "Formate o código corretamente." Verificável: "Use indentação de 2 espaços nos ficheiros
.ts."
"Não complique demasiado" é a primeira regra a que as pessoas costumam renunciar, porque a correção não é uma frase mais curta, mas uma frase mais longa: explicar claramente o que significa a menor alteração que funciona fornece ao agente critérios contra os quais ele pode comparar o próprio diff.
O tamanho apresenta o mesmo problema com outra forma. As orientações do Claude Code recomendam menos de 200 linhas por ficheiro de instruções e afirmam diretamente que ficheiros mais longos reduzem a adesão. Um ficheiro com 700 linhas não contém instruções mais firmes. Contém 700 afirmações com mais possibilidades de se contradizerem, e é contabilizado na sua janela em cada turno, o que aparece diretamente na utilização dos seus tokens. Estruturar o ficheiro para que cada regra fique sob um heading que o leitor consiga consultar rapidamente é abordado em escrever um ficheiro de instruções que um agente consiga executar.
Como diagnosticar o problema em dez minutos
Execute estes comandos pela ordem indicada. Saltar diretamente para o último passo é a razão pela qual se acaba com um ficheiro longo de regras imperativas que continua sem funcionar.
- Confirme que foi carregado. Execute
/contexte leia a lista de ficheiros de memória. Se o ficheiro não estiver presente, corrija a localização e pare. Nada mais desta lista se aplica ainda. - Reproduza o problema numa sessão nova. Inicie uma sessão nova e forneça a tarefa mais pequena que deve acionar a regra. Se funcionar aqui, mas falhar numa sessão longa, o problema está na distância ou na compactação. Se também falhar aqui, o problema está na própria regra.
- Remova a concorrência. Peça a mesma alteração num diretório cujo código existente já siga a regra. Se a conformidade voltar, o código envolvente estava a sobrepor-se à sua frase.
- Procure um conflito. Dois ficheiros que fornecem orientações diferentes para o mesmo comportamento constituem uma falha documentada: o modelo pode escolher um deles arbitrariamente e não lhe dirá que o fez.
- Torne a regra verificável e teste novamente. Reescreva a regra com um caminho concreto e uma condição. Um aumento significativo da conformidade indica que a formulação era a causa.
O passo 4 consiste num único comando. Procure o tópico em todas as fontes de instruções, não apenas no ficheiro que estava a editar:
grep -rni "migration" --include="CLAUDE.md" --include="CLAUDE.local.md" .
grep -rni "migration" .claude/rules/ ~/.claude/CLAUDE.md ~/.claude/rules/ 2>/dev/nullUma ocorrência em dois ficheiros que dizem coisas diferentes é o seu erro. Apague uma delas. Não tente definir a prioridade com uma formulação mais forte, porque não existe nenhum mecanismo de classificação ao qual possa recorrer.
As correções, por ordem de eficácia
Cada passo abaixo tem mais eficácia do que o anterior e custa mais a configurar. Comece pelo topo quando for simples reformular uma regra. Desça assim que uma regra for importante o suficiente para que falhas ocasionais sejam inaceitáveis.
- Torne a regra concreta. Indique um caminho, um comando ou uma condição. Acrescente as evidências em contrário que o agente encontrará no repositório, como mostrado anteriormente. Isto não tem custo e resolve uma parte surpreendentemente grande dos casos.
- Aproxime a regra do que ela controla. Use um
CLAUDE.mdaninhado, uma regra com escopo de caminho em.claude/rules/ou um comentário no início do próprio ficheiro. A regra é então lida juntamente com o código a que se aplica. Aceite a contrapartida: tudo o que for carregado dessa forma desaparece na compactação seguinte e volta a ser carregado na próxima leitura correspondente. - Transfira a aplicação da regra para um hook. A prosa pede. Um hook decide. Os hooks são executados como código em eventos fixos do ciclo de vida e aplicam-se independentemente da conclusão do modelo.
- Entregue a regra a uma ferramenta determinística e elimine a prosa. Formatação, ordem dos imports, comprimento das linhas, imports proibidos, formato das mensagens de commit.
ruff format,prettier --write,eslint, um hookpre-commit. O formatter está certo todas as vezes e não custa tokens. A frase está certa na maioria das vezes e custa tokens em cada interação.
Passo 3 em detalhe. Suponha que os ficheiros de migração nunca devem ser editados pelo agente. Coloque isto em .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/guard-migrations.sh"
}
]
}
]
}
}E isto em .claude/hooks/guard-migrations.sh:
#!/usr/bin/env bash
set -euo pipefail
path=$(jq -r '.tool_input.file_path // empty')
case "$path" in
*/migrations/*)
echo "Files under migrations/ are written by hand. Stop and ask first." >&2
exit 2
;;
esac
exit 0Execute chmod +x .claude/hooks/guard-migrations.sh, depois inicie uma nova sessão e peça ao agente para editar um ficheiro em migrations/. A edição é recusada e a sua mensagem é devolvida como motivo. O código de saída 2 em PreToolUse bloqueia a chamada da ferramenta antes da execução, e o texto em stderr é entregue ao modelo como mensagem de bloqueio. ${CLAUDE_PROJECT_DIR} resolve para a raiz do projeto, pelo que o hook funciona independentemente do diretório onde o agente se encontra. O agente não precisa de concordar com a regra, de se lembrar dela nem de ainda a ter no contexto. A edição não ocorre.
Para uma proibição simples, sem lógica, permissions.deny nas suas definições faz o mesmo trabalho sem um script para manter, e os modos de permissão determinam o que é executado sem lhe perguntarem primeiro. Se uma instrução tiver realmente de ficar ao nível do system prompt, em vez de numa mensagem do utilizador, --append-system-prompt coloca-a nesse nível, embora tenha de ser passada em todas as invocações, o que é mais adequado para scripts do que para trabalho interativo.
O que você não consegue eliminar com instruções
Seja claro sobre qual parte é sua. Posicionamento, redação, conflitos entre ficheiros e tamanho do ficheiro são problemas do autor, com correções do autor. O restante é comportamento do modelo, e uma redação melhor não o elimina.
Concordar não significa cumprir. Um agente pode reconhecer uma regra, repeti-la corretamente e violá-la duas chamadas de ferramenta depois. O reconhecimento não tem custo e não prevê nada. Não o interprete como uma correção nem o contabilize como um teste.
Alguns hábitos persistem. Adicionar comentários, incluir tratamento defensivo de erros, escrever um resumo final e executar o próximo comando óbvio. Estes comportamentos reaparecem quando existe uma regra que os proíbe, embora com uma frequência menor, e não igual a zero. Pode medir a sua própria frequência: execute a mesma tarefa dez vezes em sessões novas e conte as violações. Quando esse número tiver de ser zero, a regra tem de sair do prompt.
A própria sessão torna-se um exemplo. Se o agente violar a regra no turno 12 e você deixar passar, essa violação fica no contexto como uma demonstração e é muito mais recente do que a regra. Corrija uma violação assim que a identificar. Uma violação não corrigida ensina o restante da sessão.
Um ficheiro de instruções não é um limite de segurança. Ele orienta o comportamento, mas não o impõe. Tudo aquilo em que uma falha seja dispendiosa, como credenciais ou comandos destrutivos, deve ficar sujeito a permissões ou a um hook. Mantenha os segredos fora do alcance de um agente aplica o mesmo princípio aos dados: não peça a um agente para não ler um ficheiro; faça com que o ficheiro não possa ser lido.
A versão curta: prove que o ficheiro foi carregado, torne a regra verificável, coloque-a junto ao elemento que ela governa e, quando a taxa de falhas ainda for relevante, retire-a da prosa. Uma regra que um agente não consegue ignorar é uma regra que nunca foi pedida ao agente.
FAQ
Por que o Claude Code ignora o meu CLAUDE.md?
Confirme se o carregou antes de concluir que foi ignorado. Execute /context e consulte a lista Memory files; um ficheiro que não aparece nessa lista não está na conversa. Os ficheiros de instruções são enviados como uma mensagem de utilizador depois do prompt do sistema e tratados como contexto, não como configuração aplicada de forma estrita. Por isso, não existe uma garantia de conformidade total. Na maioria dos casos, a causa é uma de quatro: o ficheiro está num subdiretório que o agente nunca leu, dois ficheiros têm instruções contraditórias e o modelo escolheu uma delas arbitrariamente, a regra é demasiado vaga para ser verificada numa ação ou o código existente demonstra o oposto do que a regra define.
Alterar o ficheiro de instruções durante a sessão produz algum efeito?
Não para a cópia que já está na conversa. Os ficheiros acima do diretório de trabalho são carregados integralmente no arranque. Por isso, o texto que o modelo tem é o texto existente no momento do arranque. Para carregar uma alteração, inicie uma nova sessão ou peça ao agente para ler o ficheiro com as ferramentas normais de ficheiros. Isso coloca a versão atual na conversa como uma mensagem nova. Depois de uma compactação, o ficheiro na raiz do projeto é lido novamente a partir do disco. A nova versão também fica disponível nesse momento.
Qual ficheiro prevalece quando um CLAUDE.md na raiz e outro aninhado têm instruções contraditórias?
Nenhum prevalece de forma fiável. Os ficheiros descobertos são concatenados no contexto, em ordem decrescente, desde a raiz do sistema de ficheiros até ao diretório de trabalho. Por isso, o ficheiro mais próximo é simplesmente lido por último. Não existe um mecanismo de precedência para resolver contradições. A documentação do Claude Code indica que regras contraditórias podem ser resolvidas arbitrariamente. Escreva os ficheiros aninhados como adições e indique o caminho que governam. Elimine a contradição em vez de tentar dar prioridade a uma regra.
As minhas instruções sobrevivem a /compact?
Depende da forma como foram carregadas. O ficheiro na raiz do projeto CLAUDE.md, as regras sem escopo e a memória automática são reinjetados a partir do disco depois de uma compactação. As regras com frontmatter paths: e os ficheiros CLAUDE.md aninhados em subdiretórios são perdidos até que um ficheiro correspondente seja lido novamente. Qualquer conteúdo que tenha escrito apenas no chat sobrevive somente se o sumarizador o tiver mantido. Se uma regra tiver de vigorar durante toda a sessão, coloque-a no ficheiro da raiz do projeto sem frontmatter paths:.
Quando deve uma regra tornar-se um hook em vez de permanecer em prosa?
Quando a verificação é determinística e o custo de uma falha é superior ao custo de escrever um script pequeno. Restrições de caminhos de ficheiros, comandos obrigatórios antes de um commit e chamadas de ferramentas proibidas são exemplos deste caso. Um hook PreToolUse que termine com o estado 2 bloqueia diretamente a chamada da ferramenta e devolve o texto de stderr ao modelo como motivo. Assim, a regra continua a ser aplicada mesmo que já não esteja no contexto. Qualquer verificação que um formatter ou um linter consiga decidir deve ficar a cargo dessa ferramenta e ser removida integralmente do ficheiro de instruções.