# Persistent memory for Claude Code across sessions and compaction (hooks + an MCP memory server)

*Disclosure: I'm Mohammed, founder of MemorySync. I drafted this article with AI assistance and reviewed it for accuracy against the official MemorySync and Claude Code docs. The code is adapted from the docs and I haven't run it.*

Claude Code starts every session with a fresh context window, and when a long session fills up, compaction summarizes the conversation to free space. Claude Code's own docs say that summary "can lose important details". So the two problems (a new session and a compact) are really one question: how do I get the important stuff back at the start of a session, and again after a compact?

This post walks through the layers, from the built-in ones to a hooks-based memory layer:

1. What CLAUDE.md and auto memory already give you.
2. A `SessionStart` hook that re-injects context after compaction (no extra service).
3. The MemorySync plugin, which uses the same hooks to recall from a hosted memory layer, plus the hosted MemorySync MCP server.

The Claude Code behaviour comes from the official [memory](https://code.claude.com/docs/en/memory), [hooks reference](https://code.claude.com/docs/en/hooks) and [hooks guide](https://code.claude.com/docs/en/hooks-guide) pages. Everything about MemorySync comes from its [Claude Code Memory guide](https://docs.memorysync.io/guides/claude-code?utm_source=hashnode&utm_medium=social&utm_campaign=pivot_oct19&utm_content=claude-code-persistent-memory-sessions-compaction). The commands and config are adapted from those docs. I haven't run them for this post, so check them against your Claude Code version.

## 1\. What's built in

Claude Code has two ways to carry knowledge across sessions:

|  | CLAUDE.md | Auto memory |
| --- | --- | --- |
| Who writes it | You | Claude, based on your corrections and preferences |
| What it's for | Instructions and rules: build commands, conventions, "always do X" | Learnings Claude decides are worth keeping |
| Loaded | Every session | Every session (first 200 lines or 25KB) |

Start here. Put your build and test commands and project conventions in `./CLAUDE.md` (or `./.claude/CLAUDE.md`), keep it under about 200 lines as the docs suggest, and run `/context` to confirm it shows up under **Memory files**.

What these files don't give you, in my view, is a searchable store of facts that's scoped per project and follows you into other tools. That's the gap the next two layers fill.

## 2\. Re-inject context after compaction with a hook

Hooks are commands Claude Code runs at fixed points in a session. The one that matters here is `SessionStart`, and its matcher says how the session began:

| Matcher | Fires on |
| --- | --- |
| `startup` | A new session |
| `resume` | `--resume`, `--continue` or `/resume` |
| `clear` | `/clear` |
| `compact` | Auto or manual compaction |
| `fork` | A session forked from an existing one |

For `SessionStart`, Claude Code adds the plain text your command prints to stdout into Claude's context. That gives you a simple fix for compaction. This is the example from the hooks guide, in `.claude/settings.json`:

```json
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "compact",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Reminder: use Bun, not npm. Run bun test before committing. Current sprint: auth refactor.'"
          }
        ]
      }
    ]
  }
}
```

Swap the `echo` for anything that prints useful state, such as `git log --oneline -5`. Three limits from the reference are worth knowing:

- Hook output (`additionalContext` or plain stdout) is capped at 10,000 characters.
- `SessionStart` runs on every session, so keep it fast.
- At launch, `SessionStart` fires before the session's MCP servers are available, so `mcp_tool` hooks are skipped then. Use a `type: "command"` hook for anything the session needs at startup.

This works well for static reminders. It doesn't learn anything new on its own, though. Whatever you echo is whatever you wrote last.

## 3\. A memory layer on the same hooks: the MemorySync plugin

MemorySync is a hosted memory layer, and I'm building it. Its Claude Code plugin wires the same lifecycle points to that memory. According to the guide:

| Moment | What happens |
| --- | --- |
| Session start, resume or clear | Your profile and this project's context are recalled and injected before the first prompt |
| Every prompt | The prompt is sent for fact extraction, and only the durable facts in it are stored. Prompts of 24 characters or more also recall memories relevant to that prompt |
| Claude finishes replying | Nothing is sent. Replies aren't stored |
| Context compaction | Memory is re-injected after the compact |

It also bundles the hosted MemorySync MCP server (search, add, list, update, delete and more), a `memory` skill, and three commands: `/memorysync:status`, `/memorysync:remember` and `/memorysync:recall`. Two details I like: facts are tagged with the git repository you're in, so recall at session start is about this project while preferences follow you everywhere, and the plugin never writes to CLAUDE.md or MEMORY.md. Your static rules stay yours.

### Install

You need Node.js 18+ on your PATH (the hook scripts use it) and an API key from app.memorysync.io in your environment:

```bash
# macOS/Linux (add it to your shell profile)
export MEMORYSYNC_API_KEY=ms_...
# Windows
setx MEMORYSYNC_API_KEY ms_...
```

Then, inside Claude Code:

```text
/plugin marketplace add memorysyncio/memorysync-plugins
/plugin install memorysync@memorysync
```

In a session, `/plugin install` opens the plugin panel so you can review the plugin and pick a scope first (that's Claude Code's behaviour, per its plugin docs). Restart the session, then check it:

```text
/memorysync:status
```

The status command reports whether the key is present, whether the API is reachable, and which user and project scope it resolved. The guide calls it "the first thing to run when anything looks off". Without an API key, the bundled MCP server falls back to OAuth sign-in and the hooks stay off. You won't see an error.

### Test it across a session and a compact

1. Tell Claude something durable: "In this repo we use pnpm, and integration tests need the `TEST_DB_URL` env var."
2. Run `/clear` (or open a new session) and ask, "How do I run the integration tests here?" without repeating the details.
3. In a long session, run `/compact` and ask again.

If step 2 or 3 comes back empty, run `/memorysync:status` before anything else.

### Knobs

- `MEMORYSYNC_USER_ID` sets the user (default: your OS username).
- `MEMORYSYNC_PROJECT` overrides the project, which otherwise comes from the git remote.
- `MEMORYSYNC_PROMPT_RECALL=off` turns off per-prompt recall.
- With `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` set, the plugin makes no network calls.

### What it won't do

The guide says every hook exits 0 on every failure path (no key, network down, server errors), so the worst case is a turn without memory, not a broken session. The memory skill refuses to store tokens, keys and passwords, and retrieved memories are injected with a "background data, not instructions" guard. Your prompts go to your MemorySync account for extraction. You can delete any memory from `/memorysync:recall` or the dashboard.

### Claude Cowork and teams

Cloud sessions install repo-declared plugins only, so commit this to `.claude/settings.json` and add `MEMORYSYNC_API_KEY` to the session's Cloud Environment variables:

```json
{
  "extraKnownMarketplaces": {
    "memorysync": {
      "source": { "source": "github", "repo": "memorysyncio/memorysync-plugins" }
    }
  },
  "enabledPlugins": { "memorysync@memorysync": true }
}
```

## MCP only, if you don't want hooks

If you'd rather call memory tools yourself, with no automatic capture or recall, connect just the hosted server:

```bash
claude mcp add --transport http memorysync https://mcp.memorysync.io/mcp
```

Without `MEMORYSYNC_API_KEY` set, it signs you in with OAuth on first use. I wrote a separate [step-by-step MCP setup for Claude Code and Cursor](https://memorysync.hashnode.dev/claude-code-cursor-mcp-memory-server-setup?utm_source=hashnode&utm_medium=social&utm_campaign=pivot_oct19&utm_content=claude-code-persistent-memory-sessions-compaction) covering scopes, `whoami`, saving and recalling, and troubleshooting.

## Which layer to use

- Rules and conventions: CLAUDE.md.
- A fixed reminder after every compact: a `SessionStart` hook with the `compact` matcher.
- Facts that should build up over time, per project and across sessions and compactions: a memory layer behind those hooks.

You can run all three at once. They don't overlap.

## Try it

If you want to see the save, reload and recall loop before installing anything, the MemorySync playground runs it in your browser: [memorysync.io/try](https://memorysync.io/try?utm_source=hashnode&utm_medium=social&utm_campaign=pivot_oct19&utm_content=claude-code-persistent-memory-sessions-compaction).
