zero-memory
Guides

Briefings

How sessions open with the right context, and how the briefing pack is composed, budgeted, and kept free of noise.

A briefing is a context pack that zero-memory assembles for the start of work: standing rules, the most relevant memories for a topic, the entities involved, live relations between them, recent changes, and open loops. It is produced by the build_context MCP tool called with briefing: true, so an agent gets its working context in one call instead of many recalls.

Why context is pushed, not requested

The rule "memory first, before code search or the web" is easy to state and easy to forget. Briefings make it mechanical: context unfolds by itself at the moments it matters, instead of depending on agent discipline. And because a briefing is injected context rather than conversation, every token in it competes with the task itself, so the pack has to be ranked, budgeted, and noise-free.

Session and task briefings

Two briefing kinds cover two different questions. A session briefing answers "where are you": at session start, a hook briefs on the current project (and, where applicable, the working-branch topic) and injects the pack as additional context.

A task briefing answers "is anything still missing": on the first substantive prompt of a session, a hook calls build_context for the project and injects whatever the session briefing did not already deliver. It is the second chance for a session whose start briefing failed — that call is where the project scope and the conversation's thread token are recovered — and the second delivery for standing rules that missed the context window.

The prompt itself never leaves the machine. It decides only WHETHER the briefing is worth spending: short prompts, common one-word confirmations, and slash commands are skipped without any server call. They still carry the next piece of the briefing's remainder, read from local state (see The rest of the briefing follows by itself). What to ask about is not taken from it: subject-specific retrieval is the agent's own recall, in English, per the tool contract.

Task briefings fire once per context window (see below), keyed by session id in a local state file. A client without a per-prompt context channel skips task briefings entirely. The session briefing and mid-session recall still apply; see Client adapters.

The two kinds deduplicate on the client: the session hook records which memory ids it injected, and the task hook filters those out of its own pack, so the same memory never arrives twice.

A context window ends at a compaction, which condenses the conversation and discards everything the hooks injected into it. What a window carried is then owed again, and which parts come back depends on the client:

  • Standing rules and the task briefing re-arm on every client that reports the boundary. The task briefing also stops leaving out what the old window had been given, so its memories and open loops come back with it.
  • The session briefing also comes back on Claude Code, which re-fires its session-start hook, and on Hermes, whose plugin sees that its session briefing has left the replayed context.

See Client adapters for how each client reports the boundary.

Stored content is canonical English, so an English topic retrieves best. The server never translates a topic to get there: what a caller sends is what is searched. Writing the topic in English is the caller's job, and the tool contract says so.

Both hooks are best-effort and never block the client. A successful session briefing is cached per project; if the server is unreachable later, the hook serves the last cache entry with an explicit OFFLINE header and timestamp, up to 7 days by default (ZM_BRIEF_CACHE_TTL_DAYS). Even with no usable cache the hook still states what it knows locally: the project line persisted for this repository, so the session is never left guessing its project. Writes are never queued offline. Each live briefing also emits a metering event tagged with its kind, so session and task hit-rate can be tracked separately. See Value metering.

Project attachment and the session thread

The briefing is also how a session learns where it is. The session hook resolves the project from the working directory and leads the injected pack with a PROJECT: line naming the resolved scope, instructing the agent to pass project_hint on its first memory call. The briefing call itself carries that hint, which pins the reads and attaches the agent's MCP session to the project: later scope-less writes land there, and a write from a session that never attached is refused rather than mis-filed (see Scopes and isolation).

A briefing that carries a conversation id also mints a durable thread: the pack returns session: { attached_project, thread }, and the task hook re-states PROJECT: … · THREAD: … on every user message — deliberately above its early returns, so even a session restored mid-conversation, or one whose context was compacted, is re-told its project. The two halves are stored differently, and the difference matters: the resolved scope is shared by the repository and persists across sessions, while the thread token belongs to one conversation and is kept with that session's own state. A repository routinely has several sessions open at once; a token held per repository would be overwritten by whichever briefed last, and the others would then quote a conversation that is not theirs. A session that has not resolved a token yet is told its project alone. No token is the honest state. The hook's assertion wins over a stale echoed thread when the working directory disagrees. Clients without a per-prompt channel lose this line along with task briefings; for them, attachment rests on the session briefing and the tool results' session state.

Echoing the thread is not the same as naming the project, and the line says so because the difference is easy to miss. project_hint answers where knowledge belongs; the thread answers which conversation produced it, and on a write it is what stamps the stored memory with its birth conversation. A remember that passes only the hint lands in the right project and records no conversation at all, an absence no later pass can reconstruct, which costs exactly the questions the marker exists to answer ("what did this conversation produce", "were these facts born in one reasoning", "is this a refinement or a drift").

How the pack is composed

The pack has several legs:

  • Standing rules: promoted General rules plus rules addressed to the briefed project. rules[] carries { text, pinned } objects, pinned first. Pinned rules are exempt from the 12-rule unpinned cap and the 90-day delivery TTL. Hook-capable clients render them above the JSON pack as an imperative STANDING RULES section. Within the hook's channel budget that section has its own ceiling: pinned rules always arrive in full, the others in full while they fit and by their headline after, with a line saying where their full text is.

  • Memories: top-ranked hits for the topic, scope-isolated by default. A briefing with no resolvable project narrows to the personal root and core scope rather than assembling from every visible scope, because "everything you have ever touched" is not a working context. Point reads (recall, entities) keep the wide degrade, and scopes: ["*"] is honored verbatim.

  • Linked memories: memories reached through the graph, from two sources sharing one cap. Most arrive by entity co-mention, scored with the same ranker as the hits. A small reserved share is claimed by typed-link neighbours of the hits — what supersedes or contradicts a hit, what it was derived from, what its author linked to it — ranked among themselves and followed in both directions. The reservation displaces entity co-mentions rather than enlarging the leg, and an unused reservation returns to the entity source, so a corpus without links yields the pack it always did. The leg excludes the lifecycle kinds (episode, task, open-question; loops have their own leg) and caps long content, marking truncated entries.

  • Entities and edges: entities are collapsed by normalized name; edges drop self-loops and below-threshold weights.

  • Recent, briefing mode only: a handful of live decisions, facts, gotchas, and conventions from the last two weeks, selected by recency and independent of topic similarity. This is the "what changed since your last visit" leg, deduplicated against the memories leg. It takes authoritative writes only (the watcher's provisional captures do not qualify), and its scope restriction keeps another project's freshest memory out of an unpinned briefing. Window and size are instance-tunable.

  • Open loops: active tasks and open questions of the briefed scopes, oldest first, limited by the 14-day soft briefing TTL. A loop that ages out remains open and recallable.

  • Work, project briefings that name a max_tokens budget only: the project board's work in progress — the card bound to this conversation, with its state and the reason for it and how much is attached, the active and waiting counts, and the first three other cards, each with the branches it holds open (open_branches, each with the squashes of it the board already recorded). Each named card carries the cards that block it and are not done (blocked_by) and whether anyone ever said how it relates to the board (links_assessed); the bound card also carries the cards directly above it (above): its parent, its blockers and what it depends on, each marked when it was archived. A card on another board carries that board's scope, and the line names it ZM-3 on acme. When the calling conversation is bound to no card, the work also carries continuation: the card the caller worked on last (still active, within 30 days), their two newest entries on it, their last step when it was on another card, and the calling thread for the attach command. It takes the place of one row of the memories leg rather than adding to the pack. It rides budgeted briefings only because that is where giving up the row was measured harmless: on a copy of a real corpus, one of six rows cost no expected hit, while the twelfth row of an unbudgeted call carried two. A loop attached to one of the named cards leaves the open-loops leg; its card points at it.

Every section inlines content only up to its own cap and marks the row as truncated past it; the full text stays one id away through recall or the zm://memory/{id} resource. The caps differ by what a section is for: a hit carries the substance of a fact, while recent answers "what changed". Row counts and ranking are unaffected. A cap changes how much of a memory is inlined, never which memories arrive.

The memories section spends its budget the same way. The top hits arrive whole; below them a hit arrives as an excerpt taken from the part of it that matched your topic, rather than from its first paragraph, which for a long record is often about something else entirely. An excerpt that does not begin at the start of the record, or does not run to its end, is marked with an ellipsis so it is never mistaken for the opening. What this delivers is the matched region: the excerpt begins where the matching window begins, and that window is wider than the excerpt itself.

Open loops are the exception in the other direction, because a uniform cap served them badly: a handover record states the situation first and what to do on return last, so truncating from the front dropped the actionable half of every one of them. The section therefore spends its budget unevenly: the loops nearest the topic arrive whole, the rest keep a headline. Which loops surface, and in what order, is unchanged and still relevance-free; only depth follows the topic, and it is judged against the whole loop rather than its opening.

The max_tokens budget shapes composition (fewer items) on top of that. Both mechanisms exist because a pack is delivered through channels that impose their own limits: past a client's threshold an oversized result is spilled to a file and replaced by a short preview, which is the worst outcome available. The briefing looks delivered while its most valuable payload goes unread.

So the hook briefing is composed against a character budget below that threshold, and the budget is split before anything renders:

  1. the project line;
  2. a floor held for the work in progress — the board's lines and the open loops — whenever there is any;
  3. a floor held for the memory pack: room for about ten one-line stubs of the project's pack, so a session always sees which memories exist and can pull any of them by id;
  4. the standing rules, up to the ceiling that is left. Rules that are not pinned shorten to their headlines first; pinned rules always arrive whole and, when they alone are long enough, outrank both floors;
  5. the work and the memory pack, rendered against what was actually spent — whole memories while they fit, one-line stubs naming the rest. A second topic (the working branch's) lives on what the project's pack leaves.

The work renders against what the rules actually used, so a short rules block leaves it more than its floor. Whatever is shortened says so and names where the full text is; nothing high in that order is pushed out by something lower. Two empty outcomes are kept apart: a project with no memories says nothing, while a pack that had memories but could not show a single line says how many there are and that they are on their way.

The rest of the briefing follows by itself

The first briefing of a context window cannot carry everything, and asking the agent to fetch the rest would make delivery depend on its reading discipline — the dependence hooks exist to remove. So what did not fit is queued locally, per context window, and the following messages deliver it:

  • Each message that builds no briefing of its own — a short reply, a session whose task briefing already ran, or one whose server could not be reached — carries one queued memory, framed as a continuation with how many remain and when the snapshot was taken.
  • The one message that does build a task briefing carries that briefing's pack instead, and folds what its pack left over into the queue.
  • The queue drains in the order the server ranked the pack. The prompt never leaves the machine, so there is no per-message relevance to rank by.
  • A compaction ends the window and drops the queue with it; the next window is briefed afresh.

Noise control

Two mechanisms keep briefings from becoming an encyclopedia of a project's early days. Promoted content is filtered: a memory whose content has been distilled into standing agent rules (see the rules incubator) is excluded from briefing packs entirely, since it already reaches the agent through its rules layer.

The usage loop does the rest. Briefed memories generate usage signals; memories that prove useful are reinforced, and stale ones sink through decay. See Recall quality and Decay and reinforcement. The design preference is gradual, signal-driven improvement over one-off manual curation.

The two mandatory reads have different jobs: a briefing is a broad session broadcast, while recall answers the specific sub-problems that arise during work. Receiving a briefing never removes the need to recall before deriving a new answer.

The write path guards the same property from the other side: entity creation matches existing entities before creating new ones, extraction policy rejects facts derivable from the code itself and unanchored episode fragments, and corrections declare an explicit supersede instead of leaving two competing versions. See Supersede and versioning.

On this page