Uteke 0.17: memory that shows its work

Uteke 0.17.0 adds explainable recall, an auditable supersession ledger, and a contradiction benchmark: stale facts polluted 100% of top-5s until supersede dropped stale@5 to 0.000.

Uteke 0.17: memory that shows its work

Uteke 0.17.0 shipped on September 6, 2026. Uteke is a local-first memory engine for AI agents: a single Rust binary, no API keys, no cloud, Apache 2.0. It has 238 stars on GitHub as of this writing. This release is about trust. Recall can now explain itself, conflict resolution became an auditable ledger, and the graph stopped reporting memories that no longer exist.

The problem: memory makes decisions nobody can see

Every recall call makes judgment calls. Which memory ranks first. Which ones drop out of the top 5. When two stored memories contradict each other, which one the agent quotes. None of that was visible before. When an agent answered with a stale fact, you could not tell whether the ranking failed, the store held a conflict, or the query was vague. Debugging meant guessing.

Explain recall: the ranking, signal by signal

The headline feature is explain mode on every recall surface. Run uteke recall "deploy window" --explain and each result comes back with its vector similarity and rank, its FTS rank, the RRF score with per-channel fusion contributions, and the deltas from jaccard, salience, recency, and graph boosts. The same mode exists on POST /recall ("explain": true) and on the MCP uteke_recall tool.

Two design details matter. The explanation replays the exact pipeline the query used, with the same channel depths, RRF constants, and boost order, and it bypasses the recall cache. So the explanation always describes the results you got. The cost is about 50ms, the same as a cold recall, since the query is embedded once. FTS5 explanations work without an embedder at all.

Conflict resolution you can audit, and undo

Agents accumulate contradictions. The project moved on, the docs changed, the migration finished, and the old fact is still in the store. Version 0.17 makes resolution explicit. uteke supersede <old> <new> --reason retires the stale memory and names the winner. Supersessions are now a first-class ledger instead of a side effect: uteke contradictions list shows superseded-but-not-restored memories with the winner, reason, and timestamp, and uteke contradictions undo restores a retired memory and records the undo on both sides.

Provenance joins the schema (v18, additive). Every memory records a SHA-256 of its content at write time, and timeline events record an actor and evidence. uteke provenance <id> returns the full report: trust tier, hash comparison against live content, and the event chain. Audits recompute the hash instead of trusting the row.

There is a measurable payoff. The contradiction segment added to benchmarks/longmemeval/RESULTS.md builds a 40-topic store where each topic holds a stale fact, a winner fact, and three distractors, then asks "which X does this topic use now". With both facts active, the stale fact sat in the top 5 for 100% of topics on every search strategy, including fusion. After one supersede per topic, fusion winner@1 went from 0.850 to 1.000 and stale@5 dropped to 0.000 on every strategy. The segment is synthetic and deterministic. It measures the resolution pipeline, not dataset recall, and the script that produced the numbers ships in the repo.

The rest of 0.17

  • Namespace management: move a memory with PUT /memory, rename or merge namespaces, delete with an explicit strategy (refuse, merge, or deprecate). CLI parity with uteke namespace move|rename|delete, and delete requires --confirm.
  • POST /list pagination metadata: "include_meta": true returns {memories, total, has_more, next_offset} so clients stop blind-paginating with 100-row guesses. The default response is unchanged and existing clients are untouched.
  • Graph fixes: GET /graph no longer returns nodes whose parent memory was forgotten or deprecated, and memory nodes get readable labels (a content preview) instead of raw UUIDs.
  • Fixed: POST /graph/edge resolved memory IDs to graph nodes instead of failing with a 500 on valid input.
  • Official binaries now ship both vector engines (usearch and vecq) in one build, selected at runtime.

Upgrade

Install or upgrade with:

curl -sSL codecora.dev/uteke/install | sh

Prebuilt archives are on the releases page. The /list default response is unchanged, so existing clients keep working without changes.

Repo: github.com/codecoradev/uteke. Every benchmark number above comes from benchmarks/longmemeval/RESULTS.md, and benchmarks/longmemeval/contradiction_segment.py reproduces the segment locally.