← Notes

Two memories, not one: the lawyer’s preferences and the team’s doctrine

A well-injected playbook answers ‘what does the rule say?’, never ‘how does this team work?’. On a contract review agent, I separated each lawyer’s personal memory from the team doctrine, approved by an admin. Two levels, two prompts, and a model that proposes but never writes.

  • agents
  • memory
  • governance
  • legal

The same contract review agent, once in daily use, ends up hearing the same remarks over and over. Picture them like this: ‘Don’t suggest revisions on the confidentiality clauses, we handle those separately.’ ‘Your wording is too aggressive, we’ve been negotiating with these suppliers for years.’ ‘On this type of contract, a twelve-month warranty is acceptable even if the playbook says twenty-four.’

These sentences aren’t noise: they’re the job itself. The problem is that they vanish with the session. The next day, the agent starts from scratch and the lawyer explains it all again. If nothing changes, they eventually stop explaining and fix things by hand: the tool stays open, but nobody uses it any more.

Why document retrieval doesn’t solve it

The reflex is to add document retrieval (RAG): index past exchanges, find the relevant passages and slip them into the prompt, the instructions sent to the model. That fixes nothing: retrieval answers ‘what does the playbook say?’, not ‘how does this team work?’.

On this agent, in fact, there is no vector database at all. The playbook comes down to a few dozen clauses and risk scenarios, handed to the model in full on every audit; on the conversation side, the agent only has a keyword search over that same playbook. Finding the right clause is not the problem.

What was missing were two things the playbook doesn’t contain, and mustn’t contain:

  1. One person’s preferences: their style, their scope, their habits. There is no reason for them to apply to anyone else.
  2. The team’s working doctrine: what the team has settled audit after audit, which clarifies or qualifies the playbook for a given context without changing its text. It commits the team, so someone has to approve it.

Mixing the two in a single memory guarantees that one person’s preference will end up weighing on a colleague’s audit.

Two levels, two prompts

The agent has two uses. The audit puts a contract through the playbook and draws proposed corrections from it. The chat is where the lawyer reworks those proposals with the assistant. Hence the architecture: two separate memories, one per use, with no point of contact.

                     working session (chat)
                              │
    ‘remember that…’          │        end of session: harvest
    (remember_rule tool)      │        (1 model call, 6 proposals max)
                              ▼
          proposals  { action, section, text, route, justification }
                              │
              ┌───────────────┴────────────────┐
  route =     │                                │   route = "clausier"
  "agent_md"  ▼                                ▼
  ┌──────────────────────────┐    ┌────────────────────────────┐
  │ LAWYER’S MEMORY          │    │ CANDIDATE DOCTRINE RULE    │
  │ 4 sections, 8,000 chars  │    │ status: draft              │
  │ approved by them, line   │    │ approved by an admin       │
  │ by line                  │    │                            │
  └────────────┬─────────────┘    └──────────────┬─────────────┘
               │                                 │
    injected into the prompt          injected into the prompt
    of the CHAT only                  of the AUDIT only

The two arrows at the bottom never meet. A rule filed in personal memory weighs on no audit; an approved doctrine rule doesn’t change the way the assistant talks to its lawyer. No code has to arbitrate between the two: they never end up in the same prompt.

The corollary: a personal rule is never ‘promoted’ to the team. A ‘remember that…’ always feeds personal memory. It is the end-of-session harvest that routes each proposal via the route field, and the agent can also propose a doctrine rule mid-session, straight into draft. The sorting test, for the model as for the human: does this describe the way you work, or what is acceptable in a contract?

The file is never written by the model

Personal memory is not a database: it is a plain text file per lawyer, split into four fixed sections, read by the agent at the start of every session.

MEMORY_MAX_CHARS = 8000
MEMORY_COMPACTION_THRESHOLD = 0.8

MEMORY_SECTIONS = [
    "Style d'écriture",
    "Priorités & scope",
    "Patterns récurrents",
    "Dépendances entre règles",
]

MEMORY_ACTIONS = {"add", "modify", "remove"}
MEMORY_ROUTES = {"agent_md", "clausier"}

Two decisions carry everything else.

The model never touches the file. It produces proposals: an action, a section, a text, a justification. The lawyer ticks, edits or rejects them, and deterministic code then applies them: add inserts a line at the end of the section, modify replaces the line containing the target text, remove deletes it. If the text to replace can’t be found, the operation fails with an explicit error. No blind writes.

There is never any silent truncation. The budget is hard: 8,000 characters. At 80%, the interface flags that it’s time to tidy up; the threshold named compaction in the code triggers that warning, not a clean-up. Beyond the budget, saving is refused. No mechanism decides on the lawyer’s behalf which rule is worth keeping.

The end-of-session harvest is a single model call, tuned to limit variability, that reads two things: the conversation, and what the lawyer did with the audit’s proposals. An ignored proposal says something about their scope, a reworked one about their style, an accepted one about their priorities. The instruction to the model: generalise. A rule has to serve the next sessions, not describe this contract.

Governance: nobody approves their own rules

The second level demands real governance: an approved rule weighs on other people’s audits.

The tool distinguishes three roles: user, who runs audits; lawyer, who also has access to the assistant; admin, who approves the doctrine.

  • Proposing doesn’t require being an admin. Any lawyer can propose a candidate rule, mid-session or during the harvest. It is created as a draft, and a draft is applied nowhere.
  • Approving is reserved for the admin role. The check is done by the server: hiding a button in the interface wouldn’t be enough.
  • A rule cannot be activated incomplete. Activation requires a scope, an instruction and at least one explicit limit. The condition is checked at approval time, not at creation: nobody is stopped from proposing a vague idea, but it can’t be put into production. A proposal’s scope isn’t entered by hand: it is inherited from the session where the rule was born. Failing that, the rule stays ‘to be assigned’ and cannot be activated.
  • A duplicate guard compares each proposal with existing rules in the same scope and blocks creation, showing the similar rules. You can override it by explicitly ticking a box that confirms the rule really is distinct.
  • The lifecycle is complete: draft, active, suspended, deactivated, archived, with versions and restore. Restoring an old version never restores its status or its approval; otherwise, going back to an active version would reactivate the rule without anyone approving it.

A deliberate choice: an active rule whose review deadline (90 days) has passed stays applied. The deadline feeds a ‘to review’ queue in the admin area; it is not a circuit breaker. A doctrine rule that switches itself off, without anyone noticing, is a more serious incident than a rule that is a little old.

What worked, what got stuck

What worked. Routing at the source rather than promotion between levels: it removes a whole class of leaks and conflicts. Deterministic application: the model cannot silently rewrite a rule it has misunderstood. And the order of operations: personal memory is saved before the candidate doctrine rules. If that second save fails, the failure is reported rule by rule and personal memory stays intact.

What gets stuck. Three things:

  • Rules requested mid-session aren’t stored anywhere before the harvest. If the session is interrupted before then, a ‘remember that…’ is lost. The agent does say the rule will be put forward for approval, but the friction is real.
  • Nothing technically stops a contract excerpt from landing in memory. The barrier is a prompt instruction (guidance on how to work, never the content of a contract) and human approval. There is no personal data detector. On a more sensitive scope, that’s the first building block I would add.
  • Two people don’t get the same audit. Today, the doctrine is only applied to audits run by an admin; lawyers and users get an audit based on the playbook alone. Every enriched audit logs the rules considered and then those actually applied, but the gap has to be explained to users, otherwise it looks like a bug.

Checklist: designing the memory of a business agent

  1. Write down in black and white what the memory is not allowed to contain. Here, for personal memory: the way of working, never the content of a contract or a substantive rule, which belongs to the doctrine.
  2. Separate what commits only one person from what commits the team, right from the proposal: two write paths, not a status in the same table or a promotion after the fact.
  3. The model suggests, a human ticks, the code applies. Every change must be deterministic, reversible, and must fail visibly.
  4. Set a hard budget and refuse writes beyond it. Never silent truncation.
  5. Make approval asymmetric: proposing is open, activating is restricted and logged (who, when, on what scope).
  6. Forbid activating an incomplete rule, block duplicates, and provide suspension, archiving, versions and restore, without a restore reactivating anything.
  7. Decide whether the review deadline cuts off or alerts, and write it down. Both are defensible; leaving it implicit is not.
  8. Log, on every run, which rules were considered and which were applied, and show users their memory, in plain text and editable. A memory you can’t read back is a memory you can’t correct.

Where it really plays out

The hard part of agent memory isn’t technical: a text file per lawyer and a table of rules are enough. It’s organisational: who has the right to teach the agent something that will apply to others, and how it gets undone.

That’s what I build through Ongoing support, over time: who proposes, who approves, how you roll back, then the handover to the teams who will keep these rules alive without me.