Recall
A minimal, self-hosted sync service for Claude Code's auto memory — the notes Claude writes about itself as it works (~/.claude/projects/<project>/memory/). Works from your laptop, your other laptop, and any fresh ephemeral cloud session, with no device pairing required.
Why
Claude Code's auto memory is explicitly machine-local by design (see Anthropic's own docs — and a related feature request on anthropics/claude-code closed as "not planned"). CLAUDE.md already syncs fine via git; auto memory doesn't. Existing community tools (claude-sync, claude-brain, and similar) all assume a fixed set of named "devices" that pair with each other — that model breaks the moment one of your environments is an ephemeral cloud session that's never seen your other machines and won't exist tomorrow.
Recall exists for that specific gap: a central service any environment can talk to, with no prior introduction.
What it is not
- Not a replacement for git-based
CLAUDE.mdsync — that's already solved, don't touch it. - Not a multi-user product. Personal tool, single owner, no Anthropic API key, no auth system beyond a personal token. See
CLAUDE.md's Ground rules. - Not append-only. Merge works like
claude-brain's does: a semantic merge via the localclaudeCLI, not naive line-dedup — implemented and verified live, seeROADMAP.mdPhase 2.
How it plugs into Claude Code
No custom client daemon. Claude Code's own hook system does the work:
- Push: a
PostToolUsehook matchingEdit|Writerunsrecall push, which checks whether the edited file is a memory file and, if so, sends it to Recall's API. (An earlier design assumed aFileChangedevent and a declarativehttphook type — neither exists in the installed CLI; seedocs/history/phase-0-findings.md.) - Pull: a
SessionStarthook runsrecall pull, which fetches the latest synced state before Claude loads context.
Neither can break a session: an unreachable server or an unconfigured machine warns on stderr and exits 0.
Both hooks live in the project's own .claude/settings.json, checked into git — so any environment that clones the repo (laptop or fresh cloud session) picks up sync automatically. See ARCHITECTURE.md.
Start here
Recall is a single Rust binary that is both halves: recall serve runs the
server, everything else runs beside your editor. Which half you need depends
on what you already have.
A. You don't have a server yet — set one up
Do this first. Every client instruction below asks for a RECALL_URL and a
RECALL_TOKEN, and both come from the server; there is nothing to connect to
until it exists.
What it costs, before you start: a host that stays up (a small VPS is the
usual answer), Docker with Compose v2, a clone of this repository on that
host — both compose files build from source — and either a domain you control
or a Cloudflare account, depending on which ingress you pick.
deploy/README.md walks the whole thing, ingress first,
because that is the choice everything else follows from.
B. You have a server — connect a machine to it
Install the binary, connect it to your server once, and opt each project in:
|
# project: wires it and sends its memory
&&
connect asks one question at a time and skips what is already done, so
running it again is safe. It saves to ~/.recall
(docs/reference/token-setup.md). Each
further project is recall init and recall backfill, or recall connect
again from inside it.
"Connect" means your own second machine, or a fresh cloud session — not
someone else's. Recall is single-owner by design: one token, no accounts, no
per-user anything. See CLAUDE.md's ground rules for why that is a decision
rather than an omission.
What each install channel actually does, and the rest of the client story, is
in docs/reference/install.md.
On the crate name. cargo install recall has installed this project since
0.2.0; through v0.1.0 the crate was recall-sync. Version 0.1.0 under the
recall name is a different project entirely — a flashcard CLI by Matthew
Blode, still at mblode/recall — and it
stays on the index where it is. Thanks to him for handing the name over.
Then, whichever door you came through
Notes about you rather than the repo can follow you into every project: set
RECALL_GLOBAL_KEY, then recall promote <file> moves one there. Notes true
of one box and wrong on the next — its RAM, which of two dotnet installs
wins — belong in neither: naming the machine ([machine] name in
~/.recall/config.toml) gives them a scope that comes back only on that machine, and recall promote <file> --to machine files them
there. And where the owner/repo key derived from the git remote is wrong — a
repo with no remote, a monorepo, a fork — RECALL_PROJECT_KEY declares it
instead. All three are in
docs/reference/install.md.
To talk to the server directly, see the HTTP API reference.
Status
Phases 0 through 9 done. Recall is one Rust binary
(docs/history/rust-rewrite.md) that runs both halves: the push/pull round-trip
proven from a genuine claude.ai cloud session, conflicting edits semantically
merged rather than last-write-wins, multi-project isolation verified, and a
global scope so a note about you is not stuck in whichever repository Claude
happened to learn it in — with a machine scope beside it, for the facts that
describe one box and would be wrong on the next.
The Rust server runs in production as of 2026-09-14 (Phase 9), behind Traefik, reading the database the Node implementation wrote — no migration, which is what the frozen schema was always for.
The Node server and the bash hooks it replaced are gone from the tree
(Phase 7) — git history is the rollback path, and what they were really
carrying is now fixtures/node-written.db, a database the Node server
actually wrote, so scripts/compat-check.sh still proves this server reads
production's rows.
ROADMAP.md has the evidence behind each phase, including what was measured
rather than assumed and two conclusions that turned out wrong.
Project docs
docs/ is the index. The short version:
| Start here | For |
|---|---|
deploy/README.md |
Door A — standing the server up, ingress first |
docs/reference/install.md |
Door B — installing the CLI and opting a project in |
docs/reference/token-setup.md |
The token both doors need, onto every machine, laptop and cloud |
docs/reference/releasing.md |
Cutting a release across all four channels |
docs/reference/api.md |
The HTTP API: endpoints, schemas, status codes, examples |
ARCHITECTURE.md |
How it works, and the code map |
docs/history/rust-rewrite.md |
Why Rust, honestly — including every bug this project has shipped |
docs/history/memory-loading-findings.md |
What Claude Code actually does with memory files, and why one probe proves nothing |
ROADMAP.md |
Every phase, the evidence behind it, and what is deliberately deferred |
CONTRIBUTING.md |
Building, testing, and what not to "clean up" |
CHANGELOG.md |
What changed between releases, for someone deciding whether to upgrade |
And the tree:
| Path | What's in it |
|---|---|
crates/ |
The binary. recall-wire (frozen contract) · recall-hooks (client, including path derivation) · recall-server · recall (main, for both halves — serve included). See ARCHITECTURE's code map. |
deploy/ |
The image, and a Compose file per ingress — Cloudflare Tunnel or an existing Traefik. Runs on anything with Docker. |
scripts/ |
compat-check.sh (the cutover matrix), api-doc-check.sh, trusted-ip-check.sh, install-worker-test.js, wrangler-check.py, release.sh, and probes/. |
npm/, Formula/, install.sh |
Three of the four install channels. The fourth, cargo install recall, needs no file here. |
fixtures/ |
A database the retired Node server actually wrote, so the cutover stays testable without it. |
License
MIT — see LICENSE.