Uteke 0.21 stopped counting my automation's recall as attention

Session hooks recalling the same context every morning were quietly voting their own queries to the top of my memory store. v0.21.0 separates recall from attention, and the drift stops.

Uteke 0.21 stopped counting my automation's recall as attention

I run several agents against a local Uteke store every day. Session hooks pull project context at the start of almost every conversation, always with similar queries. Version 0.21.0, released October 13, fixed a bias I had half-noticed for months and never named: the memories my automation recalled most were drifting to the top of the pile, not because they mattered most, but because they got asked for most.

The mechanics were simple. Every recall, search and recall_context call bumped the same access_count as a deliberate get. A default fusion recall touched the same memory three times per call, and counted candidates that never made it into the results. Salience scoring read that counter back. The store was, in effect, learning its own query log.

My session hooks made this concrete. The same three or four project-context queries run every morning. Those memories accumulated attention the way a song accumulates streams from sitting on a playlist: not because anyone chose it that day, but because the automation never stopped queueing it. A memory I saved once and consciously retrieved twice could outrank something I rely on weekly, simply because a hook kept asking for the first one.

Version 0.21 splits the counters. Machine recall and search hits now land in a new recall_count field. access_count grows only when something explicitly gets a memory. Scoring blends them with a 0.5 weight on recall, so automation still matters but cannot out-shout deliberate retrieval. Recalls are counted once per call, on the final results only. Old access_count values stay untouched, because splitting them retroactively would mean inventing data. That refusal to fabricate a backfilled history is the detail I respect most in this change.

Any memory system that lets retrieval reinforce salience will converge on its own habits. Recommenders fought this fight years ago; it is the standard exploration versus exploitation problem. A personal memory store is small enough that you never notice the drift, and persistent enough that the drift compounds. Left alone, six months of hooks quietly decide which of your ten thousand memories count as important.

The deletion bug nobody talks about

The same release fixes a bug so mundane it deserves retelling. Id prefix resolution used SQL LIKE matching without escaping, so a forget id of %25 would match every memory whose id contains the characters 25, and delete one if exactly one matched. Percent-encoding met SQL wildcards, and the wildcard won. Ids are now validated as hex, and the HTTP forget endpoint rejects anything outside the expected charset.

MCP over HTTP also got a real access policy. A read-only token used to be locked out of every MCP tool because the endpoint was classified as a write route, while a token that could reach the endpoint could call every tool on it. Tools are gated individually now: read-only tokens get recall, search, list, get and the read-only room tools, and every write tool answers with a tool error.

Supply-chain hygiene ahead of popularity

Third change worth attention: release checksums are now signed with cosign in keyless mode. The certificate binds to the repository's workflow identity, so there is no long-lived key to leak and no web-of-trust ceremony to perform. Most projects with 273 stars ship checksums and call it done. Signing them, and documenting verification in SECURITY.md, is the correct order of operations. The changelog is honest about the remaining gap: the uteke upgrade command does not verify the signature yet.

Deprecation with manners

Namespaces also started their deprecation. Phase 1 is a warning, nothing more: write to a non-default namespace and you get one sentence telling you that rooms, tags and author are the future. Reads and storage unchanged, default namespace responses byte-identical. I keep dozens of legacy namespaces alive in my own deployment, so I appreciate a deprecation that waits for its migration tooling instead of forcing a flag day. Removal lands in a future 0.x release, after the tooling exists.

If you run Uteke and upgrade

A few practical notes. Anything you have that reads access_count now under-counts, because machine recall moved to the new field. Hooks that depended on recall reinforcing importance will notice salience settling down; that is the point, not a regression. The schema migration runs automatically on first open, and a backup before upgrading still costs nothing.

Counting rules are memory policy. Most tools never write theirs down; they let the numbers accumulate however they accumulate. v0.21 writes them into the schema, where they can be argued about. That is the right place for them.

Release: Uteke v0.21.0 | Changelog: CHANGELOG.md