Repository navigation
How a session uses memory
An MCP server cannot make an agent call it. A session that never asks has a memory server and no memory. MemAI closes that gap with hooks: they put the store in front of every session, make it read before it works, and remind it to write before it stops.
sequenceDiagram
autonumber
participant H as memai-hook
participant A as Agent
participant S as memai-mcp
participant W as Warden subagent
H->>A: SessionStart: the brief (counts, domains, latest checkpoint)
A->>H: any tool call
H-->>A: held: read your memory first
A->>S: pulse(domain) or must_read()
H-->>A: MemAI: session warmed up
loop while working
A->>S: search · get_memory · note · task_item …
H-->>A: guard: refuses a write whose text never arrived
end
H->>A: Stop: checkpoint nudge, open tasks of the domains it touched
A->>W: launch in the background when one is owed
W-->>A: only the memories that bear on the work
When a session starts, the session-start hook reads the store directly — no
server needed — and adds a short brief to the session's context:
- how many memories the active project holds, and its busiest domains
- the latest checkpoint
- one line counting what is pending: open tasks, pitfalls, notes, flows
- one line counting what a person pinned as mandatory reading
- the instruction to call
pulse(domain)andmust_read()before working
It is capped at about 2,400 characters, and every cap it hits is reported, so a short brief never reads as an empty store.
A briefed session has its tools held until it calls pulse() or must_read().
Any other call is refused with a message saying what to do. The memai tools and
ToolSearch (which loads deferred tools) always go through.
After three refusals the hold gives way, so a host where the memai server is missing never loses its tools for good.
pulse("acme/checkout") # bearing: latest checkpoint + what is open
must_read("acme/checkout", type="task") # the open tasks, as headers
get_memory(uid) # one record: fields, and counts of the rest
search("webhook retry duplicate") # anything specific, by keywordspulse and must_read return counts and headers, not bodies. The session
opens only what the work touches, and every listing carries est_tokens so it
knows what a full read costs before making it.
The agent writes when it learns something, not at the end:
note() a fact, anti_pattern() a trap, checkpoint() before a pause,
task() for work that outlives the session. See Memory types.
The guard hook checks every memai write before it leaves the host. A
parameter tag the model typed wrong is dropped by the parser and its text is
lost; the guard refuses that call and says how to retry. A missing optional
field (domain, tags) is a warning, and the write goes through.
At the end of a turn, the stop hook may add:
| reminder | when |
|---|---|
| checkpoint nudge | nothing was written in the last 45 minutes |
| open tasks | the session named a domain that has open tasks; once per 30 minutes |
| warden | the warden interval (20 minutes) has passed |
Each one is silent unless it has something to say. The task reminder and the warden can be switched off, and their intervals changed, in Dashboard → Maintenance → Reminders.
A busy session does not stop to search its memory. The warden is a subagent that does it on the session's behalf: it reads the turns since its last run, searches the store, and reports only what bears on the work — a pitfall being walked into, a decision about to be contradicted. Most runs report nothing.
It runs in the background and its findings arrive as a task notification. See Hooks and the warden for how it is launched and turned off.
See also: Hooks and the warden for every flag and state · Tools for the read and write calls.
Home · Getting started · Troubleshooting · Changelog · MIT licence
Getting started
Concepts
Guides
Reference