Memória para Agentes de Código: Guardar É a Metade Fácil
O post sobre o Harness da semana passada mostrou um briefing de sessão de verdade, e uma linha dele trabalhava mais do que todas as outras:
- **MCP Server** [PITFALL] (claude-code/vincent, 1 day ago): every new ID argument
name must be added to idArgumentResolvers in authz.go, or the cross-org check
silently skips it.
Um agente que lê aquilo economiza a tarde que o agente anterior perdeu. Ótimo. Agora envelheça essa linha em seis meses. A mesma frase, no mesmo tom confiante, servida a um agente trabalhando num arquivo que duas pessoas reescreveram nesse meio-tempo. Nada na linha parece diferente. O agente não tem como perceber, e você também não.
Esse é o problema de verdade da memória para agentes de código, e não é a parte que a maioria das ferramentas constrói. Escrever as coisas é a metade fácil.
Por que um monte de notas não consegue responder à pergunta
As formas comuns de memória de agente hoje são um arquivo markdown no qual o agente vai acrescentando linhas, e um vector store no qual ele escreve. Os dois guardam bem. Os dois recuperam razoavelmente. Nenhum dos dois consegue te dizer que o chão embaixo de uma nota se mexeu, porque nenhum dos dois sabe do que a nota trata em nenhum sentido estrutural. Um vector store sabe que uma nota está perto das palavras "gateway" e "headers". Ele não sabe que ApiGateway é um container do seu sistema, que ele tem um caminho no código-fonte, e que o código naquele caminho parou de bater com o modelo documentado três semanas atrás.
Um modelo de arquitetura sabe as três coisas. É esse o argumento inteiro para colocar memória ao lado de um, e é a única parte deste post que outro produto não conseguiria copiar em um sprint.
Memória está no Archyl agora, em todos os planos. É isto que ela faz.
Uma memória fica presa a um elemento, não a uma conversa
Uma memória é um fato tipado como note, convention ou pitfall, anexado a um elemento C4 ou ao projeto como um todo. Os agentes escrevem via MCP; as pessoas escrevem no Agent Hub ou no painel de detalhes de qualquer elemento do diagrama.
▶ remember(projectId: …, element: "ApiGateway", kind: "pitfall",
content: "The gateway strips custom headers longer than 8KB — payloads must go in the body.")
Existe um quarto tipo, session_outcome, escrito automaticamente quando uma sessão de trabalho termina. Uma sessão que segurava oito leases produz uma memória anexada a oito elementos, não oito cópias do mesmo parágrafo. O formato importa para a recuperação: um agente que pergunta sobre qualquer um desses elementos recebe o resultado uma vez, em vez de reler o mesmo resumo oito vezes só porque a sessão por acaso tocou em oito coisas.
Conteúdo e títulos de memória são criptografados em repouso, como toda outra coluna de conteúdo sensível do produto.
O recall ordena por significado, não por substrings em comum
recall mistura similaridade semântica com sobreposição de termos, com pesos 0.55 e 0.45. Um agente perguntando sobre "rate limiting" recebe de volta a nota que outra pessoa escreveu sobre "throttling" — exatamente o caso que uma busca por palavras perde e que um colega nunca perderia.
Os vetores são best-effort de propósito. Sem um provedor de IA configurado (compatível com OpenAI ou Ollama), não há vetores e a pontuação continua puramente lexical, do jeito que se comportava antes. Ela degrada em vez de quebrar, e isso importa se você faz self-host sem provedor. E as memórias escritas enquanto nenhum provedor existia não ficam de segunda classe para sempre: um worker em background preenche os vetores delas assim que um provedor é configurado.
Escrever o mesmo fato duas vezes confirma o fato
Repetir algo que o projeto já sabe não cria uma segunda cópia. Acima de uma similaridade de cosseno de 0.94, a escrita confirma a memória existente no lugar disso, e a resposta diz deduplicated: true. Um agente reafirmando o que aprendeu é evidência, não ruído.
Entre 0.82 e 0.94 fica a faixa interessante: perto, mas não o mesmo fato. Essas são guardadas, e as quase-correspondências voltam em similarTo, para que quem escreve possa chamar remember(supersedes: "Old title") de propósito em vez de contradizer em silêncio uma memória que ainda está viva e ainda está sendo servida.
A memória aprende com o uso
Todo recall registra quais memórias ele serviu para qual sessão. Quando a sessão termina, usedMemories nomeia aquelas em que ela realmente se apoiou.
Esses dois sinais não têm o mesmo peso, e isso é de propósito. Receber uma memória é circunstancial. Dizer que você a usou é testemunho. Então só as citações levantam o rank de uma memória, em escala logarítmica e com teto em 1.8x, para que uma memória popular não consiga enterrar a mais nova que a corrige. Uma memória servida para cinco sessões sem uma única citação recebe um multiplicador de 0.75 e é tratada como ruído.
Tratada como, não apagada. Nada na memória é jamais removido por uma heurística. Memórias ignoradas caem numa fila de revisão com a contagem de impressões, e uma pessoa decide. O mesmo princípio atravessa a funcionalidade inteira: corrigido, nunca apagado.
Uma memória tem um ciclo de vida
O frescor decai com meia-vida de 45 dias a partir do momento em que a memória foi conhecida como verdadeira pela última vez, que é a criação dela ou a confirmação mais recente. confirm_memory zera esse relógio e aumenta a contagem de confirmações. remember(supersedes: …) substitui um fato que mudou: a versão antiga sai da recuperação mas fica no histórico e no grafo, então você ainda consegue ver no que o projeto acreditava no ano passado.
Por cima disso ficam os pesos por tipo, e eles são opinativos: um pitfall pontua 3.0, uma convention 2.0, uma note simples 1.5, um session outcome 1.0. Para um agente prestes a mudar código, "isso vai te morder" vale mais do que "foi assim que aconteceu".
O que de fato invalida uma memória é o drift
Tudo acima é escrituração decente. Esta seção é a razão pela qual memória pertence a uma ferramenta de arquitetura.
Tempo é um substituto fraco para verdade. Uma convention escrita dois anos atrás sobre como funcionam as fronteiras dos seus serviços provavelmente ainda está certa. Uma nota escrita mês passado sobre um arquivo que desde então foi reescrito provavelmente está errada. O decaimento trata as duas de forma idêntica, porque um relógio é tudo o que ele tem.
O que de fato torna uma memória suspeita é o código por trás do elemento dela mudar. O Archyl já calcula isso, de forma determinística: o drift score compara o modelo documentado com o repositório e nomeia os elementos que não batem mais. Rode a partir da UI, a partir da API, ou a cada push com a GitHub Action drift-score. A memória agora está ligada nisso.
Quando o drift encontra um elemento fora de sincronia, toda memória anexada a esse elemento recebe o carimbo do momento em que isso aconteceu. Uma memória confirmada pela última vez antes desse carimbo descreve algo que desde então se mexeu por baixo dela. Três coisas decorrem disso:
- Ela é rebaixada no ranking, por um multiplicador de 0.6. Rebaixada, não escondida: ela pode ser a única coisa que alguém já escreveu sobre aquele elemento, e escondê-la seria pior do que servi-la com um aviso.
- Ela aparece na fila de revisão para um humano.
- O agente lê um aviso, no briefing, em palavras em vez de metadados:
- **ApiGateway** [PITFALL] [VERIFY — the element drifted since this was written]
(claude-code/sarah, 96 days ago): the gateway strips custom headers longer than 8KB.
Reconfirmar a memória limpa a marca, porque uma confirmação responde à pergunta do drift diretamente: alguém olhou, e continua valendo.
As duas metades desse mecanismo moram no mesmo produto. O conhecimento está aqui, e a comparação modelo-contra-código que pode derrubá-lo também. Uma camada de memória parafusada num cliente de chat tem a primeira metade e nenhum jeito de conseguir a segunda.
As memórias se ligam umas às outras
Dê um título a uma memória e ela se torna endereçável. Qualquer outra memória pode então referenciá-la com [[Title]] no conteúdo, no estilo Obsidian. A mesma sintaxe resolve para elementos C4 pelo nome ([[ApiGateway]]) e para decisões ([[ADR-17]]), e um link para um título que ainda não existe fica pendente e se prende sozinho no momento em que alguém escreve aquela memória.
Os links não servem só para leitura. recall segue eles: as melhores correspondências puxam junto as vizinhas ligadas, marcadas com via para você ver o que as trouxe. Um pitfall sobre o gateway que aponta para o ADR explicando por que aquela fronteira existe chega com o raciocínio anexado.
O knowledge map, e o grafo que a gente jogou fora
A primeira versão do painel de memória era um grafo de nós e arestas. Ele renderizava, agrupava em clusters, tinha cara daquilo de que você tira print. Ele respondia "qual memória liga em qual memória", e essa não é uma pergunta que alguém estivesse fazendo.
O que as pessoas precisam saber é quais partes da arquitetura delas o projeto entende e sobre quais partes ninguém escreveu uma palavra. Então trocamos. O painel agora mostra uma célula por elemento C4: o que se sabe sobre ele, quão fresco é esse conhecimento, quantos pitfalls estão ali, e, para os elementos sem absolutamente nada, um vazio visível. Isso produz uma manchete que nenhum dashboard te deu antes:
3 of 19 elements documented
Essa frase é desconfortável de um jeito útil. O grafo não era.
O que ela não faz
Recall semântico precisa de um provedor de IA. Nenhum endpoint compatível com OpenAI e nenhum Ollama significa nenhum vetor, e o ranking cai de volta para sobreposição de termos. Todo o resto desta página continua funcionando.
O casamento de elementos ainda é lexical. A memória agora ordena por significado. O passo anterior, find_relevant_context escolhendo de quais elementos a sua tarefa trata, continua pontuando por sobreposição de palavras em nomes, descrições, tags e caminhos. Uma tarefa sobre "checkout" ainda não vai trazer à tona um component chamado OrderProcessor. Sinalizamos isso como um limite em muitos agentes, uma arquitetura e continua sendo verdade.
O sinal de utilidade só existe se os agentes citarem o que usaram. O skill archyl-harness ensina o agente a passar o sessionId dele para recall e a nomear usedMemories quando termina. Nada obriga. Um agente conectado sem o skill produz impressões e nenhuma citação, o que se lê exatamente igual a uma memória que ninguém achou útil.
Memória tem escopo de projeto. Uma convention que vale para a organização inteira tem que ser escrita em cada projeto que precisa dela. É a próxima coisa que estamos consertando.
E a ressalva honesta geral: memória acabou de sair. Não temos números de adoção, nenhum benchmark, e nenhum cliente para te dizer que economizou alguma coisa. O que está acima é o que o código faz, e você pode conferir cada pedacinho contra o seu próprio projeto.
Por onde começar
Se você já roda o Harness, a memória já está ligada. remember, recall e confirm_memory são três das dezesseis tools do perfil coding. A versão 0.8.0 do plugin do Claude Code é a peça que ensina a um agente os dois hábitos dos quais o ranking depende: passar o seu sessionId para recall, e nomear o que usou quando terminar.
A primeira coisa que vale a pena fazer não é escrever memórias. É abrir o knowledge map e ler a linha de cobertura. Seja qual for a fração que ela mostra, essa é a fração da sua arquitetura que sobrevive à pessoa que a entende sair de férias. Chute o número antes de olhar, depois olhe.
Depois escolha o elemento com mais tráfego e menos coisa escrita, e escreva a armadilha que você contaria para alguém novo no primeiro dia. Essa é a memória de que o próximo agente precisa, e até alguém digitar, nenhuma quantidade de recuperação vai encontrá-la.
A memória faz parte do Archyl Harness: as sessões de trabalho, o preflight gate, o hook do Guard e a Fleet console. O plugin, os skills e o hook do Guard e as GitHub Actions são open source, e a referência completa está no guia do Harness. Leitura relacionada: sessões de trabalho, muitos agentes, uma arquitetura, e por que seus agentes têm um arquivo de regras e não um modelo.