Memora

Um servidor MCP leve para armazenamento de memória semântica, grafos de conhecimento e contexto entre sessões

Documentação

Memora Logo Memora

"Você nunca sabe realmente o valor de um momento até que ele se torne uma memória."

Dê aos seus agentes de IA memória coletiva persistente
Uma camada de memória MCP para agentes: armazenamento estruturado, recuperação semântica, relações em grafo e contexto entre sessões com respaldo em fontes.

Version License Mentioned in Awesome Claude Code

Memora absorb and digest flow

Absorva o trabalho do agente em memória de grafo durável e use memory_digest(topic) para recuperar memórias relevantes, TODOs/questões, arestas relacionadas e IDs de fonte.

Recursos · Pré-visualização · Instalação · Uso · Configuração · Multi-DB · Contêineres · Grafo ao Vivo · Grafo na Nuvem · Chat · Busca Semântica · Documentos · Dedup com LLM · Vinculação · Neovim

Recursos

Armazenamento Principal

  • 💾 Armazenamento Persistente - SQLite com sincronização opcional na nuvem (S3, R2, D1)
  • 🗄️ Roteamento multi-banco de dados - Um processo atende a vários armazenamentos; um workspace alcança o seu próprio em /mcp/<name> (veja Roteamento multi-banco de dados)
  • 📂 Organização Hierárquica - Estrutura de seção/subseção com atribuição automática de hierarquia
  • 📦 Exportar/Importar - Backup e restauração com estratégias de mesclagem

Absorção e Linhagem

  • 🧬 Absorção - Alimente fatos; um LLM classifica cada um em relação ao armazenamento (duplicado / atualização / contradição / relacionado / novo), ignora duplicados, vincula relações e consolida fatos relacionados — com pré-visualização dry_run
  • 🌱 Linhagem de Substituição - Atualizações substituem conhecimento antigo em vez de excluí-lo; a recuperação segue a cadeia até a versão atual por padrão (modos follow: active, latest, full_history)
  • 🗞️ Resumo de Tópico - memory_digest(topic) agrupa memórias relevantes, TODOs/questões abertos, arestas relacionadas e IDs de fonte em uma única recuperação

Busca e Inteligência

  • 🔍 Busca Semântica - Embeddings vetoriais (TF-IDF, sentence-transformers, OpenAI)
  • 🎯 Consultas Avançadas - Texto completo, intervalos de datas, filtros de tags (AND/OR/NOT), busca híbrida
  • 🔀 Referências Cruzadas - Memórias relacionadas vinculadas automaticamente com base em similaridade
  • 🤖 Deduplicação com LLM - Encontre e mescle duplicados com comparação alimentada por IA
  • 🔗 Vinculação de Memórias - Arestas tipadas, aumento de importância e detecção de clusters

Armazenamento de Documentos

  • 📄 Documentos Estruturados - Armazene documentos markdown como árvores de fragmentos pesquisáveis (afirmações, itens de plano, referências, riscos)
  • 🔒 Integridade de Fragmentos - Protege contra exclusão/mesclagem/absorção acidental de fragmentos de documentos
  • 🔍 Busca Granular - Afirmações e descobertas individuais são pesquisáveis semanticamente enquanto o documento completo permanece recuperável como uma unidade

Ferramentas e Visualização

  • Automação de Memória - Ferramentas estruturadas para TODOs, questões e seções
  • 🕸️ Grafo de Conhecimento - Visualização interativa com renderização Mermaid e sobreposições de clusters
  • 🌐 Servidor de Grafo ao Vivo - Servidor HTTP integrado com opção hospedada na nuvem (D1/Pages)
  • 💬 Converse com Memórias - Painel de chat com RAG e chamada de ferramentas LLM para buscar, criar, atualizar e excluir memórias via chat em streaming
  • 📡 Notificações de Eventos - Sistema baseado em polling para comunicação entre agentes
  • 📊 Estatísticas e Análises - Uso de tags, tendências e insights de conexões
  • 🧠 Insights de Memória - Resumo de atividade, detecção de obsolescência, sugestões de consolidação e análise de padrões alimentada por LLM
  • 📜 Histórico de Ações - Acompanhe todas as operações de memória (criar, atualizar, excluir, mesclar, aumentar, vincular) com visualização de linha do tempo agrupada

Pré-visualização

Memora memory graph demo Memora memory interaction demo

Instalação

Dois caminhos. pip é um filho stdio local que o cliente inicia. Um contêiner é um serviço HTTP destacado que você inicia com up; com MEMORA_DATABASES ele atende a vários armazenamentos a partir de um único processo. O LaunchAgent supervisiona o proxy, não o contêiner — após uma reinicialização do host, o ouvinte pode voltar enquanto seu upstream ainda está parado. Se você está executando memora como um serviço, o caminho do contêiner é a instalação.

pip (local / stdio)

pip install memora-mcp

O pacote PyPI é memora-mcp (memora puro no PyPI é um projeto não relacionado). Inclui armazenamento em nuvem (S3/R2) e embeddings OpenAI prontos para uso.

# Optional: local embeddings (offline, ~2GB for PyTorch)
pip install "memora-mcp[local]"

# Latest development version straight from git
pip install "git+https://github.com/agentic-box/memora.git"

Em seguida, inicie-o a partir de .mcp.json com "command": "memora-server" (veja Configuração).

Contêiner (serviço HTTP)

O runtime padrão é o CLI container da Apple. Cada operação de contêiner que scripts/memora-instance.sh executa (build, up, status, logs, down) usa $MEMORA_CONTAINER_BIN (padrão container). O processo proxy gerado não usa; ele codifica container list.

Antes do primeiro build:

  1. Instale o CLI container da Apple (pkg assinado dos seus releases no GitHub). Ele precisa de um Mac com silício da Apple executando macOS 26 — a Apple não suporta versões mais antigas do macOS para container.

  2. Inicie o runtime — o primeiro comando documentado pela Apple, que também instala um kernel se nenhum estiver configurado:

    container system start
    
  3. Clone este repositório e cd nele:

    git clone https://github.com/agentic-box/memora.git
    cd memora
    
  4. Copie o modelo de instância. Ele vem com INSTANCE=myinstance para que as linhas build/up/proxy posteriores correspondam sem renomear. Edite PORT e um backend (STORAGE_URI, VOLUME ou MEMORA_DATABASES):

    cp instances/example.env instances/myinstance.env
    
  5. Crie o arquivo de credenciais e instale o proxy que o LaunchAgent executará. cred_args() requer um .mcp.json cujo mcpServers.memora.env contém CLOUDFLARE_API_TOKEN (acesso D1) e as chaves de embedding/LLM — up falha se esse arquivo estiver ausente. O script procura por ~/.config/memora/credentials.mcp.json se esse arquivo existir, caso contrário ~/repos/agentic-box/.mcp.json. Defina CRED_SOURCE no arquivo de instância para escolher um caminho. Separadamente, proxy renderiza um plist cujo executável é $MEMORA_PROXY_BIN (padrão ~/.local/libexec/memora/memora_proxy.py) e cujos logs ficam em $MEMORA_LOG_DIR (padrão ~/.local/var/log) — nada cria qualquer um deles em um clone novo.

    mkdir -p ~/.config/memora ~/.local/libexec/memora ~/.local/var/log
    cp scripts/memora_proxy.py ~/.local/libexec/memora/
    # real values; any key is fine, an absent file is not
    # the default umask is permissive -- chmod 600 keeps other local accounts out
    cat > ~/.config/memora/credentials.mcp.json <<'JSON'
    {"mcpServers":{"memora":{"env":{"CLOUDFLARE_API_TOKEN":"REPLACE","OPENAI_API_KEY":"REPLACE"}}}}
    JSON
    chmod 600 ~/.config/memora/credentials.mcp.json
    

    Esse JSON é a configuração mínima correta: tanto o LLM quanto os embeddings usam o host padrão da OpenAI com uma chave OpenAI real. Não adicione OPENAI_BASE_URL apontando para OpenRouter sem o par de embeddings de Embeddings — OpenRouter não tem endpoint de embeddings, toda chamada de embed retorna 404, e memora silenciosamente recorre a sacos de palavras TF-IDF enquanto parece saudável.

Em seguida:

./scripts/memora-instance.sh build myinstance   # tags IMAGE from myinstance.env (memora-pilot if IMAGE is unset)
./scripts/memora-instance.sh up      myinstance # runs that same IMAGE
./scripts/memora-instance.sh proxy   myinstance # render the LaunchAgent; run the printed launchctl

up não publica uma porta do host. O ouvinte ao qual o workspace se conecta é o proxy. proxy apenas renderiza um LaunchAgent do macOS e imprime os comandos launchctl — ele não carrega o serviço. Execute esses comandos impressos.

A URL do workspace impressa é sempre http://127.0.0.1:<PORT>/mcp (o padrão do registro). Para um armazenamento não padrão, acrescente /<name> você mesmo — um /mcp puro em um registro vincula silenciosamente MEMORA_DEFAULT_DB:

{"mcpServers": {"memora": {"type": "http", "url": "http://127.0.0.1:<PORT>/mcp/<store>"}}}

Justificativa do proxy, credenciais, arquivos de instância e MEMORA_CONTAINER_BIN: Implantação de Contêiner.

Uso

O servidor é executado automaticamente quando configurado no Claude Code. Invocação manual:

# Default (stdio mode for MCP)
memora-server

# With graph visualization server
memora-server --graph-port 8765

# HTTP transport (alternative to stdio)
memora-server --transport streamable-http --host 127.0.0.1 --port 8080
Configuração

Claude Code

Adicione a .mcp.json na raiz do seu projeto:

Banco de dados local:

{
  "mcpServers": {
    "memora": {
      "command": "memora-server",
      "args": [],
      "env": {
        "MEMORA_DB_PATH": "~/.local/share/memora/memories.db",
        "MEMORA_ALLOW_ANY_TAG": "1",
        "MEMORA_GRAPH_PORT": "8765"
      }
    }
  }
}

Banco de dados na nuvem (Cloudflare D1) - Recomendado:

{
  "mcpServers": {
    "memora": {
      "command": "memora-server",
      "args": ["--no-graph"],
      "env": {
        "MEMORA_STORAGE_URI": "d1://<account-id>/<database-id>",
        "CLOUDFLARE_API_TOKEN": "<your-api-token>",
        "MEMORA_ALLOW_ANY_TAG": "1"
      }
    }
  }
}

Com D1, use --no-graph para desabilitar o servidor de visualização local. Em vez disso, use o grafo hospedado na sua URL do Cloudflare Pages (veja Grafo na Nuvem).

Banco de dados na nuvem (S3/R2) - Modo de sincronização:

{
  "mcpServers": {
    "memora": {
      "command": "memora-server",
      "args": [],
      "env": {
        "AWS_PROFILE": "memora",
        "AWS_ENDPOINT_URL": "https://<account-id>.r2.cloudflarestorage.com",
        "MEMORA_STORAGE_URI": "s3://memories/memories.db",
        "MEMORA_CLOUD_ENCRYPT": "true",
        "MEMORA_ALLOW_ANY_TAG": "1",
        "MEMORA_GRAPH_PORT": "8765"
      }
    }
  }
}

Codex CLI

Adicione a ~/.codex/config.toml:

[mcp_servers.memora]
  command = "memora-server"  # or full path: /path/to/bin/memora-server
  args = ["--no-graph"]
  env = {
    AWS_PROFILE = "memora",
    AWS_ENDPOINT_URL = "https://<account-id>.r2.cloudflarestorage.com",
    MEMORA_STORAGE_URI = "s3://memories/memories.db",
    MEMORA_CLOUD_ENCRYPT = "true",
    MEMORA_ALLOW_ANY_TAG = "1",
  }
Variáveis de Ambiente
VariávelDescrição
MEMORA_DB_PATHCaminho local do banco de dados SQLite (padrão: ~/.local/share/memora/memories.db)
MEMORA_STORAGE_URIURI de armazenamento: d1://<account>/<db-id> (D1) ou s3://bucket/memories.db (S3/R2). Usado quando MEMORA_DATABASES não está definido.
MEMORA_DATABASESObjeto JSON {name: uri} mapeando cada armazenamento que este processo atende. Os nomes são um segmento de caminho de URL (/mcp/<name>): letras, dígitos, -, _, . apenas. Chaves duplicadas, valores vazios, nomes inseguros ou não-objetos recusam a inicialização em vez de escolher silenciosamente um armazenamento. Não definido = armazenamento único (legado). Consulte Roteamento de múltiplos bancos de dados.
MEMORA_DEFAULT_DBNome do registro que um /mcp simples usa. Obrigatório quando o registro tem mais de um banco de dados; com exatamente um nome, esse nome é o padrão. Um valor que não está no registro recusa a inicialização.
CLOUDFLARE_API_TOKENToken de API para D1 (URI d1://). CF_API_TOKEN é aceito como alias.
MEMORA_CLOUD_ENCRYPTCriptografa o arquivo local antes de enviar para S3/R2. Não definido/false = desativado; 1/true/yes = ativado.
MEMORA_CLOUD_COMPRESSComprime o arquivo local antes de enviar para S3/R2. Não definido/false = desativado; 1/true/yes = ativado.
MEMORA_CACHE_DIRDiretório de cache local para um banco de dados sincronizado com S3/R2. Não definido: o backend escolhe um caminho de cache.
MEMORA_ALLOW_ANY_TAGPermite qualquer tag sem validação contra a lista de permissões (1 para ativar)
MEMORA_TAG_FILECaminho para um arquivo JSON contendo uma matriz de tags permitidas, ex.: ["plan", "memora/issues"]
MEMORA_TAGSLista de tags permitidas separadas por vírgula
MEMORA_HOSTEndereço de bind para transportes HTTP (padrão 127.0.0.1). Substituível com --host.
MEMORA_PORTPorta de bind para transportes HTTP (padrão 8000). Substituível com --port.
MEMORA_GRAPH_PORTPorta para o servidor de visualização do grafo de conhecimento (padrão: 8765)
MEMORA_TRANSPORTstdio (padrão), sse ou streamable-http. Um valor env desconhecido cai para stdio; --transport ainda rejeita valores desconhecidos. O roteamento de múltiplos bancos de dados e a proteção de sessão são executados apenas em streamable-http.
MEMORA_TOOL_PROFILESubconjunto de ferramentas exposto aos clientes: full (padrão, todas as 43), leader (19), agent (12). Não definido/vazio = full; um valor desconhecido recusa a inicialização. Consulte Perfis de Ferramentas.
MEMORA_MAX_SESSIONSLimite máximo de sessões MCP simultâneas (padrão 128). 0 desativa. Uma taxa de criação mais um tempo limite de inatividade não é um limite — um cliente que mantém IDs de sessão ativos pode crescer sem limite na taxa de criação. Valores inválidos recusam a inicialização. Apenas Streamable-HTTP.
MEMORA_MAX_INIT_PER_MINNovas sessões admitidas por minuto (padrão 120). 0 desativa. Valores inválidos recusam a inicialização. Apenas Streamable-HTTP.
MEMORA_MAX_INIT_BODY_BYTESTamanho máximo do corpo da solicitação de inicialização aceito/armazenado em buffer (padrão 65536, mínimo 1024). Solicitações maiores recebem 413. Valores inválidos recusam a inicialização. Apenas Streamable-HTTP.
MEMORA_SESSION_IDLE_TIMEOUTSegundos antes que uma sessão válida abandonada seja coletada (padrão 1800). 0 desativa. Valores inválidos recusam a inicialização. Apenas Streamable-HTTP.
MEMORA_HEALTH_TOKENToken Bearer para corpos /health/db detalhados (nomes, contagens, texto de erro). Não definido: apenas um peer de loopback vê detalhes; todos os outros recebem status agregado. FastMCP custom_route() não é autenticado mesmo quando a autenticação MCP está configurada. Apenas transportes HTTP (memora.health é importado para SSE/streamable-http, não stdio).
MEMORA_HEALTH_TTLSegundos que um snapshot de prontidão pode ser servido antes que uma atualização seja devida (padrão 10, limite 3600). Deve ser > 0. Valores inválidos recusam a inicialização. Apenas transportes HTTP — um valor malformado não aborta stdio.
MEMORA_HEALTH_TIMEOUTLimite em uma passagem de atualização e em cada sondagem de armazenamento (padrão 15, limite 300). Deve ser > 0. Apenas transportes HTTP.
MEMORA_HEALTH_REFRESH_INTERVALCom que frequência o servidor atualiza a prontidão por conta própria (padrão 15, limite 3600). 0 = somente sondagem. Sem isso, uma implantação de proxy não tem chamador de loopback e a superfície de alerta permanece unknown enquanto todos os bancos de dados estão OK. Quando a atualização periódica está ativada, interval + timeout deve ser < MEMORA_HEALTH_MAX_STALE. Apenas transportes HTTP.
MEMORA_HEALTH_MAX_STALEIdade após a qual um resultado por banco de dados em cache não pode mais ser relatado como pronto (padrão 60, limite 3600). Deve ser >= MEMORA_HEALTH_TTL. Apenas transportes HTTP.
MEMORA_STALE_DAYSDois consumidores, dois padrões, mesmo nome: memory_insights trata um TODO/issue aberto como desatualizado após 14 dias; a UI do grafo esmaece itens fechados após 30 dias. Defina a variável para substituir ambos.
MEMORA_EMBEDDING_MODELBackend de embeddings: openai (padrão), sentence-transformers ou tfidf
SENTENCE_TRANSFORMERS_MODELModelo para sentence-transformers (padrão: all-MiniLM-L6-v2)
MEMORA_EMBEDDING_API_KEYChave de API do provedor de embeddings (atômica com URL base — veja abaixo)
MEMORA_EMBEDDING_BASE_URLURL base do provedor de embeddings (atômica com chave de API — veja abaixo)
MEMORA_EMBEDDING_STRICTRecomendamos 1. Falhe de forma rígida em erros de embeddings em vez de TF-IDF silencioso. Sem isso, um endpoint quebrado continua respondendo enquanto cada vetor se torna um saco de palavras-chave (como 756 memórias degradaram despercebidas).
OPENAI_API_KEYSomente LLM (dedup/chat) quando MEMORA_EMBEDDING_* está definido. Embeddings caem para esta chave apenas se ambos MEMORA_EMBEDDING_API_KEY e MEMORA_EMBEDDING_BASE_URL não estiverem definidos
OPENAI_BASE_URLURL base do LLM (OpenRouter, Azure, etc.). Mesma regra de fallback atômica que a chave — não é uma URL de embeddings quando você usa uma configuração dividida
OPENAI_EMBEDDING_MODELID do modelo para o backend de embeddings openai. Deve existir no host de embeddings (padrão text-embedding-3-small é somente OpenAI; Cloudflare precisa, ex.: @cf/baai/bge-m3)
MEMORA_LLM_ENABLEDAtiva a comparação de deduplicação alimentada por LLM (true/1/yes; padrão: true)
MEMORA_LLM_MODELModelo para comparação de deduplicação e, se não definido, para reescrita de consulta e chat local (padrão: gpt-4o-mini)
MEMORA_LLM_TIMEOUTSegundos que o cliente OpenAI espera (padrão 60, mínimo de 1). Um valor não numérico cai para 60.
MEMORA_REWRITE_MODELModelo para reescrita de consulta RAG no painel de chat do grafo. Não definido/vazio usa MEMORA_LLM_MODEL.
MEMORA_VECTOR_SCAN_PAGE_SIZELinhas por página ao carregar embeddings do D1 (padrão 1000; não numérico ou <1 cai para 1000; limite máximo 10000). No padrão, um armazenamento com menos de 1000 linhas retorna o corpus inteiro mais cada embedding em uma resposta D1, o que competiu com o limite de 30s por solicitação da Cloudflare e fez memory_absorb falhar completamente. Use 100 no D1 (o script da instância já injeta isso). Paginação é uma mitigação, não a correção: absorb lê o corpus uma vez por chamada e reutiliza um cache local ao processo chaveado no embedding_change_epoch monotônico do banco.
CHAT_MODELModelo para o painel de chat do grafo local. Não definido/vazio cai para MEMORA_LLM_MODEL. (O padrão deepseek/deepseek-chat é Cloudflare Pages wrangler.toml, não este processo.)
MEMORA_CLOUD_GRAPH_ENABLEDtrue/1/yes para notificar o grafo hospedado sobre gravações (padrão desativado).
MEMORA_CLOUD_GRAPH_WORKER_URLURL base do worker para essas transmissões (POST <url>/broadcast). Não definido: transmissões são ignoradas.
MEMORA_CLOUD_GRAPH_DEBOUNCESegundos para agrupar gravações rápidas antes de transmitir (padrão 1.0).
MEMORA_CLOUD_GRAPH_SYNC_SCRIPTCaminho capturado na inicialização (padrão: memora-graph/scripts/sync.sh se esse arquivo existir). O caminho de gravação atual não executa este script — D1 é a fonte da verdade e apenas a transmissão do worker é executada.
AWS_PROFILEPerfil de credenciais AWS de ~/.aws/credentials (útil para R2)
AWS_ENDPOINT_URLEndpoint compatível com S3 para R2/MinIO
R2_PUBLIC_DOMAINDomínio público para URLs de imagens R2
Perfis de Ferramentas (MEMORA_TOOL_PROFILE)

Todas as 43 ferramentas MCP são registradas incondicionalmente, então cada sessão de agente é injetada com o esquema completo de ferramentas de ~12.700 tokens, mesmo quando a maioria das ferramentas nunca é chamada. MEMORA_TOOL_PROFILE expõe um subconjunto por implantação, de modo que uma ferramenta restrita está genuinamente ausente — faltando em tools/list E não despachável (call_tool retorna unknown-tool, não uma execução oculta). O perfil é aplicado e atestado na inicialização; o perfil ativo e a contagem de ferramentas expostas são registrados em stderr.

ValorFerramentasUso
full (padrão)todas as 43Uso direto via stdio; toda implantação existente permanece byte por byte inalterada
leader19O conjunto de agente mais memory_create_section, memory_store_document, memory_get_document, memory_tags, memory_delete, memory_digest, memory_list
agent12A superfície de leitura/criação que um agente trabalhador precisa: memory_absorb, memory_semantic_search, memory_hybrid_search, memory_list_compact, memory_get, memory_related, memory_link, memory_stats, memory_create, memory_create_issue, memory_create_todo, memory_update
  • Não definido / vazio = full. Nenhuma implantação existente muda de comportamento.
  • Um valor desconhecido aborta a inicialização com uma mensagem listando os valores válidos. Ele nunca cai silenciosamente para full — um erro de digitação não deve reexpor ferramentas de manutenção destrutivas (memory_rebuild_embeddings, memory_delete_batch) a todos os workers. Falha fechada.
  • memory_list está em leader, mas não em agent. Foi excluído de ambos enquanto custava 163-174s em um armazenamento D1 contra os 0,22s de memory_list_compact; #973 corrigiu isso (agora ~1,1s). Ele permanece fora de agent porque a superfície de leitura de um worker é deliberadamente estreita, não por velocidade.
  • A fronteira líder/agente é dados em memora/tool_profile.py (dois frozensets). Editá-la é uma linha, não uma varredura de 43 decoradores.
  • O prune exclui do dict privado _tool_manager._tools do FastMCP, então memora fixa mcp>=1.27,<1.28 (o minor auditado) e executa uma atestação de inicialização através dos manipuladores de requisição MCP registrados de baixo nível (_mcp_server.request_handlers[ListToolsRequest] / [CallToolRequest] — o callable de despacho real que requisições de clientes usam, não os helpers Python FastMCP.list_tools / call_tool) que se recusa a iniciar se o SDK instalado rotear listagem/despacho para outro lugar (deriva de implementação privada). O pin é a proteção estática; a atestação é o backstop em tempo de execução. Aumentar o limite superior exige reexecutar tests/test_tool_profile.py.
  • Sob implantação em contêiner, o perfil é por contêiner, enquanto os papéis são por agente. Um contêiner servindo o líder de um workspace e seus workers precisa do superconjunto líder; agent removeria create_section/store_document/delete/digest/tags do líder.
  • memora-server (ou seja, memora.server.main()) é o único caminho de serviço com perfil suportado. Um embedder direto que importa memora.server.mcp e chama mcp.run() por conta própria ignora o perfilamento completamente (o mcp global ainda contém todas as 43 ferramentas); embedders que desejam perfilamento devem chamar apply_tool_profile por conta própria ou usar main().
# Leader deployment — exposes 19 tools
MEMORA_TOOL_PROFILE=leader memora-server

# Agent worker — exposes 12 tools
MEMORA_TOOL_PROFILE=agent memora-server

# Full (default) — all 43 tools, existing behaviour
memora-server

# Typo refuses to start:
# MEMORA_TOOL_PROFILE=agnt memora-server
# Error: unknown MEMORA_TOOL_PROFILE='agnt'; valid values: full, leader, agent
Roteamento multi-banco de dados

Um processo memora pode servir todos os workspaces. MEMORA_DATABASES é um registro JSON de {name: storage URI}; um cliente alcança seu armazenamento em /mcp/<name>. O seletor é a URL já em .mcp.json, não um argumento de ferramenta — um db opcional em cada ferramenta são 43 chances de esquecer um, e cada erro escreveria no armazenamento de outra pessoa.

MEMORA_DATABASES não definido é o formato antigo: um backend de MEMORA_STORAGE_URI / MEMORA_DB_PATH, um /mcp. Implantações stdio existentes não mudam.

Roteamento (streamable-http apenas):

URLResolve para
/mcp/<name>Essa entrada do registro. Nomes desconhecidos retornam 404 {"error":"unknown database"} — o corpo não lista os outros nomes.
/mcpMEMORA_DEFAULT_DB. Obrigatório quando o registro tem mais de um banco de dados; um registro de nome único usa esse nome.

A vinculação é fixa por sessão MCP, não por requisição. Uma sessão aberta em /mcp/alpha e reutilizada contra /mcp/beta ainda resolve para alpha. Um cliente não pode trocar de banco de dados no meio de uma conversa.

Configuração malformada se recusa a iniciar (não cai para o banco de dados legado): JSON inválido, um não-objeto, chaves duplicadas, uma URI vazia, um nome que não é um segmento de caminho de URL, ou MEMORA_DEFAULT_DB ausente/desconhecido quando mais de um banco de dados está listado.

Par funcional — execute isto, conecte-se a isto. Um listener streamable-HTTP, não uma entrada MCP command (isso geraria um filho stdio que nunca fala MCP no stdio). As credenciais vivem no processo do servidor.

MEMORA_DATABASES='{"memora":"d1://<account-id>/<memora-db-id>","ob1":"d1://<account-id>/<ob1-db-id>"}' \
MEMORA_DEFAULT_DB=memora \
CLOUDFLARE_API_TOKEN='<token>' \
MEMORA_VECTOR_SCAN_PAGE_SIZE=100 \
memora-server --transport streamable-http --host 127.0.0.1 --port 8000 --no-graph
{
  "mcpServers": {
    "memora": {
      "type": "http",
      "url": "http://127.0.0.1:8000/mcp/ob1"
    }
  }
}

Variante contêiner / proxy (o lançador usual deste host, não o comando acima): scripts/memora-instance.sh up myinstance inicia o mesmo servidor HTTP dentro de um contêiner e coloca scripts/memora_proxy.py em 127.0.0.1:<PORT> (8910 para a instância memora). A URL do workspace é então http://127.0.0.1:8910/mcp/ob1. Veja Implantação em Contêiner.

Um registro pode misturar d1://, s3:// e caminhos locais; parse_backend_uri despacha com base no esquema.

memory_stats relata o banco de dados vinculado. Ele retorna database (o nome que esta sessão realmente resolveu) e database_source (path, registry_default ou unconfigured). Um nome válido, mas errado, em .mcp.json é de outra forma indetectável: toda ferramenta funciona, leituras são bem-sucedidas e escritas caem silenciosamente no armazenamento de outro projeto. Chame memory_stats e verifique database contra o workspace que você pretendia.

Saúde de um processo multi-banco de dados: GET /health é liveness (sem I/O de banco de dados — o único sinal em que um supervisor pode reiniciar). GET /health/db é uma superfície de alerta (sempre HTTP 200; status é ok, degraded, unknown — sem snapshot ainda, uma atualização expirou, ou evidência mais antiga que a máxima obsolescência — ou error se o próprio registro está inutilizável). GET /health/db/{name} é a sonda específica do workspace (200 ou 503). Retirar todo o processo porque um armazenamento está degradado derruba os saudáveis junto.

Implantação em Contêiner

Com MEMORA_DATABASES não definido, um processo ainda vincula um banco de dados por sua vida útil (MEMORA_STORAGE_URI / MEMORA_DB_PATH). Esse é o formato original um-armazenamento-um-contêiner-uma-porta.

Com MEMORA_DATABASES definido, um contêiner serve todos os workspaces e clientes selecionam um armazenamento pelo caminho da URL (/mcp/<name>). Veja Roteamento multi-banco de dados. scripts/memora-instance.sh quer um de STORAGE_URI, VOLUME ou MEMORA_DATABASES por arquivo de instância (load() exige pelo menos um). Se mais de um estiver definido, cmd_up usa MEMORA_DATABASES, depois STORAGE_URI, depois VOLUME.

Dockerfile constrói uma imagem sem credenciais; scripts/memora-instance.sh implanta uma instância de instances/myinstance.env (ou outro arquivo nomeado). O CLI de tempo de execução do script é $MEMORA_CONTAINER_BIN (padrão container — o CLI da Apple). Cada operação de contêiner que o script executa honra essa substituição (build, up, status, logs, down). O processo memora_proxy.py gerado codifica container list, que também é o motivo do proxy existir: esse tempo de execução reatribui o IP do contêiner a cada início.

./scripts/memora-instance.sh build   myinstance   # build the image
./scripts/memora-instance.sh up      myinstance   # run the container
./scripts/memora-instance.sh proxy   myinstance   # render a LaunchAgent + print install commands
./scripts/memora-instance.sh status                # every instance at a glance

Então aponte o workspace para ele — a configuração completa do cliente, sem segredos nela. Uma instância de registro precisa do armazenamento no caminho (/mcp/<name>); /mcp puro é o padrão do registro:

{"mcpServers": {"memora": {"type": "http", "url": "http://127.0.0.1:8910/mcp/ob1"}}}

Credenciais nunca entram na imagem, no arquivo de instância ou na configuração HTTP do workspace. Elas são lidas em tempo de execução de uma configuração de credenciais separada ($CRED_SOURCE — em si um .mcp.json contendo apenas o bloco mcpServers.memora.env) e injetadas com -e. Se o arquivo de instância não definir CRED_SOURCE, o script usa ~/.config/memora/credentials.mcp.json quando esse arquivo existe, caso contrário ~/repos/agentic-box/.mcp.json. Passe todas as variáveis que esse arquivo define, não algumas escolhidas a dedo: um contêiner iniciado com apenas as chaves de incorporação perde silenciosamente a consolidação LLM de memory_absorb em vez de falhar ruidosamente.

Por que o proxy existe — leia isto antes de decidir que você não precisa dele. O tempo de execução padrão (container da Apple) reatribui o IP de um contêiner a cada início, não apenas na recriação. Um cliente MCP lê sua configuração uma vez na inicialização, então um endereço movido não produz um erro: produz um travamento silencioso permanente. scripts/memora_proxy.py mantém um 127.0.0.1:<PORT> estável na frente do endereço móvel e re-resolve por conexão.

Dois modos de falha que ele distingue, que custaram uma interrupção para aprender:

  • A consulta executou e o contêiner não está listado → ele realmente se foi. Recuse.
  • A consulta não pôde executar (timeout sob pressão de memória do host) → nada de novo é conhecido. Continue servindo o último endereço bom conhecido, limitado por MEMORA_PROXY_STALE_GRACE (300s). Conflitar os dois derrubou todos os workspaces enquanto os contêineres estavam respondendo normalmente em endereços inalterados.

Defina MEMORA_TOOL_PROFILE por instância (veja Perfis de Ferramentas). Observe que o perfil é por contêiner, enquanto os papéis são por agente: se um contêiner serve o líder de um workspace e seus workers, ele precisa do superconjunto líder.

Variável de script em tempo de implantação (não uma variável de ambiente do memora-server — ela nunca chega ao processo dentro do contêiner):

VariávelSignificado
MEMORA_CONTAINER_BINCLI que toda operação de contêiner memora-instance.sh usa (build, up, status, logs, down; padrão container). O processo memora_proxy.py gerado não honra isto; ele codifica container list.

instances/README.md cobre os campos de configuração e launchd/README.md o proxy supervisionado. REVERT.md documenta a restauração de um workspace para o servidor stdio direto.

Busca Semântica e Embeddings

Memora suporta três backends de embeddings:

BackendInstalaçãoQualidadeVelocidade
openai (padrão)IncluídoAlta qualidadeLatência de API
sentence-transformerspip install memora[local]Boa, roda offlineMédia
tfidfIncluídoCorrespondência básica de palavras-chaveRápida

Embeddings e o LLM são configurados separadamente.

PapelVariáveis
LLM (deduplicação, chat)OPENAI_API_KEY + OPENAI_BASE_URL
EmbeddingsMEMORA_EMBEDDING_API_KEY + MEMORA_EMBEDDING_BASE_URL (ambos ou nenhum — par atômico)
FallbackSe ambos MEMORA_EMBEDDING_* estiverem não definidos, embeddings usam o par completo OPENAI_*

Uma divisão parcial (apenas um MEMORA_EMBEDDING_* definido) é rejeitada para que o segredo de um provedor nunca seja enviado a outro host.

Armadilha — OpenRouter não tem endpoint de embeddings. O catálogo do OpenRouter é apenas chat/multimodal (sem modelos de embedding). Não aponte o caminho de embeddings para o OpenRouter via OPENAI_BASE_URL (ou uma URL base MEMORA). Essa combinação retorna 404 em toda chamada de embed; sem MEMORA_EMBEDDING_STRICT=1, Memora cai para TF-IDF e continua respondendo, então o armazenamento se enche de sacos de palavras-chave enquanto parece saudável. OpenRouter continua bom apenas para o LLM.

Exemplo funcional (LLM via OpenRouter, embeddings via Cloudflare Workers AI):

@cf/baai/bge-m3 é 1024-dimensional. O token precisa de permissão Workers AI. Formato do endpoint:

https://api.cloudflare.com/client/v4/accounts/<account_id>/ai/v1

{
  "env": {
    "MEMORA_EMBEDDING_MODEL": "openai",
    "OPENAI_API_KEY": "<openrouter-key>",
    "OPENAI_BASE_URL": "https://openrouter.ai/api/v1",
    "MEMORA_LLM_MODEL": "deepseek/deepseek-chat",
    "MEMORA_EMBEDDING_API_KEY": "<cloudflare-api-token-with-workers-ai>",
    "MEMORA_EMBEDDING_BASE_URL": "https://api.cloudflare.com/client/v4/accounts/<account_id>/ai/v1",
    "OPENAI_EMBEDDING_MODEL": "@cf/baai/bge-m3",
    "MEMORA_EMBEDDING_STRICT": "1"
  }
}

O que esta correção faz (sem exageros): embeddings e LLM podem usar provedores diferentes; uma divisão parcial é rejeitada; o modo estrito transforma degradação silenciosa em uma falha dura e nomeada.

Automático: Embeddings e referências cruzadas são calculados automaticamente quando você memory_create, memory_update ou memory_create_batch.

Reconstrução manual necessária quando a impressão digital do armazenamento muda — não apenas MEMORA_EMBEDDING_MODEL, mas também:

  • Endpoint de embeddings (MEMORA_EMBEDDING_BASE_URL / host)
  • ID real do modelo (OPENAI_EMBEDDING_MODEL, por exemplo, mudar para @cf/baai/bge-m3)
  • Tipo ou dimensões do vetor (sacos TF-IDF de palavras-chave vs densos 1024-d; ou 384 vs 1024)
  • Armazenamento misto (algumas linhas densas, algumas esparsas) — similaridade de cosseno só compartilha chaves, então tipos mistos resultam em recall 0.0 para linhas antigas

Formato da impressão digital: backend|model|repr (por exemplo, openai|@cf/baai/bge-m3|dense:1024). O valor de meta legado openai sozinho é tratado como incompatibilidade.

# After changing embedding model/endpoint, rebuild all embeddings
memory_rebuild_embeddings

# Then rebuild cross-references to update the knowledge graph
memory_rebuild_crossrefs
Servidor de Grafo ao Vivo

Um servidor HTTP integrado inicia automaticamente junto com o servidor MCP, fornecendo uma visualização interativa do grafo de conhecimento.

Details Panel
Painel de Detalhes
Timeline Panel
Painel de Linha do Tempo

Acesso local:

http://localhost:8765/graph

Acesso remoto via SSH:

ssh -L 8765:localhost:8765 user@remote
# Then open http://localhost:8765/graph in your browser

Configuração:

{
  "env": {
    "MEMORA_GRAPH_PORT": "8765"
  }
}

Para desativar: adicione "--no-graph" aos argumentos na sua configuração MCP.

Recursos da Interface do Grafo

  • Painel de Detalhes - Visualize conteúdo de memórias, metadados, tags e memórias relacionadas
  • Painel de Linha do Tempo - Navegue pelas memórias cronologicamente, clique para destacar no grafo
  • Painel de Histórico - Registro de ações de todas as operações com entradas consecutivas agrupadas e referências de memória clicáveis (memórias excluídas mostradas com tachado)
  • Painel de Chat - Faça perguntas sobre suas memórias usando chat com LLM baseado em RAG, com respostas em streaming e referências [Memory #ID] clicáveis
  • Controle Deslizante de Tempo - Filtre memórias por intervalo de datas, arraste para explorar o histórico
  • Atualizações em Tempo Real - Grafo, linha do tempo e histórico atualizam via SSE quando as memórias mudam
  • Filtros - Menus suspensos de tag/seção, controles de zoom
  • Renderização Mermaid - Blocos de código são renderizados como diagramas

Cores dos Nós

  • 🟣 Tags - Tons de roxo por tag
  • 🔴 Problemas - Vermelho (aberto), Laranja (em andamento), Verde (resolvido), Cinza (não será corrigido)
  • 🔵 TODOs - Azul (aberto), Laranja (em andamento), Verde (concluído), Vermelho (bloqueado)

O tamanho do nó reflete o número de conexões.

Grafo na Nuvem (Recomendado para D1)

Ao usar Cloudflare D1 como seu banco de dados, a visualização do grafo é hospedada no Cloudflare Pages - sem necessidade de servidor local.

Benefícios:

  • Acesso de qualquer lugar (sem túnel SSH)
  • Atualizações em tempo real via WebSocket
  • Suporte a múltiplos bancos de dados via parâmetro ?db=
  • Acesso seguro com Cloudflare Zero Trust

Configuração:

  1. Crie o banco de dados D1:

    npx wrangler d1 create memora-graph
    npx wrangler d1 execute memora-graph --file=memora-graph/schema.sql
    
  2. Implante o Pages:

    cd memora-graph
    npx wrangler pages deploy ./public --project-name=memora-graph
    
  3. Configure os bindings no painel do Cloudflare:

    • Pages → memora-graph → Configurações → Bindings
    • Adicione D1: DB_MEMORA → seu banco de dados
    • Adicione R2: R2_MEMORA → seu bucket (para imagens)
  4. Configure o MCP com o URI D1:

    {
      "env": {
        "MEMORA_STORAGE_URI": "d1://<account-id>/<database-id>",
        "CLOUDFLARE_API_TOKEN": "<your-token>"
      }
    }
    

Acesso: https://memora-graph.pages.dev

Proteja com Zero Trust:

  1. Painel do Cloudflare → Zero Trust → Access → Applications
  2. Adicione um aplicativo para memora-graph.pages.dev
  3. Crie uma política com e-mails permitidos
  4. Pages → Configurações → Ative a Política de Acesso

Consulte memora-graph/ para configuração detalhada e configuração de múltiplos bancos de dados.

Chat com Memórias

Faça perguntas sobre sua base de conhecimento diretamente da interface do grafo. O painel de chat usa RAG (Geração Aumentada por Recuperação) para buscar memórias relevantes e transmitir respostas do LLM com suporte a chamadas de ferramentas.

  • Alternar via o ícone de chat flutuante no canto inferior direito
  • Busca semântica encontra as memórias mais relevantes como contexto
  • Respostas em streaming com referências [Memory #ID] clicáveis que focam o nó do grafo
  • Chamada de ferramentas — o LLM pode criar, atualizar e excluir memórias diretamente do chat (ex.: "salve isso como uma memória", "exclua a memória #42", "atualize a memória #10 com...")
  • Funciona tanto no servidor local quanto na implantação do Cloudflare Pages

Configure o modelo de chat:

BackendVariávelPadrão
Servidor localvariável de ambiente CHAT_MODELRecorre a MEMORA_LLM_MODEL
Cloudflare PagesCHAT_MODEL em wrangler.tomldeepseek/deepseek-chat

Requer uma API compatível com OpenAI (OPENAI_API_KEY + OPENAI_BASE_URL para local, segredo OPENROUTER_API_KEY para Cloudflare). O modelo de chat deve suportar uso de ferramentas (chamada de funções).

Deduplicação com LLM

Encontre e mescle memórias duplicadas usando comparação semântica com IA:

# Find potential duplicates (uses cross-refs + optional LLM analysis)
memory_find_duplicates(min_similarity=0.7, max_similarity=0.95, limit=10, use_llm=True)

# Merge duplicates (append, prepend, or replace strategies)
memory_merge(source_id=123, target_id=456, merge_strategy="append")

Comparação com LLM analisa pares de memórias e retorna:

  • verdict: "duplicado", "semelhante" ou "diferente"
  • confidence: pontuação de 0,0 a 1,0
  • reasoning: Breve explicação
  • suggested_action: "mesclar", "manter_ambas" ou "revisar"

Funciona com qualquer API de chat compatível com OpenAI (OpenAI, OpenRouter, Azure, etc.) via OPENAI_BASE_URL. OpenRouter é adequado para este caminho de LLM; ele não fornece embeddings — configure embeddings separadamente (consulte Busca Semântica e Embeddings).

Armazenamento de Documentos

Armazene documentos estruturados (relatórios de pesquisa, decisões de arquitetura, post-mortems) como árvores de fragmentos pesquisáveis:

# Store a markdown document — auto-parsed into typed fragments
memory_store_document(
    content="# Research Report\n\n## Evidence Table\n| Claim | Confidence |\n...",
    document_key="research/memora-enhancements-2026-04-08",
    tags=["memora/research"]
)
# Returns: {root_id: 230, fragment_count: 100, node_map: {claim: [...], plan_item: [...], ...}}

# Retrieve the full document or specific fragment types
memory_get_document(document_key="research/memora-enhancements-2026-04-08")
memory_get_document(document_key="...", node_kinds=["claim"], content_mode="full")

# Delete a document and all its fragments
memory_delete_document(document_key="research/memora-enhancements-2026-04-08")

Como funciona: O analisador divide o markdown por estrutura — tabelas se tornam afirmações individuais, listas numeradas se tornam itens de plano, listas de URLs se tornam referências, e seções de risco se tornam fragmentos de risco. Cada fragmento é pesquisável independentemente via memory_semantic_search enquanto o documento completo é recuperável como uma unidade.

Tipos de fragmentos: claim, plan_item, reference, section_chunk, risk

Proteções de integridade: Fragmentos de documentos são protegidos contra modificação acidental:

  • memory_delete requer force=True para fragmentos
  • memory_merge recusa mesclar fragmentos
  • memory_absorb exclui fragmentos da correspondência de similaridade
  • memory_find_duplicates e memory_detect_supersessions ignoram fragmentos
  • A interface do grafo oculta fragmentos, mostrando apenas o nó raiz do documento
Ferramentas de Automação de Memórias

Ferramentas estruturadas para tipos comuns de memória:

# Create a TODO with status and priority
memory_create_todo(content="Implement feature X", status="open", priority="high", category="backend")

# Create an issue with severity
memory_create_issue(content="Bug in login flow", status="open", severity="major", component="auth")

# Create a section placeholder (hidden from graph)
memory_create_section(content="Architecture", section="docs", subsection="api")
Insights de Memórias

Analise memórias armazenadas e apresente insights acionáveis:

# Full analysis with LLM-powered pattern detection
memory_insights(period="7d", include_llm_analysis=True)

# Quick summary without LLM (faster, no API key needed)
memory_insights(period="1m", include_llm_analysis=False)

Retorna:

  • Resumo de atividade — memórias criadas no período, agrupadas por tipo e tag
  • Itens em aberto — TODOs e problemas abertos com detecção de obsoletos (configurável via MEMORA_STALE_DAYS; padrão memory_insights de 14, padrão da interface do grafo de 30 — mesma variável, dois consumidores)
  • Candidatos a consolidação — pares de memórias semelhantes que poderiam ser mesclados
  • Análise com LLM — temas, áreas de foco, lacunas de conhecimento e um resumo (requer OPENAI_API_KEY)
Vinculação de Memórias

Gerencie relacionamentos entre memórias:

# Create typed edges between memories
memory_link(from_id=1, to_id=2, edge_type="implements", bidirectional=True)

# Edge types: references, implements, supersedes, extends, contradicts, related_to

# Remove links
memory_unlink(from_id=1, to_id=2)

# Boost memory importance for ranking
memory_boost(memory_id=42, boost_amount=0.5)

# Detect clusters of related memories
memory_clusters(min_cluster_size=2, min_score=0.3)
Exportação do Grafo de Conhecimento (Opcional)

Para visualização offline, exporte memórias como um arquivo HTML estático:

memory_export_graph(output_path="~/memories_graph.html", min_score=0.25)

Isso é opcional - o Servidor de Grafo ao Vivo fornece a mesma visualização com atualizações em tempo real.

Integração com Neovim

Navegue pelas memórias diretamente no Neovim com Telescope. Copie o plugin para sua configuração:

# For kickstart.nvim / lazy.nvim
cp nvim/memora.lua ~/.config/nvim/lua/kickstart/plugins/

Uso: Pressione <leader>sm para abrir o navegador de memórias com busca difusa e pré-visualização.

Requer: telescope.nvim, plenary.nvim e memora instalados no seu ambiente Python.