Skip to content

Latest commit

 

History

110 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mimir

PyPI Python License: MIT

Experience-driven memory for autonomous agents. Mimir helps agents learn from their past successes and failures instead of starting from scratch on every task.

Named after Mímir, the keeper of wisdom in Norse mythology.


The problem

Today's agents have memory, but they don't really learn.

Most frameworks store one of two things:

  • Conversation history (LangGraph memory, buffer memory)
  • Vector embeddings of documents (RAG, AGENTS.md, CLAUDE.md)

Both let an agent remember information. Neither lets it remember experience.

Task:     Fix authentication latency
Action:   Added Redis cache
Outcome:  Success

A month later, the agent has no meaningful understanding that this strategy worked. It solves the same class of problem from zero, every time.

Why you need Mimir

If you run agents on real work, you have seen these symptoms:

  • The agent solves the same problem again and again. It fixed a flaky deploy last week, and this week it burns the same tokens rediscovering the same fix.
  • It repeats mistakes. An approach that failed three times gets tried a fourth time, because nothing remembers that it failed.
  • Its knowledge lives in a hand-written file. AGENTS.md and system prompts capture what you told it, not what it learned, and someone has to keep them current by hand.
  • You can't answer "how often does this actually work?" There is no track record behind the agent's choices, so there is nothing to trust, tune, or audit.

Mimir fixes this by giving the agent a track record. Every task it attempts becomes a data point: what was tried, and whether it worked. Then, on the next task:

  • recall() surfaces the most relevant past attempts, successes and failures both, so the agent starts from evidence instead of from zero.
  • recommend() returns the single best-supported action with an honest confidence, a conservative success rate you can threshold on. Reuse the strategy when confidence is high, explore when it is low, and never repeat an action that has only ever failed.
  • Stale knowledge fades. Supersede an experience explicitly, or set a half-life and let old evidence lose weight on its own as the world drifts.

The result is an agent that gets measurably cheaper and more reliable on the task families it sees often, with a memory you can inspect: every recommendation cites the experiences behind it.

And it costs almost nothing to adopt: one pip install, a local SQLite file, no server, no LLM in the loop, and two calls (record after acting, recall/recommend before) wired into the agent loop you already have.

The idea

Instead of storing documents, embeddings, and metadata, Mimir stores experiences:

Problem  →  Action  →  Outcome  →  Confidence  →  Context  →  Time

From a stream of experiences, Mimir reflects, extracts reusable strategies, and recommends actions for new tasks, so the agent gets measurably better over time.

from mimir import Mimir

memory = Mimir()

# Record what happened
memory.record(
    task="Fix authentication timeout",
    action="Implemented Redis caching",
    outcome="success",
    score=0.95,
)

# Recall relevant past experience
past = memory.recall("authentication latency")

# Get a recommended strategy with confidence
strategy = memory.recommend("login timeout")
# -> Strategy: "Redis caching"  |  confidence: 0.80  |  based on 23 successes / 2 failures

How it differs from AGENTS.md / CLAUDE.md

AGENTS.md / CLAUDE.md Mimir
Knowledge type Static, hand-written rules Dynamic, learned from outcomes
Updates Manually edited Updates itself from results
Example "Use FastAPI. Use PostgreSQL." "Redis caching solved auth latency 23/25 times (92%)."
Failures Not tracked First-class: agents stop repeating mistakes

AGENTS.md answers "What should the agent remember?" Mimir answers "How does an agent accumulate experience and become wiser over time?"

Design principles

Mimir is built as a modular monolith Python library, not a microservice swarm or managed cloud product. The library is the product.

  • No LLM and no web server required for v1. Storage, retrieval, and ranking come first. Reflection via an LLM is added later, behind an interface.
  • Pluggable seams. Storage, embeddings, and the write path are interfaces, so scaling up (SQLite → Postgres → async reflection → Redis cache) is a swap, never a rewrite.
  • Derived knowledge is rebuildable. Strategies and reflections are computed from raw experiences and can always be regenerated.
  • Failures are first-class. Learning from what didn't work is treated as importantly as what did.

Architecture

┌────────────────────────────────────────────────────────────┐
│  Public API   Mimir()  .record() .recall() .recommend()     │
├────────────────────────────────────────────────────────────┤
│  Write chokepoint   ──►  [validation / provenance hook]      │   single write path
├──────────────┬───────────────┬─────────────────────────────┤
│  Episodic    │  Reflection   │  Recommendation             │
│  Engine      │  Engine       │  Engine                     │
│  (record/    │  (reflect/    │  (recommend / rank /         │
│   recall)    │   extract)    │   confidence)               │
├──────────────┴───────────────┴─────────────────────────────┤
│  Retrieval layer        (keyword + optional vector hybrid)   │
├────────────────────────────────────────────────────────────┤
│  Storage interface      SQLite (v1) · Postgres (v2) · …      │   pluggable
├────────────────────────────────────────────────────────────┤
│  Embedding provider     none (default) · local · API        │   pluggable
└────────────────────────────────────────────────────────────┘

Data model

Experience
  id, task, action, outcome (success|failure|partial),
  score (0..1), context (json), embedding (nullable),
  created_at, superseded_by (nullable)

Strategy   (derived)  problem_pattern, recommended_action, confidence,
                      success_count, failure_count, source_experience_ids
Reflection (derived)  id, summary, pattern, supporting_experience_ids, created_at

Installation

pip install mimir-learn

The distribution is named mimir-learn on PyPI, but you import it as mimir:

from mimir import Mimir

Optional extras (keyword recall and recommendations work without any of them):

pip install "mimir-learn[embeddings]"  # local embeddings for semantic recall
pip install "mimir-learn[vector]"      # sqlite-vec ANN index for fast vector search
pip install "mimir-learn[mcp]"         # MCP server for Claude Code, Codex, and friends

For development:

git clone https://github.com/AshNicolus/mimir.git
cd mimir
pip install -e ".[dev]"

Requirements: Python 3.10 or newer, tested in CI on 3.10 through 3.14 (Linux, macOS, Windows). Supporting the older end matters for agents, which run on whatever Python their host ships, and 3.10 is still the default on several current Linux distributions. There are no required external services: storage is a local SQLite file, and semantic search is an optional extra.

Quick start

from mimir import Mimir

memory = Mimir(db_path="mimir.db")

memory.record(
    task="Fix login latency",
    action="Added Redis cache in front of session lookups",
    outcome="success",
    score=0.9,
    context={"service": "auth", "language": "python"},
)

memory.record_failure(
    task="Throttle abusive clients",
    action="Added a fixed-window rate limiter",
    reason="WebSocket traffic wasn't handled; limiter only saw HTTP",
)

for exp in memory.recall("authentication is slow", k=5):
    print(exp.action, exp.outcome, exp.score)

print(memory.recommend("login times out under load"))

Give your coding agent a memory (MCP)

Claude Code, Codex, and Cursor start every session knowing nothing about the last one. Mimir ships an MCP server, so any MCP client can record what it tried and consult that track record later, with no code changes on your side. Three steps.

1. Install

pip install "mimir-learn[mcp]"

This adds a mimir-mcp command that serves Mimir over stdio. Your MCP client has to be able to find that command, so if you installed into a project virtualenv, either use its absolute path in the config below or install it globally instead:

uv tool install "mimir-learn[mcp]"    # or: pipx install "mimir-learn[mcp]"

2. Connect your agent

Claude Code (the CLI does it for you; --scope user makes it available in every project rather than just this one):

claude mcp add --scope user mimir -- mimir-mcp
claude mcp list                       # confirm it connects

Codex, in ~/.codex/config.toml:

[mcp_servers.mimir]
command = "mimir-mcp"

Cursor, in ~/.cursor/mcp.json for every project, or .cursor/mcp.json for one. Claude Desktop uses the same shape in claude_desktop_config.json, as do most other clients:

{
  "mcpServers": {
    "mimir": {
      "command": "mimir-mcp"
    }
  }
}

To share one memory across machines or keep separate stores per project, set the path explicitly:

{
  "mcpServers": {
    "mimir": {
      "command": "mimir-mcp",
      "env": { "MIMIR_DB_PATH": "/Users/you/.mimir/memory.db" }
    }
  }
}

3. Tell the agent to use it

Connecting only makes the tools available; the agent still needs to know when to reach for them. Put something like this in your CLAUDE.md, AGENTS.md, or Cursor rules:

Before starting a non-trivial task, call recommend_action for the task, and recall_experiences with outcome="failure" to see what has already failed. After finishing, call record_experience with what you did and how it went, or record_failure with the reason if it did not work.

What the agent gets

Tool What it does
recommend_action The action with the best track record, plus a confidence you can threshold on
recall_experiences Relevant past attempts, filterable to just the failures
record_experience Store what was tried and how it turned out
record_failure Store a dead end with the reason, so it is not repeated
recent_experiences The newest entries, for a quick look at what has been learned
memory_stats How many experiences are stored, and where

The read-only tools are annotated as such, so clients that ask permission per tool only prompt you for writes.

One memory, many tools

Memory lives in ~/.mimir/memory.db unless MIMIR_DB_PATH says otherwise. Point several clients at the same path and they genuinely share it: the store is SQLite in WAL mode, whose locking is per-process rather than per-thread, so concurrent readers and serialized writers work across separate client processes. What Claude Code learns in the morning, Codex has in the afternoon.

If a client reports the server failing to start, it is almost always that mimir-mcp is not on the PATH that client inherits. Run which mimir-mcp (where on Windows) and paste the absolute path into command.

To serve a store with embeddings, a half-life, or a custom backend, build the server in your own process; the Playbook shows how.

Recommendations

recommend() aggregates past experiences for a task and returns the best action. Its confidence is the lower bound of a Beta posterior on the action's success rate from its raw counts (a Jeffreys prior keeps small samples honest), so it reads as a success rate: a 9/10 action beats a lucky 1/1, and the number means the same whatever the query. Relevance and recency steer only which action wins, not the confidence: with weighting on (the default), an action proven on closely matching tasks outranks an equally confident one proven on loosely related ones. Turn weighting off to rank on track record alone:

memory.recommend("login times out under load", weight_by_relevance=False)

Pass explore=True to draw the winner by Thompson sampling instead of always exploiting: promising but less-proven actions win a share of calls, which is how an agent that records its outcomes discovers better strategies over time. Actions that have only ever failed are still never recommended.

By default actions are grouped by normalized text, so "Added Redis cache" and "use redis caching" count as separate strategies. Plug in a clusterer to merge equivalent phrasings and pool their evidence:

from mimir import Mimir, EmbeddingClusterer

memory = Mimir(clusterer=EmbeddingClusterer(my_embedder))

ExactClusterer is the default and needs no embeddings. Any other strategy can implement ActionClusterer.

Hybrid recall and the vector index

Configure an embedder and recall becomes hybrid: keyword (SQLite FTS5) and vector candidates are fused with reciprocal-rank fusion, so an experience can be found by meaning even when it shares no words with the query. Install the vector extra to back vector search with a sqlite-vec ANN index; without it, recall falls back to a Python cosine scan (numpy-accelerated when numpy is installed), so the behavior is identical and only the speed differs.

Query embeddings are cached in a small per-instance LRU, so an agent retrying the same query doesn't pay to re-embed it. Tune it with Mimir(query_cache_size=...), or pass 0 to disable.

Superseding stale experiences

Knowledge goes stale. Mark an old experience as replaced, and it drops out of recall and recommendation by default while staying retrievable by id:

# record a replacement and link it in one call
new = memory.record("auth is slow", "add a read cache", supersedes=old_id)

# or link two experiences that already exist
memory.supersede(old_id, new.id)

Pass include_superseded=True to recall() or recommend() to see superseded rows anyway, which is useful for studying concept drift and decay.

Time decay

Superseding is manual. For gradual staleness, set a half-life so recommend() discounts older evidence: an experience's weight halves every half_life_days, so a recent result outweighs an equally successful but older one. Off by default, which keeps all evidence equal.

memory = Mimir(half_life_days=30)  # evidence from 30 days ago counts for half

The same half-life also reweights recall(): a fresh experience outranks an equally relevant but staler one. Reported counts stay exact; decay only affects ranking.

Roadmap

Phase Goal Status
1: Episodic memory record() / recall(), outcome tracking, SQLite backend ✅ Done
2: Failure memory record_failure(), failures queried separately ✅ Done
3: Reflection engine reflect(): synthesize patterns across experiences (pluggable, LLM optional) ✅ Stored as reflections; does not yet feed back into ranking
4: Strategy extraction Turn experiences into reusable strategies with confidence Planned
5: Recommendation engine recommend(): rank strategies for a new task ✅ Beta-posterior confidence over relevance/recency-weighted evidence, pluggable action clustering (non-LLM)
6: Shared org memory Multiple agents learn from a shared store ✅ MCP server over a shared SQLite file; Postgres backend still future
Hybrid retrieval Keyword + vector recall, optional sqlite-vec ANN index ✅ Done
Reliability Versioned schema with a migration runner; staleness via superseded_by and time decay ✅ Done
Quality eval Labeled recall@k / MRR / recommendation-accuracy gate in CI ✅ Done
Concurrency Per-thread connections so reads scale under WAL, writes serialized ✅ Done
Runtime support Run on the Python versions agent hosts actually ship, across Linux, macOS, and Windows ✅ Python 3.10 and newer

Scaling path

Mimir starts as a single SQLite file and grows by swapping seams, no rewrites:

  1. v1: SQLite, in-process; WAL with per-thread connections so reads scale across threads while writes serialize.
  2. v2: Postgres + pgvector backend for concurrent multi-agent writes.
  3. v3: extract the (slow, batch) reflection engine into an async worker.
  4. v4: Redis cache for hot/recent experiences on the read path.

Status

Beta, and published on PyPI as mimir-learn (the badge above shows the current release).

What works today, with no LLM anywhere in the read or write path:

  • Episodic and failure memory, complete and tested.
  • Recommendations ranked by a Beta-posterior confidence over relevance and recency weighted evidence, with pluggable action clustering, plus an opt-in Thompson-sampling explore mode.
  • Hybrid recall, keyword and vector fused, with an optional sqlite-vec index and a query-embedding cache.
  • Staleness handling through explicit superseding and optional time decay.
  • An MCP server, so Claude Code, Codex, and Cursor can share one memory without any code.
  • Conversation distillation behind a pluggable seam, for turning a finished transcript into an experience.
  • Reflection, reflect(), synthesizing a pattern across a set of experiences behind the same kind of pluggable seam. Stored as a Reflection, and rebuildable rather than authoritative; it does not yet feed back into recall() or recommend().
  • Reliability: versioned schema with a migration runner, concurrent reads under WAL, and a recall@k / recommendation-accuracy gate in CI.

Not built yet: materialized strategy rows and the Postgres backend for multi-agent writes. See the Playbook for a basic-to-advanced guide, or run the whole loop yourself in the demo notebook. APIs may still change before 1.0. Feedback and ideas welcome.

License

MIT

About

Experience-driven memory and learning for autonomous agents.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages