recall 0.3.0

Sync Claude Code's auto memory across machines and cloud sessions
recall-0.3.0 is not a library.

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.md sync — 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 local claude CLI, not naive line-dedup — implemented and verified live, see ROADMAP.md Phase 2.

How it plugs into Claude Code

No custom client daemon. Claude Code's own hook system does the work:

  • Push: a PostToolUse hook matching Edit|Write runs recall push, which checks whether the edited file is a memory file and, if so, sends it to Recall's API. (An earlier design assumed a FileChanged event and a declarative http hook type — neither exists in the installed CLI; see docs/history/phase-0-findings.md.)
  • Pull: a SessionStart hook runs recall 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:

npm install -g @pimlabs/recall                    # or bun, or pnpm
brew install pimlabs/tap/recall
curl -fsSL https://recall.pimlabs.id/install | bash
cargo install recall
recall connect https://recall.yourdomain.com # asks for the token, checks it, saves it
                                             # to ~/.recall (docs/reference/token-setup.md)
recall init                                  # wires .claude/settings.json
git add .claude/settings.json && git commit  # so fresh clones get it too
recall backfill                              # send memory that predates all this
recall status                                # confirm it's actually working

"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: RECALL_MACHINE_KEY 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.