Codex-style persistent memory for Cursor — user-global, local-only, powered by hooks.
Extracts learnings from agent transcripts with GPT-5.6 Luna, consolidates via git workspace diff, injects compact summary at every session start.
See docs/codex-memory-reference.md for full Codex architecture reference.
sessionStart → inject memory_summary.md into agent context
stop/sessionEnd → cadence + generation + transcript-mtime gates
→ spawn Luna extract (sandbox) on changed transcript
→ write raw/stage1/<session>.json + rollout_summaries/
→ sync raw_memories.md + git diff
stage1 ≥ 3 → spawn sandboxed consolidate agent on phase2_workspace_diff.md
→ update MEMORY.md + memory_summary.md → git baseline commit
| Layer | Role |
|---|---|
| Read path | sessionStart hook injects memory_summary.md |
| Extract (Phase 1) | Luna (gpt-5.6-luna-high) reads full transcript — explicit + implicit learnings |
| Consolidate (Phase 2) | Sandboxed agent merges via git workspace diff |
| Skills | memory-read, memory-extract, memory-consolidate |
Inspired by the memory system in openai/codex.
- Cursor with hooks enabled
- Node.js ≥ 18 (hooks run via
node) cursorCLI on PATH (cursor agent …for background extract/consolidate)giton PATH (workspace diff baseline)
git clone <this-repo> ~/code/cursor-memory # or your path
cd ~/code/cursor-memory
chmod +x install.sh uninstall.sh
./install.shInstall copies into ~/.cursor/:
| Source | Destination |
|---|---|
src/hooks/* |
~/.cursor/hooks/ |
skills/* |
~/.cursor/skills/ |
templates/memory/* |
~/.cursor/memory/ (only if missing) |
| hook entries | merged into ~/.cursor/hooks.json |
Existing hooks.json entries (e.g. caveman) are preserved — memory hooks are appended.
Re-running ./install.sh is safe: hooks and skills are refreshed; MEMORY.md and other memory data are never overwritten.
While editing this repo, symlink instead of copy:
./install.sh --linkUpdates to src/hooks/ and skills/ take effect immediately.
./uninstall.sh # remove hooks + skills; keep memory data
./uninstall.sh --purge-data # also delete ~/.cursor/memory/After install, data lives under ~/.cursor/memory/ (user-global, not per-project):
~/.cursor/memory/
├── memory_summary.md # line 1 must be "v1" — injected every session
├── MEMORY.md # searchable registry
├── raw_memories.md # merged stage-1 outputs (Phase 2 input)
├── phase2_workspace_diff.md # git diff for consolidate (ephemeral)
├── .git/ # single-commit baseline for diffs
├── raw/
│ ├── stage1/<session>.json # Luna extraction output
│ └── processed/ # archive after consolidation
├── rollout_summaries/ # per-rollout distilled evidence
└── state/
├── capture.log
├── extract.log
├── consolidate.log
├── transcript-index.json
├── consolidate.lock
└── last-capture.json
Skills installed to ~/.cursor/skills/memory-read/, memory-extract/, memory-consolidate/, memory-feedback/.
Phase 1 (Luna) reads the full transcript and extracts:
- Explicit prefs — "always…", "never…", corrections
- Implicit learnings — repeated steering, failure shields, repo orientation, tooling quirks
- Task outcomes and rollout summaries
Rejected:
- Secrets / credentials / tokens
- Generic advice, one-off trivia
- Embedded instruction blocks (
AGENTS.md, skills, hooks) - One-off bug investigations (single ticket, single component/API quirk, no reusable pattern)
No-op when nothing would change future agent behavior. Repeatable workflows stay in memory; this system never creates skills automatically.
Extraction requires:
- 10 completed top-level turns since the previous extraction
- 120 minutes since the previous extraction
- a transcript mtime newer than
state/transcript-index.json
Repeated generation_id hook events are ignored. Successful and no-op extractions
both advance the transcript index; failed extractions remain retryable.
When raw/stage1/ reaches 3 entries and git workspace is dirty after sync:
- Sync
raw_memories.mdfrom stage-1 JSON files - Write
phase2_workspace_diff.md(git diff vs baseline) - Spawn sandboxed consolidate agent (Luna by default)
- Archive stage-1 files, commit new git baseline
Runs outside your chat. Check ~/.cursor/memory/state/extract.log and consolidate.log.
If extract wedges on stale lock or extractQueued:
npm run retry-extract -- --clear-stuck
npm run retry-extract -- --session <conversation-id> [--cwd <project-dir>]cursor agent -p --sandbox enabled --model gpt-5.6-luna-high --workspace ~/.cursor/memory \
"Consolidate pending memories per ~/.cursor/skills/memory-consolidate/SKILL.md"Or run the runner directly:
node ~/.cursor/hooks/memory-consolidate-runner.js| Variable | Default | Description |
|---|---|---|
MEMORY_MODEL |
gpt-5.6-luna-high |
Model for extract + consolidate |
MEMORY_CONSOLIDATE_THRESHOLD |
3 |
Stage-1 files before consolidate |
MEMORY_CAPTURE_MIN_TURNS |
10 |
Completed top-level turns before extract |
MEMORY_CAPTURE_MIN_MINUTES |
120 |
Minimum minutes between extracts |
MEMORY_SANDBOX |
enabled |
Sandbox mode for background agents |
MEMORY_CONSOLIDATE_DEBOUNCE_MS |
60000 |
Min ms between consolidate spawns |
MEMORY_LOCK_STALE_MS |
1800000 |
Stale lock timeout (30 min) |
MEMORY_CURSOR_BIN |
auto-detect | Path to cursor binary |
Set in shell profile or wrap hook commands if needed.
- Open a new agent chat — memory summary should appear in context.
- Complete a coding chat with reusable learnings.
- Check
~/.cursor/memory/state/extract.logandraw/stage1/. - After 3 extractions —
consolidate.logshould show a spawn line. - Cursor Customize → Hooks tab + Hooks output channel for debug.
./scripts/doctor.shFile sanitized public issues from any agent session:
- Invoke skill
memory-feedback(or ask agent to file cursor-memory feedback) - Agent runs
npm run feedback, rewrites diagnostics by hand (no company paths, names, or secrets) - You approve preview →
gh issue createonBhacaz/cursor-memory
Issue templates: Memory quality (captures/consolidate) and Ops / install bug. Skill blocks company names, internal URLs, ticket IDs, secrets, and real project paths.
Requires gh auth login. Override target repo with MEMORY_FEEDBACK_REPO=owner/repo.
npm run feedback # raw diagnostics for agent to summarize (do not paste verbatim into issues)cursor-memory/
├── README.md
├── docs/codex-memory-reference.md # Codex architecture reference
├── install.sh / uninstall.sh
├── hooks.fragment.json
├── package.json
├── src/hooks/
│ ├── memory-lib.js
│ ├── memory-git.js
│ ├── memory-session-start.js
│ ├── memory-capture.js
│ ├── memory-extract-runner.js
│ └── memory-consolidate-runner.js
├── scripts/
│ ├── merge-hooks.js
│ └── doctor.sh
├── skills/
│ ├── memory-read/
│ ├── memory-extract/
│ └── memory-consolidate/
└── templates/memory/
See hooks.fragment.json. Merged into your existing ~/.cursor/hooks.json:
sessionStart→memory-session-start.jsstop→memory-capture.jssessionEnd→memory-capture.js
./install.sh --link creates symlinks. Moving the folder breaks them.
cd ~/Documents/code/cursor-memory
./install.sh --link
./scripts/doctor.shExtraction runs after the capture cadence is met, via Luna on the changed full transcript.
- Capture state:
~/.cursor/memory/state/last-capture.json - Transcript index:
~/.cursor/memory/state/transcript-index.json - Stage-1 queue:
~/.cursor/memory/raw/stage1/*.json - Consolidate at 3 stage-1 files when git diff is dirty
MEMORY.mdupdates only after consolidate
tail -f ~/.cursor/memory/state/extract.logIf you see skip: no transcript_path, enable transcripts in Cursor settings.
./scripts/doctor.shMIT