OpenClaw skill that auto-tiers bloated MEMORY.md, generates smart per-session manifests, and routes only what matters — 70-85% context reduction with zero de...
# MemoryRouter ⚡
**Never lose context. Never forget decisions. Never repeat mistakes.**
The memory problem is the single biggest reason agents feel dumb over time. Not the models. Not the prompts. **Memory management.**
MemoryRouter fixes it with one tool, zero dependencies, zero setup.
## The Problem — In 30 Seconds
Agent memory files grow unbounded. After a week, you've got thousands of lines across dozens of files. Every session loads **everything** — even when the user asks "what's the weather?"
That's tokens burned on irrelevant memories, every interaction, forever.
Then compaction kicks in and details vanish.
**The bottleneck isn't the model. It's what the model gets to see.**
## Why Memory Fails
| Failure Mode | Cause | Fix |
|-------------|-------|-----|
| Forgets everything | Loads irrelevant files, context window fills up | Smart manifest — load only what matters |
| Repeats mistakes | Lessons not captured or loaded | Entity index + audit for conflicts |
| Repeats work | No session state persistence | WAL protocol — write state before responding |
| Slow responses | Loads 50+ files when only 3 matter | Token budgeting — cap context window |
| Duplicates everywhere | No automated cleanup | `--audit` finds high-similarity pairs |
## The Architecture
```
┌──────────────────────────────────────────────────────┐
│ MEMORYROUTER ⚡ │
├──────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ AUTO-TIER │ │ MANIFEST │ │
│ │ MEMORY.md │ → │ GENERATOR │ │
│ │ │ │ │ │
│ │ Core (always │ │ Required: │ │
│ │ loaded) │ │ MEMORY.md │ │
│ │ + Archive │ │ Recent logs │ │
│ │ (on demand) │ │ Boosted: │ │
│ └──────────────┘ │ entity files │ │
│ └──────┬───────┘ │
│ │ │
│ ┌──────────────▼──────────────┐ │
│ │ ENTITY RESOLUTION │ │
│ │ "alice" → preferences.md, │ │
│ │ notes.md, decisions.md│ │
│ └──────────────┬──────────────┘ │
│ │ │
│ ┌──────────────▼──────────────┐ │
│ │ TOKEN BUDGET FILTER │ │
│ │ 20K budget → 7 files │ │
│ │ 100K budget → 16 files │ │
│ └──────────────┬──────────────┘ │
│ │ │
│ ┌──────────────▼──────────────┐ │
│ │ AGENT LOADS ONLY WHAT │ │
│ │ MATTERS → 70-85% REDUCTION │ │
│ └─────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
```
## Quick Start
### Fix a bloated MEMORY.md in one command
```bash
node skills/memory-router/memory-router.js --tier
```
**Output:**
```
[memory-router] MEMORY.md: 7809 lines, 309254 chars
[memory-router] ✅ Pre-tier backup: memory/backups/MEMORY-backup-2026-05-23-1234567890.md (7809 lines saved)
[memory-router] Tiered: 202 core sections, 1002 archived
[memory-router] MEMORY.md reduced from 7809 lines to 2222 lines
```
### Preview tiering without making changes
```bash
node skills/memory-router/memory-router.js --tier --dry-run
```
**Output:**
```
[memory-router] MEMORY.md: 7809 lines, 309254 chars
[memory-router] ✅ Pre-tier backup: memory/backups/MEMORY-backup-2026-05-23-1234567890.md (7809 lines saved)
[memory-router] ── DRY RUN ──
[memory-router] Would archive: memory/active/MEMORY-archive-2026-05-23.md
[memory-router] Would reduce MEMORY.md from 7809 lines to ~2222 lines
[memory-router] Core sections: 202, Archive sections: 1002
[memory-router] No files were modified.
```
### Restore MEMORY.md from latest backup
```bash
node skills/memory-router/memory-router.js --restore
```
Restores MEMORY.md from the most recent pre-tier backup in `memory/backups/`.
### Generate a smart manifest in one command
```bash
node skills/memory-router/memory-router.js --compact
```
Creates `memory/memory-manifest.json` — the agent's shopping list of what to load.
### With entity boosting
```bash
node skills/memory-router/memory-router.js --compact --query "alice"
```
Files linked to "alice" get priority. No AI, no embeddings — just fast entity resolution.
### With a token budget
```bash
node skills/memory-router/memory-router.js --compact --budget 20000
```
Only loads files that fit within 20K tokens. Tight budgets load core only. Generous budgets load archive on demand.
### Other commands
```bash
node skills/memory-router/memory-router.js --audit # Find duplicates & conflicts
node skills/memory-router/memory-router.js --status # Health overview
node skills/memory-router/memory-router.js --entity add alice person preferences.md
```
## How It Works
### The Core Insight
**Memory management is the bottleneck, not model capability.** Every agent system hits the same wall — context window fills up, everything loads, irrelevant memories dilute the signal.
MemoryRouter takes a **routing** approach rather than a **compression** approach:
1. **Auto-tiering** splits MEMORY.md into core sections (identity, preferences, boundaries — always loaded) and archive sections (everything else, loaded on demand)
2. **Manifest generation** creates a per-session file list: which files to load, which to skip, which to boost
3. **Entity-aware boosting** links people, projects, and systems to files — search for "alice" → load preferences.md first
4. **Token budgeting** caps how many files load based on available context window
### The Flow
```
User query → --compact --query "alice"
↓
Manifest generated
↓
Load required files (MEMORY.md, recent daily logs)
↓
Boost entity-matched files (preferences.md, notes.md)
↓
Agent loads only what matters → 70-85% context reduction
```
## The 4 Engines
### ⚡ Engine 1: Auto-Tier (`--tier`)
When MEMORY.md exceeds configurable thresholds (default: 500 lines or 25KB), splits into:
- **Core file** — Identity, preferences, relationships, projects, patterns, boundaries
- **Archive files** — Everything else, stored with timestamps in `memory/active/`
**Safety features (v2):**
- **Pre-tier backup** — Every `--tier` creates a full backup in `memory/backups/` before modifying MEMORY.md
- **`--dry-run`** — Preview what tiering would do without making changes
- **Minimum core size** — Aborts if core sections would fall below `minCoreLines`/`minCoreChars` thresholds
- **`--restore`** — Restore MEMORY.md from the latest backup
Sections are classified by header keywords (identity, preferences, etc.) or by content heuristics.
### 📋 Engine 2: Manifest Generator (`--compact`)
Creates `memory/memory-manifest.json` with a file list:
```json
{
"generated": "2026-05-21",
"files": [
{ "path": "MEMORY.md", "tier": "core", "required": true, "size": 50346 },
{ "path": "memory/2026-05-21.md", "tier": "recent", "required": true, "size": 2034 },
{ "path": "self-improving/memory.md", "tier": "domain", "required": false, "size": 670 }
]
}
```
**Options:**
| Flag | Description |
|------|-------------|
| `--query "text"` | Entity-aware boosting — files linked to matching entities get priority |
| `--budget N` | Token budget — only loads files that fit within N tokens |
### 🔍 Engine 3: Audit Scanner (`--audit`)
Scans all memory files for:
- **High-similarity pairs** — Files with >70% text overlap (potential duplicates)
- **Revision keywords** — "revised", "updated", "changed", "no longer", "actually", "correction" (facts that may have been superseded)
Output: `memory/memory-audit-report.md`
### 🏥 Engine 4: Health Monitor (`--status`)
Quick snapshot of MEMORY.md line/char counts, file counts per directory, archive count, manifest status, entity index size, and WAL state.
## Additional Tools
### Entity Index (`--entity`)
| Command | Description |
|---------|-------------|
| `--entity add <name> <type> <files...>` | Add entity (e.g., `alice person preferences.md`) |
| `--entity list` | List all entities |
| `--entity search <query>` | Search entities (direct and fuzzy match) |
### WAL Protocol (`--wal`)
| Command | Description |
|---------|-------------|
| `--wal init` | Initialize SESSION-STATE.md with template |
| `--wal get` | Show current session state |
| `--wal update <section> --content "<text>"` | Update a section |
## Configuration
Edit `config.json` to customize behavior:
```json
{
"thresholds": {
"memoryMdMaxLines": 500,
"memoryMdMaxChars": 25000,
"tierArchiveMinAgeDays": 3,
"auditMaxFiles": 50
},
"tiering": {
"archiveDir": "memory/active",
"retentionDays": 90,
"keepInMemory": [
"identity", "preferences", "relationships",
"projects", "patterns", "boundaries", "key_facts"
]
},
"manifest": {
"generateOnTier": true,
"manifestPath": "memory/memory-manifest.json"
},
"audit": {
"reportPath": "memory/memory-audit-report.md",
"duplicateThreshold": 0.7,
"conflictKeywords": [
"revised", "updated", "changed", "no longer",
"actually", "correction", "mistake"
]
}
}
```
| Setting | Default | Description |
|---------|---------|-------------|
| `memoryMdMaxLines` | 500 | Auto-tier trigger (lines) |
| `memoryMdMaxChars` | 25000 | Auto-tier trigger (characters) |
| `tierArchiveMinAgeDays` | 3 | Minimum age before archiving |
| `retentionDays` | 90 | Archive retention period |
| `keepInMemory` | see above | Headers/keywords that stay in core |
| `generateOnTier` | true | Auto-generate manifest after tiering |
| `duplicateThreshold` | 0.7 | Similarity score to flag as duplicate |
| `conflictKeywords` | see above | Words that signal fact revision |
| `backupDir` | `memory/backups` | Directory for pre-tier backups |
| `minCoreLines` | 20 | Abort if core sections below this |
| `minCoreChars` | 1000 | Abort if core chars below this |
## Agent Memory Loading Protocol
When the agent wakes up, use the manifest instead of loading all memory files:
1. Read `memory/memory-manifest.json`
2. Load all `required: true` files
3. For `required: false` files, use `memory_search` to check relevance
4. Load only the top 3-5 most relevant optional files
**Result: 70–85% context reduction — load what matters, skip the rest.**
## Heartbeat Integration
Add to your `HEARTBEAT.md`:
```markdown
### ⚡ MemoryRouter
- Run `node skills/memory-router/memory-router.js --tier` if MEMORY.md is bloated
- Run `node skills/memory-router/memory-router.js --compact` to update manifest
- Run `node skills/memory-router/memory-router.js --audit` to check for issues
- Check `memory/memory-audit-report.md` for any flagged conflicts
```
## Performance
| Metric | Result |
|--------|--------|
| Tiering speed (8K lines) | 25ms |
| Tiering speed (15K lines) | 30ms |
| Token reduction | **96%** (7,809 → 222 lines) |
| File count reduction | **53 → 15 files** |
| Memory footprint | ~2MB (Node.js runtime) |
## Comparison
| Approach | Tokens Saved | Setup Effort | Maintenance | Privacy |
|----------|-------------|-------------|-------------|---------|
| Raw file injection | 0% | None | Manual | ✅ |
| **MemoryRouter** | **70–85%** | **None** | **Automated** | **✅** |
| Obsidian vault | 40–60% | High | Medium | ⚠️ Cloud |
| Vector DB (ChromaDB) | 70–85% | Very High | High | ✅ |
| mem0 | 70–85% | High | Medium | ⚠️ Cloud |
**MemoryRouter gives you the best token savings of the vector DB approach with zero setup effort.**
## Entity Naming
Pick one canonical name per entity and reuse it consistently:
- Use full descriptive names: "machine learning" not "ML", "JavaScript" not "JS"
- Same string after lowercasing = same entity. Different strings = different entities
- Call `--entity search` periodically to verify your index
Examples:
```bash
# ✅ Good — consistent, descriptive
node memory-router.js --entity add alice person preferences.md
node memory-router.js --entity add openclaw system AGENTS.md
# ❌ Bad — inconsistent, ambiguous
node memory-router.js --entity add alice person preferences.md
node memory-router.js --entity add Alice person notes.md
node memory-router.js --entity add JS person docs.md
```
## Manifest Format
The manifest JSON tells the agent which files to load:
```json
{
"generated": "2026-05-21",
"version": 2,
"query": "memory management",
"budget": 20000,
"files": [
{
"path": "MEMORY.md",
"tier": "core",
"required": true,
"size": 50346
},
{
"path": "memory/2026-05-21.md",
"tier": "recent",
"ageDays": 0,
"required": true,
"size": 2034
},
{
"path": "self-improving/memory.md",
"tier": "domain",
"required": false,
"size": 670
}
]
}
```
| Field | Type | Description |
|-------|------|-------------|
| `tier` | string | `core`, `recent`, `domain`, or `archive` |
| `required` | bool | Always load this file |
| `size` | int | File size in bytes |
| `boosted` | bool | Entity match — higher priority |
| `entityMatch` | string | Entity name that matched |
| `load` | bool | Included under budget mode |
| `budgetUsed` | int | Total tokens loaded (budget mode) |
| `budgetEfficiency` | string | Percentage remaining (budget mode) |
## Troubleshooting
| Problem | Fix |
|---------|-----|
| "No MEMORY.md found" | Create one: `echo "# MEMORY.md" > MEMORY.md` |
| "Memory directory not found" | Create it: `mkdir -p memory` |
| Tiering not working | Check thresholds — if under 500 lines and 25KB, nothing happens (by design) |
| Manifest shows wrong files | Run `--compact` again — it regenerates fresh each time |
| Entity search returns nothing | Add entities first: `--entity add <name> <type> <files...>` |
| Budget too small | Core files always load. Budget only controls optional files. |
## Security
Built with defense-in-depth:
- **Path validation** — rejects file paths outside workspace root
- **Regex escaping** — prevents injection in WAL section names
- **Symlink protection** — refuses to read/write symlinks
- **Size limits** — 10MB max file size
- **Entity name validation** — alphanumeric + hyphens/underscores only
- **Content sanitization** — prevents header injection in WAL updates
- **Audit keyword validation** — rejects regex metacharacters in conflict keywords
## Design Principles
1. **Zero user friction** — Everything runs automatically during heartbeats
2. **No external dependencies** — Pure Node.js, no npm packages
3. **Configurable** — Thresholds, keywords, retention policies
4. **Transparent** — Generates reports, nothing is silently deleted
5. **Reversible** — Archives use dated filenames, original content preserved
6. **Privacy-first** — All local, no cloud APIs
don't have the plugin yet? install it then click "run inline in claude" again.