How the hook works
Every Edit, Write, or MultiEdit Claude Code attempts is intercepted by mneme-hook before it writes to disk. The hook reconstructs the full post-edit file content, checks it against your recorded decisions, and returns a verdict.
The exit code semantics are deterministic: exit 0 allows the edit; exit 2 blocks it and surfaces the violated decision id as feedback to Claude Code. Claude Code sees the block as an error message, reads the decision id and rule, and adjusts its approach without you having to intervene.
on Edit / Write / MultiEdit:
content = reconstruct_full_file(tool_input)
result = mneme check --file <path> <content>
if result.violation:
exit 2 # block — surfaces decision_id to Claude Code
else:
exit 0 # allow
Fail-open by design. The hook never blocks on Mneme malfunction. If mneme is not found, the file can't be read, or mneme check times out (10 s limit), the hook exits 0 and allows the edit.
Install
-
Install the package
pip install mneme -
Initialise project memory (if you don't have one yet)
mkdir .mneme # Create .mneme/project_memory.json — see examples/project_memory.json for the schema. -
Run the installer
Project-scoped (recommended — only affects this project):
python scripts/install_claude_code.pyUser-scoped (applies to all Claude Code sessions):
python scripts/install_claude_code.py --userThe installer is idempotent — safe to run again after updates.
-
Verify
Open Claude Code in your project, make an edit that violates a recorded decision, and confirm the hook blocks it and surfaces the decision id.
Slash commands
After installing, four slash commands are available in Claude Code:
| Command | Purpose |
|---|---|
| /mneme-context | Retrieve decisions relevant to your current task |
| /mneme-check | Check a file or draft against project memory |
| /mneme-record | Record a new architectural decision |
| /mneme-review | Audit all pending diff changes against decisions |
Modes
| Mode | Behaviour | Set via |
|---|---|---|
| strict (default) | Block on any non-zero verdict from mneme check |
export MNEME_HOOK_MODE=strict |
| warn | Surface warning to Claude, never block | export MNEME_HOOK_MODE=warn |
Switch to warn while you're iterating on decisions to avoid friction:
export MNEME_HOOK_MODE=warn
Retrieval: what the hook checks and what it misses
The hook query is "edit to <file_path>" — tokens from the target file name determine which decisions are retrieved and checked. Decisions are scored by keyword overlap between the query and their scope, id, decision text, and anti-pattern fields.
What this means in practice:
- A decision with
scope: ["storage", "database"]and a file namedstorage_layer.pywill reliably be retrieved — "storage" appears in both the query and the scope. - The same decision may not be retrieved for an edit to
models.py— neither token overlaps with the scope. - Generic file names like
utils.pyorhelpers.pywill rarely retrieve any decisions at all.
Mitigations:
- Choose scope keywords when recording decisions that match file names in your project. Use
/mneme-recordand follow the scope tip in the command. - Run
/mneme-contextbefore non-trivial edits with a descriptive phrase describing the domain (e.g. "storage layer", "auth middleware"). This uses a richer query than the hook and surfaces decisions the hook might miss. - Run
/mneme-reviewafter a batch of edits to catch violations the per-edit hook missed due to retrieval gaps.
The hook is a first line of defence, not a complete audit. Use the slash commands for coverage on domains where file names are not self-describing.
Fail-open guarantees
The hook never blocks on execution errors. It exits 0 (allow) when:
mnemeis not found on$PATH- The target file cannot be read (common for Write — the file doesn't exist yet)
mneme checktimes out (limit: 10 s)- Any other OS-level error occurs
Only a real verdict returned by mneme check can cause a block.
Troubleshooting
Hook is not firing
- Confirm
mneme-hookis on$PATH:which mneme-hook(orwhere mneme-hookon Windows). - If not, the pip scripts directory may not be on
$PATH. Add it, or install withpipx. - Confirm
.claude/settings.jsoncontains thePreToolUseentry (run the installer again).
Hook fires but nothing is blocked
- Confirm
.mneme/project_memory.jsonexists in the project root (or a parent directory). - Check your decision scope keywords against the file names being edited — see the retrieval section above.
- Switch to warn mode temporarily and check stderr output from
mneme-hookfor clues.
Too many false positives / blocks
- Switch to
MNEME_HOOK_MODE=warnwhile refining your decisions. - Review the triggered anti-patterns with
/mneme-contextto see if they're too broad.