-
Notifications
You must be signed in to change notification settings - Fork 2
Recall
A turn reads about thirty messages of a desk whose log is unbounded. Everything older is, from that turn's point of view, gone — including the decision the room settled two hundred messages ago, which is why it gets re-litigated and sometimes answered differently the second time.
Enlarging the window moves the cliff without removing it, and charges every participant for it on every turn. Worse, it does not buy what it looks like it buys: Lost in the Middle reports a U-shaped curve, where a fact in the middle of a long input is used less reliably than the same fact at the edge of a short one. A bigger window relocates the problem into its own middle.
Recall does the other thing: it makes the transcript queryable, keeps a small pinned working set arriving regardless, and states the budget each message is spending.
Three mechanisms, no new port, no new stored state.
Recursive Language Models (Zhang, Kraska & Khattab, MIT CSAIL) makes the same move on a single prompt. Instead of feeding a model a long context as a prefix, hold the context in a REPL as an environment and let the model write code to inspect it, chunk it, and recursively call itself over the parts that turn out to matter. It handles inputs two orders of magnitude past the window — and, more usefully here, beats base models and long-context scaffolds on prompts that would have fit, at comparable or lower cost per query. Querying a context can beat holding it even when holding it was an option.
A desk already has the environment. The host's append-only log is right there
behind SessionLog, and what was missing was a way for a turn to interrogate
it rather than receive a prefix of it. That is all search_messages,
search_threads and select are: the query, and an ordering over what comes
back, returned as addresses plus excerpts so a turn decides what is worth
reading in full.
Three things do not carry over, and are worth being explicit about:
- No recursion. The caller here is an agent taking one turn. A fold that could call a model would be a port, and the charter puts ports in the host.
- No index. Search is a bounded backward walk over the port everything else uses, honest about its bound. An index would be a second store, which the charter's first rule forbids.
- No quality claim. Those results are on retrieval-shaped single-prompt benchmarks. A deliberation is not a retrieval task, and nothing measured there says a room decides better — the same discipline the Benchmarks page applies to every other mechanism this library borrowed.
Pinning has no analogue in the paper at all, and the reason is the interesting one: a single prompt has nobody else to lose a message on. A shared desk does, so a small set of messages is made to arrive whether or not anybody queried for them.
Everything that picks — agents, people, desks, threads, messages — ranks
through
select,
so an agent search and a desk search cannot disagree about what a better match
is.
A match falls in a tier, and the score is that tier's base plus a density term worth at most 100:
| tier | base | what it means |
|---|---|---|
Exact |
1000 | the text is the query |
Prefix |
800 | the text starts with it |
WordPrefix |
600 | it starts a word inside the text |
Substring |
400 | it appears somewhere |
Subsequence |
200 | its characters appear in order |
Tiers are 200 apart, so density orders candidates within a tier and never promotes one past another. All of it is fixed-point integer arithmetic: the same snapshot and query always produce the same list, on any machine.
use tinyhivemind_core::{find, select::SELECT_LIMIT};
let hits = find::agents("naka", &roster, SELECT_LIMIT);
let desks = find::desks("shipping", &desks, SELECT_LIMIT);A candidate's label and id are matched at full weight and its description at half, so a desk named for the query always outranks one that merely mentions it.
Pickers work off snapshots the turn already holds. Searching messages has to
wait on a read, so it lives behind the SessionLog port in
search.
use tinyhivemind::{SearchQuery, search_messages};
let query = SearchQuery::new("rate limiter")
.in_conversation(conversation)
.by_author("alice");
let hits = search_messages(&log, &query).await?;A hit carries the row's address, its author, its thread parent, and a whitespace-collapsed excerpt around the match — enough to decide whether to go read the row.
Two things differ from projection, deliberately:
- A desk-scoped search reads the desk's whole interior, thread replies included. The projection is narrow so a turn stays readable; the search exists precisely to reach the reply buried three deep.
-
Reaching the scan bound is success, not failure. A search walks at most
2048 raw rows and is honest about it, exactly as
project_sessionis.
search_threads ranks a desk's threads by their opening words, bounded the way
the thread index is, because which threads are live is a recency question.
A query written /…/ is an expression rather than a literal — one input box,
two intents. It needs the crate's regex feature, which is off by default.
let hits = search_messages(&log, &SearchQuery::new("/^ship(ped)?\\b/")).await?;An expression hit is read onto the same tiers, from the span the engine
matched: covering the whole text is Exact, at offset zero is Prefix, at a
word boundary is WordPrefix. So expression hits and literal hits rank in one
comparable list.
Without the feature, a Regex pattern is Error::RegexUnsupported; one that
does not compile is Error::InvalidPattern. It never quietly falls back to
searching for the expression source as text, which would return confidently
wrong results.
Search makes an old message reachable. A pin makes it unavoidable.
!pin [^N] [#label] [free text]
!unpin ^N
!pin with no target pins the message carrying it — an agent marking the
insight it just wrote. !unpin requires a target: a marker that removes
something has to say what, and an incomplete one yields nothing at all, the
same fail-closed rule the trace grammar uses.
The board is a fold over the log, not a record beside it. That is the charter's first rule: there is no second journal to keep consistent with the first, and a host that already stores the transcript stores the pins for free.
use tinyhivemind::{PIN_LIMIT, read_pinboard};
let board = read_pinboard(&log, &conversation, PIN_LIMIT).await?;- Later markers win: pinning something already pinned updates it rather than duplicating it.
- The board holds twelve, most recently pinned first. Over that, the least recently pinned drops — a full board means something has to come off, and the oldest pin is the one the room stopped arguing about.
- A desk board looks inside threads. A pin exists to lift a message out of the depth it is buried at.
SessionContext carries the board and initialize_session_with_context reads
it, so a pinned message is in every turn's context for that conversation
whether or not anybody searched for it.
The window is a shared resource. An agent that writes six paragraphs pushes five other messages out of everybody's view, sometimes including the one that answered the question.
TeamBriefing carries a BrevityPolicy — 600 characters against a 30-message
window, by default — and states it in the briefing text next to the pin and
search spellings, so an agent knows what it is spending.
overrun(content) reports the characters a message goes over by. It is
reported, never applied: nothing here rewrites an authored message, because
a transcript that disagrees with what was said is worse than a long one.
-
docs/specs/recall.md— the full specification, including what is deliberately not here. -
docs/research/long-context.md— position bias, context rot, and what was and was not borrowed from RLMs. - Further reading — every mechanism, and where it came from.
- Threads — the other answer to a busy desk.
- Transcript projection — the window recall works around.
tinyhivemind is GPL-3.0-only. Built by @senamakel.
Start here
The algebra
- Shared medium
- Desks and rosters
- Mentions
- Cross-desk referral
- Transcript projection
- Threads
- Recall
- Responder ladder
Hive mechanics
Working on it
Reference