Designing Persistent Memory for AI Agents

Every conversation with an AI agent starts with amnesia. The agent knows nothing about you, your preferences, or the lessons learned from previous sessions. For a single-device setup, this is solvable: persist everything locally. But when you run agents across multiple devices — a Mac Mini handling automated tasks, a laptop for interactive work, a cloud instance for always-on monitoring — the problem becomes architectural.

This article explores how to build a cross-device memory system for AI agents: what to persist, what should remain local, and how to synchronize state without conflicts or data loss.

The AI Amnesia Problem

Modern AI agents are stateless by default. Each conversation begins with a fresh context window. While this ensures deterministic behavior and simplifies scaling, it creates friction for users who expect continuity. You teach the agent a lesson on Monday, then repeat the same correction on Tuesday because the agent has no memory of the earlier interaction.

The solution is persistent memory: a system where agents write important information to disk and reload it in subsequent conversations. Claude Code, for instance, implements this with a markdown-based memory system. The agent writes memory files during conversations, and future conversations load relevant memories into context.

But when you scale beyond a single device, new challenges emerge. If both your laptop and your Mac Mini write to the same memory store, you risk conflicts. If they maintain separate stores, they diverge and lose consistency. The architecture must handle synchronization, conflict resolution, and scope management.

Memory Taxonomy

Not all agent knowledge should be persisted. The first step is categorizing what memory types exist and which deserve persistence.

User preferences: Information about the user’s role, expertise, communication style, and workflow preferences. Example: “User prefers terse responses, no emoji unless requested.” These should sync across all devices — your preferences shouldn’t change based on which machine you’re using.

Project context: Details about ongoing work, architectural decisions, and team conventions. Example: “PR freeze after Thursday 2026-03-05 for mobile release cut.” This is workspace-scoped: relevant to a specific repository, not globally applicable.

History: A log of past interactions, including which files were read, what commands were run, and what tasks were completed. This is valuable for debugging and audit trails but should remain local. Syncing conversation history across devices creates privacy risks and context pollution.

Lessons learned: Corrections and guidance the user has provided. Example: “When touching request-path code, check the Grafana oncall dashboard.” These should sync selectively: workspace-scoped lessons stay with the workspace, while global lessons sync everywhere.

Semantic key-value pairs: Structured data the agent needs for operations, like API endpoints, credential locations, or deployment targets. These should sync when they’re global (e.g., “JIRA API URL”) but stay local when machine-specific (e.g., “local database connection string”).

The key insight: memory types differ in scope, privacy sensitivity, and conflict tolerance. A one-size-fits-all sync strategy will either leak sensitive data or fail to provide consistency where needed.

Sync vs Local: The Decision Matrix

Here’s how different memory types should be handled in a multi-device setup:

Memory TypeSync StrategyReasoning
User preferencesSync globallyShould be consistent across all devices
Global lessonsSync globallyLearning should propagate everywhere
Project contextSync workspace-scopedRelevant only within a specific repo
Workspace lessonsSync workspace-scopedOnly applicable in this codebase
Conversation historyNever syncContains sensitive data, not useful cross-device
Credentials/secretsNever syncMachine-specific, security risk if synced
Local configNever syncDevice-specific paths and settings

This categorization drives the architecture. Memory that syncs globally lives in a shared store. Memory that never syncs stays in a local directory. Memory that syncs per-workspace lives in the repository itself (e.g., .claude/memory/ in each repo).

Sync Mechanisms Evaluated

Three approaches were considered for synchronizing global memory:

Dropbox symlink: Create a symlink from ~/.claude/memory/global/ to a Dropbox-managed folder. Dropbox handles syncing, conflict resolution, and versioning. This works well for small files and infrequent writes but struggles when both devices write simultaneously. Dropbox’s conflict resolution creates duplicate files (memory (1).md), which the agent won’t automatically merge.

Rsync cron job: Run a cron job every N minutes that rsyncs ~/.claude/memory/global/ to a remote server. Simple and robust, but requires setting up SSH keys, handling network failures, and implementing conflict detection. Unidirectional by default — bidirectional sync requires additional logic to detect which side has newer data.

Git-based sync: Store global memory in a git repository and push/pull changes. Provides full version control, merge conflict detection, and a clear audit trail. The downside is complexity: you need git installed, SSH keys configured, and logic to handle merge conflicts when both devices modify the same memory file.

For a two-device setup (laptop and Mac Mini), git-based sync provides the best balance. It’s overkill for most use cases but justifiable when you need conflict detection and history. A startup script on each device runs git pull --rebase to fetch remote changes before the agent starts.

Conflict Resolution Strategies

Even with git, conflicts occur when both devices modify the same memory file between syncs. The resolution strategy depends on memory type.

Last-write-wins for preferences: User preferences rarely change, and when they do, the latest version is usually correct. If both devices modify user_preferences.md, accept the most recent timestamp.

Append-only for lessons: Lessons learned are cumulative. If both devices add new lessons, merge both. Git handles this well: if one device appends lines to a file while the other also appends (without modifying existing lines), git auto-merges cleanly.

Manual review for semantic conflicts: If both devices modify the same lesson file (e.g., editing an existing entry rather than appending), flag it for manual review. The agent can detect conflict markers and prompt the user to resolve.

Never-sync for history: Since conversation history doesn’t sync, conflicts are impossible. Each device maintains its own local history.

The key is designing memory files to minimize conflicts. Use append-only patterns where possible. Split memory into small, focused files rather than large monoliths. Timestamp each entry so the agent can reason about recency.

Scope System: Global vs Workspace

Some lessons apply everywhere (“user prefers terse responses”), while others are repo-specific (“main branch is develop, not main”). The scope system manages this.

Global memory: Stored in ~/.claude/memory/global/ and synced across all devices. Includes user preferences, global lessons, and cross-project references. Loaded in every conversation regardless of working directory.

Workspace memory: Stored in .claude/memory/ within each git repository. Includes project context, workspace-specific lessons, and architectural decisions. Only loaded when the agent is working in that directory.

The agent determines scope based on keywords. If the user says “remember this for all projects,” it writes to global memory. If they say “remember this for this repo,” it writes to workspace memory. When in doubt, default to workspace scope — it’s safer to under-share than over-share.

Workspace memory doesn’t require a separate sync mechanism: it lives in the git repository itself. When you clone the repo on a new device, the workspace memory comes with it. When you push commits, workspace memory updates propagate.

Bootstrapping a New Instance

When you provision a new device, it starts with empty memory. The bootstrap process restores global state:

  1. Clone the global memory repository: git clone <memory-repo> ~/.claude/memory/global/
  2. Load user preferences and global lessons from the synced store
  3. Do NOT sync conversation history — let the new device start fresh
  4. Configure device-specific settings (e.g., local paths, credentials) in a non-synced config file

Workspace memory bootstraps automatically when you clone a repository. The .claude/memory/ directory is part of the repo, so it’s present immediately.

One edge case: what if you want to seed a new agent instance with history from another device (e.g., for debugging)? Export history as a standalone archive, transfer manually, and import explicitly. This keeps history transfer intentional rather than automatic.

Architecture Diagram

Here’s the two-instance memory architecture with sync flows:

Laptop AgentGlobal MemoryLocal HistoryWorkspace Memory (repo/.claude/)Mac Mini AgentGlobal MemoryLocal HistoryWorkspace Memory (repo/.claude/)Git RemoteGlobal Memory Repogit pushgit pullgit pushgit pullNo syncLegend:Synced via gitNever synced (local only)

Practical Considerations

Latency and offline operation: Git-based sync requires network access. If a device is offline, it operates on stale global memory until reconnection. For most use cases, this is acceptable — lessons learned aren’t time-critical. To minimize staleness, run git pull on a cron job every 30 minutes.

Conflict frequency: In practice, conflicts are rare. User preferences change infrequently. Lessons are append-only. If both devices add new lessons simultaneously, git merges them automatically. True conflicts (editing the same line) occur only when you’re actively refining a memory entry on both devices at once.

Performance impact: Loading memory adds latency to agent startup. For a global memory store with 50 files totaling 100KB, load time is negligible (<50ms). For large workspaces with extensive project context, use lazy loading: only read memory files when the agent needs them.

Security: Global memory syncs via git, so secure the repository. Use private repos with SSH keys. Avoid storing credentials or API keys in memory — those belong in environment variables or secret managers. Treat memory as “persistent preferences” not “secret storage.”

Conclusion

Persistent memory transforms AI agents from stateless tools into adaptive collaborators. But extending memory across multiple devices requires careful architectural decisions: what to sync, how to resolve conflicts, and how to bootstrap new instances.

The key principles:

  • Categorize memory by scope (global vs workspace) and sensitivity (sync vs local-only)
  • Use git for global memory sync to get version control and conflict detection
  • Design memory files to minimize conflicts (append-only, small focused files)
  • Never sync conversation history or credentials
  • Bootstrap new devices by cloning the global memory repo

With this architecture, you can run AI agents on a laptop, a Mac Mini, and a cloud instance while maintaining consistent memory across all three. The agent learns once and applies that knowledge everywhere.