← all docs · memory-proactive26 août 2026

Proactive memory — save and use, edit later — design spec

Status: Implemented
Author: Claude (memory-proactive lane)
Date: 2026-08-26
Repo: north-os (packages/agent-runtime/src/memory, apps/worker-memory, apps/mcp-server/src/tools, apps/web/lib/memory, apps/web/components/settings)
Related: supersedes the review-queue half of 2026-06-25-user-memory-chat-import-design.html and Layers 3–4 of 2026-06-29-memory-calibration-design.html / 2026-06-29-memory-calibration.html

Decision

North's memory behaves like Claude's memory: North decides to remember, saves it, and uses it immediately. The lawyer is never asked to confirm a memory. Settings → Memory is where they see everything North remembers and edit or delete any of it, at any time.

Three consequences, and they are the whole spec:

  1. No confirmation, anywhere. Every captured memory is written active and is injected on the next turn. Two gates go, not one: the review queue (pending / rejected stop being produced, and keep/discard verbs disappear from the API, the UI and the MCP tools) and the chat's "Save this note?" confirm card — save_memory / update_memory raise an in-tool confirm interrupt today, which is the ask's most visible violation on the primary surface. The tools stop interrupting immediately; the machinery that resumes an already-paused thread stays for one release, because a thread paused on a persisted confirm checkpoint at deploy time would otherwise have no button and would refuse every new message.
  2. Standing rules apply on creation. The trust profile stops proposing a rule for the lawyer to confirm — when it sees a category the lawyer keeps deleting, it writes the rule. Rules live in Settings → Memory and are deletable there.
  3. Proactivity does not depend on the lawyer, on any surface. Web chat and MCP (Cowork / claude.ai / Claude Code) both instruct the model to save durable facts on its own initiative and to recall before answering — same no-confirmation semantics.

Matter memory is firm-shared: a matter fact one lawyer's session captures is recalled for every colleague who opens that matter. That is already how the store reads (§4); this spec makes it reachable by removing the gate that kept most matter captures invisible, and states it in the product copy.

1. Why the queue goes entirely, instead of shrinking

The queue is not a setting, it is the architecture. Today a memory only steers an answer after a human acts on it, so four mechanisms exist purely to decide what to ask about:

LayerWhat it is todayUnder auto-save
1 — hybrid gateclassifyMemoryDisposition: high confidence + safe type + safe scope → active, else pendingcollapses to "always active" — deleted
2 — standing rulesalways_remember / always_review / never_rememberonly never_remember still means anything
3 — calibrationinline LLM second opinion that can only downgrade activepending, fail-closedits only output is a queue that no longer exists — deleted
4 — trust profilemines keep/discard history into suggested rules the lawyer confirmsmines delete history into rules that apply on creation; memory_rule_suggestion becomes the applied-rule ledger

Keeping any of them "just in case" leaves a status a user can never reach, a verb no UI calls, or an LLM call on the capture path with nowhere to send its verdict. Each is removed in this change, not deprecated.

Removing Layer 3 also takes a synchronous Anthropic call (6 s timeout, fail-closed) off every capture: mining gets faster and stops discarding memories during a provider outage.

2. What the lawyer sees

Settings → Memory becomes two tabs, not three:

No "Review (N)" tab, no keep/discard, no batch triage, no "confirm before it's used" copy, no suggestion cards. A matter-scoped row is labelled as shared with the firm, because it is.

3. Statuses and rule vocabulary after the change

Live memory statuses: active (live), superseded (replaced by an edit), archived (deleted by a lawyer). pending and rejected are never written again. Only one rule action remains creatable: never_remember, which refuses the write. always_remember is what everything already does and always_review has no meaning without a queue, so the rule composer and the API schema accept never_remember alone, and rule matching treats any other stored action as no match — a legacy row must never silently block a save.

Nothing is filtered on the way in. A first draft of this spec had the unattended miner drop low-confidence captures, on the reasoning that confidence would otherwise be collected and read by nobody. Cross-model review was right to reject it: silent non-persistence with no recovery surface is a new retention policy, not the removal of a confirmation step, and it was reached for to tidy a field rather than to serve the ask. Every capture is saved active; confidence stays on the row as audit metadata. If a discard threshold is ever wanted it gets its own change, with recall and false-positive numbers behind it.

The DB enums keep their historic values (no migration in this change); the application stops producing the dead ones and a one-shot script (§6) settles the rows that carry them.

4. Shared matter memory — what already holds, what this makes reachable

Already true, and unchanged: agent_memory_candidate rows are firm-isolated by app.organization_id, and the RESTRICTIVE owner-wall walls only user_private rows to their target_user_id. A matter row carries target_matter_id and a NULL target_user_id (the scope_shape_chk constraint enforces that shape), so it is visible to every member of the firm. Recall matches the same way: the matter bucket filters on organization + status + scope + target_matter_id and never on the reader's user id, in web chat and through north__memory_recall alike.

Worth recording while in this code: retrieval reads two buckets and only two — personal and matter. firm_global is stored, listed and deletable but never injected (§8).

So the shared-matter behaviour was designed in; what blocked it in practice is that most matter captures were mined at medium confidence and parked in pending, and every MCP save was forced to pending — invisible to everyone including their author. Auto-activation is what makes a colleague's matter fact actually arrive. This change adds a regression test that pins it (a matter memory written by user A is recalled for user B in the same firm, and A's personal memory is not) and says it in the UI copy.

5. MCP surface

north__memory_save today forces status: "pending" and its description justifies calling without asking because the save is inert. Under this spec the save is live, so the contract is restated rather than dropped: save durable facts unprompted, and say plainly that the memory is live and the lawyer can edit or delete it in North. north__memory_update performs a real supersede instead of queueing a replacement. north__memory_recall gains an explicit instruction to be called before answering a matter question, not only on request. One line in the MCP server instructions carries the same rule for hosts that read them.

Unchanged: the NetDocuments ethical wall still refuses matter / firm_global memory writes from a session that consulted NetDocuments. It runs before the status is chosen and never depended on the queue — the comment claiming the forced pending "softens" it is wrong today and is corrected.

6. Legacy rows

Three populations exist in preprod and need settling once, by a one-shot script under packages/db/scripts/ (house rule: a data fix is a script, never a migration):

The suggestion table survives with a different job. An auto-applied rule needs one guarantee: if the lawyer deletes it, the nightly sweep must not write it again next night. memory_rule_suggestion already records exactly that — one row per (lawyer, scope, type) the sweep has acted on, with the keep-rate and sample size that justified it. It stops being a queue and becomes the applied-rule ledger: the sweep writes the real memory_rule and a ledger row in the same transaction, and never revisits a bucket that has one. No confirm, no dismiss, no surfacing to the lawyer — the rule itself is what they see and delete in Settings. This keeps the table load-bearing rather than orphaned, and needs no schema change.

7. Invariants that do NOT change

8. Open question for plan review — firm_global blast radius

firm_global and playbook_rule captures were always queued on purpose: they steer answers for every lawyer in the firm. Auto-saving them means an agent-inferred firm practice goes live firm-wide with no human in the loop, including from an MCP session. Options:

Decided: A — and plan review found the premise of the question to be wrong in a way that makes A the safe answer rather than the bold one. A firm_global memory steers no answer for anybody today. Retrieval fetches exactly two buckets, personal and matter; north__memory_recall and the Cowork briefing use that same loader, and the update-matcher excludes firm scope outright. The automated miner cannot even produce the scope — only an explicit save_memory / north__memory_save call can. So the blast radius of auto-activating firm_global is clutter in every lawyer's Settings list (where any of them can delete it), not a firm-wide steer. B keeps alive the queue this spec exists to remove; C is the honest cleanup of a dead scope but touches two tool schemas, the NetDocuments wall registry and their tests for a capability nothing reads — scope creep. Take A, and record the standing condition: the change that ever adds a firm bucket to retrieval re-opens this sign-off question.

9. Success criteria

  1. A fact stated in a chat is recalled in the next chat, with nothing clicked in between.
  2. A matter fact captured by lawyer A's session is injected for lawyer B on that matter.
  3. The same holds through MCP: a Cowork session saves a memory unprompted; the next web chat uses it.
  4. Editing a memory in Settings changes what the next turn sees; deleting it removes it.
  5. Repeatedly deleting one category of memory makes North stop capturing that category, with a rule visible in Settings that the lawyer can remove.
  6. No pending / rejected write, and no confirm/dismiss endpoint, action, copy, test or product_event name, survives anywhere in the tree.