How to setup Memmy memory hub for AI agents on VPS
Make your AI agents share memory with Memmy on Ubuntu. Build from source to run the service on port 18960. Keep your data private and local with this SQLite solution.
Wetin be Memmy and wetin e dey store
Memmy na local memory hub for AI agents wey dey run for your own VPS (virtual private server). E dey keep one SQLite database of wetin your agents don learn, and every agent wey dey for the box dey read and write inside that same store. The project na memmy-agent from MemTensor, e get MIT license, and e dey version 1.2.401 as of 1 November 2026; Memory dey use im own separate version wey be 2.1.7.
Na only small part of am you need for server. Memmy dey ship memory service wey dey listen for http://127.0.0.1:18960, one memmy-memory command line interface (CLI) wey dey talk to that service, and desktop workbench. Dem package the workbench for macOS and Windows only, so for Linux VPS, you go run the service and the CLI. That one don enough to give Claude Code, Codex, and Cursor shared memory.
Memmy dey arrange wetin e store into four layers. Capture dey first store separate Raw Turn, then e go write one L1 Trace item for every step wey dem capture, wey include requests, responses, tool calls, and results. L2 Policy na procedure wey dem derive from traces wey prove say e dey useful. L3 World Model na stable knowledge about project or environment. Skill na procedure wey you fit call wey dem form from policy. Capture dey create L1 traces, background jobs dey evolve the higher layers, and you fit use explicit writes select layer. If those distinctions dey look like say e too abstract, memory na one of the later stages for staged path to learn how to build agents, and the layers go make more sense once you don write plain agent loop by yourself and watch am as e dey forget everything between runs.
Wetin shared memory hub dey change compare to memory wey be per-tool
Every agent today dey carry im own memory. Claude Code dey keep instruction files inside the repository. Cursor dey keep rules for im workspace database. Codex dey keep session logs under ~/.codex. Each store belong to one tool, so fact wey you teach on Monday for one tool, another tool no go know am on Tuesday. You dey pay for that twice: first one na tokens wey you spend dey explain the same project again, and second one na wrong work wey go happen when agent act base on assumption wey you don already correct for another place.
One hub go move the store comot from the tool. Memmy self dey read the existing stores, so you no go start from empty database. Im scanner sabi ten built-in sources: Claude Code for ~/.claude/projects/**/*.jsonl, Codex for ~/.codex/sessions/<YYYY>/<MM>/<DD>/rollout-*.jsonl, OpenCode for ~/.local/share/opencode/opencode.db, Cursor state.vscdb files, OpenClaw SQLite databases under ~/.openclaw, Hermes under ~/.hermes, DeepSeek Harness under ~/.dsh/sessions, WorkBuddy under ~/.workbuddy/projects, Pi under ~/.pi/agent/sessions and QwenWork under ~/.qwenworkcn/projects. The desktop workbench fit add another agent by name, and e go ask for the history path only when e no fit find the agent imself. The server-side scanner no get custom sources, so for headless VPS, na only the built-in ones you go get.
The import counters no go align, and that one dey expected. The scanner dey group messages by source and conversation, then e go write one L1 memory per complete turn. Turn dey count as complete when e get user content wey no empty and e end with assistant message wey no empty, so incomplete turn no go contribute anything until later sync fit complete am. Messages dey deduplicated with conversation checkpoints and stable turn IDs. The scanned count, the imported message count and the new memory count all go differ for the same run.
This na the piece wey pair with how Claude Code dey manage context inside one session. Context management dey decide wetin fit enter one window. Memory hub dey decide wetin go survive after that window close.
Wetin you need for your VPS
- Node.js 22 or newer. Na wetin Memmy docs need be this, and Ubuntu 24.04 dey come with Node 18.
gitand build toolchain, sake of saybetter-sqlite3na native module wey fit compile during installation.- RAM for the root workspace install and the frontend build chain.
- Free disk space for
node_modulesand the database.
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 suppose print v22 or higher for the source build wey we document. If you see v18 for here, e mean say the NodeSource step no work. npm engine-strict dey default to false, so if the engine declaration no match, e go usually show warning instead of make the install fail sharp-sharp.
Install Memmy from source for 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 dey compile the @memmy/memory workspace go Memory/dist. E still dey build AgentSourceCore, the memory viewer, and the integration assets wey that workspace need. Make you check say the native module load well:
node -e "const Database = require('better-sqlite3'); const db = new Database(':memory:'); db.close(); console.log('better-sqlite3 loads')"If that line show error instead of wetin you expect, read the error make you know whether na load failure or database initialization failure. If na native module mismatch, run npm rebuild better-sqlite3; na exactly wetin the project own start script dey do before e launch anything.
The README talk say bash scripts/dev-start.sh na one-command start. No run am for headless VPS. E dey start the Electron desktop shell and one Vite dev server for port 19000 near the memory service, and Electron need display. So, for server wey no get graphical session, the script go hang or stop.
Recent releases still dey attach memmy-agent-linux-cli.tar.gz and one install.sh for Linux x64 and arm64. The installer need Node.js 22.23.4+ inside 22.x, 24.22.1+ inside 24.x, or 26.12.1+ inside 26.x, plus systemd user session; e no dey accept other major versions. E dey put the memmy and memmy-memory launchers for ~/.local/bin, and e dey start the memory service as user unit for 127.0.0.1:18960. This guide still dey use source build because na the way you fit read every script before e run.
Start the memory service and check say e dey answer
npm run memory:serve:devDis na di documented way to run di memory service from source. E dey bind 127.0.0.1:18960, e dey keep di database for ~/.memmy/memory-service/memory.sqlite, and e dey read config from ~/.memmy/config.yaml. Di server fit accept di same values as flags if you want dem explicit:
npm run memory:serve:dev -- \
--host 127.0.0.1 --port 18960 \
--db ~/.memmy/memory-service/memory.sqlite \
--config ~/.memmy/config.yamlFrom one second shell, ask di service weda e dey alive:
curl -sS http://127.0.0.1:18960/api/v1/healthHealth no dey ask for token, na why e be di correct probe. If curl exit with code 7 and one Failed to connect to 127.0.0.1 port 18960 message, di connection fail; dat one alone no mean say listener no dey. Check di address, port, and local firewall, and read di terminal wey dey run di service for startup errors. ss -lntp | grep 18960 go confirm di socket once di service don start.
Di rest of di HTTP API (application programming interface) dey under /api/v1.
POST /api/v1/memory/adddey write memory andPOST /api/v1/memory/searchdey query am.GET /api/v1/memory/:idandDELETE /api/v1/memory/:iddey read and remove one entry.POST /api/v1/sessions/openandPOST /api/v1/sessions/:sessionId/closedey bracket one agent session.POST /api/v1/turns/startandPOST /api/v1/turns/:turnId/completedey record one turn.GET /api/v1/panel/overview,/api/v1/panel/analysisand/api/v1/panel/itemsdey feed di dashboard.
Memmy dey reserve one block of ports, and if you dey use headless, you go use only di first one: 18960 for memory, 18970 for gateway health, 18980 for di web UI and admin HTTP, 18990 for di OpenAI-compatible API wey memmy serve dey start, den 19000 for di desktop frontend Vite dev server and 19001 for im hot reload socket. Di project ports page still list 19010 for hot reload, but di Vite config set am to 19001. If something for your box don already hold one of those ports, na dat list you go check.
Wia memmy-memory command really dey come from
Na for here first install dey usually go wrong, so read am from the package instead of guessing. The command name no get anything to do with the repository name. E come from the bin field of the workspace wey define am:
node -p "JSON.stringify(require('./Memory/package.json').bin)"That one go print {"memmy-memory":"./dist/src/cli/index.js"}. So the built entry point na Memory/dist/src/cli/index.js, and e go only exist after npm run memory:build, because na the build dey create dist and mark the file executable. Run am directly:
node Memory/dist/src/cli/index.js healthIf you want the short name for your PATH, link that same file:
sudo ln -s "$PWD/Memory/dist/src/cli/index.js" /usr/local/bin/memmy-memory
memmy-memory healthThe CLI default na http://127.0.0.1:18960 and e accept --url, --token, --config, --source and --user-id. Its subcommands na init, health, search, add, get and delete, plus session and turn calls wey agents dey use instead of people, and install, upgrade, service and stop to manage the service itself. memmy-memory search "deploy steps" and memmy-memory add "staging migrates on deploy" na the two wey agent dey run pass.
How you go take connect Claude Code go Memmy?
Memmy no dey register itself as server inside Claude Code. E dey connect through files wey Claude Code don dey read already, and how far e go reach depend on which memmy-memory you run. From source checkout, memmy-memory init --agent claude dey write memmy-memory Skill enter ~/.claude/skills/ and one marked memory block enter ~/.claude/CLAUDE.md, and Claude Code go come run memmy-memory as ordinary shell command when those instructions tell am to do so. The launcher wey the Linux installer dey put for ~/.local/bin dey go further: the same command still dey register hooks for ~/.claude/settings.json for SessionStart, UserPromptSubmit, Stop, PostCompact and SessionEnd, wey dey inject relevant memory and save every turn wey finish without make the model need to decide to do am.
Write the instruction by hand one time, because if you do am, you go know exactly wetin dem tell the agent. Claude Code dey read CLAUDE.md from the project root for the start of every session, so section like this na the whole integration for the source path:
## 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.Make you clear about wetin that one dey give you. Without the hooks, na instruction level integration, so e dey work when the model decide to run the command, and no be otherwise. Nothing dey force the call. If session end without the add, the instruction itself no save anything; later history scan fit still import the turn wey finish. That one na the same trade-off as Claude Code own memory files, with one difference: the store dey shared, so the note still dey reach Codex and Cursor for the same machine. Hooks dey close the gap instead of make you dey beg nicely, wey be the reason why durable memory dey stay side-by-side with budget caps and permission rules among the DeepSeek Harness plugins wey make sense to install.
The other direction no need any setup at all. Memmy scanner don dey read ~/.claude/projects/**/*.jsonl already, na there Claude Code dey write its session transcripts. Run Memmy for the same server where you dey run Claude Code inside one tmux session and the work wey you do yesterday go turn to memory without you configure anything.
Memmy dey work as MCP server for Claude Code?
No. If you know how e dey work, you go save one afternoon. MCP (model context protocol) get clients and servers. Memmy na client. E dey connect to MCP servers and make their tools available to im own agent runtime. E no publish any MCP endpoint wey claude mcp add fit connect to. The only MCP bridge for the repository dey with the Composio integration inside the desktop local API. That API bind one random port on 127.0.0.1 behind im own x-memmy-mcp-token header.
You configure the client side for ~/.memmy/config.yaml, the file wey MEMMY_CONFIG point to, under tools.mcpServers:
tools:
mcpServers:
example:
type: stdio
command: npx
args:
- "-y"
- "your-mcp-server"
toolTimeout: 30
enabledTools:
- "*"type dey accept stdio, sse and streamableHttp. A stdio server dey run as Memmy child process. This mean say im command must dey for the same box and run as the same user. If you already dey keep MCP servers wey dey run for VPS, na those ones you suppose list here.
How to keep your memory store private
Everything wey Memmy get dey live inside ~/.memmy: config.yaml, the workspace, memory-service/memory.sqlite and runtime files. Scanning and ingestion dey happen locally, and dem dey write memories go that local SQLite file, so the default way e dey work na strictly local.
The cloud connection na one path wey you suppose watch. MEMMY_CLOUD_SERVICE dey name the cloud origin. The code no get default for am, but .env.example, wey the install steps dey copy go .env, dey set am to https://api.memmy.cn. E dey back account mode with im trial tokens, and anytime wey e set, Memmy analytics code go also post usage events go there, even for API key mode: event and command names, versions and one installation ID. The CLI dey report only fixed command words, e no dey ever report search queries or memory text, and the analytics code no dey send anything if the value no set, so for server wey only dey use API keys, empty that line for .env before you start anything. The memory improvement program na separate toggle wey dey inside privacy settings.
Model calls na another path. If you configure one hosted embedding provider, the memory text wey dem dey embed go go that provider so dem fit turn am to vector. Local storage no fit help for that side. Use the built-in local embedding provider or one embedding endpoint wey you host yourself to close that path. Hosted summary, evolution and relevance-filter models also dey receive memory content when those jobs run, so check those model settings too.
Keep port 18960 for the loopback address. E no need firewall rule, because service wey bind to 127.0.0.1 no fit reach from outside the box at all. Reach am from your laptop through SSH instead:
ssh -N -L 18960:127.0.0.1:18960 you@your-vpsThe current memory service dey reject non-loopback bind addresses. If you set storage.token for the config, or the MEMMY_MEMORY_TOKEN or MEMORY_SERVICE_TOKEN environment variable, e go protect ordinary memory API calls with bearer token; health check no need authentication, and the browser viewer dey use separate checks for local requests. Config values dey support ${ENV_NAME} references, so the token and your model API keys go stay outside the file itself. That one na the same habit as keeping secrets out of AI agents everywhere else, and a default deny ufw policy na your backstop if future version change im default bind address.
Make backup of ~/.memmy before you trust am
memory.sqlite na the full store. The vectors dey inside that same file through the sqlite-vec extension, so na one file you need backup. If you copy am with cp while the service dey write, the database fit spoil (torn database). Use the backup command wey SQLite get:
mkdir -p ~/memmy-backup
sqlite3 ~/.memmy/memory-service/memory.sqlite ".backup '$HOME/memmy-backup/memory.sqlite'"That one go produce copy wey dey consistent while the service still dey run. Send the file comot from the box for schedule, na that one be the work of restic to off-site storage. If you lose config.yaml, you go just need retype your provider settings. If you lose memory.sqlite, you go lose all the memories wey you record since the last backup wey you fit use; the service sef dey create local backup before e do schema migrations, but that one no be current off-site copy.
Run the memory service under systemd
If you run npm run memory:serve:dev inside one shell, e go die once the shell close. One unit file go make sure the service dey run even after you reboot. Make e run as one memmy user, from one checkout for /opt/memmy, with the config inside that user home directory. Stop the copy wey dey run for your shell, move the checkout and the config, then update the memmy-memory link:
sudo useradd -m -s /bin/bash memmy
sudo mkdir -p /opt/memmy
sudo mv ~/memmy-agent /opt/memmy/memmy-agent
sudo chown -R memmy:memmy /opt/memmy
sudo ln -sfn /opt/memmy/memmy-agent/Memory/dist/src/cli/index.js /usr/local/bin/memmy-memory
sudo install -d -o memmy -g memmy -m 700 /home/memmy/.memmy
sudo install -o memmy -g memmy -m 600 ~/.memmy/config.yaml /home/memmy/.memmy/config.yaml
sudo install -d -m 755 /etc/memmyThe service dey keep im database for /home/memmy/.memmy, so e go start with empty store.
[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.targetNo put the token inside the unit file. Put am for /etc/memmy/memory.env, make root own am, and set the mode to 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/healthIf you see status=203/EXEC for the status output, e mean say systemd no fit run ExecStart at all, so check which npm: e dey /usr/bin/npm if you use NodeSource install, or e fit dey inside user home if you use nvm, wey systemd no go fit see. If one unit start and exit sharp-sharp, you must check the exit status and the journal: code 0 mean say e exit well, but other numbers mean say error, signal, or timeout happen. Run journalctl -u memmy-memory -n 50 to see wetin the service dey output. The way e dey work na the same as any other systemd service on a VPS.
The project now get two ways wey user fit use. The README route for source build na memmy-memory install --service-only, e go download the Memory runtime wey dem pin and register one user service, and the Linux installer go setup memmy-memory.service as one systemd --user unit. None of dem dey enable linger, so run sudo loginctl enable-linger <user> so that the user service manager go continue dey run after you logout and start when the system boot.
Wetin Memmy never fit do yet
- No Linux desktop build dey. The packaging scripts cover macOS and Windows, so the workbench and the onboarding wizard no dey available for the server itself. The memory service now get one browser viewer for
http://127.0.0.1:18960/viewer/, wey you fit reach through the SSH tunnel wey we mention up so. Linux get CLI tarball andinstall.shinstead. memory:serve:devdey run the TypeScript entry point throughtsx, wey be development path. The repository also getmemory:servefor compiled output. Runnpm runwithout any arguments to see which scripts your checkout actually get.- Retrieval dey build im search window from the latest 2,000 vector rows, then e go apply Top-K selection inside that window. For very large store, old memory fit stay outside that window.
- Embedding dey happen after capture, and if e fail, e go go retry queue instead of make e block the agent turn. Memory wey you add just now fit no show for vector search yet.
- Second server wey get im own local SQLite database get separate memory.
Version 1.2.401 as of 1 November 2026 still show say the project still young and dey move fast. Flags, paths, and script names dey change between releases. Read the bin field and the output of npm run for your own checkout instead of make you trust command wey you copy from anywhere, even from here.
FAQ
Why does the health check return connection refused?
If you see curl exit code 7 with Failed to connect to 127.0.0.1 port 18960, e mean say connection fail. E no mean say Memmy stop, crash, dey listen for another place, or say you no fit reach am. Check the address and port, run ss -lntp | grep 18960, and read the terminal or journal wey the service start inside. If the log talk say native SQLite module mismatch, run npm rebuild better-sqlite3. Check your Node version too: the source docs need Node 22 or newer, but the Linux installer only gree for Node.js 22.23.4+ inside 22.x, 24.22.1+ inside 24.x, or 26.12.1+ inside 26.x.
Where does the memmy-memory command come from after building from source?
E come from the bin field of the @memmy/memory workspace package, no be from the repository name. Run node -p "JSON.stringify(require('./Memory/package.json').bin)" inside the checkout and e go print {"memmy-memory":"./dist/src/cli/index.js"}. That file only dey after npm run memory:build, because the build process create dist and mark the file as executable. Run am as node Memory/dist/src/cli/index.js health, or symlink am go /usr/local/bin if you want use the short name.
Can I add Memmy to Claude Code with claude mcp add?
No. Memmy na MCP client, e no be MCP server. E dey connect go servers wey dey listed under tools.mcpServers for ~/.memmy/config.yaml and e dey offer dia tools to im own runtime. Claude Code dey reach Memmy the other way, by running the memmy-memory CLI as a shell command. memmy-memory init --agent claude dey write a Skill and a CLAUDE.md block wey dey tell am when, and the launcher from the Linux installer sef dey add Claude Code hooks wey dey save turns automatically.
Does running Memmy send my memories to a cloud service?
Scanning and ingestion dey run locally, and dem dey write memories go ~/.memmy/memory-service/memory.sqlite for your own disk. MEMMY_CLOUD_SERVICE, wey you set to https://api.memmy.cn for .env.example, dey serve account mode and trial tokens and e dey receive usage analytics wey no get memory text while e dey active, so make you empty am if na only API keys you dey use. The memory improvement program get separate privacy toggle. A hosted embedding model dey receive the memory text wey e turn to vector; use the built-in local provider or an endpoint wey you run yourself if you want keep that processing local. Hosted summary, evolution, and relevance-filter models sef dey receive memory content when those jobs dey run.