# Epistemic Inbox The Epistemic Inbox is Exomem's daily, review-only answer to "what deserves my attention?" It composes deterministic measurements into one ranked list: - close active conclusions that may restate, refine, or contradict each other; - conclusions that are old, rarely surfaced, and weakly linked; - raw sources that have never been compiled; - active compiled notes with no durable outbound Markdown connections; - open Planning items that recorded events already join to. None of these signals is a judgment. Exomem does not decide that a conclusion is wrong, infer a relationship as fact, decay memory, or edit a note. The agent or user inspects the evidence and chooses what to do. ## Daily command ```bash exomem review ``` Human output shows a compact ranked inbox. Automation keeps the shared JSON envelope: ```bash exomem review --json exomem review --state all --json exomem review --category relation_debt --json ``` The MCP/REST product route is `list_review_items(queue="due")`. Every item includes its current path, canonical target reference, reasons, stable `exomem://review/` reference, signal fingerprint, and review state. ## Unreflected outcomes `unreflected_outcomes` is the one family that reads structured collections rather than pages. It fires where two authored facts disagree by omission: a Records collection holds events that join to a Planning item, and that item is still open (`lifecycle: active`, status not `completed` or `cancelled`). The binding is authored, never inferred. A Records manifest declares it on its Planning link: ```yaml links: plans: - reference: exomem://memory/ query: {limit: 50} join: title: title ``` `join` maps one to four declared record fields to plan field names, matched exactly. Records itself never resolves the Planning side: the link stays opaque on every Records operation, and this family is its only consumer. What resolves a finding: the item leaves the open state, the binding is removed from the manifest, or the joined records are gone. Never time, and never the runtime — no command, sweep or write-path advisory edits either side. You move the item yourself with `edit_plan_item`. The fingerprint is the item reference plus the joined record keys, so a new event on a dismissed item resurfaces it under the ordinary material-change rule while the dismissal record stands. A record append or a plan transition applies its own bounded delta, so the response to the write that opens the gap is the response that reports it. A Planning reference that cannot be resolved produces no finding and is reported as unevaluated in the audit's own metadata — never silently skipped. ## Triage Triage is explicit write-capable state, separate from read-only review: ```bash exomem review snooze exomem://review/0123456789abcdef01234567 --until 2026-08-01 exomem review dismiss exomem://review/0123456789abcdef01234567 --why "intentionally standalone" exomem review reopen exomem://review/0123456789abcdef01234567 ``` Agents call `decide_review_item` with the same `dismiss`, `snooze`, or `reopen` `decision`. Decisions live in `.review-state.json` under the external per-vault machine-local state root. The file is portable JSON and stores no note content. A decision binds to the exact signal fingerprint reviewed. Ranking changes and age counters do not change that fingerprint. A material note edit, new review reason, changed contradiction partner, or changed source state does, so the item automatically resurfaces instead of being hidden forever. Expired snoozes also return to the open inbox. ## Repairing relation debt Relation debt means an active compiled note has no outbound wikilinks or typed relations. It does not mean Exomem should invent edges. 1. Inspect the note and nearby context. 2. Run `connect_memory(operation="suggest-relations")` or `suggest-links`. 3. Accept only relationships whose meaning is defensible. 4. Write note-level edges under `## Relations` as `- relation_type [[Target]]`; use semantic-block `relations:` metadata for claim/finding/evidence-level edges. 5. Re-run review. The repaired note leaves the relation-debt queue. For batch repair, `list_review_items(queue="relation_suggestions")` presents the same deterministic suggestions as a fingerprint-guarded accept/reject queue (see the Review Studio's Relations worklist): accept via `decide_review_item` with `decision="accept"`, reject via `decide_review_item`. Rejections are fingerprint-bound and resurface when the signal materially changes. Existing vaults are repaired incrementally through this loop. There is no automatic bulk rewrite, and semantic similarity alone never becomes a durable typed relation. ## Reason codes Every triage decision records *why*, as a closed code. Lead the free text with one of `intentional:`, `false_positive:`, `handled:`, `deferred:`, or `too_frequent:`; anything else records `unspecified` and is never an error for an item decision. The CLI composes the token for you: ```bash exomem review dismiss exomem://review/0123456789abcdef01234567 \ --reason handled --why "closed in the incident review" ``` The code rides inside the existing free-text `why` rather than a parameter of its own, so no tool input schema moves and a client that only ever sends `why` keeps working unchanged. The `why` is stored verbatim either way: a closed code alone does not say what you actually meant. Each record also carries an `origin`: `manual` when a person decided through the triage surface, `automatic` when the runtime wrote it itself. Records migrated from the older schema carry `manual`, because that schema could only be written by the triage surface. ## Silencing a whole signal family Triage is per item. When a *kind* of signal is noise for your corpus, set that family's disposition instead of lowering prominence, which silences everything: ```bash exomem review quiet prediction_window --reason too_frequent --why "fires more than it helps" exomem review off near-duplicate --reason false_positive exomem review normal prediction_window ``` Agents use the `review.set_family` operation of `manage_memory` with a family reference, `exomem://review/family/`, and the `quiet`, `off`, or `normal` action. `quiet` and `off` require a reason code. - `quiet` drops the family from the default review union, from every due-state carrier, and from write-path advisories, while it stays reachable on an explicit category request. - `off` additionally drops it from explicit category review; only the all-states view still shows it. - `normal` restores it. **A quiet family is silent, not clean.** The full audit still measures it, and a due-state block that omits a family is never evidence that family has nothing due. `list_review_items(queue="dispositions")` lists every non-default family with its reason, `why`, timestamp, origin, and the number of items of that family you had already dismissed by hand before quieting it. ## What the review store records, and how it stays small The external per-vault `.review-state.json` holds three things: the triage decisions, the family dispositions, and a first-surfaced ledger recording when each signal first reached a served surface — the review list, a due-state carrier, or a write advisory. "Reached" means DELIVERED, not produced: a carrier block that a batch, the change-only rule, or a `legacy` response dropped was shown to nobody and is not recorded. Neither is anything withheld by governance, filtered by a disposition, seen only by the audit, or merely looked up — resolving one reference scans every queue to find it, and a scan is not a surface. The ledger is never backfilled, and a store that cannot be written changes nothing a reader acts on. Reading the store is the other way round. The ledger write is best effort, but the DECISIONS are not: a `.review-state.json` that cannot be read or parsed makes the review surfaces refuse with `REVIEW_STATE_INVALID` rather than answer as though nothing had ever been decided, because the second one silently resurrects every dismissal in the vault. `maintain_memory(mode="reconcile")` is the way back — it reads at a raised limit precisely so a store that outgrew the ordinary one can still be compacted, and it reports `review_state_compaction: {"error": ...}` when it cannot, because a healer that fails silently is indistinguishable from one that found nothing to do. The due-state carriers fail closed too, in the direction that suits a carrier: they serve **no block** rather than refusing. Every count they report is filtered by a triage decision and a family disposition read out of the same store, so an unreadable one would otherwise put every dismissed item back in front of you. Silence costs an advisory you can still ask for by name; the alternative costs the trust that dismissing works. The write itself is unaffected — this is the advisory attached to the response, not the mutation. The store compacts itself, within limits worth stating plainly. Expired snoozes older than 90 days and ledger entries older than 400 days are dropped once the file passes its size or record threshold; a standing decision is never dropped, whatever its age. So compaction bounds the ledger and it does not bound the store: a vault that accumulates dismissals grows, and no retention rule brings it back down. The drop is reported under `stats.compaction` with `origin: automatic`, and `maintain_memory(mode="reconcile")` returns the same report so a compaction is never silent. ## Emission counters The external per-vault `.due-state.json` carries the maintained due-state projection and an `emission` section: `writes` counts the governed writes the projection has absorbed and `emissions` counts the due-state blocks actually delivered. A command that writes many pages at once is one batch, and a batch delivers at most one block rather than one per write — the counters are how that is checkable rather than merely claimed, and checking it is the point of writing them down. Successive single `add_record` or `add_plan_item` calls each carry a block, and that is the accepted behaviour rather than a leak: the governor suppresses an identical total, and each of those writes genuinely changes the total. Turning that into one block per session would be a change to the governance rule, not to the carrier. The section also carries `due_total`: how many items were in the last block a caller was actually handed. It has exactly one writer — the delivery path — so a vault that has delivered nothing reports `0`. It is informational, and deliberately not a measure of any particular batch: it describes the last delivery whenever that happened, and survives every batch after it. Telling "governance suppressed eleven repeats" from "this batch delivered nothing" therefore needs the DELTA, not the totals. `writes` and `emissions` are cumulative over the vault's whole life, so the batch under test is the difference between two readings — which is what the bench's counter assertion compares, and why a batch that delivered nothing reports `unsupported` instead of inheriting a `pass` from a block emitted before it started. Which is what it reports today. No product command commits more than one governed write through the write carrier: measured on `adoption_studio` apply, `maintenance.fix`, `save_evidence` and `media.process`, each of which writes eight to twelve pages and reaches the carrier zero times. The batch scope those leaves hold is therefore a guard for a route nothing takes yet, not a mechanism doing work today; where the carrier IS reached — a single governed write, and the recall and bootstrap carriers — one scope over twelve runs still delivers at most one block, and that is where the requirement is proven.