Portable memory for coding agents. Claude Code, Codex and other agents learn
things about a project while they work on it — your preferences, lessons from
past mistakes, where a task was left. By default that memory stays on one
computer. Rove Memory keeps it in a private Git repository of the project's
own, checked out as the ignored .agent-memory/ folder, so the same memory
follows you to every computer you work from.
- One private repository per project, one folder per agent (
claude/,codex/, …). Each agent writes only its own folder. - An edit lease so two sessions on the same machine — or two machines — never overwrite each other's memory, and a write that would publish someone else's change is refused.
- Markdown only, bounded: a short
MEMORY.mdindex plus topic files, with size limits, validated before anything is pushed. - No service, no model calls, no runtime dependencies: a Node.js command that drives Git.
It is not a vector store or a retrieval system for LLM applications. It is the durable notebook your coding agents keep about a project, versioned like the project itself.
- Node.js 22 or later and Git.
- A package manager to install it (pnpm is used in the examples).
- For each project, an empty private Git repository for its memory, and Git credentials on each computer that can read and push it.
-
Create the project's memory repository, for example
gh repo create <owner>/<project>-agent-memory --private, with aREADME.mdonmainthat says what it is and that each agent owns only its folder (setupcreates the folders). -
In the project's
package.json, add the tool pinned to a commit, a script for it, and the configuration:{ "scripts": { "memory": "rove-memory" }, "devDependencies": { "rove-memory": "github:jayyanez/rove-memory#<commit>" }, "roveMemory": { "project": "<Project>", "remote": "https://github.com/<owner>/<project>-agent-memory.git" } }The remote must be a plain HTTPS or SSH Git URL: credentials, query strings and fragments are refused, so the configuration can be committed safely.
-
Add
.agent-memory/to the project's.gitignore. -
Tell your agents to use it: add a section like the one below to the project's
CLAUDE.md/AGENTS.md. -
Run
pnpm install, thenpnpm memory setup --agent claude(or--agent codex, …).
To move a project to a newer version, change the pinned commit.
A public project may not want to publish the address of its private memory
repository. Leave remote out of roveMemory and give it once on each
computer instead:
pnpm memory setup --agent claude --remote https://github.com/<owner>/<project>-agent-memory.git
setup keeps it in the repository's local Git configuration
(git config --local rove-memory.remote), which every linked worktree shares
and which is never committed; every later command reads it from there. A
different value is never overwritten silently, and package.json and the local
setting may both be present only when they name the same repository.
In the project's Git directory, shared by every linked worktree: the
operation lock rove-memory.lock, and the edit lease named after the memory
repository — <name>.lease, with a <name>.lock taken together with the
operation lock — where <name> is the memory repository's name (lower-case
letters, digits and hyphens, always holding "memory", e.g.
project-agent-memory). Every worktree must use the same memory repository
(a checkout cloned from another remote is refused), so every worktree uses the
same lease. An earlier copy of this tool that named its files after the
memory repository shares the lease and its lock with Rove Memory while both
are in use; the lease format is the same.
## Portable memory
Agents' memory for this project lives in the private
`<owner>/<project>-agent-memory` repository, checked out as the ignored
`.agent-memory/` folder in the canonical checkout. Each agent uses one stable
lowercase id (`claude`, `codex`, …) and owns only `.agent-memory/<id>/`. The
policy is `node_modules/rove-memory/POLICY.md`; read it before the first
memory write of a session.
- Session start, in every checkout and linked worktree: `pnpm install`, then
`pnpm memory setup --agent <id>`, then read `MEMORY.md` in the agent folder
it prints. If setup fails, stop and report it.
- Every write is a lease: `pnpm memory edit --agent <id>` prints a token;
write; `pnpm memory sync --agent <id> --lease <token> --message "<id>: …"`
publishes and releases it. Never end a turn holding a lease.
- Never touch another agent's folder. Memory is advisory: Git, the code and
the project's documents override it. Store only durable context — never
secrets, transcripts, logs or machine-local paths.From any checkout or linked worktree of the project:
| Command | What it does |
|---|---|
pnpm memory setup --agent <id> [--remote <url>] |
Clone or fast-forward .agent-memory/, create and publish <id>/ when it is missing; for claude, point this checkout's autoMemoryDirectory at it. --remote stores the memory remote in the repository's local Git configuration. |
pnpm memory status --agent <id> |
Project, memory remote, folder bounds, unsynced changes, unpublished commits, the edit lease, and Claude Code's configuration. |
pnpm memory edit --agent <id> [--holder-pid <pid>] |
Take the edit lease and print its token. --renew --lease <token> after a commit of the same agent landed; --reclaim-stale for a lease whose holder is gone. |
pnpm memory sync --agent <id> --lease <token> [--message <text>] |
Validate, commit, rebase, push, and release the lease. |
pnpm memory release --agent <id> --lease <token> |
Give back a lease with nothing to publish. |
A leading -- (as some package managers pass it) is ignored. The memory
checkout lives in the project's canonical checkout (found through Git's common
directory), so every linked worktree shares it.
Claude Code loads its memory from autoMemoryDirectory, a per-checkout
setting. setup --agent claude writes it into the checkout's ignored
.claude/settings.local.json, pointing at .agent-memory/claude, so a
session opened in that checkout loads the portable memory. Run setup once in
each new checkout or worktree.
If Claude Code already kept memory for the project in its per-machine folder
(~/.claude/projects/<project path>/memory/), import the durable facts that
are missing into .agent-memory/claude/ once, publish them under a lease, and
rename the old folder so it cannot load again.
Agents without a memory-directory setting read
.agent-memory/<id>/MEMORY.md at the start of a session, as their
instructions say, and write through the same lease.
- Only to the configured repository. Every URL the memory checkout would
fetch from or push to, after Git's
insteadOf/pushInsteadOfrewriting, must be the configured remote — the same scheme, account, host (without case) and path (with case); HTTPS and SSH name the same repository only on github.com, which documents it. This is checked at every command and again right before each push. A remote from the environment is honoured only as a local path (the test suites' bare repositories). - Only your folder, only your commits. A change outside the agent's
folder is refused and named, never staged or discarded. Memory history is
linear and every commit changes something. The commit published is the one
the agent made, on the
HEADit checked, identified by its SHA. If a rebase is needed, every one of the agent's commits is replayed and the result must match them one for one before it is adopted. - Validated as committed. Every commit that will be pushed is checked as
committed: Markdown only, no NUL bytes, no symlinks or control characters in
paths,
MEMORY.mdwithin 200 lines and 25 KiB, a topic file within 256 KiB, a folder within 2 MiB.
Commands that change the memory checkout or the lease hold one operation lock
(rove-memory.lock in the project's Git directory, see "Where the lock and
lease live"), so linked worktrees never change the checkout at the same time.
File writes cannot be locked, which is what the lease (<name>.lease, same
directory) is for:
- A lease with a holder pid is live while that process exists with the same
start time, and stale once it is gone; a probe that cannot read the start
time never dispossesses a holder. A lease without a holder pid is live for
30 minutes after the last command that carried its token (the environment
variable
ROVE_MEMORY_LEASE_TTL_MSchanges that span; the tests use it). - Only the live holder's token can sync or release; a stale token authorizes
nothing, and its holder re-takes its own lease with
edit --reclaim-stale --lease <token>, which keeps its unsynced edits. - Sync refuses when a commit of the same agent landed after the lease's
baseline, locally or on the remote, and keeps the holder's commit;
edit --renewrebases it and names the files that changed remotely. - An edit that arrives while sync publishes keeps the lease instead of being abandoned; a write that lands after a release can be adopted only with the released token.
- A first bootstrap whose push failed is published by the next
setup, unless another machine published the folder meanwhile: then its commits stay local, andeditadopts them under a lease forsyncto publish.
The operation lock is a file a crashed command can leave behind; the error names its recorded owner, and it may be removed by hand only after confirming that process is gone.
POLICY.md is the policy for the agents themselves: what
belongs in memory, ownership, and the lease routine.
Windows, macOS and Linux. The holder probe uses Windows PowerShell on Windows
and ps elsewhere. Continuous integration runs the suite on all three.
pnpm install --frozen-lockfile
pnpm test
The suites drive the real command against real Git with temporary bare repositories; they need no network and no accounts. See CONTRIBUTING.md.
Rove Memory grew out of the agent workflow of Rove, an upcoming desktop application, where several coding agents share one machine and one project. Like Rove Sentinel, it is an independent project that makes that piece available to anyone. Rove has not been publicly released.
Apache-2.0. See NOTICE. This license does not cover the Rove application or any agent or service the tool works with.