New machine, logged in, everything works — except your AI assistant has amnesia. Here's what "context" physically is, which parts are worth carrying over, and how to merge a year of it without contaminating anything.

The surprise: logging in doesn't bring your context

On the new laptop, Claude Desktop signed in and every chat was right there — chats are server-side, tied to the account. But the Code side was empty: no session history, no memories, no learned preferences. A stats panel that once knew months of activity showed a single session.

That's the split that matters:

LayerLivesFollows your login?
Chats (desktop app, web)Server-sideYes — automatic
Claude Code context: session transcripts, auto-memory, prompt history, settings, permission grantsLocal disk (~/.claude)No — it stays on the old machine

If you use Claude Code seriously, the local layer is your assistant's accumulated knowledge of how you work. It's also just files — which means it migrates.

What's actually in the context directory

From the old machine, grab two things: the CLI config dir (~/.claude) and, mostly for completeness, the desktop profile (~/Library/Application Support/Claude). Mine came to ~1 GB. Survey before copying — most of that gigabyte is noise.

Worth migrating (the ~110 MB that matters):

  • projects/<encoded-path>/memory/auto-memory: curated facts the assistant saved about your projects and preferences. Highest value per byte.
  • projects/<encoded-path>/*.jsonlsession transcripts. Makes old sessions resumable (claude --resume) and greppable by future sessions.
  • history.jsonl — prompt history.
  • settings.json / settings.local.json — settings and the permission allowlist you spent months accepting one prompt at a time.
  • .claude.json — per-project trust flags and config.
  • plans/, tasks/, todos/, file-history/ — small, cheap to keep.

Not worth migrating:

  • Desktop profile contents — login/cookies (you'll log in fresh), caches, IndexedDB (rebuilds), a bundled copy of the CLI (obsolete on arrival), pending upload blobs. In my 912 MB desktop dump, nothing was uniquely valuable.
  • shell-snapshots/ — captured shell environments from the old machine; stale by definition.
  • Installed desktop extensions — reinstall in a click; skip the 21 MB of node_modules.

One structural detail decides whether transcripts are worth it at all: project dirs are named by encoded absolute path (-Users-you-code-repo-x). If your repos live at the same paths on the new machine, everything maps; if not, the transcripts won't attach to your new working directories. Keep your directory layout stable across machines — or accept that transcripts become a grep-able archive rather than resumable sessions.

The merge, in order

0. Back up the destination first. The migration merges into a live profile. Snapshot the files you'll touch — memory dir, history.jsonl, settings.local.json — so there's an undo button. Mine was 9 KB.

1. Diff memories before copying. I expected a messy reconciliation; diff -q showed five of seven old memory files were byte-identical to the new machine's (they'd been partially recreated). Only two were genuinely new — copied those, added their lines to the MEMORY.md index. The index and the files must stay in sync; the index is what gets loaded each session.

2. Copy project dirs; merge collisions. Most project dirs didn't exist on the new machine — straight copy. For the one that did, check transcript filename collisions first (session IDs are UUIDs, so genuine collisions are near-impossible — verify anyway with comm -12), then copy the .jsonl files in.

3. Merge prompt history. history.jsonl is line-per-entry JSON with timestamps: concatenate old-then-new, dedupe exact lines. 5,846 + 27 → 5,868.

4. Merge the permission allowlist — and audit it. Union the permissions.allow arrays. This is also the moment to read what you're granting: my old list of 295 rules contained four malformed entries (fragments of multi-line commands the permission system had mangled, like Bash(do echo:*)). Dropped them; merged the rest.

5. Per-project config (.claude.json). Merge project entries that don't exist on the new machine; keep current ones where they collide.

Sanitization: the part worth slowing down for

Three things I filtered, each a category you'll likely have too:

Personal content in the work dump. A personal side project's sessions were sitting in the work profile — one claude account, mixed use, the exact problem the dual-profile setup from Part 1 now prevents. Excluded it everywhere it appeared: project dir, history entries, file-history, config. Migration is the cheapest moment to draw that boundary; after the merge it becomes forensic work.

Stale secret-pointer memories. One migrated memory instructed the assistant to load DB credentials from a file path on the old machine. The memory contained no secrets itself, but migrated verbatim it becomes a standing instruction pointing at nothing — or worse, at whatever lands at that path later. Decide per-memory: re-establish the workflow or retire the memory. I retired it and left a tombstone note in the related project memory.

Cross-references. Memories link to each other ([[name]]). Deleting one leaves dangling links in others — grep for the deleted name and clean up.

Verifying it worked

Resume test: cd into a migrated repo → claude --resume → the old machine's sessions list (29 in my most-used repo). Two details make or break this: sessions are grouped by project directory, so the picker only shows sessions started where you're standing — that's exactly why the encoded-path matching from the survey step matters. (claude --continue skips the picker and reopens the most recent session in the current directory.)

Contamination test: grep the work profile for the excluded personal project — zero hits.

The stats panel as proof: the desktop app's Code tab rebuilt its usage stats from the migrated transcripts — 65 sessions, 16.5k messages, 17M tokens, and a "favourite model" I'd never used on the new machine. Unfakeable evidence it's reading the old data.

One expectation to set: the desktop app's session sidebar lists only sessions it started itself — migrated CLI sessions won't appear there, and that's by design, not a failed migration. The stats, the memory, and claude --resume are where the history lives.

The checklist

  • Copy ~/.claude from old machine (desktop profile optional — likely skip)
  • Survey: sizes, project dirs, memory files, what's personal
  • Back up destination files you'll touch
  • Diff memories; copy new ones; update MEMORY.md index
  • Copy/merge project dirs (collision-check the overlapping ones)
  • Merge history.jsonl (concat + dedupe)
  • Union permission allowlists — audit while you're in there
  • Merge .claude.json project entries
  • Exclude personal content end-to-end (projects, history, file-history, config)
  • Review secret-pointer memories: re-establish or retire
  • Fix dangling [[links]] from anything retired
  • Verify: resume test, contamination grep, stats panel
  • Delete the dump; keep the tiny destination backup for a week

Same environment as Part 1: macOS, Claude Desktop 1.26x, Claude Code 2.1.x. Part 1 covers running work and personal Claude side by side — the isolation that made keeping a personal project out of the work profile a one-line exclusion rather than an impossibility.