Memmy: memória local para agentes em um VPS
Aprenda a compilar o Memmy no Ubuntu e executar o serviço na porta 18960. Claude Code, Codex e Cursor compartilham notas em uma base SQLite local.
O que é o Memmy e o que armazena
O Memmy é um hub de memória local para agentes de IA que é executado no seu próprio VPS (servidor privado virtual). Mantém uma base de dados SQLite com o que os seus agentes aprenderam, e todos os agentes nesse servidor leem e escrevem no mesmo armazenamento. O projeto é memmy-agent da MemTensor, tem licença MIT e está na versão 1.0.4 em julho de 2026.
Apenas parte do projeto é relevante num servidor. O Memmy disponibiliza um serviço de memória que escuta em http://127.0.0.1:18960, uma memmy-memory interface de linha de comandos (CLI) que comunica com esse serviço e um ambiente de trabalho. O ambiente de trabalho só é disponibilizado para macOS e Windows. Num VPS Linux, execute o serviço e a CLI. Isto é suficiente para dar uma memória partilhada ao Claude Code, ao Codex e ao Cursor.
O Memmy organiza o que armazena em quatro camadas. L1 Trace é o turno bruto: o pedido, a resposta e as chamadas de ferramentas. L2 Policy é um procedimento induzido a partir de traces que demonstraram ser úteis. L3 World Model é conhecimento estável sobre um projeto ou ambiente. Skill é um procedimento chamável, consolidado a partir de uma policy. O serviço atribui uma camada quando ingere um turno; por isso, não é necessário criá-las manualmente. Se estas distinções parecerem abstratas, a memória é uma das fases posteriores de um percurso faseado para aprender a criar agentes, e as camadas tornam-se mais claras depois de escrever um loop de agente simples e observar que ele se esquece de tudo entre execuções.
O que um hub de memória partilhada altera em comparação com a memória por ferramenta
Atualmente, cada agente traz a sua própria memória. O Claude Code mantém ficheiros de instruções no repositório. O Cursor mantém regras na base de dados da sua área de trabalho. O Codex mantém logs de sessão em ~/.codex. Cada armazenamento pertence a uma ferramenta, pelo que um facto que ensinou na segunda-feira numa ferramenta é desconhecido na terça-feira noutra. Paga esse custo duas vezes: uma vez nos tokens gastos a explicar novamente o mesmo projeto e outra no trabalho incorreto quando um agente age com base numa suposição que já corrigiu noutro local.
Um hub retira o armazenamento da ferramenta. O Memmy também lê os armazenamentos existentes, pelo que não começa com uma base de dados vazia. O scanner conhece seis fontes: Claude Code em ~/.claude/projects/**/*.jsonl, Codex em ~/.codex/sessions/<YYYY>/<MM>/<DD>/rollout-*.jsonl, OpenCode em ~/.local/share/opencode/opencode.db, os ficheiros state.vscdb do Cursor, as bases de dados SQLite do OpenClaw em ~/.openclaw e o Hermes em ~/.hermes. Pode adicionar uma fonte manualmente com um nome e um caminho local.
Os contadores de importação não coincidem, e isso é esperado. O scanner agrupa as mensagens por fonte e conversa e depois grava uma memória L1 por turno completo. Um turno é considerado completo quando tem conteúdo de utilizador não vazio e termina com uma mensagem não vazia do assistente, pelo que uma sessão interrompida não contribui com nada. As mensagens são desduplicadas com checkpoints de conversa e IDs de turno estáveis. A contagem analisada, a contagem de mensagens importadas e a contagem de memórias novas são todas diferentes na mesma execução.
Esta é a parte que complementa a forma como o Claude Code gere o contexto numa única sessão. A gestão de contexto determina o que cabe numa única janela. Um hub de memória determina o que permanece depois de essa janela fechar.
O que é necessário no VPS
- Node.js 22 ou mais recente. A documentação do Memmy exige essa versão, e o Ubuntu 24.04 fornece o Node 18.
gite uma cadeia de ferramentas de compilação, porquebetter-sqlite3é um módulo nativo que pode ser compilado durante a instalação.- Cerca de 2 GB de RAM. A instalação na conta root obtém um workspace grande e uma cadeia de compilação frontend.
- Alguns GB de espaço livre em disco para
node_modulese para a base de dados.
sudo apt update
sudo apt install -y git build-essential python3 curl ca-certificates sqlite3
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
node --versionnode --version deve apresentar v22 ou superior. Um v18 neste ponto indica que o passo do NodeSource não foi aplicado, e a instalação falhará mais tarde na verificação do engine do projeto.
Instalar o Memmy a partir do código-fonte no Ubuntu 24.04
git clone https://github.com/MemTensor/memmy-agent.git
cd memmy-agent
cp .env.example .env
npm install
npm run memory:buildnpm run memory:build compila o workspace @memmy/memory em Memory/dist. Num servidor headless, não é necessário compilar mais nada na árvore. Confirme que o módulo nativo foi carregado:
node -e "require('better-sqlite3'); console.log('better-sqlite3 loads')"Se essa linha gerar um erro em vez de imprimir o resultado, o módulo nativo não é compatível com a sua versão do Node. Execute npm rebuild better-sqlite3. Esse é exatamente o comando que o script de arranque do próprio projeto executa antes de iniciar qualquer componente.
O README documenta bash scripts/dev-start.sh como um comando de arranque único. Não o execute num VPS headless. Ele inicia a shell de desktop Electron e um servidor de desenvolvimento Vite na porta 19000, juntamente com o serviço de memória. O Electron precisa de um display. Por isso, num servidor sem uma sessão gráfica, o script fica bloqueado ou termina.
Inicie o serviço de memória e confirme que responde
npm run memory:serve:devEsta é a forma documentada de executar o serviço de memória a partir do código-fonte. O serviço fica associado a 127.0.0.1:18960, mantém a base de dados em ~/.memmy/memory-service/memory.sqlite e lê a configuração de ~/.memmy/config.yaml. O README apresenta os mesmos valores de forma explícita:
npm run memory:serve:dev -- \
--host 127.0.0.1 --port 18960 \
--db ~/.memmy/memory-service/memory.sqlite \
--config ~/.memmy/config.yamlNuma segunda shell, peça ao serviço para indicar se está ativo:
curl -sS http://127.0.0.1:18960/api/v1/healthO endpoint de estado é o único que nunca pede um token, por isso é a sonda correta. Se o curl terminar com o código 7 e uma mensagem Failed to connect to 127.0.0.1 port 18960, não há nada a escutar. Leia o terminal onde o serviço está a ser executado, porque um crash durante o arranque é apresentado aí. A causa habitual é a falha ao carregar o módulo nativo do SQLite. ss -lntp | grep 18960 confirma o socket depois de o serviço arrancar.
O restante da API HTTP (interface de programação de aplicações) está em /api/v1.
POST /api/v1/memory/addescreve uma memória ePOST /api/v1/memory/searchconsulta memórias.GET /api/v1/memory/:ideDELETE /api/v1/memory/:idleem e removem uma entrada.POST /api/v1/sessions/openePOST /api/v1/sessions/:sessionId/closedelimitam uma sessão de agente.POST /api/v1/turns/startePOST /api/v1/turns/:turnId/completeregistam um turno.GET /api/v1/panel/overview,/api/v1/panel/analysise/api/v1/panel/itemsalimentam o dashboard.
O Memmy reserva um bloco de portas. No modo headless, utiliza apenas a primeira: 18960 para a memória, 18970 para o estado do gateway, 18980 para a interface web e o HTTP de administração, 18990 para a API compatível com OpenAI iniciada por memmy serve, e depois 19000 e 19010 para o servidor de desenvolvimento do frontend da aplicação desktop. Se algo no seu servidor já estiver a utilizar uma dessas portas, é nessa lista que deve procurar.
De onde vem realmente o comando memmy-memory
É aqui que uma primeira instalação costuma falhar. Por isso, leia a informação a partir do pacote, em vez de fazer suposições. O nome do comando não tem relação com o nome do repositório. Ele vem do campo bin do workspace que o define:
node -p "JSON.stringify(require('./Memory/package.json').bin)"Isto imprime {"memmy-memory":"./dist/src/cli/index.js"}. Portanto, o ponto de entrada compilado é Memory/dist/src/cli/index.js. Ele só existe depois de npm run memory:build, porque a compilação cria dist e marca o ficheiro como executável. Execute-o diretamente:
node Memory/dist/src/cli/index.js healthSe quiser o nome curto no seu PATH, crie uma ligação para esse mesmo ficheiro:
sudo ln -s "$PWD/Memory/dist/src/cli/index.js" /usr/local/bin/memmy-memory
memmy-memory healthA CLI usa http://127.0.0.1:18960 por predefinição e aceita --url, --token, --config, --source e --user-id. Os seus subcomandos são init, health, search, add, get e delete, além das chamadas de sessão e de turno que os agentes usam, e não as pessoas. memmy-memory search "deploy steps" e memmy-memory add "staging migrates on deploy" são os dois comandos que um agente executa com mais frequência.
Como ligar o Claude Code ao Memmy?
O Claude Code não tem uma interface de plugins de memória, por isso o Memmy não se integra diretamente com ele. A integração é mais simples do que isso. O Claude Code executa memmy-memory como um comando de shell normal, e um ficheiro de instruções indica-lhe quando o deve fazer. O instalador documentado do Memmy cria esse ficheiro por si: memmy-memory init --agent coloca um ficheiro de instruções de memória no diretório de regras do agente de destino.
Escreva a instrução manualmente uma vez. Assim, sabe exatamente o que foi indicado ao agente. O Claude Code lê CLAUDE.md a partir da raiz do projeto no início de cada sessão. Por isso, uma secção como esta constitui toda a integração:
## Memory
Before starting a task, run `memmy-memory search "<topic>"` and read what comes back.
When a task is done, run `memmy-memory add "<what you learned>"` for anything that will matter next session.Defina claramente o que isto oferece. É uma integração ao nível das instruções. Funciona quando o modelo decide executar o comando, e não de outra forma. Nada obriga a fazer a chamada. Se uma sessão terminar sem add, nada é guardado. O único sinal é um resultado vazio na pesquisa seguinte. Esta é a mesma limitação dos ficheiros de memória próprios do Claude Code, com uma diferença: o armazenamento é partilhado. Assim, a nota também fica disponível para o Codex e o Cursor na mesma máquina. Um harness que disponibilize uma interface de plugins real elimina essa limitação em vez de depender de instruções. É por isso que a memória persistente aparece ao lado dos limites de orçamento e das regras de permissões entre os plugins do DeepSeek Harness que vale a pena instalar.
A outra direção não exige qualquer configuração. O scanner do Memmy já lê ~/.claude/projects/**/*.jsonl, que é onde o Claude Code escreve as transcrições das sessões. Execute o Memmy no mesmo servidor onde executa o Claude Code dentro de uma sessão tmux. O trabalho de ontem passa a estar disponível como memória sem qualquer configuração adicional.
O Memmy funciona como servidor MCP para o Claude Code?
Não. Saber isto evita perder uma tarde. O MCP (model context protocol) tem clientes e servidores. O Memmy é um cliente. Liga-se a servidores MCP e disponibiliza as respetivas ferramentas ao seu próprio runtime de agente. Não publica um endpoint MCP ao qual o claude mcp add possa ligar-se. A única ponte MCP no repositório pertence à integração Composio dentro da API local do desktop, e essa API fica ligada a uma porta aleatória em 127.0.0.1, protegida pelo seu próprio cabeçalho x-memmy-mcp-token.
O lado do cliente é configurado em ~/.memmy/config.yaml, o ficheiro indicado por MEMMY_CONFIG, em tools.mcpServers:
tools:
mcpServers:
example:
type: stdio
command: npx
args:
- "-y"
- "your-mcp-server"
toolTimeout: 30
enabledTools:
- "*"type aceita stdio, sse e streamableHttp. Um servidor stdio é executado como processo filho do Memmy. Por isso, o comando tem de existir no mesmo sistema e ser executado pelo mesmo utilizador. Se já mantém servidores MCP em execução num VPS, são esses que deve indicar aqui.
Manter o armazenamento de memória privado
Tudo o que o Memmy gere fica em ~/.memmy: config.yaml, o espaço de trabalho, memory-service/memory.sqlite e os ficheiros de runtime. A análise e a ingestão são feitas localmente, e as memórias são gravadas nesse ficheiro SQLite local. Por isso, a configuração predefinida é realmente local.
Há dois caminhos que acedem à rede. MEMMY_CLOUD_SERVICE aponta por predefinição para https://memmy-api.memtensor.cn e suporta o modo de conta com os respetivos tokens de avaliação. Por isso, o modo de chave de API nunca o chama. O programa de melhoria de memórias é uma opção separada nas definições de privacidade. Fica desativado até o ativar.
Há um terceiro caminho que é mais fácil de ignorar. Se configurar um fornecedor de embeddings alojado, o texto de cada memória é enviado para esse fornecedor para ser convertido num vetor. O armazenamento local não resolve esse problema. Um endpoint de embeddings alojado por si é a única forma de o eliminar.
Mantenha a porta 18960 associada ao endereço de loopback. Não precisa de uma regra de firewall, porque um serviço associado a 127.0.0.1 não pode ser acedido a partir de fora do sistema. Em vez disso, aceda-lhe a partir do seu portátil através de SSH:
ssh -N -L 18960:127.0.0.1:18960 you@your-vpsSe alguma vez o associar a um endereço mais abrangente, defina primeiro um token. Definir storage.token na configuração, ou a variável de ambiente MEMMY_MEMORY_TOKEN ou MEMORY_SERVICE_TOKEN, faz com que todos os endpoints, exceto o de health, exijam um bearer token. Os valores de configuração suportam referências ${ENV_NAME}, pelo que o token e as suas chaves de API dos modelos ficam fora do próprio ficheiro. Este é o mesmo princípio de manter os segredos fora dos agentes de IA em todo o lado, e uma política ufw default deny funciona como proteção caso uma versão futura altere o endereço de bind predefinido.
Faça uma cópia de segurança de ~/.memmy antes de confiar nele
memory.sqlite é todo o armazenamento. Os vetores ficam nesse mesmo ficheiro através da extensão sqlite-vec, por isso um único ficheiro é suficiente para a cópia de segurança. Copiá-lo com cp enquanto o serviço está a escrever pode produzir uma base de dados inconsistente. Use o comando de cópia de segurança do próprio SQLite:
mkdir -p ~/memmy-backup
sqlite3 ~/.memmy/memory-service/memory.sqlite ".backup '$HOME/memmy-backup/memory.sqlite'"Isto produz uma cópia consistente enquanto o serviço continua em execução. Envie-a para fora do servidor segundo um agendamento; é para isso que serve o restic para armazenamento externo. Perder config.yaml custa-lhe definições do fornecedor que pode voltar a introduzir. Perder memory.sqlite custa-lhe todas as memórias, e nenhum outro componente da máquina mantém uma segunda cópia.
Execute o serviço de memória com systemd
npm run memory:serve:dev numa shell termina quando a shell termina. Um ficheiro de unidade mantém o serviço ativo após reinícios.
[Unit]
Description=Memmy memory service
After=network-online.target
[Service]
Type=simple
User=memmy
WorkingDirectory=/opt/memmy/memmy-agent
EnvironmentFile=/etc/memmy/memory.env
ExecStart=/usr/bin/npm run memory:serve:dev
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetMantenha o token fora da unidade. Coloque-o em /etc/memmy/memory.env, pertencente a root, com o modo 600:
MEMMY_CONFIG=/home/memmy/.memmy/config.yaml
MEMMY_MEMORY_TOKEN=replace-this-with-a-long-random-stringsudo systemctl daemon-reload
sudo systemctl enable --now memmy-memory
systemctl status memmy-memory --no-pager
curl -sS http://127.0.0.1:18960/api/v1/healthstatus=203/EXEC na saída de estado significa que o systemd não conseguiu executar ExecStart, por isso verifique which npm: numa instalação do NodeSource, está em /usr/bin/npm; com nvm, está em algo dentro da home do utilizador, que o systemd não encontra. Uma unidade que inicia e termina imediatamente falhou dentro do npm; journalctl -u memmy-memory -n 50 mostra o motivo. O procedimento é igual ao de qualquer outro serviço systemd num VPS.
O que o Memmy ainda não faz
- Não existe uma versão para desktop Linux. Os scripts de empacotamento abrangem macOS e Windows, por isso o workbench, o assistente de configuração inicial e o painel de memória não estão disponíveis no próprio servidor.
memory:serve:devexecuta o ponto de entrada TypeScript através detsx, que é um caminho de desenvolvimento. O repositório também incluimemory:servepara a saída compilada. Executenpm runsem argumentos para ver quais scripts o seu checkout realmente tem.- A recuperação cria a janela de pesquisa a partir das 2,000 linhas vetoriais mais recentes e aplica a seleção Top-K dentro dessa janela. Num armazenamento muito grande, uma memória antiga pode ficar fora dela.
- A criação de embeddings ocorre depois da captura, e uma falha é enviada para uma fila de novas tentativas, em vez de bloquear o turno do agente. Uma memória adicionada há pouco pode ainda não estar disponível na pesquisa vetorial.
- Um único ficheiro SQLite corresponde a um único nó. Não existe clustering, por isso um segundo servidor representa uma memória separada.
A versão 1.0.4 e cerca de 329 estrelas em julho de 2026 caracterizam um projeto recente. As flags, os caminhos e os nomes dos scripts mudam entre versões. Leia o campo bin e a saída de npm run no seu próprio checkout, em vez de confiar num comando copiado de qualquer lugar, incluindo aqui.
FAQ
Por que a verificação de integridade devolve "connection refused"?
Nada está a escutar na porta 18960. Um código de saída 7 do curl com Failed to connect to 127.0.0.1 port 18960 significa que o serviço de memória não está em execução ou terminou durante o arranque. Leia o terminal ou o journal onde o serviço foi iniciado. As duas causas habituais são um módulo nativo better-sqlite3 incompatível com a sua versão do Node, corrigido com npm rebuild better-sqlite3, e uma versão do Node inferior a 22. Confirme o socket com ss -lntp | grep 18960 quando o serviço estiver em execução.
De onde vem o comando memmy-memory depois de compilar a partir do código-fonte?
Vem do campo bin do pacote @memmy/memory do workspace, não do nome do repositório. Execute node -p "JSON.stringify(require('./Memory/package.json').bin)" dentro do checkout para obter {"memmy-memory":"./dist/src/cli/index.js"}. Esse ficheiro só existe depois de npm run memory:build, porque a compilação cria dist e marca o ficheiro como executável. Execute-o como node Memory/dist/src/cli/index.js health ou crie um symlink para /usr/local/bin para usar o nome curto.
Posso adicionar o Memmy ao Claude Code com claude mcp add?
Não. O Memmy é um cliente MCP, não um servidor MCP. Liga-se aos servidores indicados em tools.mcpServers dentro de ~/.memmy/config.yaml e disponibiliza as respetivas ferramentas ao seu próprio runtime. O Claude Code acede ao Memmy no sentido inverso, executando a CLI memmy-memory como um comando de shell, orientado por um ficheiro de instruções que memmy-memory init --agent escreve no diretório de regras do agente.
Executar o Memmy envia as minhas memórias para um serviço cloud?
A análise e a ingestão são executadas localmente, e as memórias são gravadas em ~/.memmy/memory-service/memory.sqlite no seu próprio disco. MEMMY_CLOUD_SERVICE aponta para https://memmy-api.memtensor.cn no modo de conta e para os tokens de avaliação, e o programa de melhoria da memória permanece desativado até ser ativado. O ponto a monitorizar é o fornecedor de embeddings: um modelo de embeddings alojado recebe o texto de cada memória que transforma num vetor. Se isso for relevante, utilize um endpoint que seja executado por si.