Too little, and it re-asks
Preferences, decisions, and hard-won corrections die with the context window. You explain the same architecture on Monday that you explained on Friday.
Your coding agent starts every session from nothing. umg0 gives it a memory that holds on to what keeps proving useful and lets the rest fade, so it stops re-asking without drowning in stale context. Four tiers, six MCP tools, one SQLite file on your machine.
npx -y @umg0/umg0Every memory fades as it ages, and how fast depends on what kind it is. Scratch notes are gone within a day. Things your agent keeps proving are still there years later. Anything that drops below the line is forgotten, unless something recalls it first. These are the real decay curves, at the settings umg0 ships with.
The same server everywhere. Only where the config lives changes.
The problem
Forgetting everything and remembering everything look like opposite problems. They have the same cause: nothing is deciding what a fact is worth, or how long it should stick around.
Preferences, decisions, and hard-won corrections die with the context window. You explain the same architecture on Monday that you explained on Friday.
Pour everything into one flat store and every question drags back a decision that was reversed a month ago. You pay for the tokens and get a worse answer.
The model
A memory is more than the text in it. The moment it is written it gets a tier, a score for how much it matters, and a date it runs out. Scratch notes are gone tomorrow. A lesson your agent learned the hard way never runs out at all.
| tier | runs out | halves every | max kept | |
|---|---|---|---|---|
| working | Current task scratch | 24h | 12h | 50 |
| episodic | What happened in a session | 30d | 14d | 500 |
| semantic | Facts, preferences, decisions | 365d | 120d | 1000 |
| procedural | Skills and lessons | none | 730d | 200 |
Run prune with dry_run before any destructive pass
Sessions are cookie based, not JWT
Rate limit is per tenant, not per key
Dropped the Redis cache after the p99 came back flat
tools
Six words an agent already understands. Nothing to learn, and nothing to wire up in your prompts.
Write path
A store that is quick to combine things is a store that loses facts. Throwing one away here takes real confidence that it says the same thing as something already saved. Anything short of that and both are kept, along with a note saying why it did not choose.
retain(content, tier?)
how much does this matter
How specific and how rare the content is sets a score. Anything below the bar for its tier is turned away rather than saved.
have we heard this before
It looks for close matches, and only inside the same project. It never reaches across to find one.
then decide what to do
The old one is archived and the trail back to it is kept. Nothing is deleted.
The two become one. This needs real confidence, not just a close match.
Both are kept, and the store writes down why it did not pick one.
save it, then tidy up
It lands with its tier, its score, and its expiry date already set. Every 25 writes, a quick clear-out runs behind it.
Recall and interface
v0.3 does one thing on purpose. Everything is stored locally, behind an interface clean enough to swap later. Spreading memories across hosted providers is not on the roadmap yet, and the README says so too.
Recall
Matching the text counts for the most, but an old memory that matched perfectly still loses to a fresher one that matched well. How much it matters, how much it has faded, which tier it is in, how recent it is, and which names it mentions all move it up or down. Every one of those is yours to change.
how much each one counts
adds up to 1.00, and you can change any of them
Interface
It runs on your machine, right next to your agent, and writes to one SQLite file. No account, no API key, nothing to keep paying for. The same command is a normal CLI when you want to look around yourself.
.mcp.json
{
"mcpServers": {
"umg": {
"command": "npx",
"args": ["-y", "@umg0/umg0", "mcp"]
}
}
}$ umg0 stats
$ umg0 prune --dry-run
$ umg0 inspect
Lifecycle
Every memory carries one score, and everything the system does moves it. Combining two lifts it. Being used lifts it. Sitting untouched pulls it down. A clear-out is just the moment that score gets checked against the line. Watch one fact go all the way through.
It is written, a near-duplicate is folded into it, it gets used twice, it sits untouched for 21 days, a clear-out checks it against the line, and it is promoted. Only the last of those changes the line itself.
The scores above are not made up for the picture. They are what umg0 actually works out for this exact sequence, at the settings it ships with.
Inspector
Deciding what to keep is the part of a memory system you never see, which is exactly why it goes wrong quietly. One command opens a window on it, and it is safe to point at a file your agent is using right now.
$ umg0 inspect
inspector listening on http://127.0.0.1:51734
database ~/.umg/memory.db opened read-only
Nearly empty store? --demo builds a throwaway set with near-duplicates, contradictions and stale entries planted in it, so every decision the system makes has something to show you.
~/.umg/memory.db
62 over cap · eviction pressure
The inspector never writes to your memories.
A real state, not a mockup: episodic is 62 over what it is allowed to hold, so something there is about to go.
Quickstart
There is no migration and no signup. Point your agent at the server, restart it, and the six tools show up. Node 20 or newer is the only requirement.
Install
npx -y @umg0/umg0One writer per database file. Point every client at the same server command rather than running several against one SQLite file.
{
"mcpServers": {
"umg": {
"command": "npx",
"args": ["-y", "@umg0/umg0", "mcp"],
"env": {
"UMG_LOG_LEVEL": "info"
}
}
}
}
// Same block for Claude Code, Cursor, Cline, VS Code, Zed.
// Only the config file location differs.
//
// Installed globally: "command": "umg0", "args": ["mcp"]
// From a clone: "command": "node",
// "args": ["/absolute/path/to/umg/dist/index.js", "mcp"]
//
// Use an absolute path. Most hosts do not expand ~.# Package @umg0/umg0, binary umg0.
npx -y @umg0/umg0 retain --content "Sessions are cookie based" --tier semantic
npx -y @umg0/umg0 recall --query "sessions"
npx -y @umg0/umg0 stats
npx -y @umg0/umg0 prune --dry-run
npx -y @umg0/umg0 inspect
# Faster cold start:
npm i -g @umg0/umg0
umg0 recall --query "sessions"
# From a clone:
npm i && npm run build && npm i -g .# Session start: pull context before doing anything.
recall(query: "project + task + entity names",
namespace: "project:acme")
# Mid session: only durable things.
retain(content: "Rate limit is per tenant, not per key",
tier: "semantic")
# Session end: write back decisions and corrections.
reflect(text: "Decision: ...\nCorrection: ...\nPreference: ...")
# Periodically, dry run first.
prune(dry_run: true)
promote_to_skill(dry_run: true)Where it fits
Get started
One npx command, one config block, one file on your disk. Nothing to sign up for and nothing to cancel.