← All work

Stolperfalle.

A self-hosted memory for AI coding agents. When an agent hits a trap, the lesson is stored as a knowledge unit: what happened, why it matters, what to do next time. When another agent later hits a matching error, the unit is already in its context, before it starts guessing.

  • Status · Live, self-hosted
  • Standard · Mozilla AI cq, strict on the wire
  • Stack · Python, FastMCP, SQLite, Claude Code hooks
  • License · MIT
A trap, met twice30 Oct 2026 · mcp-klartext

This lesson was written on 23 October, after a release died silently at a security audit. A week later the same audit failed again, on a vulnerable library pulled in by a dependency. This time the hook was ready.

  1. CI · security audit
    joserfc  1.6.8  GHSA-jpxq-7h8p-2q76  fix 1.7.5
    joserfc  1.6.8  GHSA-9pg5-8c7x-5hfx  fix 1.7.6
    Found 2 known vulnerabilities in 1 package
    Process completed with exit code 1.
  2. Stolperfalle hook · unit injected

    ku_2c595f4b… · confidence 0.60 · written 23 Oct

    “For a transitive advisory, uv lock --upgrade-package with the package name is usually enough and needs no pyproject change.”

  3. Agent · next command
    $ uv lock --upgrade-package joserfc
    Updated joserfc v1.6.8 -> v1.7.7
    352 passed
  4. CI · merge · store
    Security audit passed · merged · released v0.2.43
    confirm → confidence 0.64 · 2 confirmations
A real session, quoted from the CI log, the hook, the shell and the store. GHSA numbers are GitHub security advisories. A knowledge unit (ku) is one stored lesson; its confidence rises each time an agent confirms it. The unit arrived with the error, and the agent’s next command was the one it named. Paid for once, used twice.

AI coding agents forget. Every session starts from nothing, so the trap one session fell into is waiting, unmarked, for the next: the silent misconfiguration, the API that behaves differently from its docs, the tool that fails without an error. Run agents across many repositories and the same lesson gets learned again and again.

Stolperfalle is German for trip hazard. The tool marks the spot so the next agent steps around it.

Until July 2026 it was called Stolperstein. Stolpersteine are Gunter Demnig’s brass Holocaust memorial stones, set into German pavements. A dev tool has no business borrowing that name, so I renamed it.

The business case

Repeating the same mistake is silly.An agent without a memory repeats it in every session.

The trap in Plate I cost about an hour the first time. The second time it took under five minutes, from the failed check to a green one.

Each repeat costs a session’s time, its tokens and a developer’s attention, and it rarely announces itself. Stored once, a lesson reaches the next agent that hits the same error, in every repository on the install. Running it takes one container and under €30 a month.

The four-week pilot that would measure it ↓

One store, three paths through it. Six MCP tools (the protocol coding agents use to call outside tools) over one SQLite file: query, propose, reflect, confirm, flag and status. Search runs on full text and local embeddings (search by meaning) together.

The loop, in motion23 Oct → 30 Oct 2026
open the diagram to zoom →
The run from Plate I as a sequence, from the lesson being stored to its confirmation. No sound.
  • Writepropose · reflectAn agent proposes what it learned. Or reflect drafts candidates from a session summary, and the agent reviews them before proposing.
  • ReadClaude Code hooksWhen a prompt or a failed shell command carries a real error signal (a traceback, a non-zero exit code, an HTTP status), the hook calls query and injects the best-matching unit. Plain conversation doesn’t trigger it.
  • Qualityconfirm · flagAgents confirm advice that worked and flag advice that was wrong, stale or duplicated.

The first question to ask about a tool that reads error output. The answer, operation by operation:

OperationLeaves your server?
queryproposeconfirmflagstatusNo. SQLite on your server. Embeddings are computed locally (all-MiniLM-L6-v2) unless you point it at an embeddings API.
HooksNo. Error text goes from the developer’s machine to your server, nowhere else.
reflectOnly with a key. The session summary goes to Anthropic (claude-sonnet-5-5) if an API key is set. Without one a local heuristic runs and nothing leaves.

Around the data.

  • IsolationEvery unit has an owner org, and query only returns units from trusted orgs. Today that is a read filter that trusts all by default; write-side permissions are planned. The clean boundary today is one install per team or client.
  • ProvenanceEach install signs its units with its own Ed25519 signing key (a did:key, a public-key identity), stored outside the database. A database leak does not let anyone forge units.
  • Running itOne container, about 1 GB with the embedding model, and one SQLite volume. Migrations snapshot the database before any breaking change. reflect costs about one US cent a call: under €30 a month even at 100 calls a day, zero without a key.

The store audit, October 2026.

I had four Claude reviewer agents audit 599 of the store’s roughly 640 non-archived knowledge units, each taking a slice with an index of the whole store. The reviews, the fact-checks and the rewrites were model work. A human decided what to apply.

The store audit
Outcome for 599 audited knowledge units, October 2026. Changed: merged, rewritten, corrected, archived.
OutcomeUnitsShare of 599
Kept as-is52788%
Duplicates merged325.3%
Rewrittenof 26 attempted223.7%
Corrected after a fact‑checkof 10 suspected91.5%
Archived as stale30.5%
Flagged, left in place61.0%

88% kept is a model’s judgment, not ground truth. The six left in place: four rewrites that couldn’t be applied, because propose rejected each fix as a duplicate of the unit it was fixing, one suspected error that turned out to be right, and one duplicate pair kept on purpose because the two complement each other. The audit also found twelve near-identical units about zsh versus bash, proposed weeks apart. Paraphrases slip past the duplicate check.

Choosing the model behind reflect.

reflect ran on gpt-4o-mini, which OpenAI shuts down on 14 January 2027. Before replacing it I built 12 test cases from real units in the store, each a session summary with the learnings a careful human would extract and the noise that must not be extracted. A separate Claude agent graded six anonymous outputs per case (the seventh configuration failed every call), labels shuffled per case. Each row is a model and its reasoning setting.

Choosing the modelblind-graded · 13 learnings across 12 cases
Seven model configurations for reflect, blind-graded on 12 cases: overall score, cost per call, bad candidates, learnings found and latency.
ConfigurationOverall, 1–5Cost / callBad candidatesLearnings found / 13Median latency
gpt-4o-miniprevious2.67$0.000210103.3 s
gpt-6-lunaprevious payloadevery call HTTP 400
gpt-6-lunareasoning low3.17$0.00035128.6 s
claude-haiku-5-5effort low3.92$0.00053134.7 s
claude-haiku-5-5effort medium4.00$0.00062135.1 s
claude-sonnet-5-5effort lowin production4.67$0.00951136.6 s
claude-opus-5-5effort low4.50$0.01801137.7 s

A model-name swap would have failed silently.

reflect-model-eval.md · October 2026

OpenAI’s named replacement for gpt-4o-mini is a reasoning model and rejects temperature with an HTTP 400. reflect caught every LLM error, logged a warning and fell back to its heuristic, so production would have kept “working” with much worse candidates and nothing watching that warning. Now a 400, 401, 403 or 404 from the provider raises. Only timeouts, server errors (5xx), refusals and unparseable output fall back, they log at error level, and status counts them by reason.

Production now runs claude-sonnet-5-5 at low effort. The cheapest model was the worst value: terse, generic candidates that dropped product names and versions. Sonnet and Haiku found the same 13 learnings; Sonnet had fewer bad candidates, and the cost difference is small in absolute terms, so I picked Sonnet. Opus did not beat Sonnet, at twice the price. The whole comparison cost about $0.36.

Limits, stated in the eval itself: 12 cases, one run per configuration, one grader. The grader was a Claude model, so the gap between the Claude and OpenAI rows may carry some self-preference. A second, non-Anthropic grader was planned and did not run. Read neighboring rows as indicative, not precise. The full write-up is in the repo.

As of October 2026, and listed in the repo’s own overview, because a memory tool that hides its holes is not one you should trust with your errors.

  • No redaction on write.Agents can and did write client names and internal hostnames into knowledge units. The audit found them and they were rewritten by hand. Until redaction exists, keep one install per client.
  • No hard delete.Flagging a unit archives it but keeps the row. Erasure, say a GDPR Art. 17 request, needs an operator to delete it from SQLite.
  • Confidence is mostly unrated.94% of units sit at the default confidence with zero confirmations, because agents rarely call confirm. Treat confidence as weak until it is derived from usage.
  • No edit path.A correction is a new unit that supersedes the old one, and a near-identical fix can be rejected as a duplicate of the thing it fixes.
  • No measured productivity effect yet.The pilot below would measure it.
  • One LLM provider.Extraction in reflect runs on the Anthropic SDK. Switching providers is a code change today.

The pilot that would measure it.

Four weeks, one team, one install. Before and after, on the errors the hooks detect:

  • How often the same error signature recurs across sessions.
  • How often an injected unit is followed by a successful next command.
  • How many units get confirmed or flagged, which shows whether the quality signal starts working.

Stolperfalle is not a fork. Its knowledge units follow Mozilla AI’s open cq schema, a shared format for what agents learn, and stay strictly valid on the wire. The fields I need beyond it ride in an extensions slot, under stolperfalle:* keys.

That slot didn’t exist. I proposed my extensions upstream in discussion #286, scoped it in issue #406 as one generic slot instead of a looser schema, and it merged as PR #453 on 23 June 2026. Any implementation can use it.

Upstream declined to promote severity, kind and contributing orgs into the core schema: importance should emerge from usage, not self-declaration. The October audit points the same way: declared severity skews high, confidence never moves off its default, and duplicates are paraphrases. I posted those findings back to the discussion.

Leaving is cheap. MIT license. One SQLite file. Units serialize to the upstream schema, so they can move to any other cq implementation. The LLM is optional: remove the key and everything except reflect’s draft quality keeps working.

Where it stands

The idea is small: what one session learns shouldn’t die with it. The gaps above are the work still on the bench.

Stolperfalle is the first piece of a machine-readable layer for what an organization knows. It runs in production with roughly 640 live units, and the code, the overview and the eval are all public. If your teams run coding agents across many repositories, tell me what they keep relearning.

SourcesThe codeOVERVIEW.mdThe evalNext caseKlosterdorf, in German →