v0.3 · MIT · runs on your machine

Agent memory that forgets on purpose

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/umg0
4
tiers
6
MCP tools
0
network calls

Every 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.

  • Claude Code
  • Cursor
  • Hermes
  • Cline
  • Copilot
  • Zed
  • Any MCP client

The problem

Two ways to get memory wrong.

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.

01

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.

02

Too much, and the answers go noisy

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

Four tiers, each with its own clock.

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.

Default retention per memory tier
tierruns outhalves everymax kept
working24h12h50
episodic30d14d500
semantic365d120d1000
proceduralnone730d200
namespace: project:acmeone SQLite file · one writer
  • procedural

    Run prune with dry_run before any destructive pass

    0.94
  • semantic

    Sessions are cookie based, not JWT

    0.91
  • semantic

    Rate limit is per tenant, not per key

    0.72
  • episodic

    Dropped the Redis cache after the p99 came back flat

    0.58

tools

  • retain
  • recall
  • reflect
  • list_memories
  • prune
  • promote_to_skill

Six words an agent already understands. Nothing to learn, and nothing to wire up in your prompts.

Write path

It adds. It only replaces when it is sure.

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.

Default outcome
Keep both rows
On ambiguity
Defer, and log why
Quick clear-out
Every 25 writes
Full clear-out
Up to 3 passes

retain(content, tier?)

  1. 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.

  2. have we heard this before

    It looks for close matches, and only inside the same project. It never reaches across to find one.

  3. then decide what to do

    • it clearly contradictsreplace

      The old one is archived and the trail back to it is kept. Nothing is deleted.

    • it is certainly the samecombine

      The two become one. This needs real confidence, not just a close match.

    • anything elsekeep bothdefault

      Both are kept, and the store writes down why it did not pick one.

  4. 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

Six things decide what comes back.

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 words is not enough.

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.

  • Search runs offline, with no call out to anything while you wait
  • Embeddings are available, and off unless you turn them on
  • Keep each project separate, with a hard wall between them if you want
How much each thing counts when ranking what to bring back: how well the words match 0.32, how much it matters 0.18, how much it has faded 0.18, names in common 0.16, which tier it is in 0.08, how recent it is 0.08.

how much each one counts

fts0.32
how well the words match
importance0.18
how specific and rare it is
decay0.18
how much it has faded
entity0.16
names it has in common
tier0.08
which tier it is in
recency0.08
how long ago it was written

adds up to 1.00, and you can change any of them

Interface

A server, not a service.

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.

  • Seven days of stats, from the command line or from the agent
  • Clear out, compact and list by hand whenever you want to
  • Works with any MCP client, from Claude Code to Zed

.mcp.json

{
  "mcpServers": {
    "umg": {
      "command": "npx",
      "args": ["-y", "@umg0/umg0", "mcp"]
    }
  }
}

$ umg0 stats

$ umg0 prune --dry-run

$ umg0 inspect

Lifecycle

One number decides what survives.

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.

A chart of one memory's decay score across six events. It is written at 0.40, rises to 0.44 when a near-duplicate is folded into it, spikes to 0.67 when it is used twice, falls to 0.47 after 21 days untouched, holds at 0.47 through a clear-out because that is above the line of 0.12, and reaches 0.54 when it is promoted to the procedural tier, at which point the line it is judged against rises from 0.12 to 0.40.
one memory, start to finishdecay score after each event
0.8forgotten below 0.12line rises to 0.40
  1. retain
  2. merge
  3. recall
  4. decay
  5. prune
  6. promote

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

It can look. It cannot touch.

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.

  • The file is opened read-only, behind a layer that refuses every change.
  • There is no edit or delete button anywhere. Not greyed out, absent.
  • It only listens on your own machine, prints the address, and opens your browser.
Inspector docs

$ umg0 inspect

inspector listening on http://127.0.0.1:51734

database ~/.umg/memory.db opened read-only

--demo
Made-up data, held in memory, never written to disk
--db <path>
Look at a particular file
--port <n>
Use a port you pick instead of any free one
--no-open
Do not open a browser
--api-only
Serve the raw data only, for building the UI

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.

A real state, not a mockup: episodic is 62 over what it is allowed to hold, so something there is about to go.

Quickstart

Paste one block. Restart the client.

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/umg0

One 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 ~.

Where it fits

Anywhere context resets.

Coding agents
Project decisions, naming rules, and the fix you found at midnight, still there next session instead of relearned.
Standing instructions
Preferences and constraints that outlive a context reset and follow you between tools.
One codebase at a time
Keep each project separate, so a decision made in one never turns up in another.
Lessons that stuck
Things that keep proving useful get promoted to permanent skills, once they have earned it rather than automatically.

Get started

Give your agent something worth remembering.

One npx command, one config block, one file on your disk. Nothing to sign up for and nothing to cancel.