{"id":50885099,"url":"https://github.com/mcs-cli/shared-memories","last_synced_at":"2026-06-15T16:30:59.010Z","repository":{"id":353648750,"uuid":"1216907530","full_name":"mcs-cli/shared-memories","owner":"mcs-cli","description":"Team-shared Claude Code memories via a dedicated git repo","archived":false,"fork":false,"pushed_at":"2026-04-24T20:52:05.000Z","size":22,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-24T21:36:12.252Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mcs-cli.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-21T10:56:25.000Z","updated_at":"2026-04-24T20:52:10.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mcs-cli/shared-memories","commit_stats":null,"previous_names":["mcs-cli/shared-memories"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/mcs-cli/shared-memories","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcs-cli%2Fshared-memories","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcs-cli%2Fshared-memories/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcs-cli%2Fshared-memories/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcs-cli%2Fshared-memories/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mcs-cli","download_url":"https://codeload.github.com/mcs-cli/shared-memories/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcs-cli%2Fshared-memories/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34372116,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-15T02:00:07.085Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-15T16:30:58.248Z","updated_at":"2026-06-15T16:30:59.003Z","avatar_url":"https://github.com/mcs-cli.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Shared Memories\n\nA [tech pack](https://github.com/mcs-cli/mcs) that auto-syncs Claude Code's `.claude/memories/` across a team via a dedicated shared git repo. Captures are handled by [`mcs-cli/memory`](https://github.com/mcs-cli/memory) (the `continuous-learning` skill + semantic retrieval); this pack **shares** those captures across the team without anyone remembering to commit or push.\n\nBuilt for the [`mcs`](https://github.com/mcs-cli/mcs) configuration engine.\n\n```\nidentifier: shared-memories\nrequires:   mcs \u003e= 2026.4.12\n```\n\n---\n\n## When Is This Useful?\n\n**You probably don't need this pack if** your team commits `.claude/memories/` directly into the project repo — normal git workflow already shares those memories across the team and this pack adds nothing.\n\n**This pack is useful when**:\n\n- You want memories in a **dedicated repo**, separate from project code — to avoid noising project PRs with memory-only diffs, to apply different access or review rules, or because the project's default-branch rulesets make small auto-commits painful.\n- You run **multiple related repos** (microservices, mobile + web + backend, split client/server) that should share the **same memory corpus** — a learning about the auth contract is relevant to every service that talks to it, and a central memories repo lets all of them read/write the same KB.\n- You want team memories to **outlive individual project repos** — short-lived prototypes, archived services, or repos that come and go shouldn't take institutional knowledge with them.\n\n---\n\n## The Problem\n\nClaude Code's `.claude/memories/` is great — you accumulate `learning_*.md` and `decision_*.md` files and Claude gets smarter about your codebase over time. But memories are **per-engineer**: when someone figures out a gnarly integration quirk or pins down a subtle architecture decision, only they benefit.\n\nThe obvious fix is a shared git repo. Two friction points kill adoption:\n\n1. **Remembering to push.** People forget. Memories sit on laptops for weeks.\n2. **Branch protection on the shared repo.** If every Claude turn needs a PR + ticket + approval, nobody will bother pushing their tiny observations.\n\n## The Solution\n\nThis pack implements a **closed-loop sharing system** that pulls the latest team memories at session start and pushes new ones when Claude finishes a turn.\n\n```\n                             SHARED MEMORIES LOOP\n\n ┌──────────────┐     ┌──────────────┐     ┌──────────────┐     ┌──────────────┐\n │   SESSION    │     │   TEAM KB    │     │     WORK     │     │     STOP     │\n │    START     │────\u003e│    PULL      │────\u003e│   SESSION    │────\u003e│  AUTO-PUSH   │\n └──────────────┘     └──────────────┘     └──────────────┘     └──────────────┘\n        ^                    |                    |                     |\n        |                    |                    |     filename guard  |\n        |                    |                    |     + configurable  |\n        |                    v                    v     push policy     v\n        |             ┌────────────────────────────────────────────────────┐\n        |             │              \u003cshared memories repo\u003e                 │\n        |             │  memories/                                          │\n        |             │    learning_background_task_watchdog_timeout.md     │\n        +─────────────│    learning_orm_batch_insert_memory_spike.md        │\n                      │    decision_architecture_mvvm_coordinators.md       │\n                      │    ...                                              │\n                      └────────────────────────────────────────────────────┘\n```\n\nCaptures still come from [`mcs-cli/memory`](https://github.com/mcs-cli/memory). This pack is the distribution layer that makes them team-shared.\n\n---\n\n## How It Works\n\n### The Five Pieces\n\n| Piece | What | How |\n|-------|------|-----|\n| **SessionStart Hook** | Pulls the latest team memories at session start | `git pull --ff-only` against the shared checkout; also flags lingering uncommitted/unpushed state — a stuck auto-push in `auto` / `full` mode, or pending changes awaiting decision in `review` mode |\n| **Stop Hook** | Handles new/modified memory files after each Claude turn per `MEMORIES_AUTOPUSH_MODE` (`auto` / `full` / `review`) | Runs async; filename guardrail blocks bad names in every mode; mode dictates whether deletions auto-push, whether anything is committed at all, and (in `review`) prints the per-turn pending-changes report |\n| **PostToolUse Hook** | Tells Claude in-conversation that a memory was saved in `review` mode, so it can mention pending review and invoke `/approve-memories` when the user confirms | Fires sync after `Write` / `Edit` / `MultiEdit` to `.claude/memories/`; injects `additionalContext` into Claude's next decision step. Silent in `auto` and `full` |\n| **/approve-memories Slash Command** | One shared approval surface both the user and Claude invoke identically — stages, commits, pulls `--rebase`, pushes everything pending under `memories/` | Re-runs the Stop-hook filename guardrail; takes an optional commit-message reason; works in every mode (primary use is `review`; also unblocks state stuck after a push failure in `auto` / `full`) |\n| **Sparse Checkout + Symlink** | Keeps the shared repo invisible on disk | `.claude/.memories-repo/` is a blobless single-branch sparse clone; `.claude/memories` is a symlink Claude Code reads from |\n\n### The Feedback Loop\n\n1. **First `mcs sync`** — the configure script clones the shared repo sparsely into `.claude/.memories-repo/`, symlinks `.claude/memories` to it, and migrates any pre-existing local memories into the shared folder (conflicts are preserved for manual review)\n\n2. **Session starts** — the SessionStart hook fast-forwards the shared checkout and warns about any lingering state (auth failure / rebase conflict / guardrail-rejected files in `auto` / `full`; pending review items in `review`)\n\n3. **During work** — Claude uses the [`continuous-learning`](https://github.com/mcs-cli/memory) skill to write new `learning_*.md` / `decision_*.md` files\n\n4. **Claude finishes a turn** — the Stop hook collects dirty files and dispatches by mode (`MEMORIES_AUTOPUSH_MODE`, see [Auto-Push Modes](#auto-push-modes)):\n   - **Naming guardrail (all modes)** — any file failing `^memories/(learning|decision)_[a-zA-Z0-9_-]+\\.md$` halts everything until renamed\n   - **`auto` (default)** — adds/mods auto-pushed; deletions parked in the working tree for manual review\n   - **`full`** — adds/mods AND deletions auto-pushed in one commit\n   - **`review`** — nothing auto; the hook prints a per-file report and the user (or Claude, via the PostToolUse nudge) invokes `/approve-memories` to push, or runs the discard commands shown in the report\n\n5. **Next session** — teammates pull your new memories via SessionStart and the loop continues\n\n---\n\n## What's Included\n\n### Session Hooks\n\n| Hook | Event | What It Does |\n|------|-------|-------------|\n| **memories_pull.sh** | `SessionStart` | Fast-forwards the shared memories checkout; emits a mode-aware warning if previous state is stuck (or, in `review` mode, summarises pending review) |\n| **memories_autopush.sh** | `Stop` (async) | Dispatches by `MEMORIES_AUTOPUSH_MODE` mode (`auto` / `full` / `review`); filename guardrail applies in every mode |\n| **memories_announce.sh** | `PostToolUse` (Write/Edit/MultiEdit) | In `review` mode only, surfaces the just-written memory to Claude's context so it mentions pending review in chat. Silent in `auto` and `full` |\n\n### Slash Commands\n\n| Command | What It Does |\n|---------|-------------|\n| **/approve-memories** | Stages, commits, pulls `--rebase`, and pushes everything pending under `memories/`. Primary entry point for `review` mode approval; also unblocks state stuck after a push failure in `auto` / `full` |\n\n### Configuration Script\n\n| Script | When | What It Does |\n|--------|------|-------------|\n| **configure-memories.sh** | `mcs sync` | Sparse-clones the shared repo, sets up the symlink, migrates any pre-existing `.claude/memories/` into the shared folder |\n\n### Doctor Checks\n\n| Check | What It Verifies |\n|-------|-----------------|\n| **Shared memories setup** | Sparse checkout exists and the symlink resolves to a live git repo (auto-fixable via `mcs sync`) |\n| **Shared memories remote access** | Auth + network reachability via `git ls-remote origin`; warns (doesn't fail) on issues since local reads still work |\n\n### Dependencies\n\n| Dep | Via |\n|-----|-----|\n| **jq** | brew |\n\n---\n\n## Installation\n\n### Prerequisites\n\n- macOS\n- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) CLI\n- [mcs](https://github.com/mcs-cli/mcs) CLI\n- [`mcs-cli/memory`](https://github.com/mcs-cli/memory) (companion capture pack — produces the `learning_*.md` / `decision_*.md` files this pack shares)\n- A git repo the team can push to (SSH or HTTPS access)\n\n### Setup\n\n```bash\n# 1. Install mcs\nbrew install mcs-cli/tap/mcs\n\n# 2. Register both packs (capture + share)\nmcs pack add mcs-cli/memory\nmcs pack add mcs-cli/shared-memories\n\n# 3. Sync your project\ncd ~/Developer/my-project\nmcs sync\n\n# 4. Verify everything is healthy\nmcs doctor\n```\n\nDuring `mcs sync`, you'll be prompted for:\n\n| Prompt | What It Does | Default |\n|--------|-------------|---------|\n| **MEMORIES_REPO_URL** | Clone URL for the shared memories repo, e.g. `git@github.com:org/memories.git` | *(required)* |\n| **MEMORIES_BRANCH** | Branch that holds the memory files and this pack | `main` |\n| **MEMORIES_AUTOPUSH_MODE** | Stop-hook behavior — `auto` (writes auto-pushed, deletions parked), `full` (writes + deletions auto-pushed), or `review` (nothing auto, per-turn report). See [Auto-Push Modes](#auto-push-modes). | `auto` |\n\n\u003e **Install per-project, not globally.** Run `mcs sync` from each project's root (the directory that contains `.claude/`, not `.claude/` itself) — do **not** install this pack into your user-level `~/.claude/` directory.\n\u003e\n\u003e The hooks anchor on their own on-disk location and operate on a sibling `.memories-repo/` working tree. A single global install would collapse every project onto one shared checkout, which breaks two things:\n\u003e\n\u003e 1. **Concurrent sessions race on the same working tree.** If you run Claude in two projects at the same time, both Stop hooks try to stage, commit, rebase, and push against the same `.git` index — you'll see interleaved commits, half-applied rebases, and dedupe state (`review` mode's `.review-shown`) stomped between sessions.\n\u003e 2. **Project context bleeds across sessions.** Memories Claude writes while working on project A would be auto-pushed under project B's session if B happens to end its turn first.\n\u003e\n\u003e Per-project installs keep one independent clone per repo while still sharing the same remote, so the team-wide KB stays unified without the local race conditions.\n\n---\n\n## Directory Structure\n\n```\nshared-memories/\n├── techpack.yaml                    # Manifest — defines all components\n├── commands/\n│   └── approve-memories.md          # Slash command for review-mode approval\n├── config/\n│   └── settings.json                # Templated env block — ships MEMORIES_AUTOPUSH_MODE\n├── hooks/\n│   ├── memories_pull.sh             # SessionStart: pull + stuck-state warning\n│   ├── memories_autopush.sh         # Stop: auto-commit + push (async)\n│   └── memories_announce.sh         # PostToolUse: review-mode nudge to Claude (sync)\n└── scripts/\n    ├── configure-memories.sh        # Sparse clone + symlink + migration\n    ├── doctor-memories.sh           # Setup health check\n    └── doctor-memories-remote.sh    # Remote-access health check\n```\n\nOn engineer disks, the pack materializes as:\n\n```\n\u003cproject\u003e/.claude/\n├── .memories-repo/                  # sparse clone of MEMORIES_BRANCH\n│   ├── README.md, LICENSE, etc.     # any root-level files your repo ships\n│   └── memories/\n│       ├── learning_*.md\n│       └── decision_*.md\n└── memories -\u003e .memories-repo/memories   # symlink Claude Code reads\n```\n\nThe clone uses `--sparse --filter=blob:none --single-branch` so only the `memories/` subtree plus any root-level files your repo ships (README, LICENSE) materialize on disk (~1 MB typical). Every hook git call is scoped with `-- memories/` pathspec, so root-level files are visible but never touched by the auto-commit/auto-push machinery — your teammates can edit the memories repo's README without tripping the guardrail.\n\n---\n\n## Migration From an Existing Local Memories Folder\n\nEngineers who already have `.claude/memories/` populated (from `mcs-cli/memory`, Claude Code's native memory, or manual use) are handled automatically on first `mcs sync`:\n\n1. The existing directory is moved aside to `.claude/.memories-migration-\u003ctimestamp\u003e/`\n2. The sparse clone + symlink are set up as normal\n3. Files from the backup are imported into the new shared folder, **with the shared version winning on any filename conflict** (your local copy stays in the backup dir for manual review)\n4. Well-named migrated files are auto-committed and pushed so they immediately become team knowledge\n5. If no conflicts remain, the backup dir is cleaned up automatically\n\nIf any step fails partway, an `ERR` trap restores the original folder from the backup — you're never left with a broken setup and no memories.\n\n---\n\n## Optional: Push to a Side Branch\n\nIf your org enforces PR + ticket + approval on the default branch of your memories repo, every Claude Stop auto-pushing to it would turn each memory into a PR. That kills adoption.\n\n**Workaround**: set `MEMORIES_BRANCH` to a side branch (e.g., `memories`) that no ruleset targets. Auto-push goes there; the default branch stays untouched and ruleset-compliant.\n\n### Protect the Side Branch at the Repo Level\n\nFree-push doesn't mean unprotected. Apply a repo-level ruleset to your side branch:\n\n| Rule | What it blocks | Why |\n|---|---|---|\n| `non_fast_forward` | `git push --force` | Prevents history rewrite that could erase content between reflog expiries |\n| `deletion` | `git push origin :\u003cbranch\u003e` | Prevents catastrophic branch wipeout |\n\nNormal commits (including ones that delete files via `memory-audit`) are unaffected, so the audit + manual-push flow still works.\n\n---\n\n## Auto-Push Modes\n\nThe Stop hook's behavior is set during `mcs sync` via the `MEMORIES_AUTOPUSH_MODE` prompt. The chosen value is written to `.claude/settings.local.json`'s `env` block (per-user / project-local). To change modes later, re-run `mcs sync` and pick a different value, or edit `.claude/settings.local.json` directly.\n\n| Mode | Adds / Modifications | Deletions | When to use |\n|------|----------------------|-----------|-------------|\n| `auto` *(default)* | auto-pushed | parked for manual review | Safe default for most teams. The asymmetric trust matches how memories are typically created vs. removed. |\n| `full` | auto-pushed | auto-pushed | You trust your workflow — `memory-audit` runs are deliberate, no fat-finger risk. Skips the Intentional Deletion Workflow below. |\n| `review` | not pushed | not pushed | You want to inspect every change before it propagates to the team. The hook prints a per-file report each turn end. |\n\nUnset, empty, and unrecognized values fall through to `auto` (with a one-line warning for unrecognized values), so existing installs see zero behavior change.\n\nIn `review` mode, the hook prints a report on each turn end:\n\n```\nShared memories [review mode]: \u003cN\u003e pending file(s) in memories/ and \u003cM\u003e unpushed commit(s)\n+ NEW  \u003cfile:///…/memories/learning_foo.md\u003e\n       \"\u003cfirst non-empty line preview\u003e\"\n~ MOD  \u003cfile:///…/memories/decision_bar.md\u003e  (+3 -1)\n       Diff: git -C .claude/.memories-repo diff -- memories/decision_bar.md\n- DEL  memories/learning_old.md  (last modified 3 weeks ago)\n       Recover: git -C .claude/.memories-repo checkout HEAD -- memories/learning_old.md\n\nApprove all:           /approve-memories  [optional commit reason]\nDiscard local changes: …\n```\n\n`/approve-memories` (shipped by this pack) stages everything under `memories/`, commits as `review: \u003creason\u003e` (default: `approved memories from \u003chost\u003e \u003cdate\u003e`), pulls `--rebase --autostash`, and pushes. It re-runs the Stop-hook filename guardrail, so a stray `wip.md` blocks the push. Both you and Claude invoke the same command — no copy-paste of multi-line git incantations. Also unblocks `auto` / `full` state stuck from a previous push failure.\n\nThe same pending set is reported once per session — repeated turns within the session stay silent so the report doesn't spam every prompt. SessionStart resets the dedupe so unresolved changes re-surface in the next session instead of being buried forever.\n\nIn `review` mode, Claude is also told about each memory write through a separate PostToolUse hook (`memories_announce.sh`), so it can proactively mention pending review in the same turn and invoke `/approve-memories` when you confirm — without needing to wait for the terminal report. The terminal report and the in-conversation nudge are independent channels: the report goes to your terminal, the nudge goes to Claude's context. `auto` and `full` modes keep both channels silent.\n\nPull is always automatic regardless of mode — incoming team memories arrive at session start.\n\n---\n\n## Intentional Deletion Workflow\n\nWhen you legitimately want to remove stale memories (typically after running the `memory-audit` skill from `mcs-cli/memory`), invoke the slash command:\n\n```\n/approve-memories audit cleanup\n```\n\nThat stages the deletions, commits as `review: audit cleanup`, pulls `--rebase`, and pushes — same recipe the slash command uses for any other approval, with the filename guardrail re-applied.\n\nThe deletion block in `auto` mode is deliberate friction: audit is rare enough (monthly-ish) that requiring explicit human confirmation is cheap insurance against catastrophic local-delete-then-auto-push accidents. The slash command is that confirmation step in one keystroke.\n\nIf your workflow makes the friction unnecessary, set `MEMORIES_AUTOPUSH_MODE=full` to skip the manual step entirely — `memory-audit`'s deletions will then auto-push alongside any other writes.\n\n---\n\n## Troubleshooting\n\n```bash\nmcs pack validate .                                  # verify techpack.yaml + file refs\nmcs doctor                                           # after sync: verify setup + remote access\ngit -C .claude/.memories-repo/memories log -1        # confirm auto-push landed\n```\n\n**If the Stop hook silently refuses to push**, the naming guardrail is likely rejecting a file. Run:\n\n```bash\ngit -C .claude/.memories-repo/memories status              # dirty files\ngit -C .claude/.memories-repo/memories ls-files --others   # untracked files\n```\n\nAnything not matching `memories/(learning|decision)_*.md` needs renaming.\n\n**If SessionStart warns about lingering state**:\n- In `auto` / `full` mode the previous push hit an auth/network issue (fix and wait for the next Stop, or run `/approve-memories` to retry immediately), or guardrail-rejected files are sitting dirty (rename them). `mcs doctor` will tell you which.\n- In `review` mode the warning is expected — it lists pending changes awaiting your decision. End a turn to see the per-file report, then `/approve-memories` to push.\n\n---\n\n## Links\n\n- [MCS](https://github.com/mcs-cli/mcs) — the configuration engine\n- [Creating Tech Packs](https://github.com/mcs-cli/mcs/blob/main/docs/creating-tech-packs.md) — guide for building your own\n- [Tech Pack Schema](https://github.com/mcs-cli/mcs/blob/main/docs/techpack-schema.md) — full YAML reference\n- [Claude Code hooks](https://docs.anthropic.com/en/docs/claude-code/hooks)\n- [Git sparse-checkout](https://git-scm.com/docs/git-sparse-checkout)\n- [Git partial clone](https://git-scm.com/docs/partial-clone)\n\n---\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmcs-cli%2Fshared-memories","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmcs-cli%2Fshared-memories","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmcs-cli%2Fshared-memories/lists"}