Rules incubator
Promote proven memories into standing rules and deliver them through MCP, briefings, hooks, or instruction files.
The rules incubator watches which of your memories actually fire (get recalled and confirmed useful across sessions) and distills the proven ones into standing rules. You review every candidate before promotion. Once promoted, zero-memory delivers the rule through its native MCP and briefing channels; downloadable instruction-file blocks remain available as a fallback.
Two layers, two delivery guarantees
Knowledge lives in two layers with different delivery guarantees. Memory is the living draft: probabilistic delivery, surfaced when retrieval decides it is relevant. Rules are the distillate: guaranteed delivery, loaded into every session's context unconditionally. A fact you are effectively re-asked for again and again has earned the second kind.
From signal to candidate
Detection
The detector runs with the regular hygiene cycle: the background scheduler
tick, the scan_hygiene MCP tool, and the dashboard's scan button all trigger
it. A memory becomes a candidate when all of these hold:
- its kind is
convention,preference, orgotcha; - it fired — was recalled and judged useful, per recall usage — in at least 3 distinct sessions within the detection window (30 days);
- it is stable: not superseded or invalidated, and not recently revised.
Open loops (task, open-question) are never candidates: they are work
items, not durable knowledge. Decisions are watched but not proposed either,
since their imperative core is usually bound to the context they were taken
in.
Distillation
A conservative LLM judge turns the memory — with its closest graph neighbours as context — into an imperative rule draft and proposes the target layer: personal memories suggest the General layer, project memories suggest that project's layer. When in doubt, the judge recommends dismissal rather than flooding the queue, and a draft it is not confident about is auto-dismissed instead of queued. The queue stays short enough to be read.
Alongside the deterministic part of the suggestion (the memory's origin scope, plus the global layer for personal memories, always correct by construction), the distiller may also rank other scopes where the rule looks applicable. Those cross-project suggestions are validated against your actual scope list and explicitly marked speculative: project identity is hard to infer from content alone, so they are hints for you, never decisions.
Review and promotion
Candidates appear on the dashboard's /rules screen as a review queue,
grouped by the project a rule is addressed to (General last) and filterable by
scope and status. Each card shows the drafted rule, the evidence (in how many
sessions and when the memory fired, with a link to the underlying memory), the
distiller's confidence, and three actions: approve, dismiss, or
snooze.

Approving promotes the rule into the layer you choose on the card: General, or
one concrete project. You can also promote one of your own memories directly
with the promote_rule MCP tool or from its dashboard detail page; this skips
candidacy, not human approval.
There are two layers. General is private to the owner and delivered in all of their sessions. Project is private to the owner too, and delivered only when that project is active.
Rules are not shared team policy today. Sharing a memory does not cause its promoted rule to be delivered to other members.
Promoted rules stay editable from the same screen. Pin one so it is always delivered, revoke it (with a reason) to pull it back out of the always-on layer, or copy and download its text. A promoted rule whose source memory has stopped being recalled usefully is flagged as a "still relevant?" hint rather than removed.
A promoted rule is always a live one. Promoting a rule you revoked earlier,
from the dashboard or with promote_rule, clears the revoke in the same
step, so a rule can never read as promoted while no session receives it.
A rule follows its memory
Memories get replaced: a writer supersedes an outdated one, a reviewer resolves a conflict, hygiene folds a duplicate. Whenever a memory with a promoted rule is superseded, on any of those paths, the rule moves to the memory that replaced it. It keeps everything you decided about it: the pin, the layer, the project it is delivered to and its place in the delivery TTL.
- If the rule's text was the memory's own words, it takes the successor's words. The same holds when a memory's text is rewritten in place, such as its translation into English.
- If the text was curated (distilled, or written by hand), the text is kept
and the rule is flagged Text to review on
/rules. The writer'srememberreply says so and names the call that sets a new text:promote_ruleon the successor, withrule_text. - If the successor says exactly the rule's curated text, the rule is already in sync: it moves with nothing to review. Writing a rule's text as a new memory that supersedes its old one is how to re-anchor a rule without promoting it again.
- The rule stays where it is, and stays promoted, when moving it could
cost it anything: the successor already has a rule of its own or was
dismissed or revoked as one, belongs to another owner, or is itself retired.
A task or open question closed by its answer keeps its rule too, since an
answer does not replace an instruction.
/rulesflags such a rule.
remember lists what happened to each rule under rules: carried, carried
with its curated text kept, or not carried. promote_rule on a superseded
memory names the successor to promote instead.
Forgetting a memory does not retire its rule. The rule stays promoted, within
the usual delivery limits, /rules flags that its memory is gone, and the
forget reply says so. Only you revoke a rule, on /rules.
Delivery
Promoted rules have several delivery paths, in order of how little client integration they require:
- MCP instructions. On
initialize, clients without a documented instruction cap receive the applicable rule texts inline, pinned first. A client known to cap that channel — Claude Code silently truncates server instructions at 2 KB — instead receives a compact router plus an announcement of how many standing rules apply and where to fetch them, and never a fragment of a rule: half a sentence reads as a broken instruction. Uncapped clients additionally get a project-attachment note appended to the router; the capped client receives that guidance through the briefing and tool descriptions instead, because whole segments are dropped in priority order when the budget would overflow. build_context.rules[]. Every client can retrieve the full applicable set as{ text, pinned }records, no hook required. The rendered tool result carries a prominentSTANDING RULESblock ahead of the pack, with pinned rules leading and marked.- Client hooks. Hook-capable adapters render the same
STANDING RULESsection automatically in session and task briefings. This is the uncapped full-text channel. - The
zm://rulesresource. A read of the current promoted set, pinned first, without a briefing call, useful for reloading the rules after promoting one mid-session. It is offered only where the connection can read them live, so it never advertises a capability that would then fail. - Instruction files. Copy/download and deploy-script materialization are the fallback for clients that ignore MCP instructions or need a Git-auditable rule file.
MCP instructions are fixed for the lifetime of a connection, so a rule promoted mid-session does not appear in that session's system prompt. Reconnect if that is the path you rely on. Everything else reads the current set on every call: a newly promoted rule reaches the very next briefing, including the current session's.
The server never writes into CLAUDE.md or another client-owned instruction
file. Use the dashboard download or the deploy script's --rules-file /
--rules-dest options when you deliberately want materialized rules.
Delivery follows the context window
Hook delivery is scoped to the context window, not to the session. A briefing writes its rules into the conversation transcript, and compaction is exactly what discards that transcript, so a session that was briefed hours ago may no longer hold a single rule.
A client event whose reason is compaction or a cleared conversation opens a new window, and the standing rules (and the task briefing) are delivered again. Startup and resume do not: the first has no previous window to lose, the second replays the transcript that already carries them. A client that reports no reason for its session events simply keeps the previous behaviour and re-delivers on every one.
The skip is keyed on recorded delivery, never on an attempt. A session-start briefing that failed — server unreachable, offline cache served — records nothing, so the rules still arrive from the next hook in that window. A standing rule silently missing its window is the one failure this layer must not have.
Delivery budget and pinning
Each layer delivers pinned rules first, followed by the newest unpinned rules.
At most 12 unpinned rules per layer are delivered, and unpinned rules age
out of delivery after 90 days. They remain in the catalog, stay visible on
/rules, and a single re-promotion restarts that clock.
A pin guarantees inclusion in the delivered rule set: pinned rules are exempt
from both the per-layer cap and the delivery TTL, and they lead the list a
session receives. It cannot force a capped client to expose arbitrary-length
text in its system prompt. On such a client the full pinned text still
arrives through build_context and hooks rather than the instruction window.
The /rules screen reports Delivered N of M for the General layer and turns
amber whenever a promoted rule is not being delivered, alongside a count of
pinned rules, so a budget overflow is visible rather than silent. Two filters
list the rules behind those numbers: pinned or not, and delivered or
not, where not delivered is a promoted rule the cap or the TTL keeps from
sessions. The badges open the matching filter. One function backs the badge,
the filter and the readers that build the delivered set, so what the page
shows and what a session receives cannot drift apart. For project rules it
counts each project on its own.
Closing the loop
A promoted memory is never proposed again, and a dismissal is equally terminal: the incubator does not re-litigate a decision you already took. Snoozed candidates return to the queue in place once the snooze expires (14 days). A revoked rule stays terminal too, with the reason kept alongside it. Deleting a dismissed candidate is the deliberate way back: it frees the memory to earn candidacy again.
Decisions are not deleted, they are recorded. Each candidate row keeps its status, who resolved it, and when. That record is the trail of how a rule came to exist.
A human approves every rule. The incubator distills but never auto-applies. This is both a quality gate and a structural defense against memory poisoning: nothing reaches guaranteed-delivery context without an explicit human decision.
Where a precise session identity is unavailable, firings are bucketed conservatively by day, since undercounting is preferred to overcounting.
See Memory model for kinds and links, Hygiene for the shared scan cycle, and Recall quality for how usefulness verdicts are produced.