Integration · Claude Code 6 min read · May 2026

# Claude Code Governance

Mneme HQ registers a PreToolUse hook with Claude Code. Every Edit, Write, and MultiEdit is intercepted before it reaches disk — violations surface the decision id as feedback and exit 2 (block). Claude Code adjusts its approach without manual intervention.

Claude Code is a harness — it coordinates execution, tool use, and the agent loop. Mneme is the governance layer that runs alongside it, enforcing the architectural intent the harness has no opinion about. They are different layers of the runtime stack, and they run side by side. The argument in full: Harness Engineering Still Needs Governance.

By Theo Valmis · Published May 2026 · Updated May 2026

## 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

1. Install the package

       pip install mneme-hq

2. 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.

3. Run the installer

   Project-scoped (recommended — only affects this project):

       python scripts/install_claude_code.py

   User-scoped (applies to all Claude Code sessions):

       python scripts/install_claude_code.py --user

   The installer is idempotent — safe to run again after updates.

4. 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 named `storage_layer.py` will 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.py` or `helpers.py` will rarely retrieve any decisions at all.

Mitigations:

1. Choose scope keywords when recording decisions that match file names in your project. Use `/mneme-record` and follow the scope tip in the command.
2. Run `/mneme-context` before 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.
3. Run `/mneme-review` after 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:

- `mneme` is not found on `$PATH`
- The target file cannot be read (common for Write — the file doesn't exist yet)
- `mneme check` times 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-hook` is on `$PATH`: `which mneme-hook` (or `where mneme-hook` on Windows).
- If not, the pip scripts directory may not be on `$PATH`. Add it, or install with `pipx`.
- Confirm `.claude/settings.json` contains the `PreToolUse` entry (run the installer again).

### Hook fires but nothing is blocked

- Confirm `.mneme/project_memory.json` exists 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-hook` for clues.

### Too many false positives / blocks

- Switch to `MNEME_HOOK_MODE=warn` while refining your decisions.
- Review the triggered anti-patterns with `/mneme-context` to see if they're too broad.

## FAQ

How is the Mneme hook different from CLAUDE.md?
CLAUDE.md is static context: text injected at session start that the model is asked to respect. The Mneme hook runs as a PreToolUse hook — it intercepts every Edit, Write, and MultiEdit before they touch the filesystem and can return exit code 2 to block the operation outright. CLAUDE.md is advisory; the hook is enforcement. The two are complementary: CLAUDE.md gives the model context, Mneme blocks violations regardless of whether the model attended to that context. See why prompt memory fails at scale.
Does the hook slow down Claude Code sessions?
The retriever is deterministic keyword scoring with no embedding model and no vector store, so per-call latency is in the low milliseconds for typical projects. The hook runs locally; there is no network round trip. For projects with very large decision corpora, scope filters and tag indices keep retrieval bounded.
What happens if Mneme itself fails?
The hook is designed fail-open: if the Mneme process errors, returns invalid output, or times out, Claude Code is allowed to proceed rather than being blocked. This is a deliberate safety choice — a broken governance layer should not lock the team out of editing their codebase. Strict mode (`mneme check --mode strict`) in CI is where hard-blocking lives; the editor-time hook prioritizes availability.
Can I use the hook without committing project_memory.json?
Technically yes, but you lose the value. The decision corpus is the source of truth; committing it to the repo means every team member sees the same enforcement, and changes to architectural rules show up in PR review like any other change. Local-only memory recreates the per-engineer drift problem the layer exists to solve.

## Related reading

- the Cursor integration
- the GitHub Actions enforcement gate