SSD Nodes Learn Hosting plans →
Guias Matt ConnorPor Matt Connor · Atualizado 2026-08-26

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.

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, July 31, 2026.

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.
  • git e uma cadeia de ferramentas de compilação, porque better-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_modules e 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 --version

node --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:build

npm 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:dev

Esta é 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.yaml

Numa segunda shell, peça ao serviço para indicar se está ativo:

curl -sS http://127.0.0.1:18960/api/v1/health

O 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/add escreve uma memória e POST /api/v1/memory/search consulta memórias.
  • GET /api/v1/memory/:id e DELETE /api/v1/memory/:id leem e removem uma entrada.
  • POST /api/v1/sessions/open e POST /api/v1/sessions/:sessionId/close delimitam uma sessão de agente.
  • POST /api/v1/turns/start e POST /api/v1/turns/:turnId/complete registam um turno.
  • GET /api/v1/panel/overview, /api/v1/panel/analysis e /api/v1/panel/items alimentam 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 health

Se 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 health

A 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-vps

Se 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.target

Mantenha 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-string
sudo 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/health

status=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:dev executa o ponto de entrada TypeScript através de tsx, que é um caminho de desenvolvimento. O repositório também inclui memory:serve para a saída compilada. Execute npm run sem 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.