Memory Outside the Tree

Configure one canonical memory store, migrate existing notes with verified backups, and check where the agent actually reads and writes. Git synchronization and optional aliases remain separate concerns.

Luminous data-orb tethered just outside a dark architectural cube

Persistent agent memory needs an explicit home. A folder can be easy to edit, tracked in Git, and available to a coding agent without those properties being the same thing. The important question is which store the agent actually reads and writes.

This guide replaces the earlier symlink workaround with a documented configuration approach. It does not depend on bypassing protected-path checks or on undocumented ordering between path resolution and permission checks.

Separate native memory from a project alias

Claude Code normally stores auto memory under ~/.claude/projects/<project>/memory/. Its current memory documentation supports autoMemoryDirectory for selecting a different directory. The value must be absolute or begin with ~/. A project-level .claude/memory folder is not the universal native auto-memory path.

An optional project alias can make a shared folder convenient to open. It does not configure the engine, make the content synchronized, or grant permission to write. Treat the alias, the memory setting and the synchronization mechanism as three separate decisions.

Choose one canonical store

For a repository that owns its supporting memory, one option is a claude-memory directory in that repository. For sensitive or organization-restricted work, use an appropriately protected separate location instead. Do not copy personal notes or unrelated project knowledge into a repository merely because it is convenient to synchronize.

Point the agent at the selected store through supported configuration. For example, merge the following field into the appropriate settings scope, replacing the generic path with the reviewed directory. Do not overwrite an existing settings file with this fragment.

{
  "autoMemoryDirectory": "/absolute/path/to/project/claude-memory"
}

Settings scope, workspace trust and managed permission policies still apply. This field is a storage choice, not a security exception. Confirm the effective setting with the installed version before relying on it in unattended work.

Fresh setup and migration are different operations

For fresh setup, create the chosen directory without touching an existing memory store. Add an index and a small test note, configure the location, then inspect the next session. The example above is a settings fragment, not a migration script.

For migration, first stop concurrent memory writers. Record the configured source and destination, including whether either path is a directory, a symlink or a missing path. Resolve links deliberately so the backup covers the actual files rather than only a link entry.

Make an independent backup of every existing store and verify it by checking file contents or hashes. Only after that succeeds, compare the stores and copy or merge their contents. Preserve divergent notes for reconciliation; do not choose one directory solely because its timestamp is newer.

Configure the selected canonical directory and inspect a new session before retiring the old setup. An unexpected real directory where a symlink was expected is a reason to stop the migration and inspect it. Do not use ln -sfn as a general-purpose replacement or merge operation.

Verify reading and writing separately

A successful commit proves that Git accepted a change. It does not prove which memory the agent loaded. Use /memory to inspect the active memory location, then start a new session and verify that a harmless, uniquely identifiable test note is available.

Next ask the agent to record another harmless test note. Inspect the resulting files and confirm that the change landed in the canonical store, with no parallel copy silently diverging elsewhere. Remove the test notes after checking both paths.

If a permission check rejects the operation, inspect the configured directory, client version and applicable policy. Do not assume macOS or Linux forces an application to validate a resolved path rather than the original string. Applications can check either or both.

Git carries changes only when you move them

Version control can provide history, review and a recovery path. It does not create real-time synchronization. Another machine sees changes only after the required commit, push and pull, and concurrent edits can produce conflicts.

Review memory before committing it. It may contain local environment details, unfinished hypotheses or information with a narrower audience than the repository. A separate private store is often the simpler choice when memory and code have different access requirements.

Document the chosen store, the synchronization procedure and the verification steps. Keep any optional alias subordinate to that design. There should be one named source of truth, not a symlink scheme described as one architecture and a post-commit mirror described as another.

Keep the configuration auditable

The durable lesson is to make storage and behavior observable. Prefer a supported setting, verify actual read and write locations, and keep a recoverable migration record. A clever path workaround is not evidence that the agent is using the intended memory.

Configuration checked 20 September 2026 against Claude Code’s official memory documentation. Verify the settings and trust behavior supported by the version you deploy.