Skip to main content
Glama
README.md
# Oracle Memory

> The notebook your AI agents never lose. No database, no server farm — just JSON files and a really good search.

Every coding session, your agent learns something: a port number, a gotcha, a decision you made at 2 a.m. And every session, it forgets. **Oracle Memory** is the fix — a file-backed MCP memory server that lets agents *remember* across sessions and *find* what they wrote with hybrid keyword + semantic search.

```
   remember ──▶ .oracle-memory/*.json ──▶ recall
                     (atomic writes)     (BM25 + vectors + entity graph)
```

No Postgres. No Redis. No migrations. Delete a file and the memory is gone; back up a folder and it's safe. That's the whole storage engine.

---

## 60-second start

Needs **Node.js 24+**.

```bash
npm install -g oracle-memory

# Run it as an MCP server (stdio)
oracle-memory

# ...or scope it to a project
ORACLE_MEMORY_ROOT_DIR=/path/to/project oracle-memory
```

Wire it into Claude Code:

```bash
claude mcp add oracle-memory -- /path/to/oracle-memory/dist/index.js
```

(Codex works the same way — point its MCP config at the same path.)

---

## Four kinds of memory

Not everything deserves to be remembered forever. Pick the right shelf:

| Type | For | Lives |
|------|-----|-------|
| `fact` | Preferences, decisions, conventions | 🗿 Forever |
| `insight` | Lessons learned, gotchas, discoveries | 🗿 Forever |
| `chunk` | Conversation snapshots (pre-compact) | ⏳ Auto-expires (TTL) |
| `working` | Session scratchpad, temporary context | 🧹 Cleared between sessions |

---

## The tools

| Tool | What it does |
|------|--------------|
| `remember` | Save a fact / insight / chunk / working memory |
| `recall` | Search — BM25 + vector + entity-graph ranking, fused |
| `get_memory` | Fetch one memory by id + type |
| `update_memory` | Edit content / tags / importance / meta / TTL |
| `list_memories` | List with type / agent / tag / query filters |
| `forget` | Delete a memory for good |
| `clear_working` | Wipe an agent's scratchpad (or everyone's) |
| `consolidate` | Merge lookalike memories by tag overlap |
| `reflect` | Synthesize *new* higher-level insights from clusters of memories (LLM) |
| `list_conflicts` | Surface contradictions: flagged ties + quarantined memories |
| `verify_memory` | Resolve a contradiction — `keep` (supersede the loser) or `reject` |
| `get_sessions` | Who's currently connected |
| `get_stats` | Counts by type and agent |

And read-only resources for clients that prefer URIs:

| URI | Content |
|-----|---------|
| `oracle-memory://memories` | Everything |
| `oracle-memory://memories/{type}` | Filtered by type |
| `oracle-memory://stats` | Statistics |
| `oracle-memory://sessions` | Connected agents |

---

## The search is the magic

**BM25 keyword search** is built in — zero dependencies, fully offline, deterministic. Tokenize, drop stop words, rank. Fast and boring, in the best way.

**Vector semantic search** is the optional upgrade. Turn it on and every memory is also embedded with `Xenova/all-MiniLM-L6-v2` (384-dim). On `recall`, keyword hits and semantic hits are blended with **Reciprocal Rank Fusion (RRF)** — so "port config" finds the note that says "we run on 3000" even without a word in common.

The model (~15 MB) auto-downloads on first use and caches locally. Don't want it?

```bash
ORACLE_MEMORY_DISABLE_VECTORS=1 oracle-memory
```

---

## A day in the life

```bash
# Agent learns something
→ remember(agent="claude", type="fact", content="Project uses port 3000", tags=["config"])

# Weeks later, a different session, it just... knows
→ recall(query="port configuration")
← [{ entry: { content: "Project uses port 3000" }, score: 2.3, method: "bm25" }]

# Plans changed
→ update_memory(id="20260713-...", type="fact", { content: "Project uses port 4000" })

# How much does it know?
→ get_stats()
← { totalMemories: 42, byType: { fact: 20, insight: 10, chunk: 10, working: 2 } }
```

---

## Sharing memory across a team of agents (HTTP hub)

Run one memory server, connect many agents:

```bash
ORACLE_MEMORY_TRANSPORT=http ORACLE_MEMORY_PORT=8765 oracle-memory
```

```bash
claude mcp add --transport http oracle-memory http://localhost:8765/mcp
```

Lock it down with a bearer token before exposing it:

```bash
ORACLE_MEMORY_HTTP_TOKEN=your-secret ORACLE_MEMORY_TRANSPORT=http ORACLE_MEMORY_PORT=8765 oracle-memory
```

---

## Under the hood

```
<root>/.oracle-memory/
├── config.json         # server config
├── facts/              # permanent knowledge
├── insights/           # lessons learned
├── chunks/             # conversation snapshots
├── working/            # scratchpads
├── graph/graph.json    # entity relationship graph
└── vectors/            # embeddings (optional)
```

Every write is atomic (`.tmp` → rename), so a crash mid-write never corrupts your store.

### Environment

| Variable | Default | Description |
|----------|---------|-------------|
| `ORACLE_MEMORY_ROOT_DIR` | `cwd` | Root for the `.oracle-memory/` store |
| `ORACLE_MEMORY_DISABLE_VECTORS` | `false` | `1` to disable vector search |
| `ORACLE_MEMORY_TRANSPORT` | `stdio` | `stdio` or `http`/`streamable` |
| `ORACLE_MEMORY_HOST` | `0.0.0.0` | HTTP bind host |
| `ORACLE_MEMORY_PORT` | `8765` | HTTP port |
| `ORACLE_MEMORY_HTTP_TOKEN` | — | Bearer token for `/mcp` |
| `ORACLE_MEMORY_LOG_LEVEL` | `info` | Log verbosity |

> Migrating from an older setup? The legacy `AGOYA_*` env vars still work as fallbacks.

### Build

```bash
npm run build   # TypeScript → dist/
npm run check   # type-check only
npm run dev     # run via tsx
npm start       # run compiled
npm test        # tests
```

---

## Benchmarks

A self-contained eval harness (no downloads) scores what the SOTA agent-memory papers care about: **retrieval quality** (recall@k, MRR) and **temporal correctness** — after a fact changes, does recall return the *new* value and suppress the superseded one?

```bash
npm run bench                              # BM25 + entity-graph + vectors
ORACLE_MEMORY_DISABLE_VECTORS=1 npm run bench   # skip the embedding model
```

It writes `bench/results.svg`:

![oracle-memory eval benchmark](bench/results.svg)

The bench exits non-zero if quality drops below its floors (recall@5 ≥ 75%, temporal = 100%), so it doubles as a CI regression gate.

---

## The rest of the family

Oracle Memory writes the `.oracle-memory/` format natively, so it slots right in with:

- 🧠 [Oracle](https://github.com/JonusNattapong/Oracle) — the AI coding consultant (skills + oracles)
- 📮 [Oracle Messages](https://github.com/JonusNattapong/oracle-messages) — multi-agent message bus
- 📖 [Oracle Skill](https://github.com/JonusNattapong/oracle-skill) — teaches any agent to use the stack

*One brain, one notebook, one group chat — no database in sight.*