cogvault

Memória local para agentes de IA sobre arquivos Markdown simples: recall híbrido vetorial + BM25 (RRF), uma memória isolada por diretório de agente, totalmente offline sem LLM no fluxo.

Documentação

Comece em 30 segundos

Plugin Claude Code — servidor MCP mais uma skill que informa ao agente quando lembrar e quando gravar:

/plugin install cogvault --marketplace NBibikov/cogvault

Claude Code anterior a 2.1.275: /plugin marketplace add NBibikov/cogvault, depois /plugin install cogvault@cogvault.

A memória fica em ~/.cogvault/memory (defina COGVAULT_TENANT para alterar). O plugin adiciona /cogvault:remember.

Qualquer cliente MCP, uma linha (requer uv):

claude mcp add cogvault -- uvx cogvault mcp --tenant ~/agent/memory
Claude Desktop, Cursor, Windsurf, Cline — configuração JSON

Adicione a claude_desktop_config.json, ~/.cursor/mcp.json ou à configuração MCP do seu cliente:

{
  "mcpServers": {
    "cogvault": {
      "command": "uvx",
      "args": ["cogvault", "mcp", "--tenant", "~/agent/memory"]
    }
  }
}

Já tem memória em Markdown? Aponte o tenant para ela — nada para importar. A memória automática do Claude Code funciona como está (frontmatter type, [[links]] e tudo):

M=~/.claude/projects/<project>/memory
uvx cogvault index  --tenant $M --ignore MEMORY.md   # first pass embeds, later passes are incremental
uvx cogvault search --tenant $M "how do we deploy"

O servidor MCP indexa sozinho na inicialização; a CLI search lê o índice existente. --ignore MEMORY.md impede que o arquivo de índice dispute com os cards que ele referencia.

A real Claude Code session with the cogvault plugin: asked why the worker keeps restarting, the agent recalls a memory card and answers with the fix, then saves a new card when told to remember something

Respostas não editadas de uma sessão real (Sonnet, plugin instalado, uma memória demo de seis cards); apenas o tempo de espera foi cortado.


Por quê

A maioria das ferramentas de "memória para agentes de IA" quer ser um daemon LLM autônomo que resume seu trabalho em um banco de dados opaco ou um grafo que você não consegue ler. Para uma frota de agentes de codificação que só precisam lembrar de forma confiável uma decisão, uma correção de bug ou um detalhe de infraestrutura, essa é a troca errada.

cogvault aposta no oposto:

  • Seus arquivos Markdown são a fonte da verdade. Abra-os, edite-os, git diff eles. O índice SQLite é um cache derivado — delete-o e ele se reconstrói a partir dos arquivos.
  • Uma biblioteca, muitos tenants. Cada agente recebe um namespace de memória isolado via seu próprio diretório. Um processo carrega cada modelo de embedding uma vez e o compartilha entre todos os tenants que toca; com o servidor MCP stdio, isso significa um pequeno processo por sessão de agente, não um daemon central.
  • Sem LLM no caminho. Ingestão e recuperação são determinísticas. Seu agente é o LLM — ele não precisa de um segundo para lembrar.
  • Local, privado, offline. FastEmbed roda no dispositivo. Nada sai da sua máquina.

Comparado a

Verificado contra o README e a documentação de cada projeto em 2026-10-05.

cogvaultbasic-memorymem0GraphitiLetta Code
Fonte da verdadeArquivos MarkdownArquivos MarkdownBanco vetorial (Qdrant / pgvector)Banco de grafo (Neo4j, FalkorDB, …)Markdown em um repositório git por agente
LLM necessário para armazenar ou lembrarNãoNão (reranker opcional)Sim por padrão (add() extrai fatos)Sim para ingestãoSim — o agente edita sua própria memória
RecuperaçãoVetorial + BM25, RRF, decaimento, MMRTexto completo + vetorial, rerank opcionalSemântica + BM25 + entidadesSemântica + BM25 + grafoBusca em arquivos; híbrida opcional
InfraestruturaUm processo, arquivo SQLiteUm processo, SQLite (Postgres opcional)Biblioteca, ou Docker + servidor PostgresUm banco de grafoBackend Letta

Escolha outra coisa quando: você quiser que um LLM destile e mescle fatos para você (mem0), relações entre entidades forem o ponto (Graphiti), você quiser que o agente gerencie sua própria memória (Letta), ou quiser um app de notas mais rico em torno da mesma ideia de Markdown, com sincronização Obsidian e uma opção hospedada (basic-memory — o mais próximo do cogvault).

Escolha cogvault quando: você roda vários agentes e quer que a memória de cada um fique isolada em seu próprio diretório atrás de um único processo; você quer que a recuperação seja determinística e offline; e você quer medir isso — cogvault eval pontua a recuperação nas consultas reais dos seus agentes e cogvault analyze lista o que eles tentaram lembrar e não conseguiram.

Como funciona

Markdown files are indexed into a derived SQLite database (vectors + FTS5) and recalled through MCP, CLI or Python

Anatomia de uma recuperação

A query runs through a semantic and a keyword ranker, fused with RRF, then temporal decay, MMR and one-hit-per-card

A recuperação híbrida funde a classificação semântica (vetorial) e por palavras-chave (BM25/FTS5) com Fusão de Classificação Recíproca, e então aplica decaimento temporal opcional (memória recente supera a obsoleta) e MMR (resultados diversos no topo, não cinco quase duplicados). Cada card contribui apenas com seu melhor chunk, então um arquivo longo não pode preencher toda a lista de resultados.

Benchmark

Bar chart, 65 real agent queries: e5-small with summary chunk hit@1 0.57, hit@5 0.91, MRR 0.70; MiniLM default hit@5 0.80; bge-small-en hit@5 0.77

Medido em tráfego de recuperação real, não em perguntas sintéticas: 66 consultas amostradas dos logs de consulta de 6 tenants de agentes ao vivo (58% em ucraniano, o restante em inglês), cada uma julgada contra os cards reais — incluindo respostas que nenhuma configuração retornou. Uma consulta não tem resposta na memória e conta como lacuna, então 65 são pontuadas. Cada configuração foi reindexada do zero em cópias dos mesmos tenants com cogvault 0.11.0.

Configuraçãohit@1hit@5MRR@10
multilingual-e5-small, chunk_chars = 700, chunk de resumo0.570.910.70
multilingual-e5-small, chunk_chars = 700, sem chunk de resumo0.550.860.69
paraphrase-multilingual-MiniLM-L12-v2 (padrão embutido)0.540.800.66
bge-small-en-v1.5 (somente inglês)0.570.770.65

O que os números dizem e não dizem:

  • hit@1 é um empate. Todos os quatro ficam entre 0,54–0,57, e os intervalos de bootstrap de 95% se sobrepõem quase completamente. Consultas reais de agentes parecem títulos de cards, então o card certo geralmente vence só pelo nome.
  • A lacuna está no top 5. e5-small com o chunk de resumo coloca a resposta no top 5 para 91% das consultas vs. 80% para o MiniLM padrão e 77% para bge somente inglês nesta memória de idioma misto. É isso que um agente lendo 5 resultados realmente sente.
  • 65 consultas ainda é uma amostra pequena. Trate diferenças abaixo de ~0,1 como ruído. Os números agregados estão em assets/benchmark.json; as consultas são privadas e permanecem em cada tenant.

Reranking

Um cross-encoder lê a consulta e cada card candidato juntos, então ele pode dizer qual card responde à pergunta, não apenas qual é sobre o mesmo tópico. Com rerank = "BAAI/bge-reranker-v2-m3-int8", o cogvault pontua o top 10 híbrido pelos primeiros 800 caracteres de cada arquivo de card e os reordena. Nas mesmas 65 consultas (cogvault 0.12.0, e5-small + chunk de resumo):

hit@1hit@5MRR@10
somente híbrido0.600.880.70
híbrido + reranker0.800.910.85

O reranker melhorou 17 consultas e piorou 3. O intervalo de bootstrap de 95% do ganho de hit@1 é de +0,09 a +0,34. O custo é ~2 GB de RAM e 1–2 s por recuperação em uma CPU Apple M-series, então ele roda apenas no daemon compartilhado e em cogvault eval (--no-rerank pontua sem ele).

Rode a mesma verificação na sua própria memória: coloque consultas julgadas em <tenant>/.cogvault-golden.jsonl ({"query": "...", "relevant": ["file.md"]}, vazio relevant = uma lacuna conhecida) e execute cogvault eval --tenant DIR.

Escolhendo um modelo de embedding

A memória de agentes geralmente não é somente em inglês. O padrão é multilíngue para que nada seja quebrado de fábrica — mas escolha o modelo que combina com a mistura de idiomas da sua frota (defina COGVAULT_MODEL, ou Config(model=...)). Trocar de modelo reconstrói o índice automaticamente.

Modelo (COGVAULT_MODEL)DimTamanhohit@5 em consultas reais*Cirílico / multilíngueQuando
paraphrase-multilingual-MiniLM-L12-v2 (padrão)3840,22 GB0,80✅ funcionaFrotas de idioma misto; padrão seguro
BAAI/bge-small-en-v1.53840,13 GB0,77❌ vetores cirílicos quebramMemória somente em inglês
intfloat/multilingual-e5-small3840,47 GB0,91✅ melhor por GB (janela de 512 tokens)Frotas de idioma misto; use chunk_chars = 700
intfloat/multilingual-e5-large10242,24 GBnão medido✅ melhorQualidade máxima, RAM de sobra

*Do benchmark acima: 65 consultas reais sobre memória mista EN/UK, cogvault 0.11.0. Em memória somente em inglês, bge-small-en é uma boa escolha; em conteúdo ucraniano ele retorna uma margem de relevância negativa (um distrator supera a resposta), então é inseguro para memória não inglesa. Rode cogvault eval no seu próprio vault para decidir.

COGVAULT_MODEL=BAAI/bge-small-en-v1.5 cogvault index --tenant ~/agent/memory

Fixe o modelo por tenant para que ele viaje com os dados em vez de depender de cada comando exportar COGVAULT_MODEL (esqueça uma vez e uma incompatibilidade de modelo re-embute silenciosamente todo o índice). Coloque um .cogvault.toml na raiz do tenant:

# ~/agent/memory/.cogvault.toml
model = "BAAI/bge-small-en-v1.5"
# optional: recursive = true, strip_frontmatter = true, ignore_globs = ["Templates/*"]

Agora cogvault search --tenant ~/agent/memory "…" usa o modelo certo sem variável de ambiente. Precedência: --model / $COGVAULT_MODEL explícitos > .cogvault.toml > padrão embutido.

Instalação

uv tool install cogvault        # CLI on PATH
# or
pip install cogvault

Ou pule a instalação e rode sob demanda com uvx cogvault …. A primeira execução baixa o modelo de embedding (~0,2–0,5 GB, uma vez por máquina).

Adicione ao Claude Code como servidor MCP em uma linha:

claude mcp add cogvault -- uvx cogvault mcp --tenant ~/agent/memory

Também listado no Registro MCP oficial como io.github.NBibikov/cogvault. Wheels estão anexados a cada release do GitHub.

Início rápido

# index a tenant's markdown memory
cogvault index --tenant ~/agent/memory

# search (hybrid semantic + keyword)
cogvault search --tenant ~/agent/memory "how do I restart the worker service"

# enable temporal decay (recent wins) and tune diversity
cogvault search --tenant ~/agent/memory "deployment steps" --half-life 30 --mmr 0.5

# only cards of one frontmatter type (user / feedback / project / reference / …)
cogvault search --tenant ~/agent/memory "hard rules for deploys" --type feedback

Cards de memória

O cogvault entende duas convenções leves de Markdown (ambas opcionais — arquivos simples indexam bem):

  • Frontmatter type — plano (type: reference) ou aninhado (metadata: → type: reference). Analisado na indexação e filtrável na busca (--type, parâmetro MCP type, search(card_type=...)). Cada resultado carrega um campo type; cards sem frontmatter recebem null.
  • [[wiki-links]] — os alvos dos links são indexados, e o principal resultado de busca inclui uma lista related de cards vinculados que existem no índice (links fantasmas são descartados; a correspondência é pelo nome exato do arquivo sem extensão).

Como servidor MCP (Claude Code, Cursor, qualquer cliente MCP)

claude mcp add cogvault -- uvx cogvault mcp --tenant ~/agent/memory

Expõe duas ferramentas:

  • cogvault_recall — busca híbrida em linguagem natural sobre a memória deste agente. O parâmetro opcional type filtra para um tipo de card de frontmatter; o principal resultado inclui uma linha Related: construída a partir do seu [[wiki-links]].
  • cogvault_record — salva um fato; ele é gravado como um card Markdown e indexado

Indexando uma árvore de pastas (vaults Obsidian, bases de conhecimento)

Por padrão, um tenant é um único diretório plano de arquivos .md. Para um vault aninhado (ex.: Obsidian, com 01-Projects/…, frontmatter e pastas para pular), opte por:

cogvault index --tenant ~/vault \
  --recursive \
  --strip-frontmatter \
  --ignore ".obsidian/*" --ignore ".trash/*" --ignore "Templates/*"
  • --recursive percorre subdiretórios; os arquivos mantêm seu caminho relativo ao tenant, então duas notas chamadas Tasks.md em pastas diferentes nunca colidem.
  • --strip-frontmatter remove um bloco YAML --- … --- inicial para que suas chaves não poluam o embedding.
  • --ignore GLOB (repetível) pula caminhos relativos à raiz do tenant.

As mesmas flags existem em search e mcp, e como Config(recursive=True, strip_frontmatter=True, ignore_globs=(...)) para a biblioteca. A indexação é incremental: a primeira passada incorpora tudo, passadas posteriores só re-incorporam arquivos alterados. (Referência: um vault de ~3.500 notas → ~9.500 chunks, primeira indexação ≈ 3–4 min, depois recuperação quente em milissegundos de um dígito.)

Como biblioteca

from cogvault import Vault, Config

vault = Vault("~/agent/memory", Config(half_life_days=30))
vault.reindex()
for hit in vault.search("where are credentials stored"):
    print(hit["score"], hit["file"], hit["snippet"])

Mantendo um tenant saudável

cogvault doctor --tenant DIR relata o que degrada silenciosamente a recuperação: cartões sem frontmatter ou tipo, nomes de arquivo com timestamp legado, frontmatter aninhado dentro de frontmatter, slugs duplicados de name: e [[links]] que não resolvem para nada. Links são resolvidos pelo name: do frontmatter, pelo nome do arquivo, por ambos os estilos de separador e com ou sem o prefixo do tipo de cartão; links dentro de código e caminhos para arquivos fora do tenant não são contados.

cogvault repair --tenant DIR corrige a parte mecânica (dry run por padrão, --apply para gravar): desaninha frontmatter aninhado, infere um tipo ausente, renomeia card-<timestamp>-….md para <type>_<slug>.md e reescreve toda referência a ele (incluindo MEMORY.md), e adiciona frontmatter mínimo a cartões <type>_*.md que não o possuem. Cartões saudáveis são deixados intactos, e cartões reparados mantêm seu mtime para que a decadência temporal não seja reiniciada.

Registro de eficácia

Cada recuperação é registrada (uma linha JSONL) para que você possa medir se a memória está realmente ajudando. cogvault analyze transforma o log em um relatório:

cogvault analyze            # recalls, latency, per-tenant hit distance, weakest hits, card writes
cogvault analyze --json     # machine-readable
cogvault analyze --since 7  # only the last 7 days (or --since 2026-10-05)

A seção que importa é hits mais fracos: o pior decil de cada tenant por distância vetorial — consultas onde a recuperação retornou algo (a busca híbrida quase sempre retorna) mas provavelmente não a resposta. Essa lista é o que seus agentes tentaram recuperar e não conseguiram, ou seja, as lacunas de memória a preencher. Defina COGVAULT_LOG=off para desativar, ou COGVAULT_LOG=/path.jsonl para realocar.

Frotas multi-tenant

Aponte um processo para muitos tenants — cada diretório é um namespace isolado, comprovado pela suíte de testes (test_multi_tenant_isolation). O Agente B nunca pode recuperar a memória do Agente A, a menos que você aponte B para o diretório de A.

Four agents, each pointed at its own memory directory with its own index; tenants are isolated

Daemon compartilhado

Cada cliente MCP inicia seu próprio cogvault mcp. Sem um daemon, cada um desses processos carrega o modelo de embedding (~1 GB), e nenhum pode arcar com o reranker. cogvault daemon carrega cada modelo uma vez para todos os tenants e os serve por um socket Unix (~/.cache/cogvault/daemon.sock, modo 600). cogvault mcp e cogvault search o encontram automaticamente e encaminham para ele; o processo MCP então permanece em ~40 MB. Quando o daemon está fora do ar, eles buscam em processo como antes, sem o reranker, e registram um evento daemon-fallback no log de consultas.

cogvault daemon            # run in the foreground
cogvault daemon --status   # ping it: version, loaded models, tenants served

O daemon descarrega um modelo após 10 minutos sem busca ou reindexação, e o carrega novamente na próxima recuperação (~1,5 s extras nessa chamada). Defina --idle-unload SECONDS ou $COGVAULT_IDLE_UNLOAD (0 mantém os modelos carregados). Medido com e5-small e o reranker: ~1,8 GB carregados, ~0,4 GB descarregados. ONNX Runtime usa 4 threads ($COGVAULT_THREADS, 0 = todos os núcleos) e sem arena de memória de CPU, então uma reindexação completa atinge o pico de ~1 GB em vez de manter vários GB depois. Um shim que iniciou enquanto o daemon estava fora do ar espera até 60 s por ele antes de carregar um modelo por conta própria, e descarta um modelo que carregou assim que o daemon responde novamente.

O reranker tem sua própria contagem de threads ($COGVAULT_RERANK_THREADS, padrão = os núcleos de desempenho no Apple silicon, senão 4). Ele roda apenas no momento da recuperação e é a maior parte da latência de recuperação: em 10 P-cores, a recuperação p50 passou de 2,3 s (4 threads) para 1,65 s, e para 1,05 s com onnxruntime 1.31 (essa versão também reduziu a recuperação de 4 threads para 1,5 s).

No macOS, execute-o sob launchd com RunAtLoad e KeepAlive (argumentos de programa cogvault daemon). Após atualizar o cogvault, reinicie o daemon: launchctl kickstart -k gui/$(id -u)/<label>.

Notas de design

DecisãoPorquê
Markdown = fonte da verdadeLegível por humanos, versionável com git, editável, nunca bloqueado em um banco de dados
SQLite + sqlite-vec + FTS5Busca híbrida sem infraestrutura; um arquivo .db portátil; reconstruível
FastEmbed (MiniLM multilíngue padrão, 384-d)ONNX em processo, sem servidor, sem chave de API, ~220 MB
Cache de hash de conteúdoReindexação só incorpora chunks alterados
RRF + decadência + MMRPrecisão, recência e diversidade sem um banco de grafos
Um processo, muitos tenantsInfraestrutura de frota, não um sidecar de desktop para um único usuário
WAL + reindexação incrementalAgentes concorrentes leem enquanto um escreve; apenas arquivos alterados são reincorporados
Daemon compartilhado opcionalUma cópia de cada modelo para a frota; clientes recorrem ao processo quando ele está fora do ar

Roadmap

  • Importadores (migrar memória existente de outros armazenamentos)
  • Embedders plugáveis (Ollama, endpoint compatível com OpenAI)
  • valid_until validade temporal por cartão
  • Transporte FastMCP opcional

Licença

MIT — sua memória, seus arquivos, sua infraestrutura. Para sempre.

Figuras são SVG construídas à mão a partir de assets/make_graphics.py — python assets/make_graphics.py --png as regenera.