stella memory

View, edit, promote, or retire your project's memories, all from one command.

stella memory lets you see your project's memories, sorted by how often they're cited, along with how useful and how true each one has turned out to be. You can promote a proven memory to a project rule, retire one that stopped being useful, or mark one as wrong so it never comes back. This command only reads local files. It doesn't need an API key.

See Memory for how memories, reflections, and the code graph fit together.

Synopsis

stella memory <list|edit|promote|validate> [args]
stella memory <retire|reaffirm|retired> [args]
stella memory <forget|restore|forgotten> [args]
stella memory <compact|index> [flags]

What it does

Memories are Markdown files you write by hand. Each one has a stable ID. When stella recalls a memory and hands it to the model, it also records whether that memory turned out to be useful and true. Those records add up into a usefulness score and a truthfulness score for each memory. stella memory is how you view, edit, and manage that whole process.

Subcommands

stella memory list

List memories ranked by how often they're cited, along with their average usefulness, how often they turned out true, and whether they qualify to become a rule.

stella memory list
stella memory list --format json

--format can be text, the default, shown as an aligned table, or json. The JSON output has a schema_version field followed by the rows.

stella memory edit <id> <text>

Rewrite a memory in place. This creates a new version of the same memory — it doesn't create a separate one.

stella memory edit nod_9f2c1a "the store API takes a workspace root, not a db path"

The old text is kept as history, not as a second, separate memory. There's one live record with one ID, and stella stops recalling the words you replaced.

Each edit leaves behind the old version's embedding vector, since nothing points to it anymore. stella memory compact cleans up rows like this, so if you edit memories often, running compact once in a while helps the most.

stella memory promote <id>

Promote a qualifying memory to a project rule, saved at .stella/rules/<slug>.md. Pass the memory's ID, shown as nod_… by stella memory list.

stella memory promote nod_9f2c1a

A memory only qualifies after being cited successfully more than 10 times in a row since its last negative mark. One negative citation resets that count back to zero.

stella memory validate

Check old memories against your current code. stella scans each memory for file paths it mentions, for example crates/stella-cli/src/agent.rs, and checks whether those files still exist. If a memory's file is gone, that's a strong sign the memory is about deleted code, and it could mislead you.

stella memory validate

It also checks the anchor edges written by the reflection loop. When a lesson mentions a file, stella records that as an observed_in edge in the code graph. That means a question like "what do we know about registry.py" can be answered by following real edges in the graph, instead of guessing from similar text.

stella memory validate --end-stale

--end-stale marks anchors that point to deleted files as invalid. This is the only thing this flag changes, and it's more limited than it sounds:

  • The memory is not retracted. It wasn't wrong; the file just went away. as_of queries still return it, and stella memory list still shows it.
  • Only the edge's current validity ends. Live recall stops using that edge, but a question like "what was true last March" still gets answered correctly.
  • Running it twice is safe. The second run reports no change instead of moving the date the file disappeared.

stella only writes an anchor for a file that exists when the lesson is learned. If a filename matches more than one file, like mod.rs, stella skips it instead of guessing. A wrong edge would teach the graph something false. A missing edge just costs a little accuracy later.

Retiring and forgetting

These are two different tools for two different situations. Picking the wrong one is the most common mistake here.

retire: it's not helping anymore

The memory isn't wrong. It just stopped helping. stella stops selecting it automatically, but you can still pull it up directly by ID. Undo this with reaffirm.

forget: it was wrong

The memory should never come back. This writes a tombstone, which also stops the reflection loop from learning a reworded version of the same thing later. Undo this with restore.

Three rules

These rules apply everywhere in this section. They don't change with future updates:

Retirement is reversible

You can undo any retirement with stella memory reaffirm <id>. The retirement record stays in the log. The later decision outranks it instead of erasing it, so you can always answer "why did this come back?"

Nothing is ever deleted

A retired record is skipped by automatic recall, but you can always look it up by ID. stella works out selection health from permanent use and feedback records, and can rebuild it exactly every time. Nothing here is a counter that can drift out of sync.

The agent cannot talk itself into forgetting

When the agent itself reports on a citation, that feedback is tagged agent_self_report. This tag is never allowed to trigger a retirement on its own. It can factor into selection health, but it can't retire anything by itself.

The third rule is the easiest one to accidentally break with a well-meaning change. If a self-report could retire the memory it's about, that creates a loop: the model misreads a memory, reports it as unhelpful, the memory gets retired, and the evidence that the model misread it disappears. stella closes that loop on purpose.

Only one place in the code decides this: the check that says whether a given feedback method is allowed to retire a record. Retirement requires a person's judgment or another reliable source. If you're adding a new kind of feedback, that's the one check to update, and self-reports should never be let through it.

stella memory retire <id> --reason <why>

Stop stella from selecting a memory automatically. You can undo this later.

stella memory retire nod_9f2c1a --reason "the API it describes was replaced in 0.6"

--reason is required. An empty reason is rejected, because a retirement needs a clear cause you can look back on later. Citations alone can't retire a memory, so a person's judgment is the strongest evidence stella currently has. The loop shows its work, and you make the call.

Some records can't be retired at all:

blocking

A rule marked Blocking.

user-confirmed

A record a person confirmed. This checks the action, not who did it: a system auto-activation doesn't count as confirmation, so it can still be retired.

published

A record that has already been published.

already retired

You can't retire something twice. stella refuses rather than logging it again.

stella memory reaffirm <id>

Put a retired memory back into automatic selection.

stella memory reaffirm nod_9f2c1a
stella memory reaffirm nod_9f2c1a --reason "still the only note on the legacy path"

--reason is optional. If you skip it, stella records "reaffirmed by the user". If a memory was never retired, reaffirm refuses rather than logging anything, so the log never claims a reversal that didn't happen.

stella memory retired

List what this workspace stopped selecting, and why.

stella memory retired

Each row shows the reason you gave, the evidence behind the decision (how many uses were rated unhelpful, out of how many total, across how many different tasks), and the exact reaffirm command to restore it. The output is always sorted the same way, so running this twice gives you the same result.

stella memory forget <id>

Stop a memory from steering the agent, and stop the reflection loop from learning it again.

stella memory forget nod_9f2c1a
stella memory forget nod_9f2c1a --reason "superseded by the new store API"

This writes a tombstone. It does not delete the memory, and that difference matters. The reflection loop reads your session log for lessons and can record a reworded version of something it already learned. If stella just deleted the row, the same memory would grow back under a new ID within a few sessions. The tombstone blocks that at both points where a new lesson could enter: when a lesson is first recorded, and when session logs are mined into skills.

--reason is optional, and stella memory forgotten shows it later. Write one anyway. Months from now, you'll probably be the one deciding whether to restore it.

forget hides a memory. It does not remove the text from your disk. The original row stays in .stella/private/context.db. forget also copies the full text into the tombstone record, and keeps that copy forever. If a memory holds something you want gone, not just hidden, forget alone will not do that. You would need to edit context.db by hand.

stella memory restore <id>

Remove a tombstone. The memory can be recalled again, and stella can learn it again too.

stella memory restore nod_9f2c1a

stella memory forgotten

List this workspace's tombstones: what was forgotten, when, and why.

stella memory forgotten

forget is reversible, and validate mostly just reports, it doesn't change anything on its own (aside from --end-stale). Neither one destroys data. Together, they're how you clean up a memory store that's drifted: use validate to find memories pointing at deleted code, and forget for memories that turned out to be wrong, not just outdated.

Maintaining the store

These two commands work on .stella/private/context.db, the index recall uses behind the scenes. They don't touch the memories themselves. Neither one is required for stella to work correctly; they're both about performance.

stella memory compact

Free up space by removing derived index rows whose original memory is already gone.

stella memory compact --dry-run
stella memory compact
stella memory compact --stale-fingerprints --vacuum

Two kinds of rows qualify: embedding vectors that no memory, node, or episode points to anymore (every stella memory edit leaves one of these behind), and tags pointing at missing rows.

Compacting never touches memories, episodes, facts, or forget tombstones. Queries about a specific point in time give the same answer before and after a compaction, which is why it's safe to run on a schedule.

--dry-run

Report what would be reclaimed without deleting anything.

--stale-fingerprints

Also remove vectors written by an embedding model you're not using anymore. Recall already ignores these, so removing them frees space now. If you switch back to that embedder later, you'll need to re-embed everything.

--vacuum

Run VACUUM afterward to give freed space back to the filesystem. stella also does this automatically after a large compaction.

stella memory index

Build an approximate-similarity index, called IVF, that recall can use instead of checking every stored memory on every turn.

stella memory index --dry-run
stella memory index
stella memory index --drop

You need to turn this on in two places: this command builds the index, and the setting context.retrieval.ann_enabled in settings.json is what lets recall actually use it. An approximate index only checks part of your memories, so it can miss something an exact search would have found. That's why neither part is on by default.

--dry-run

Report what would be built without writing anything.

--drop

Remove the index. Recall goes back to checking every memory exactly, which is what it does by default anyway.

Neither command creates a database file just because you ran it. If a workspace has never been indexed, stella reports that there's nothing to do, instead of creating an empty context.db file.