TL;DR
Um CLAUDE.md resolve conhecimento estático: comandos, convenções, preferências e regras. O que ele não resolve é memória episódica: o bug investigado ontem, a abordagem que já falhou, a decisão que explica por que um PR foi abandonado. Foi para isso que construí o agent-memory-hub. A virada veio depois: eu descobri que a própria memória podia falhar em silêncio. Este artigo é a história de como uma memória persistente virou memória verificável, e de como uma ideia de produto virou uma ferramenta open-source que eu uso de verdade no dia a dia.
Para quem é este artigo
- Devs que usam Claude Code, Codex ou Cursor e sentem que o agente sabe as regras, mas esquece a história.
- Quem mantém
CLAUDE.md,AGENTS.mdou memória persistente e quer separar conhecimento estático de memória episódica. - Quem gosta de pós-morte honesto: bug silencioso de pipeline, observabilidade e uma decisão de produto deliberada.
A história inteira em uma linha
Se eu contasse isso do jeito mais óbvio, o resumo seria: construí uma memória, encontrei bugs, adicionei observabilidade. Só que esse resumo começa pelo lugar errado. A história não ficou interessante porque um bug apareceu. Ficou interessante porque o bug mostrou que eu estava confiando em uma memória sem recibo.
Essa ordem muda o peso de tudo. O agent-memory-hub começou como uma solução de continuidade para agentes de código. Depois virou uma aula prática de ingestão: qualquer coisa que captura dados automaticamente também precisa provar que capturou. Sem isso, a memória só parece memória.
A dor não era inteligência. Era memória.
Nos últimos meses eu praticamente parei de programar sem agentes de IA. Claude Code, Codex, Cursor: quando você dá contexto suficiente, cada ferramenta fica muito boa em entrar no projeto e produzir.
Então fiz o que quase todo mundo faz: escrevi um bom CLAUDE.md. Coloquei comandos de build, convenções, como gosto de escrever testes, como organizo módulos, como abro PRs. Funcionava muito bem, até eu perceber uma divisão curiosa: o agente sabia como eu queria que ele trabalhasse, mas não lembrava o que já tinha acontecido.
Sabia compilar. Mas não lembrava que ontem já tínhamos tentado outra abordagem. Sabia rodar os testes. Mas esquecia que aquele bug já tinha sido investigado durante duas horas. Sabia as regras. Mas não conhecia a história.
O hábito que mascarava o problema
Por um tempo eu compensei isso do jeito mais humano possível: repetindo. Abria uma sessão nova e despejava contexto. "Ontem tentamos isso." "Não mexe nessa camada porque ela tem um acoplamento estranho." "Esse teste falha quando roda em paralelo." "A decisão do PR anterior foi seguir por outro caminho."
O curioso é que essa repetição parecia parte natural do uso de agentes. Como a resposta melhorava depois que eu explicava tudo de novo, eu não enxergava aquilo como falha de sistema. Parecia só o ritual de entrada: antes de trabalhar, recapitular. O problema é que ritual manual cobra juros quando você alterna entre projetos, máquinas e ferramentas.
Esse foi o primeiro insight importante: o agente não precisava apenas de instruções melhores. Ele precisava de continuidade. E continuidade não é prompt longo. É a capacidade de carregar consequência de uma sessão para outra.
Existem dois tipos de conhecimento
Quando comecei a separar o problema, ficou claro que eu estava chamando duas coisas diferentes de "contexto". Uma é estática: como compilar, como fazer deploy, como estruturar um módulo, como escrever commits.
Esse conhecimento pertence ao CLAUDE.md. A outra parte muda todo dia: o bug investigado ontem, a decisão da última sessão, o experimento que deu errado, o motivo de um PR ter sido abandonado. Isso não pertence ao CLAUDE.md, porque ele teria que ser reescrito o tempo inteiro. É memória. Episódica, viva, automática.
| CLAUDE.md / AGENTS.md | agent-memory-hub |
|---|---|
| Como trabalhar | O que já aconteceu |
| Estático | Dinâmico |
| Escrito por você | Capturado automaticamente |
| Regras | História |
Foi aí que nasceu o agent-memory-hub. Não para substituir o CLAUDE.md, mas para resolver justamente aquilo que ele nunca foi feito para resolver.
O que eu queria que a memória lembrasse
Quando você usa agentes de vez em quando, repetir contexto parece só um incômodo. Quando eles entram no fluxo diário, vira custo operacional. O problema não era guardar "preferências"; era preservar continuidade entre sessões que, para a ferramenta, pareciam independentes.
Na prática, eu queria que a memória guardasse cinco tipos de episódio: decisões tomadas, hipóteses descartadas, bugs já investigados, estado mental de PRs e pequenos padrões de projeto que só aparecem depois de várias conversas.
Esse recorte protegia o projeto de virar um "depósito de tudo". Se tudo é memória, nada é memória. O valor estava em capturar aquilo que eu realmente esqueceria entre uma sessão e outra, especialmente quando alternava entre máquinas, ferramentas e contextos.
A partir daí, a pergunta deixou de ser "qual ferramenta de memória existe?" e virou outra: que tipo de sistema conseguiria capturar esses episódios sem prender meu histórico em uma ferramenta só?
Por que construir em casa
Eu poderia ter parado aqui e adotado uma ferramenta pronta. Existem boas opções para memória de agente, e eu não queria reinventar busca vetorial por esporte. Mas meu problema tinha exigências muito pessoais: funcionar entre Claude Code e Codex, atravessar máquinas, continuar meu quando eu trocasse de ferramenta e ser auditável com uma consulta SQL simples.
A escolha por Postgres via Supabase veio menos por glamour técnico e mais por previsibilidade. Eu queria posse dos dados, pg_dump, inspeção direta, uma tabela que eu pudesse abrir sem pedir licença para produto nenhum. Para memória pessoal de trabalho, isso pesa. O histórico das minhas sessões é parte do meu processo, não só cache de uma ferramenta.
Essa decisão aumentou o peso do que viria depois. Quando você compra uma ferramenta, aceita parte da caixa-preta como pacote. Quando constrói o pipeline, a responsabilidade muda de lugar: se ele falha em silêncio, a culpa não é de uma plataforma distante. É da arquitetura que você escolheu tolerar.
A primeira versão parecia perfeita
A arquitetura era simples: cada sessão era capturada automaticamente e, no início da próxima conversa, o agente recebia um resumo das sessões relevantes. Por baixo, busca híbrida (palavra-chave + pgvector) e uma camada opcional de fatos. Tudo salvo no meu próprio Postgres (via Supabase), sem SaaS, sem lock-in, com a capacidade de rodar pg_dump a qualquer momento.
O desenho: três hooks de ciclo de vida escrevem e leem a mesma tabela Postgres. Captura idempotente (upsert por session_id); o checkpoint do Stop preserva a sessão até um kill abrupto.
Funcionava entre máquinas. Funcionava entre ferramentas. Funcionava tão bem que eu parei de pensar nela. Esse foi o perigo: a automação tinha sumido da minha atenção.
Você deixa de verificar porque o sistema parece confiável, e o sistema parece confiável justamente porque as falhas não aparecem na superfície. Até o dia em que eu resolvi conferir uma sessão específica.
O dia da sessão fantasma
A sessão que me fez puxar esse fio não parecia especial. Era só mais uma conversa longa, dessas em que você empilha contexto, decisões pequenas, saídas de comando e ajustes de rota. Em algum momento, bateu uma dúvida simples: "será que isso foi salvo?".
A pergunta era quase burocrática. Eu não estava caçando bug. Só queria confirmar que a memória tinha feito o trabalho dela. Fui no log. Nada. Fui no banco. Nada. A sessão que tinha acabado de acontecer não existia para o sistema que deveria lembrar dela.
Esse tipo de momento muda sua relação com uma ferramenta. Até ali, eu pensava na memória como comodidade. Depois disso, passei a enxergar como infraestrutura. E infraestrutura que falha sem sinalização não é infraestrutura: é uma aposta silenciosa.
O erro estava escondido no exit 0
Quando segui o rastro, o padrão ficou mais desconfortável do que uma sessão perdida. Havia erros intermitentes: sessão sim, sessão não. Algumas conversas chegavam ao banco; outras desapareciam no caminho.
O hook de captura tinha um except que engolia qualquer erro e seguia em frente com exit 0. Do ponto de vista do Claude Code, tudo certo. Do ponto de vista do banco, faltavam sessões inteiras.
E isso é pior do que um crash. Crash você vê: ele para, grita, aparece. Silêncio você não vê. O agente simplesmente "esquece" coisas que deveria saber, e você atribui isso a uma limitação do modelo, não a um pipeline quebrado. A memória parecia funcionar porque ninguém era obrigado a provar que ela tinha funcionado.
Por que falha silenciosa é tão traiçoeira
A falha silenciosa não compete com o seu sistema. Ela compete com a sua interpretação do sistema. Quando o agente esquece algo, sobram explicações plausíveis: o modelo não deu peso suficiente, o resumo ficou ruim, o prompt inicial não trouxe contexto, a busca semântica não encontrou a sessão certa.
Todas essas explicações podem ser verdadeiras. E justamente por isso são perigosas. Elas dão uma narrativa confortável para um problema que talvez esteja um passo antes: a informação nunca foi capturada. Você fica ajustando recall, embeddings e prompt, enquanto o buraco está na ingestão.
Foi aí que a palavra "confiança" começou a parecer errada. Confiança, naquele contexto, era só ausência de evidência contra. O que eu precisava era evidência a favor.
A investigação: seguir o dado, não a intuição
A tentação inicial era corrigir o primeiro erro visível e declarar vitória. Mas pipeline de ingestão raramente quebra em um lugar só. O dado atravessava shell, parser Python, sanitização, insert no Postgres e logs. Qualquer uma dessas camadas podia estar mentindo por omissão.
Então eu fui seguindo o payload como quem segue uma trilha: a entrada original era válida? Ela chegava igual ao Python? O parser aceitava? O banco recusava? O log registrava a falha? O hook devolvia erro para a ferramenta?
Foi isso que mudou o tom da investigação. O bug deixou de ser "por que uma sessão sumiu?" e virou "quantas sessões poderiam sumir sem eu perceber?". Essa segunda pergunta é muito mais desconfortável, e muito mais útil.
Três bugs, todos silenciosos
O que parecia um problema virou três, em camadas diferentes do mesmo pipeline. Vale entrar no detalhe porque esse padrão aparece em qualquer sistema de ingestão que parece "simples" demais para falhar.
Bug 1: caracteres de controle
O payload de cada sessão é JSON. O parser estrito do Python rejeitava qualquer payload com caracteres de controle não-escapados, e o conteúdo de uma sessão de terminal está cheio deles (output de comandos, box-drawing, sequências ANSI). O resultado era um JSONDecodeError que o except engolia.
A correção é de uma linha, mas só funciona porque o erro estava no parse:
payload = json.load(sys.stdin, strict=False) # aceita control chars dentro das strings
Bug 2: o byte nulo
Com o parser tolerante, outra sessão falhou, agora no banco. O Postgres recusa o byte nulo em coluna text, com o erro 22P05: unsupported Unicode escape sequence. Ou seja: o parse passava, mas o INSERT era rejeitado. A correção foi sanitizar o conteúdo, recursivamente, antes de subir:
def strip_nul(obj):
if isinstance(obj, str):
return obj.replace("\x00", "")
if isinstance(obj, dict):
return {k: strip_nul(v) for k, v in obj.items()}
if isinstance(obj, list):
return [strip_nul(v) for v in obj]
return obj
Bug 3: o echo que corrompia o JSON
Este foi o mais sutil, e o mais instrutivo. O comando do hook capturava o payload e o repassava ao Python assim:
payload=$(cat); echo "$payload" | python3 capture_session.py ...
O problema é o echo. Em sh/dash, echo interpreta sequências de barra invertida. Qualquer payload com \ (e sessões têm muitos: sequências ANSI, regex, \u) chegava corrompido ao parser, com o erro Invalid \escape. Por isso alternava: sessão com barra invertida falhava, sessão sem barra passava. O parser nunca teve chance; o dado já chegava quebrado.
A correção é trocar echo por printf '%s', que não interpreta escapes. O teste lado a lado prova o ponto, com a mesma entrada JSON válida:
# mesma entrada válida; via echo quebra, via printf passa
sh -c 'p=$(cat in.json); echo "$p"' | python3 -c 'import json,sys; json.load(sys.stdin)'
# -> JSONDecodeError: Invalid \escape
sh -c 'p=$(cat in.json); printf "%s" "$p"' | python3 -c 'import json,sys; json.load(sys.stdin)'
# -> ok
A lição transversal: cada camada (parser, banco, shell) tinha uma armadilha diferente para o mesmo dado. Um pipeline "simples" de três etapas escondia três modos de falha independentes, todos silenciosos.
Consertar o presente não bastava
Depois de corrigir o hook, ainda sobrava uma pergunta chata: e o passado? As sessões que falharam não voltariam magicamente só porque o código novo estava melhor. Se a memória é história, buraco antigo também importa. Às vezes importa mais, porque ali estavam decisões e tentativas que eu não queria repetir.
O backfill virou parte da correção. Eu precisei reconciliar transcripts locais, identificar sessões que existiam no filesystem mas não no banco, sanitizar payloads antigos, anexar sessões de subagentes e lidar com uma segunda conta que também tinha histórico relevante. Não era glamouroso. Era faxina de infraestrutura.
flowchart LR
L["Transcripts locais"] --> C["Classificar sessões válidas"]
C --> M["Encontrar ausentes no banco"]
M --> S["Sanitizar payload antigo"]
S --> U["Upsert idempotente"]
U --> H["health confirma cobertura"]
H --> R["História volta a ficar inteira"]
Esse detalhe é fácil de subestimar. Muita correção de pipeline para no "daqui para frente está bom". Só que, para memória, o passado é o produto. Se você corrige apenas o futuro, deixa a parte mais valiosa da ferramenta com lacunas invisíveis.
A virada: o problema não é lembrar, é verificar
Consertar os bugs foi o de menos. O que ficou foi a pergunta que eles forçaram: eu passei semanas confiando numa coisa quebrada e não soube. O problema não era só técnico. Era epistemológico: por que eu achava que aquela memória merecia confiança?
Porque a métrica que a categoria inteira otimiza é "lembrar melhor": recall mais esperto, embeddings melhores, resumos mais densos. Isso importa. Mas a dor que me pegou estava um passo antes: prova de que a captura aconteceu. Ninguém te avisa quando a memória falha. Não há recibo, não há health check, não há detecção de gap. Você descobre quando o agente esquece, se descobrir.
Então parei de tratar confiança como sentimento e passei a construir verificação. Duas peças:
Um health check de cobertura. Um comando que reconcilia os transcripts locais (de todas as ferramentas) contra o que está no banco, ignora sessões vazias, e vigia a taxa de erro da captura nas últimas 24 horas. A saída é direta:
agent-memory-hub · health
✓ cobertura ██████████████████████ 86/86 sessões locais salvas
✓ captura últimas 24h: 51 ok, 0 erros
✓ subagentes 13/13 sessões com subagentes anexados
flowchart LR
L["Transcripts locais<br/>(todas as ferramentas)"] --> R{"health: reconcilia"}
B[("DB · public.sessions")] --> R
R -->|"gap ou erro de captura"| ALERT["aparece: cobertura abaixo de 100%"]
R -->|"tudo bateu"| OKN["86/86 · 0 erros / 24h"]
Quando algo quebra, isso aparece, em vez de passar batido. É a diferença entre memória que você confia e memória que você verifica.
Um servidor MCP para recall sob demanda. O recall padrão é passivo: injeta um resumo no início da sessão, antes de você sequer dizer o que quer fazer. Expus a memória como ferramentas MCP (em stdlib puro, sem dependências) para que o agente consulte a memória com o contexto da tarefa em mãos: recall_relevant, recent_sessions, get_facts, get_session. A ideia era simples: lembrar na hora certa, não só no começo da conversa. O coração do servidor é um handler JSON-RPC minimalista:
elif method == "tools/call":
text = _call(params["name"], params.get("arguments") or {})
_reply(rid, {"content": [{"type": "text", "text": text}]})
Os números, depois de fechar tudo: 148 sessões, 36 projetos, cobertura local↔banco reconciliada, com as sessões de uma segunda conta e os transcripts de subagentes finalmente incluídos no backfill.
O sistema mudou de personalidade
Antes, a memória era uma promessa otimista: "fica tranquilo, eu salvei". Depois, ela virou um sistema com postura mais adulta: "eu salvei estas sessões, não salvei aquelas, e aqui está a diferença entre o que existe localmente e o que chegou ao banco".
Isso também mudou como eu uso agentes. Quando o recall parece ruim, agora existe uma pergunta anterior à qualidade do modelo: a memória estava disponível? A sessão relevante foi capturada? O agente consultou a história certa? Sem essa camada, qualquer falha parece "culpa da IA". Com ela, o esquecimento vira algo que dá para investigar.
O que o projeto faz hoje
Depois dessa sequência de correções, o agent-memory-hub deixou de ser só um par de hooks. Virou uma pequena plataforma pessoal de memória para agentes: captura, consulta, verificação, console, adapters, backup, perfil e avaliação de qualidade. Não nasceu assim; foi ficando assim cada vez que uma falha pedia uma superfície melhor.
| Camada | O que resolve hoje |
|---|---|
| Captura | Hooks do Claude Code salvam sessões; adapters puxam histórico de Codex e Cursor. |
| Consulta | Recall no início da sessão, MCP sob demanda e console mem para buscar, inspecionar e resumir. |
| Observabilidade |
health reconcilia transcripts locais com o banco; log mostra o que aconteceu. |
| Qualidade | Suite pytest, CI e harness de avaliação de recall com hit@k/MRR. |
| Evolução | Perfil cross-projeto propõe regras; você aprova antes de virar comportamento. |
Os commits contam bem essa evolução. Primeiro vieram os bugs de captura. Depois health e log. Em seguida MCP, standup, adapters para outras ferramentas, empacotamento do comando mem, testes em CI e avaliação de recall. Até tuning de ranking entrou no fluxo: a ideia de aplicar viés de recência foi testada e rejeitada por dados quando piorou o recall.
Isso muda a leitura do projeto. Ele não é uma ideia abandonada depois de uma pesquisa de mercado. É uma ferramenta viva, usada, com commits empilhando aprendizado real. O cuidado foi outro: não confundir tração open-source e utilidade diária com a obrigação de transformar tudo em empresa imediatamente.
Antes de virar startup, eu testei a tese
A parte sedutora da história seria parar aqui e dizer: encontrei uma dor real, construí uma solução, agora existe uma oportunidade. E, por algumas horas, eu quis acreditar nisso. "Memória verificável para agentes" soa como categoria. Parece ter nome, urgência e um ângulo claro.
Mas uma dor real não é automaticamente uma empresa. Então eu mudei a pergunta. Em vez de procurar confirmação, procurei atrito: quem já está perto disso? O que incumbentes conseguem copiar rápido? O que é dor profunda e o que é feature adjacente? Se eu fosse concorrente de mim mesmo, quanto tempo levaria para neutralizar esse recorte?
Essa pesquisa não diminuiu o valor do projeto. Pelo contrário: deixou o valor mais claro. Como ferramenta pessoal, ele me economiza tempo e reduz repetição todo dia. Como projeto open-source, já começou a receber stars e sinalizar que a dor ressoa fora da minha máquina. Como startup, talvez ainda precisasse de uma tese mais larga do que "prova de captura". E tudo bem. Nem todo projeto útil precisa virar empresa antes de terminar de aprender o próprio formato.
O que funcionou: uso diário e sinais reais
A parte que mais me orgulho é que o projeto não ficou no campo da ideia. Ele está no meu fluxo diário. Captura sessões, aparece no começo de conversas novas, ajuda a recuperar decisões antigas e reduz aquele trabalho chato de reexplicar contexto para o agente.
Também não ficou invisível para outras pessoas. O repo já recebeu stars, e isso importa como sinal pequeno, mas honesto: não é validação de mercado, mas mostra que a dor é reconhecível. A pesquisa adversarial não serviu para abandonar o projeto; serviu para calibrar a ambição. O resultado foi sóbrio:
| Ferramenta | O que já cobre | O recorte que ainda sobra |
|---|---|---|
| MemGuard | "Datadog para memória de agente": health e trust-scoring. | Prova de captura, detecção de gap silencioso, "recibos de memória". Real, mas fino, e copiável pelos incumbentes em semanas. |
| Zep | Governança enterprise: SOC 2 Type II, HIPAA, audit de acesso. | |
| MemTrust (paper, 2026) | Audit cripto-encadeado e attestation da memória. | |
| mem0 | Events API de auditoria já embutida. |
O tema "observar/confiar na memória" está enchendo rápido. O recorte exato que sobra aberto (prova de captura, detecção de gap silencioso, "recibos de memória") é real, mas é fino, e copiável pelos incumbentes em semanas (o mem0, por exemplo, já tem um Events API de auditoria).
Então a decisão foi continuar usando, continuar abrindo, continuar melhorando e não forçar uma narrativa de startup antes da hora. Hoje o valor está bem claro: é dogfood real, open-source, com sinais públicos de interesse, e útil o suficiente para permanecer no meu dia a dia.
Um limite técnico honesto, para quem for replicar: a correção do hook só vale em sessões novas, porque hooks são carregados no início da sessão. A rede de segurança é o evento de fim de sessão, que salva o transcript inteiro de forma limpa, então mesmo com os checkpoints intermediários falhando, o estado final não se perde.
Conclusão
Se você roda agentes com memória, faça uma coisa esta semana: cheque se ela está capturando de verdade. Não assuma. Procure o equivalente do meu "fui no log, fui no banco". O modo de falha mais perigoso de um pipeline de ingestão não é o que grita, é o que falha calado e te deixa confiante.
O princípio generaliza para além de agentes de IA: para qualquer sistema que ingere dados e pode falhar em silêncio, observabilidade vale mais que otimização. Verificar é mais importante do que confiar. E o meta-aprendizado de produto, talvez o mais útil: rodar pesquisa adversarial para calibrar a própria ambição é um superpoder, não uma derrota. Às vezes o melhor resultado de uma investigação é entender que o projeto deve continuar vivo, só que no formato certo.
O projeto é open-source e self-hosted. Se te economizar uma única sessão re-explicando seu projeto ao agente, já valeu.
Publicado originalmente em buildcomcarlos.com.



Top comments (0)