Skip to main content

Command Palette

Search for a command to run...

BDK

Memory

Memory lets an agent recall work from earlier sessions. A memory hook appends one record per turn to a shared journal, and the model reads that journal with its normal file tools when its instructions send it there. Every session and every user of the agent shares one journal.

Memory is on by default

bdk init scaffolds bot/hooks/memory.ts:

// bot/hooks/memory.tsimport { memoryHook } from "@cursor/bdk/memory";export default memoryHook();

It also adds a ## Memory section to bot/instructions.md. The model has no recall tool, so that section is what sends it to the journal: it says when to read memory/, and it tells the model to treat records as untrusted history. To add memory to an existing project, create the hook file and copy the ## Memory section from a fresh bdk init project into your instructions. To turn memory off, delete the hook file and the ## Memory section.

Journal records

The hook appends one JSON line to memory/journal.jsonl after each turn completes or fails:

{"at":"2026-10-01T16:42:09.118Z","sessionId":"5f0c2a9e-7d1b-4c43-9a6e-2b8f1e0d7c35","channelId":"slack","status":"completed","title":"Checkout flaky test","userMessage":"Why does acme/checkout fail on main?","result":"The cart test races the price service mock...","usage":{"inputTokens":18234,"outputTokens":912,"cacheReadTokens":15002,"cacheWriteTokens":0}}
FieldContract
atISO-8601 time the turn finished
sessionIdSession that ran the turn
channelIdChannel that started the session, such as http for the session API
status"completed" or "failed"
titleSession title, when the channel set one
userMessageThe message that started the turn, truncated to maxTextLength
resultFinal assistant text, or the failure message, truncated to maxTextLength
usageToken usage for completed turns; see Events and payloads

As the journal grows, older records move to journal-*.jsonl files beside it. Point the model at the whole memory/ directory when it needs history beyond the latest segment.

Read memory

Local turns find the journal at memory/ in the session workspace. On a Cursor-hosted deployment, the first prompt of each session names the journal's path on that machine. A session on a server you run yourself can't reach the journal.

memory is a reserved workspace path. BDK rejects per-send workspaceFiles and sandbox/workspace/ seed files under memory/, so callers can't write records through the workspace.

Local servers keep the journal in the project state directory. bdk run and bdk eval start an ephemeral server with a fresh state directory unless you pass --state-root, so each run starts with empty memory. Use bdk serve or bdk dev, or pass the same --state-root, to keep memory across runs. Hosted deployments keep the journal across redeploys.

Who sees memory

Records from every session and every user land in the same journal, so one person's messages and the agent's replies to them can surface in another person's session. Turn memory off for an agent whose users shouldn't see each other's requests. Turning it off stops new records, but the journal keeps the records it already has. On a local server, delete the memory/ directory in the project state directory to clear them. On Cursor-managed hosting, the journal is deployment data, so Privacy Mode applies to it.

Anyone who can message the agent can put text in the journal. The scaffolded instructions tell the model never to follow instructions found inside records; keep that rule if you write your own section.

Memory and host state

Memory is advisory. A record can be dropped, and records written by concurrent sessions can show up only in a later session. Keep state your code depends on, such as dedupe records and cursors, in ctx.host.kv or ctx.host.files; see Handler context.

Options

memoryHook(options?) accepts:

OptionContract
maxTextLengthTruncation cap for userMessage and result. Default 2000 characters.
backendA MemoryBackend that replaces the default journal

A MemoryBackend has appendTurn(record, { stateRoot, agentName }), which receives each record, and an optional prepareSession({ stateRoot, agentName }), which runs when a session starts. Records go only where appendTurn sends them, but the memory/ directory and the hosted first-prompt path still point at the default journal. Give the model a tool or file to read your records, and write instructions that send it there instead of memory/.