feat: hard-gate agent memory to OpenBrain via PreToolUse hook

Agents consistently ignore written instructions about memory routing
and default to writing local MEMORY.md files regardless of rules in
RUNTIME.md, CLAUDE.md, or MEMORY.md itself. Instructions alone are
insufficient — a technical gate is required.

Changes:
- Add tools/qa/prevent-memory-write.sh — PreToolUse hook that blocks
  Write/Edit/MultiEdit to ~/.claude/projects/*/memory/*.md (exit 2)
- Register hook in runtime/claude/settings.json PreToolUse array
- Update runtime/claude/RUNTIME.md: replace soft "Memory Override"
  note with hard-gate policy, what-goes-where table, and rationale
- Rewrite guides/MEMORY.md: OpenBrain as primary layer, blocked silos
  table, project continuity files, how-the-hook-works section

The correct behavior is now the only possible behavior for Claude Code.
All agent learnings route to OpenBrain where every harness can read them.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-02 21:15:28 -06:00
parent 97ee66770a
commit 2a91f6c202
4 changed files with 114 additions and 17 deletions

View File

@@ -1,27 +1,50 @@
# Memory and Retention Rules
## Primary Memory Layer: OpenBrain
**OpenBrain is the canonical shared memory for all Mosaic agents across all harnesses and sessions.**
Use the `capture` MCP tool (or REST `POST /v1/thoughts`) to store:
- Discovered gotchas and workarounds
- Architectural decisions and rationale
- Project state and context for handoffs
- Anything a future agent should know
Use `search` or `recent` at session start to load prior context before acting.
This is not optional. An agent that uses local file-based memory instead of OpenBrain is a broken agent — its knowledge is invisible to every other agent on the platform.
## Hard Rules
1. You MUST store learned operational memory in `~/.config/mosaic/memory`.
2. You MUST NOT store durable memory in runtime-native memory silos.
3. You MUST write concise, reusable learnings that help future agents.
4. You MUST track active execution state in project documentation, not ad-hoc text files.
1. Agent learnings MUST go to OpenBrain — not to any file-based memory location.
2. You MUST NOT write to runtime-native memory silos (they are write-blocked by hook).
3. Active execution state belongs in project `docs/` — not in memory files.
4. `~/.config/mosaic/memory/` is for mosaic framework technical notes only, not project knowledge.
## Runtime-Native Memory Silos (FORBIDDEN for Durable Memory)
## Runtime-Native Memory Silos (WRITE-BLOCKED)
| Runtime | Native silo (forbidden for durable memory) | Required durable location |
|---|---|---|
| Claude Code | `~/.claude/projects/*/memory/` | `~/.config/mosaic/memory/` + project `docs/` |
| Codex | Runtime session/native memory under `~/.codex/` | `~/.config/mosaic/memory/` + project `docs/` |
| OpenCode | Runtime session/native memory under `~/.config/opencode/` | `~/.config/mosaic/memory/` + project `docs/` |
These locations are blocked by PreToolUse hooks. Attempting to write there fails at the tool level.
Treat runtime-native memory as volatile implementation detail. Do not rely on it for long-term project continuity.
| Runtime | Blocked silo | Use instead |
|---------|-------------|-------------|
| Claude Code | `~/.claude/projects/*/memory/*.md` | OpenBrain `capture` |
| Codex | Runtime session memory | OpenBrain `capture` |
| OpenCode | Runtime session memory | OpenBrain `capture` |
MEMORY.md files may only contain behavioral guardrails that must be injected at load-path — not knowledge.
## Project Continuity Files (MANDATORY)
| File | Purpose | Location |
|---|---|---|
| `docs/PRD.md` or `docs/PRD.json` | Source of requirements for planning, coding, testing, and review | Project `docs/` |
| `docs/TASKS.md` | Canonical tracking for tasks, milestones, issues, status, and blockers | Project `docs/` |
| `docs/scratchpads/<task>.md` | Task-specific working memory and verification evidence | Project `docs/scratchpads/` |
| `AGENTS.md` | Reusable local patterns and gotchas | Any working directory |
| `docs/PRD.md` or `docs/PRD.json` | Source of requirements | Project `docs/` |
| `docs/TASKS.md` | Task tracking, milestones, issues, status | Project `docs/` |
| `docs/scratchpads/<task>.md` | Task-specific working memory | Project `docs/scratchpads/` |
| `AGENTS.md` | Project-local patterns and conventions | Project root |
## How the Block Works
`~/.config/mosaic/tools/qa/prevent-memory-write.sh` is registered as a `PreToolUse` hook in
`~/.claude/settings.json`. It intercepts Write/Edit/MultiEdit calls and rejects any targeting
`~/.claude/projects/*/memory/*.md` before the tool executes. Exit code 2 blocks the call and
the agent sees a message directing it to OpenBrain instead.

View File

@@ -46,9 +46,37 @@ Task(subagent_type="Plan", model="opus", prompt="Design the multi-tenant isolati
| Status/health checks | Test writing | Security/auth logic |
| Simple one-liner fixes | Standard features | Ambiguous design decisions |
## Memory Override
## Memory Policy (Hard Gate)
Do NOT write durable memory to `~/.claude/projects/*/memory/`. All durable memory MUST be written to `~/.config/mosaic/memory/` per `~/.config/mosaic/guides/MEMORY.md`. Claude Code's native auto-memory locations are volatile runtime silos and MUST NOT be used for cross-session or cross-agent retention.
**OpenBrain is the primary cross-agent memory layer.** All agent learnings, gotchas, decisions, and project state MUST be captured to OpenBrain via the `capture` MCP tool or REST API.
`~/.claude/projects/*/memory/MEMORY.md` files are **write-blocked by PreToolUse hook** (`prevent-memory-write.sh`). Any attempt to write agent learnings there will be rejected with an error directing you to OpenBrain.
### What belongs where
| Content | Location |
|---------|----------|
| Discoveries, gotchas, decisions, observations | OpenBrain `capture` — searchable by all agents |
| Active task state | `docs/TASKS.md` or `docs/scratchpads/` |
| Behavioral guardrails that MUST be in load-path | `MEMORY.md` (read-mostly; write only for genuine behavioral overrides) |
| Mosaic framework technical notes | `~/.config/mosaic/memory/` |
### Using OpenBrain
At session start, load prior context:
```
search("topic or project name") # semantic search
recent(limit=5) # what's been happening
```
When you discover something:
```
capture("The thing you learned", source="project/context", metadata={"type": "gotcha", ...})
```
### Why the hook exists
Instructions in RUNTIME.md, CLAUDE.md, and MEMORY.md are insufficient — agents default to writing local MEMORY.md regardless of written rules. The PreToolUse hook is a hard technical gate that makes the correct behavior the only possible behavior.
## MCP Requirement

View File

@@ -1,6 +1,18 @@
{
"model": "opus",
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "~/.config/mosaic/tools/qa/prevent-memory-write.sh",
"timeout": 10
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|MultiEdit|Write",

View File

@@ -0,0 +1,34 @@
#!/usr/bin/env bash
# prevent-memory-write.sh — PreToolUse hook
#
# Blocks Write/Edit/MultiEdit calls targeting Claude Code's native auto-memory
# files (~/.claude/projects/*/memory/*.md).
#
# These files are runtime-specific silos that no other agent harness can read.
# All agent learnings MUST go to OpenBrain (capture MCP tool or REST API).
# MEMORY.md files may only contain load-path behavioral guardrails — not knowledge.
#
# Exit codes (Claude Code PreToolUse):
# 0 = allow
# 2 = block with message shown to agent
set -euo pipefail
INPUT="$(cat)"
FILE_PATH="$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null || true)"
[[ -z "$FILE_PATH" ]] && exit 0
# Resolve ~ to HOME
FILE_PATH="${FILE_PATH/#\~/$HOME}"
# Block writes to Claude Code auto-memory files
if [[ "$FILE_PATH" =~ /.claude/projects/.+/memory/.*\.md$ ]]; then
echo "BLOCKED: Do not write agent learnings to ~/.claude/projects/*/memory/ — this is a runtime-specific silo."
echo "Use OpenBrain instead: MCP 'capture' tool or REST POST https://brain.woltje.com/v1/thoughts"
echo "File blocked: $FILE_PATH"
exit 2
fi
exit 0