Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

agent-memory-kit

Collapse per-project, per-machine agent memory into one baseline you can actually read.

Claude Code stores memory per project, keyed by absolute path (~/.claude/projects/-home-user-Projects-foo/memory/). Nothing is shared between projects, and nothing is shared between machines. Give the same instruction in five repos and you get five files that drift, duplicate, and eventually contradict, and a new project starts with none of them.

The cost is not storage. It is that a rule you wrote down months ago does not apply where you need it, so the same correction gets made again, and the same mistake gets repeated in the project where the rule happens not to live.

This kit harvests all of it, distills the cross-cutting rules into one user-level CLAUDE.md, and rolls that out everywhere.

Requirements

Bash, git, and Claude Code. Tested on macOS and Linux, across four machines.

What it does

  1. Harvest. harvest.sh copies this machine's memory into a timestamped directory. Read-only against ~/.claude. Run it on every machine.
  2. Consolidate. prompts/01-consolidate.md inventories every rule, groups them by what they mean rather than what they are called, and classifies each group as promote, tier-2, keep-local, split or drop. Contradictions are listed as questions for you rather than resolved. It works one machine at a time, appending to the audit as it goes, so an interrupted run resumes instead of restarting.
  3. Draft. prompts/02-draft-baseline.md turns that audit, plus your answers to its questions, into templates/CLAUDE.md, templates/rules/*.md, a tier-3 skeleton at templates/CLAUDE.project.md, and PRUNE.md, the delete list. Every row in the delete list cites a backup path, and the path is checked to exist before the row is written.
  4. Roll out. prompts/03-rollout.md copies the baseline into your dotfiles and symlinks it into ~/.claude. prune-move.sh then moves the superseded per-project files out, and the per-project indexes get reconciled to what the script actually did, taking the filesystem as the source of truth rather than the script's output.

Nothing in steps 2 to 4 deletes anything on its own. The prompts write files and stop. You review and execute.

The tiers

tier file scope tracked in
1 ~/.claude/CLAUDE.md universal, every project every machine dotfiles
2 ~/.claude/rules/<stack>.md per-stack, imported by a project that needs it dotfiles
3 <project>/CLAUDE.md one repo's build/architecture/conventions that project
4 ~/.claude/projects/*/memory/ auto-memory; project facts only, never rules nowhere

Tier 1 loads in full in every session, so it is budgeted by attention rather than by bytes. A dozen rules all marked "always" means none of them is rule 1. The cap and the tier-1/tier-2 split are specified in prompts/02-draft-baseline.md.

@import inlines at session start with no lazy loading, so stack-specific files must be imported from a project's own CLAUDE.md, never from tier 1, or every project pays for every stack.

Tier 4 is where everything ends up by default, which is the problem. The point of the kit is to keep tier 4 holding only project facts, this codebase's quirks, and to move every behavioural rule up to tier 1 or 2 where it applies everywhere.

Usage

1. Harvest, on every machine

git clone <this-repo> && cd agent-memory-kit
./harvest.sh

Each run writes a new harvest/<hostname>_<YYYY-MM-DD>_<HHMMSS>/, so merge conflicts are impossible by construction. No branch per machine, no manual merge. The script creates and never deletes: re-running adds a harvest rather than replacing one, so earlier dumps and any notes filed alongside them survive. It refuses to run if the target directory already exists. Consolidation uses the newest harvest per hostname. If two machines answer the same hostname -s, set HOST_LABEL on one of them.

To move harvests between machines, keep them in a private repo. They quote your work verbatim. The .gitignore here excludes harvest/, pruned/, audits/ and PRUNE*.md for that reason, and those rules are in the first commit so a stray harvest.sh run cannot put your memory into a public one.

2. Consolidate, once, on one machine

Feed prompts/01-consolidate.md to Claude with the repo as cwd. Answer its questions, then run prompts/02-draft-baseline.md.

3. Roll out, on every machine

Follow prompts/03-rollout.md. Install first:

mkdir -p ~/.dotfiles/claude
cp    templates/CLAUDE.md ~/.dotfiles/claude/CLAUDE.md
cp -r templates/rules     ~/.dotfiles/claude/rules

then link it into place on each machine:

ln -sfn ~/.dotfiles/claude/CLAUDE.md ~/.claude/CLAUDE.md
ln -sfn ~/.dotfiles/claude/rules     ~/.claude/rules

which leaves this layout:

~/.dotfiles/claude/          tracked, same on every machine
├── CLAUDE.md                tier 1
└── rules/                   tier 2
    ├── python-uv.md
    └── research-outputs.md

~/.claude/
├── CLAUDE.md        -> ~/.dotfiles/claude/CLAUDE.md
├── rules            -> ~/.dotfiles/claude/rules
├── settings.json                    a tracked copy, never a symlink
└── projects/*/memory/               tier 4, untracked

CLAUDE.md and rules/ are read-only to Claude Code, so symlinks are safe and a git pull updates every project on that machine at once.

Then prune:

./prune-move.sh            # dry run, shows every move
./prune-move.sh --apply    # performs them

prune-move.sh reads PRUNE.md, takes only the section matching this machine, and for each entry copies the file into pruned/, verifies the copy is byte-identical, and only then removes the original. It refuses to overwrite anything already in pruned/, skips SPLIT entries entirely, and is a dry run unless you pass --apply.

Re-running later

The kit is re-runnable. Add a machine, or come back in six months after tier 4 has refilled: ./harvest.sh on each machine, then 01-consolidate.md again. It audits against the baseline you already have and reports only what is new or diverged.

What is in templates/

A redacted example of real output, from running this across four machines, with names removed. It is there so you can see what the method produces before you run it: nine rules, each stating what to do, the evidence it came from, and how to apply it. Running the kit overwrites these with your own.

Notes

  • harvest.sh is read-only against ~/.claude. The one thing it touches outside it is listing $HOME/Projects and $HOME/Projects/*-workspace to map slugs back to project paths. Two listings, no recursion, no searching.
  • A slug is the absolute path with /, . and _ flattened to -, which cannot be decoded back. It never needs to be: the script lists the project directories, computes each one's slug forwards, and looks the answer up. So dots and underscores need no special cases, and a slug with no match means that directory is genuinely gone rather than unrecognised.
  • A project checked out at different paths on different machines produces different slugs and therefore separate, independently drifting memory. The audit catches this; MANIFEST.md records the real path behind each slug.
  • Never symlink settings.json. Claude Code writes it, and write-by-atomic-rename replaces a symlink with a real file, silently detaching it from the repo. Keep it a tracked copy and diff it by hand.

Licence

MIT.

About

Harvest, consolidate and roll out Claude Code memory across projects and machines.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages