Files
mempalace/hooks
Igor Lins e Silva 8b26bf2ac3 chore: sync main hotfixes into release/3.2.0 (#763)
* fix: disambiguate hook block reasons to name MemPalace explicitly (#666)

Replace "your memory system" with explicit MemPalace references and
tool names (mempalace_diary_write, mempalace_add_drawer, mempalace_kg_add)
in stop and precompact hook block reasons. This prevents Claude Code from
misinterpreting the hook as a native auto-memory save instruction.

Updated in both Python (hooks_cli.py) and standalone shell scripts.

Also fix CONTRIBUTING.md Getting Started to show the fork-first workflow,
matching the PR Guidelines section.

* fix: remove chromadb <0.7 upper bound — blocks 1.x installs

The current constraint `chromadb>=0.5.0,<0.7` forces pip to install
chromadb 0.6.x, but palaces created with chromadb 1.x (which is what
the mempalace dev environment actually uses — 1.5.7 per uv.lock) have
an incompatible SQLite schema. Specifically, chromadb 0.6.x fails with
`KeyError: '_type'` when opening a collection written by 1.x.

This means a fresh `pip install mempalace` gives users a chromadb
version that cannot read palaces created in the maintainer's own
environment. The fix removes the upper bound so pip can resolve to the
current stable chromadb release.

Reproduction:
  python3 -m venv .venv && source .venv/bin/activate
  pip install mempalace          # installs chromadb 0.6.3
  # Try opening a palace created with chromadb 1.x:
  # -> _get_collection() returns None, tool_status() returns "No palace found"
  pip install chromadb==1.5.7    # force upgrade
  # -> tool_status() returns real data (26k drawers in our case)

---------

Co-authored-by: z3tz3r0 <kittipan.wang@gmail.com>
Co-authored-by: AlyciaBHZ <50111876+AlyciaBHZ@users.noreply.github.com>
Co-authored-by: Ben Sigman <1872138+bensig@users.noreply.github.com>
2026-04-12 23:44:22 -07:00
..

MemPalace Hooks — Auto-Save for Terminal AI Tools

These hook scripts make MemPalace save automatically. No manual "save" commands needed.

What They Do

Hook When It Fires What Happens
Save Hook Every 15 human messages Blocks the AI, tells it to save key topics/decisions/quotes to the palace
PreCompact Hook Right before context compaction Emergency save — forces the AI to save EVERYTHING before losing context

The AI does the actual filing — it knows the conversation context, so it classifies memories into the right wings/halls/closets. The hooks just tell it WHEN to save.

Install — Claude Code

Add to .claude/settings.local.json:

{
  "hooks": {
    "Stop": [{
      "matcher": "*",
      "hooks": [{
        "type": "command",
        "command": "/absolute/path/to/hooks/mempal_save_hook.sh",
        "timeout": 30
      }]
    }],
    "PreCompact": [{
      "hooks": [{
        "type": "command",
        "command": "/absolute/path/to/hooks/mempal_precompact_hook.sh",
        "timeout": 30
      }]
    }]
  }
}

Make them executable:

chmod +x hooks/mempal_save_hook.sh hooks/mempal_precompact_hook.sh

Install — Codex CLI (OpenAI)

Add to .codex/hooks.json:

{
  "Stop": [{
    "type": "command",
    "command": "/absolute/path/to/hooks/mempal_save_hook.sh",
    "timeout": 30
  }],
  "PreCompact": [{
    "type": "command",
    "command": "/absolute/path/to/hooks/mempal_precompact_hook.sh",
    "timeout": 30
  }]
}

Configuration

Edit mempal_save_hook.sh to change:

  • SAVE_INTERVAL=15 — How many human messages between saves. Lower = more frequent saves, higher = less interruption.
  • STATE_DIR — Where hook state is stored (defaults to ~/.mempalace/hook_state/)
  • MEMPAL_DIR — Optional. Set to a conversations directory to auto-run mempalace mine <dir> on each save trigger. Leave blank (default) to let the AI handle saving via the block reason message.

mempalace CLI

The relevant commands are:

mempalace mine <dir>               # Mine all files in a directory
mempalace mine <dir> --mode convos # Mine conversation transcripts only

The hooks resolve the repo root automatically from their own path, so they work regardless of where you install the repo.

How It Works (Technical)

Save Hook (Stop event)

User sends message → AI responds → Claude Code fires Stop hook
                                            ↓
                                    Hook counts human messages in JSONL transcript
                                            ↓
                              ┌─── < 15 since last save ──→ echo "{}" (let AI stop)
                              │
                              └─── ≥ 15 since last save ──→ {"decision": "block", "reason": "save..."}
                                                                    ↓
                                                            AI saves to palace
                                                                    ↓
                                                            AI tries to stop again
                                                                    ↓
                                                            stop_hook_active = true
                                                                    ↓
                                                            Hook sees flag → echo "{}" (let it through)

The stop_hook_active flag prevents infinite loops: block once → AI saves → tries to stop → flag is true → we let it through.

PreCompact Hook

Context window getting full → Claude Code fires PreCompact
                                        ↓
                                Hook ALWAYS blocks
                                        ↓
                                AI saves everything
                                        ↓
                                Compaction proceeds

No counting needed — compaction always warrants a save.

Debugging

Check the hook log:

cat ~/.mempalace/hook_state/hook.log

Example output:

[14:30:15] Session abc123: 12 exchanges, 12 since last save
[14:35:22] Session abc123: 15 exchanges, 15 since last save
[14:35:22] TRIGGERING SAVE at exchange 15
[14:40:01] Session abc123: 18 exchanges, 3 since last save

Cost

Zero extra tokens. The hooks are bash scripts that run locally. They don't call any API. The only "cost" is the AI spending a few seconds organizing memories at each checkpoint — and it's doing that with context it already has loaded.