engram
by MARCCHERGGI
README.md
# Engram
**The memory-trace layer for agents.** Make any agent loop learn from its own runs.
Every multi-attempt agent today throws its **raw trajectory** back into context on retry — burning tokens and degrading quality. The June-2026 research frontier showed the fix is to inject a *distillate* of what happened, not the transcript, and to bank reusable conclusions across tasks. Engram is that layer, framework-agnostic and dependency-free.
Built directly on two results:
- **RTV + PDR** — *Scaling Test-Time Compute for Agentic Coding* ([arXiv 2604.16529](https://arxiv.org/abs/2604.16529)). Compress each rollout into hypotheses + failures + leads; vote across attempts (Recursive Tournament Voting); condition the next attempt on the distillate (Parallel-Distill-Refine). +12 pts on Terminal-Bench v2.0.
- **TMAS two-bank memory** — *Scaling Test-Time Compute via Multi-Agent Synergy* ([arXiv 2605.10344](https://arxiv.org/abs/2605.10344)). One bank of reliable **conclusions**, one of meta-**strategies**, shared across runs.
## Why
The bottleneck on hard agent tasks is not the model — it's that agents don't reuse what they already learned. Engram gives them a memory trace: compress → bank → recall → select.
## Use it as an MCP server (no code)
Engram ships an MCP server, so any agent that speaks MCP — Claude Code, Claude Desktop, Cursor — gets cross-session memory without you writing a line.
```json
{
"mcpServers": {
"engram": { "command": "node", "args": ["/abs/path/to/engram/mcp.mjs"] }
}
}
```
Clone-and-point for now; the npm package name is `agent-engram`, not yet published. (`engram`, `engram-mcp` and `engram-memory` are all taken on npm by unrelated authors — worth knowing before you go looking for this by name.)
Five tools:
| tool | when the agent calls it |
|---|---|
| `engram_recall` | **first**, on any non-trivial task — returns a priors block to paste into its own reasoning |
| `engram_ingest` | when a task ends, succeeded *or failed* — compresses the trajectory and banks the durable parts |
| `engram_compress` | to hand a long transcript to another model without paying for the whole thing |
| `engram_note` | to bank one fact or strategy directly, no trajectory needed |
| `engram_stats` | how much is banked, and where on disk |
Memory is JSON under `~/.engram-store` (override with `ENGRAM_STORE`). Nothing leaves the machine.
### What Engram banks, and one measured negative result
Two kinds of thing come out of a finished run, and Engram keeps them in separate banks per TMAS:
- *"The auth token lives in `.env.local`"* — a **conclusion**, true about this codebase.
- *"When a test fails on CI but not locally, diff the env first"* — a **strategy**, true about how to work, and reusable on a task that has nothing to do with auth.
Failed runs are worth more than successful ones here. `ingest` turns each failure into an avoid-strategy carrying its root cause, which is the difference between the next session solving something and rediscovering it.
**The honest part.** The obvious argument for the split is that in one undifferentiated pile the codebase-specific conclusions out-match the transferable strategy on keywords and crowd it out of the top-k. I tested that claim against this implementation before writing it down, at 10:1, 13 items, and 200:5 conclusions-to-strategies. **It did not hold.** The single pile surfaced the same strategy, at rank #1 in two of the three runs — because TF-IDF's IDF term already boosts an item whose vocabulary is rare in the corpus, which is exactly what a lone strategy among many similar conclusions looks like.
So the split here buys structural things — a guaranteed recall budget for strategies, the ability to ask for one kind without the other, and fidelity to the paper — and **not** a retrieval win I can demonstrate. Reproduce it yourself: `node bench/two-bank.mjs`. If you find a store shape where the split does win, that is a genuinely interesting issue to open.
## Install
```bash
# zero runtime dependencies; Node 18+
npm install # nothing to build — pure ESM
npm test # node --test
npm run demo # offline, deterministic
```
## Use
```js
import { Engram } from 'agent-engram';
const engram = new Engram({ store: './engram-store' });
// 1. Recall priors before an attempt — inject the block into your prompt.
const priors = engram.recallPriors('Fix the failing checkout test');
// priors.block -> "# Relevant priors from past runs ..."
// 2. Learn from a finished attempt.
await engram.ingest({
goal: 'Fix the failing checkout test',
steps: [
{ type: 'error', content: 'TypeError: total is undefined — cart was empty' },
{ type: 'result', content: 'Guard added: default cart to [] before reducing.' },
],
outcome: 'success',
});
// 3. Or hand Engram the whole loop: it runs N attempts and selects the best.
const { winner } = await engram.solve(
'Fix the failing checkout test',
async (priorsBlock, attempt) => myAgent.run({ context: priorsBlock }),
{ attempts: 3 },
);
```
### Step types
A trajectory is an array of `{ type, content }`. Types: `thought`, `action`, `observation`, `error`, `result`. The compressor routes errors → failures (with root cause), results → artifacts, actions → leads, thoughts → hypotheses.
### Model-backed compression (optional)
By default compression is deterministic and offline. Pass an `llm` to let a model write richer distillates:
```js
const engram = new Engram({
store: './engram-store',
llm: async (prompt) => callYourModel(prompt), // returns the JSON distillate
});
```
## API
| Call | Does |
|---|---|
| `recallPriors(goal)` | TF-IDF recall from both banks → `{ block, conclusions, strategies, tokens }` |
| `ingest(run)` | Compress a run, bank its conclusions + strategies, return the distillate |
| `compress(run)` | Compress only (no banking) |
| `solve(goal, runner, { attempts })` | Run N attempts, tournament-select the winner, learn from it |
| `compressTrajectory(run)` | Standalone trajectory → distillate |
| `MemoryBank` | Standalone two-field TF-IDF memory store |
| `tournament(candidates, judge?)` | RTV selection over distillates |
## License
MIT.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues