# Agent memory (/docs/run/memory)



```json title="releases.json"
{
  "$schema": "https://docs.nylorun.com/schemas/agent-manifest/v8.json",
  "manifestSchemaVersion": 8,
  "name": "releases",
  "harness": {
    "instructions": ["Help the team ship releases."],
    "memory": { "access": "read_write", "instructions": "Keep the team's release conventions." }
  },
  "runtime": { "kind": "none" }
}
```

```ts
import { readFile } from "node:fs/promises";

await client.agentManifests.save(JSON.parse(await readFile("releases.json", "utf8")));
await client.agents.put("teams/web/releases", { manifest: "releases" });

// Seed it: the agent finds this note in its first session.
await client.agents.memories.put(
  "teams/web/releases",
  "conventions/release.md",
  "---\ndescription: How the web team tags and ships a release\n---\n\nTag releases vX.Y.Z from main.\n",
);
```

`harness.memory` in an [agent manifest](/docs/run/agent-manifests) gives each
[Agent](/docs/run/agents) made from it a memory: Markdown files under
`/memories` that the agent reads and edits, and that stay with the Agent
across its sessions, [triggered turns and wakes](/docs/run/triggers), and its
moves to new versions.

## Turn it on [#turn-it-on]

Set `memory` wherever you write the harness section:

| Where                                                                                        | How                                                                                                                                                                                                                               |
| -------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| A built agent                                                                                | `client.agentManifests.save({ agent, runtime, memory: { access: "read_write" } })`; `plan()` and `agentManifest()` take it too.                                                                                                   |
| An agent manifest                                                                            | `memory: { … }` in the frontmatter of [`AGENT.md`](/docs/build/agent-manifests#agentmd), which `npx nylorun apply` saves.                                                                                                         |
| A harness file (the deprecated [three-file format](/docs/build/agent-manifests#three-files)) | `"memory": { … }` in `harness.manifest.json`, which `npx nylorun apply` saves.                                                                                                                                                    |
| The manifest document                                                                        | `harness.memory`, as above, with `client.agentManifests.save(document)` or [`PUT /v1/agent-manifests/{name}`](/reference/runtime/agents/manifests/save-an-agent-manifest). The SDK drops `$schema`; a direct `PUT` leaves it out. |

| Field          | Meaning                                                                                                |
| -------------- | ------------------------------------------------------------------------------------------------------ |
| `access`       | `read_write` (the default) or `read_only`: the agent views its memories but does not change them.      |
| `instructions` | What this agent should remember, at most 4,096 characters. They follow our harness's own memory rules. |

```ts
// releases is the Agent() from agents/releases/agent.ts.
await client.agentManifests.save({
  agent: releases,
  runtime: { kind: "none" },
  memory: { access: "read_write", instructions: "Keep the team's release conventions." },
});
```

A flow's harness section has no `memory`; the SDK refuses it for a flow.

Each turn reads `harness.memory` from the manifest version it runs, so a save
that adds it turns memory on at each session's next turn on an Agent that
[tracks the manifest](/docs/run/agents#versions).

## What the agent gets [#what-the-agent-gets]

Our harness gives the agent one `memory` tool, the commands of Anthropic's
memory tool: `view`, `create`, `str_replace`, `insert`, `delete`, and `rename`.

* **Paths** start with `/memories/`, end in `.md`, and are at most 512
  characters. Folders are the prefixes of memory paths.
* **An index** opens each session: a line per memory, newest first, with the
  `description` from its YAML frontmatter when it has one, within
  `memoryIndexLines` (200) lines and `memoryIndexBytes` (25 KiB). When some are
  left out, the agent views folders for the rest. A compaction refreshes it.
* **Instructions:** our harness's memory rules, which tell the agent never to
  keep secrets, then `harness.memory.instructions`.
* **Access** holds for every turn, whoever starts it: a person, an app, a
  trigger, or a wake. With `read_only`, and for an agent used as a tool, a
  write fails with `memory.forbidden`; only the session's own agent writes.

Each call is a `tool.completed` with `kind: "runtime"`: the Runtime serves it
in the turn's own record, so a replayed turn applies a write once. The
[tool policy](/docs/run/tool-policy) does not hold `memory` calls. A call that
changed something writes `memory.updated` in the session (`effectId`, and
`changes`, each `{ path, operation, version }`) and `agent.memory_updated` on
the Agent's stream, with its `sessionId` and `turnId`.

## Where it lives [#where-it-lives]

Memories are the Agent's, kept in the Runtime with it:

| When                                                     | Memories                                                     |
| -------------------------------------------------------- | ------------------------------------------------------------ |
| The Agent moves to another version                       | Kept.                                                        |
| The Agent is forked                                      | Copied to the new Agent, each at version 1, without history. |
| The Agent is deleted, or `nylorun tenant reset --agents` | Deleted.                                                     |

Every change is a version that names who made it: `agent:<manifest>@<version>`
with the session, turn, and trigger run for a turn, or the caller for an API
write. Versions keep the content each change left.

## Manage it [#manage-it]

```ts
const id = "teams/web/releases";
const { memories } = await client.agents.memories.list(id, { pathPrefix: "conventions" });

const memory = await client.agents.memories.get(id, "conventions/release.md");
await client.agents.memories.put(id, "conventions/release.md", `${memory.content}\nShip on Tuesdays.\n`, {
  contentSha256: memory.contentSha256,
});

const { versions } = await client.agents.memories.versions(id, { path: "conventions/release.md" });
```

| Call                                                                | CLI                                             | Does                                                                                                              |
| ------------------------------------------------------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `client.agents.memories.list(id, { pathPrefix?, limit?, cursor? })` | `agents memories ls <id> [--prefix <folder>]`   | Memories by path: `path`, `bytes`, `contentSha256`, `description`, `version`, `updatedAt`.                        |
| `client.agents.memories.get(id, path)`                              | `agents memories cat <id> <path>`               | One memory with its `content`.                                                                                    |
| `client.agents.memories.put(id, path, content, { contentSha256? })` | `agents memories put <id> <path> <file\|->`     | Create or replace it whole: how an app seeds an Agent's memory.                                                   |
| `client.agents.memories.delete(id, path)`                           | `agents memories rm <id> <path>`                | Delete a memory, or every memory in a folder.                                                                     |
| `client.agents.memories.versions(id, { path?, limit?, cursor? })`   | `agents memories versions <id> [--path <path>]` | Every change, newest first: `operation`, `actor`, `sessionId`, `turnId`, `triggerRunId`, `fromPath` for a rename. |
| `client.agents.memories.version(id, versionId)`                     |                                                 | One version with the content it left (`null` for a delete).                                                       |

A path may be given as `conventions/release.md` or
`/memories/conventions/release.md`. `put` with `contentSha256` writes only
while the memory still has that content, and `""` writes only while no memory
has the path; otherwise it is `409 memory_conflict` with the current memory.
Reading takes `agents:read`, `agents:write`, or `sessions:own` for an Agent the
caller reaches; writing takes `agents:write`. Request and response shapes are
on [Write a memory](/reference/runtime/agents/memory/write-a-memory) and
[List an Agent's memories](/reference/runtime/agents/memory/list-an-agents-memories).

In [Studio](/docs/run/studio#agent-page), the Agent page's **Memory** tab
lists each memory with its description, version, and who changed it last. A
row opens its content and history, and **Delete** removes it.

## Keep secrets out [#keep-secrets-out]

Our harness tells the agent never to keep secrets, but nothing scans what it
writes. Read an Agent's memory before you share it, fork it, or give another
person's sessions access to it.

## Limits [#limits]

| Limit                                  | Default            | Crossing it                                                           |
| -------------------------------------- | ------------------ | --------------------------------------------------------------------- |
| `memoryBytes`                          | 100 KiB per memory | `413` on a `put`; `memory.too_large` for the agent's call.            |
| `memoriesPerAgent`                     | 10,000             | `409 limit_exceeded` on a `put`; `memory.limit` for the agent's call. |
| `memoryIndexLines`, `memoryIndexBytes` | 200 lines, 25 KiB  | The index leaves out the oldest memories.                             |

They are [Runtime limits](/docs/run/limits), set per Tenant.

## Next step [#next-step]

<Cards>
  <Card title="Triggers and wakes" description="Run the Agent on a schedule, so it uses what it remembers." href="/docs/run/triggers" />

  <Card title="Saving manifests" description="Save the manifest document and its versions." href="/docs/run/agent-manifests" />
</Cards>
