# Memory

A memory hook appends one record per turn to a journal. The model reads
the journal with its file tools when its instructions send it there.

## Memory is on by default

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

```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 tells it when to read `memory/` and
to treat records as untrusted history. To add memory to an existing
project, copy both from a new `agent-sdk init` project. To turn memory
off, delete both.

## Journal records

After each turn, the hook appends one JSON line to
`memory/journal.jsonl`:

```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                   |
| `status`      | `"completed"` or `"failed"`                        |
| `title`       | Session title, if set                              |
| `userMessage` | The turn's message, truncated                      |
| `result`      | Final assistant text or failure message, truncated |
| `usage`       | Token usage for completed turns                    |

As the journal grows, older records move to `journal-*.jsonl` files
beside it, so point the model at the whole `memory/` directory.

## Read memory

Local turns find the journal at `memory/` in the session workspace. On
Cursor hosting, Agent SDK tells the model where the journal is at the
start of each session. A session on a server you run yourself can't
reach the journal. Agent SDK rejects `workspaceFiles` and
`sandbox/workspace/` seed files under the reserved `memory/` path.

Local servers keep the journal in the project state directory. `agent-sdk run` and `agent-sdk eval` start with empty memory unless you pass `--state-root`, and hosted deployments keep the journal across redeploys.

## Caveats

- All sessions and users share one journal, so one person's messages
  can surface in another's session.
- Turning memory off keeps existing records. Locally, delete `memory/`
  in the project state directory to clear them. On Cursor hosting,
  [Privacy Mode](https://cursor.com/docs/agent-sdk/deployment.md#privacy-mode) applies.
- Anyone who can message the agent writes to the journal, so keep the
  scaffolded rule against following instructions found in records.
- Records can be dropped or arrive late. Keep state your code depends
  on in `ctx.host.kv` or `ctx.host.files`.

## Options

| `memoryHook` 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 })`
and an optional `prepareSession({ stateRoot, agentName })` that runs
when a session starts. The model still looks in `memory/`, so tell it
how to read your records.


---

## Sitemap

[Overview of all docs pages](/llms.txt)
