# 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

`agent-sdk init` scaffolds `bot/hooks/memory.ts`:

```ts
// bot/hooks/memory.ts
import { memoryHook } from "@grok/agent-sdk/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 `agent-sdk 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:

```json
{"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}}
```

| Field | Contract |
| --- | --- |
| `at` | ISO-8601 time the turn finished |
| `sessionId` | Session that ran the turn |
| `channelId` | Channel that started the session, such as `http` for the session API |
| `status` | `"completed"` or `"failed"` |
| `title` | Session title, when the channel set one |
| `userMessage` | The message that started the turn, truncated to `maxTextLength` |
| `result` | Final assistant text, or the failure message, truncated to `maxTextLength` |
| `usage` | Token usage for completed turns; see [Events and payloads](/docs/reference/hooks.md#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. Agent SDK 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. `agent-sdk
run` and `agent-sdk eval` start an ephemeral server with a fresh state
directory unless you pass `--state-root`, so each run starts with
empty memory. Use `agent-sdk serve` or `agent-sdk 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](/docs/deployment.md#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](/docs/reference/hooks.md#handler-context).

## Options

`memoryHook(options?)` accepts:

| Option | Contract |
| --- | --- |
| `maxTextLength` | Truncation cap for `userMessage` and `result`. Default `2000` characters. |
| `backend` | A `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/`.

## Related

- [Hooks](/docs/reference/hooks.md)
- [Instructions](/docs/reference/instructions.md)
- [Sessions](/docs/reference/sessions.md)
- [Deployment](/docs/deployment.md)
