I created a system to manage Claude Code's memory with git, enabling cross-device and cross-project sharing

I created a system to manage Claude Code's memory with git, enabling cross-device and cross-project sharing

Claude Code's memory system can be treated as simple Markdown files and managed in a GitHub repository to enable cross-device and cross-project sharing. This article explains a mechanism that fundamentally solves the "I'm teaching the same thing again..." problem through a two-layer Global/Project structure and promotion rules.
2026.03.23

This page has been translated by machine translation. View original

Introduction

Claude Code has a memory system that can retain information across sessions. This is a mechanism that saves feedback like "use pnpm in this project" or "don't add Co-Authored-By to commits" as Markdown files, and automatically references them in subsequent sessions.

However, this memory is isolated per project. This leads to issues such as repeatedly teaching the same corrections across multiple projects, or starting with zero memory when working on a different machine.

To address this, I created a system to manage global memory in a GitHub repository, enabling sharing across devices and projects.

Prerequisites/Environment

  • Claude Code (VS Code extension or CLI)
  • GitHub CLI (gh) installed and authenticated
  • macOS (should work similarly on Linux)

Basics of Claude Code's Memory System

First, let's understand how Claude Code's memory works.

Memory Storage Location

Project-specific memories are stored at:

~/.claude/projects/<project-path-hash>/memory/
├── MEMORY.md          # Index (always loaded into context)
├── feedback_foo.md    # Individual memory files
├── user_bar.md
└── fixes_baz.md

Memory Loading Mechanism

  • MEMORY.md (index) is always loaded at the start of a session
  • Individual memory files are read on-demand by Claude as needed, based on the description in the index
  • This means not everything is loaded at once, but rather through a semi-selective mechanism

Types of Memory

Type Purpose Example
user User role/preferences "Senior engineer, React beginner"
feedback Correction instructions for Claude "Don't add Co-Authored-By to commits"
project Project-specific context "Merge freeze starting 3/5"
reference Pointers to external resources "Bugs managed in LINEAR's INGEST project"
fixes Error patterns and solutions "ESLint 9 requires flat config"

Challenge: Memory is Project-Confined

In practical use, I noticed these issues:

  • Teaching the same feedback repeatedly — After teaching "don't add Co-Authored-By to commits" in Project A, having to teach it again in Project B
  • Cannot share across devices — Memory accumulated on Machine A doesn't exist on Machine B
  • Cannot reuse fix patterns — The lesson "next lint is deprecated in Next.js 16" learned in Project A isn't applied in Project B

Solution: 2-Tier Memory + Git Sync

I solved this with the following design.

Architecture

2-Tier Memory Structure

Tier Storage Location Content Example
Global ~/.claude/global-memory/ User-common settings/feedback "No Co-Authored-By", "Web search before package changes"
Project .claude/projects/*/memory/ Project-specific pitfalls "backend/data/ is gitignore target"

Promotion Rules

One-way only: Project → Global

  • Discover new pitfall in Project A → Save to Project A's memory
  • Same pitfall occurs in Project B → Promotion signal. Move to Global, remove from both projects
  • Global memory becomes outdated (framework updates, etc.) → Remove from Global

We don't do the reverse (Global → Project copying) to avoid drift from duplicate management.

Setup Process

1. Create a private GitHub repository

gh repo create claude-memory --private --description "Cross-project Claude Code memory system"

2. Clone locally

# Using gh CLI avoids needing SSH keys (works immediately if gh is authenticated)
gh repo clone <your-username>/claude-memory ~/.claude/global-memory

3. Create global memory files

First, create MEMORY.md (index):

~/.claude/global-memory/MEMORY.md
## Feedback
- [feedback_no_coauthor.md](feedback_no_coauthor.md) — No Co-Authored-By in commits unless asked
- [feedback_save_error_learnings.md](feedback_save_error_learnings.md) — Save error fixes to memory proactively
- [feedback_websearch_packages.md](feedback_websearch_packages.md) — Always web search before updating package configs

Each memory file is Markdown with frontmatter:

~/.claude/global-memory/feedback_no_coauthor.md
---
name: no-co-authored-by
description: Do not add Co-Authored-By trailer to commit messages unless explicitly asked
type: feedback
---

Do not add `Co-Authored-By: Claude ...` to commit messages.
The user finds it unnecessary. Only add it if explicitly requested.

4. Add global memory loading instructions to ~/.claude/CLAUDE.md

~/.claude/CLAUDE.md is a global configuration file that Claude Code reads for all projects. Add global memory reference instructions here:

~/.claude/CLAUDE.md
# Global Memory

Cross-project memories are stored in `~/.claude/global-memory/`.
This directory is a git repo synced to GitHub for cross-device access.

At the start of relevant tasks, read `~/.claude/global-memory/MEMORY.md`
for the index, then load specific memory files as needed.

## Memory tiers
- **Global** (`~/.claude/global-memory/`): User preferences, universal feedback,
  cross-project fixes (promoted after hitting 2+ projects)
- **Project** (`.claude/projects/*/memory/`): Project-specific pitfalls,
  references, goals

Promotion is one-directional: project → global only.
Never copy global memories down to project scope.

## Syncing global memory
Always use HTTPS via `gh` for this private repo (gh is always authenticated).
- Clone: `gh repo clone <your-username>/claude-memory ~/.claude/global-memory`
- Pull: `cd ~/.claude/global-memory && git pull --rebase -q`
- Push: `cd ~/.claude/global-memory && git add -A && git commit -m "update" && git push`
- Only push when the user asks to sync, or when new global memories are added

5. Initial commit & push

cd ~/.claude/global-memory
git add -A
git commit -m "init: global memory with feedback preferences"
git push -u origin main

6. Remove promoted files from project memory

Remove memory files that have been moved to Global from project scope, and update the MEMORY.md index accordingly.

Setup on a new machine

On a new machine, just one command is needed:

gh repo clone <your-username>/claude-memory ~/.claude/global-memory

You'll also need ~/.claude/CLAUDE.md, but a template is included in the README of your global memory repository, so you can copy from there or have Claude regenerate it.

Sync operations

I don't have a strict automatic sync. Sync timing is expected as follows:

  • Pull: When starting work on a new device
  • Push: When Claude adds a new entry to global memory

Just tell Claude "sync memory" and it will execute pull/push.

Key Design Decisions

Why not copy global memory to all projects?

Duplicate management leads to drift. Having it exist only once in Global, with Claude referring to it, is simpler.

Why are the descriptions in the index (MEMORY.md) important?

Claude Code decides "should I read this memory file?" based on the descriptions in MEMORY.md. Vague descriptions can cause unnecessary memory loading, wasting context space.

  • Bad: fixes.md — Various fixes
  • Good: fixes_nextjs16_eslint.md — Next.js 16 + ESLint 9 migration pitfalls

Why not elevate project-specific fixes to Global?

A fix like "next lint is deprecated in Next.js 16" is only relevant to projects using Next.js 16. If placed in Global, it would appear in the index for every project, even Python-only projects.

The rule to promote only after encountering the same issue in 2+ projects serves as an appropriate filter.

Conclusion

  • Claude Code's memory system is just Markdown files, so managing with Git is a natural choice
  • 2-tier structure (Global + Project) separates common settings from specific pitfalls
  • Promotion rules (Project → Global, after appearing in 2+ projects) prevent Global bloat
  • Using the gh CLI enables one-command setup on new machines without SSH keys
  • Hard automatic synchronization is unnecessary. Manual operation works simply

If you're using Claude Code across multiple projects and devices and find yourself repeatedly teaching the same things, give this approach a try.

Share this article

FacebookHatena blogX