memlink
by Blondu2024
README.md
# memlink
**Your Claude memory, everywhere.** memlink syncs Claude Code's memory files from your PC to an encrypted cloud store, and serves them to Claude on your phone (or any MCP client) — even while the PC is off. Whatever the phone writes lands back on your disk as plain `.md` files.
*Citește în [română](./README.ro.md).*
```
PC (Claude Code) cloud phone (Claude app)
~/.claude/**/*.md ──encrypt──▶ memlink server ◀──MCP──── memory_search / write
▲ (zero plaintext) │
└───────────── memlink watch pulls changes back ◀───────────────┘
```
## Quickstart
```bash
npx memlink-cli init --server https://memlink-omega.vercel.app --email you@example.com
# prompts for a passphrase (min. 12 characters, twice) - it never leaves your machine
npx memlink-cli watch
# watches your Claude memory folders, pushes changes, pulls what other devices wrote
```
Then connect Claude:
- **Phone / claude.ai:** Settings → Connectors → *Add custom connector* → URL `https://memlink-omega.vercel.app/mcp`. Claude opens memlink's authorization page: enter your email and passphrase (the key is derived **in your browser**; the passphrase is never sent), and the connector is live — with `memory_search`, `memory_get`, `memory_write`, `memory_list`.
- **Claude Code (another machine):** `npx memlink-cli login --server ... --email ...`, then
`claude mcp add --transport http memlink https://memlink-omega.vercel.app/mcp --header "Authorization: Bearer <output of memlink token>"`.
`memlink sync` runs one push/pull round if you prefer manual control.
## The security model — honest, both sentences
> "My database is useless if stolen, and I never store the key. The code is public — verify it."
- Notes are encrypted **on your machine**: Scrypt key derivation + XChaCha20-Poly1305 (`@noble/hashes`, `@noble/ciphers` — audited libraries). File paths are encrypted too. The server stores zero plaintext and never stores your key.
- **The limit, stated plainly:** this is NOT end-to-end encryption. To answer an MCP client the server decrypts in RAM per request — Anthropic's cloud receives plaintext in responses, otherwise Claude would have nothing to read. The key transits inside your token and lives in server RAM only for the duration of a request.
- OAuth 2.1 (PKCE + dynamic client registration), fully stateless: access tokens are sealed payloads; rotating the server's seal key revokes everything at once.
- More plainly-stated limits: the derived key sits cleartext in `~/.memlink/credentials.json` (0600 on POSIX; unprotected on Windows), and `memlink token` prints a secret granting full access to your corpus — treat both like passwords.
## Conflicts: nothing is ever lost
Last-write-wins per note, with optimistic versions. The losing version is always preserved in `~/.claude/memory-conflicts/` — same for notes deleted from the cloud (moved there, not destroyed) and for anything suspicious (undecryptable or path-escaping notes are quarantined, never written over your files).
## Self-hosting
The server is a single Vercel function backed by Supabase Postgres:
1. Create a Supabase project (or reuse one) and run `supabase/migrations/0001_init.sql` — optionally inside a dedicated schema, then expose it in PostgREST and set `MEMLINK_DB_SCHEMA`.
2. Set Vercel env vars: `SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`, `MEMLINK_SEAL_KEY` (64 random bytes, base64 — rotating it revokes all tokens), `MEMLINK_BASE_URL` (your deployment URL), optionally `MEMLINK_DB_SCHEMA`.
3. `vercel deploy --prod` from the repo root (the build bundles everything).
## Development
npm workspaces: `packages/shared` (crypto + wire format), `packages/server` (Hono API + MCP + OAuth), `packages/cli`. `npm test` (vitest), `npm run typecheck`. The CLI speaks ten languages (en native + ro, da, de, fr, es, it, pt, nl, pl) via `MEMLINK_LANG` or your system locale.
## License
MIT — see [LICENSE](./LICENSE).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues