Closet: the compressed summary that recall actually reads
2 min read
A closet is a compressed summary of several drawers, and it is what recall reads.
export interface Closet {
id: string; roomId: string;
summary: string;
drawerIds: string[];
tier: MemoryTier;
tokenCost: number;
}
Three fields worth noticing
drawerIds — the summary knows what it summarised. Compression is a pointer
rather than a replacement, so a suspicious summary can always be checked against
the verbatim source.
tokenCost — a declared price. Recall operates against a budget, and a
summary that does not know its own size cannot be selected against one. This is
what makes "give the planner 2000 tokens of memory" a decidable question rather
than an estimate.
tier — how deep this sits. Cheap, always-included context is one tier;
expensive, only-on-demand context is another.
Why the summary is the read path
Recall reads closets, not drawers, because the drawer is the whole original and including it would consume the entire budget on one item.
That makes closet quality the ceiling on memory quality. A perfect archive of drawers with poor closets recalls badly, and no amount of storage fixes it — which is why the write-only gap matters: a system producing drawers and no closets has an archive it cannot use.
Tiers and the budget
tier exists because not all recall is worth the same price. A cheap tier can
be included on every plan; an expensive one is fetched only when a topic hint
justifies it.
The practical effect is that memory selection becomes a knapsack problem with declared weights rather than a heuristic. Given 2000 tokens and a set of closets that each know their cost, "what fits" has an answer.
Without tokenCost the same question is answered by guessing, and guessing
under-fills the budget when it is cautious and overruns the context window when
it is not.
