> ## Documentation Index
> Fetch the complete documentation index at: https://opensandbox-feat-types-open-question-labels.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Document memory

> Configuration, session bindings, tools and owner APIs

`documentMemory` stores text under a resource, project and environment.
Agents share documents through session bindings. Development and Production
are separate. Notes survive session end, compaction, sandbox replacement and
deployments; memory operations start no sandbox.

See [Memory](/agents/memory) for the concepts, declaration and binding.

## Configuration

```ts theme={null}
import {
  defineMemory,
  documentMemory,
} from "@opencomputer/agent";

export const notes = defineMemory({
  id: "notes",
  description: "Workshop requirements and decisions.",
  provider: documentMemory({ maxBytes: 8_192 }),
});
```

| Field | Meaning |
| - | - |
| `id` | Shared resource name; see [limits](#limits). |
| `description` | Required, nonempty guidance for the model's tools. |
| `provider` | Defaults to `documentMemory()`. |
| `maxBytes` | Document text limit; default 8,192 UTF-8 bytes. |

The declaration registers a resource; a session binding chooses documents;
`useMemory` selects their projection and tools during render. Declarations
sharing an ID within a deployment must agree on provider and configuration.

* Promotion applies shared limits **before activating code**, including for
  sessions on older deployments. If activation fails, applied limits remain;
  retry the promotion.
* Lowering a limit never truncates notes or rejects deployment. Oversized
  documents remain readable; their next text replacement must fit.
* Changing provider kind requires a new resource and data migration.

## Session bindings

Set `memory.<resource>` when creating a session:

```json theme={null}
{
  "memory": {
    "notes": {
      "scope": "document",
      "id": "workshop",
      "access": "read-write"
    }
  }
}
```

| Scope and access | Projection | Model tools |
| - | - | - |
| Document, read | Full text | None |
| Document, read-write | Full text | `memory_save` |
| Collection, read | Recent summaries | `memory_list`, `memory_read` |

* For collections, use `"scope": "collection"` and omit `id`. Access defaults
  to `read`; collection writes are unsupported.
* Resources must be declared by the deployment and bound documents must exist.
  Invalid bindings fail admission.
* Bindings stay fixed. Schedules and webhooks do not configure them.
* One store per project and environment. An application with many users
  keeps their data apart with document bindings and application-chosen
  document IDs; a collection binding sees every document of the resource, so
  it suits a single owner or a coordinating agent, not one user among many.

Calling `useMemory` exposes the binding's tools; omitting it exposes none.
An unbound hook fails before inference. Tools accept a `memory` resource ID,
required when multiple resources **selected by that render** offer the tool.
Descriptions list those eligible resources and their declared guidance.

Session inspection returns a `memory` array. Entries contain `resource`,
`scope`, optional document `id`, `access` and current `writable`. It is false
for read-only bindings, frozen/deleted documents and ended sessions.

Reusing a session-create `Idempotency-Key` requires the same agent (or the
same pinned deployment), environment and bindings; incompatible inputs return
`409 idempotency_conflict`. The session keeps the deployment it started on,
so a redeploy does not change what the key returns. The
[management API](/agents/api#create) page has the full rules.

### Start a session on a new document

A document and a session are separate objects: the document is owner data
with its own lifetime, the binding is that session's admission to it, and
neither is created as a side effect of the other. The SDK and CLI can create
the document and then the session in one call. These are separate requests;
the document remains if session creation fails.

```ts theme={null}
import { OpenComputer } from "@opencomputer/sdk/agents";

const oc = new OpenComputer({ apiKey: process.env.OPENCOMPUTER_API_KEY! });
const { document, session } = await oc.sessions.startOnDocument({
  projectId: "<project-id>",
  environment: "development",
  agent: "<agent-id>",
  resource: "notes",
  documentId: "workshop",
  document: { title: "Workshop notes" },
  idempotencyKey: "topic/workshop/1",
});
// document.created and session.created are false when they already existed.
```

* The document is created with `If-None-Match: *`. An existing document is
  left as it is; `document` is ignored then. A deleted id is reserved and
  fails before any session is created.
* The session is created with an `Idempotency-Key` derived from
  `idempotencyKey`. The same key with the same agent, environment and
  bindings returns the existing session; anything else under that key
  fails with code `idempotency_key_reused`. `access` (default `read-write`),
  `memory` for further bindings and `source` are passed through.

The helper addresses the agent by its environment alias; the platform
records the deployment the session started on, so a retry after a redeploy
returns the same session. Do not change the key to recover a lost response:
that would create another session.

The CLI does the same for a Development session:

```bash theme={null}
opencomputer session create --memory notes=workshop --create-document --idempotency-key topic/workshop/1
```

`--memory <resource>=<documentId>[:read|read-write]` binds a document
(read-write by default); `--memory <resource>` binds a collection.
`--create-document` creates each bound document that does not exist yet,
titled after its id, and reports it as created or existing. Add a prompt to
run the first turn at once, and `--json` for the ids.

Over HTTP, send `PUT .../documents/<id>` with `If-None-Match: *`, treat `412`
as "exists" (then `GET` it; `404` means the id was deleted), and `POST
/api/managed-agents/sessions` with the document binding,
`agentId: <agent-id>@<environment>` and `Idempotency-Key`; `201` created the
session, `200` returned the one that key had already created. Keep that
envelope unchanged for retries. See [session creation](/agents/api#create)
for the body and the
[Serverless Agents client reference](/reference/typescript-sdk/agents#start-a-session-on-a-memory-document).

## Reading

The hook is synchronous; pass the definition or its ID:

```ts theme={null}
import type { MemorySource } from "@opencomputer/agent";

declare function useMemory(
  memory: string | { readonly id: string },
): {
  readonly text: string;
  readonly sources: readonly MemorySource[];
  readonly writable: boolean;
};
```

* `text`: full document text or a collection overview.
* `sources`: included documents, each with `id`, `title`, `revision` and
  `updatedAt`. Empty documents return `text: ""` and still have a source.
* `writable`: permission **at recall**, always false for collections. It
  neither reserves permission nor changes the binding's tools. Later edits,
  freezes, deletion or session end can still prevent a save.

Every bound resource is recalled before render; any failure blocks inference,
even if that render would omit the hook. The next render reads current notes.
Compaction does not alter stored memory or automatically extract new notes.

### Collections

The overview contains recent entries in this format:

```text theme={null}
workshop | Workshop notes | Node.js 22. | 2026-09-10
```

Fields are ID, title, summary and update date. Full text requires
`memory_read`; `memory_list` reaches documents beyond the overview. Model
calls, with a single selected resource:

```js theme={null}
memory_read({ id: "workshop" })
memory_list({})
memory_list({ cursor: "<nextCursor>" })
```

Read results contain `id`, `title`, `text`, `summary`, `revision`, `updatedAt`.
Lists return `{ documents, nextCursor }`; entries omit `text`. Pass the opaque
cursor with the same resource/environment; null ends pagination. These tools
require a collection binding. Missing documents return status `rejected`,
reason `not_found`; invalid cursors return reason `invalid_cursor`.

## Saving

`memory_save` replaces the bound document:

```json theme={null}
{
  "memory": "notes",
  "text": "Exercises must run on Node.js 22.",
  "summary": "Workshop runtime requirements."
}
```

`text` is required. Omitting `summary` preserves it; `""` clears it. Agents
cannot change IDs, titles or write policy. Results have these shapes:

```ts theme={null}
type SaveResult =
  | { status: "saved"; revision: string; bytes: number }
  | { status: "conflict"; text: string; summary: string }
  | {
      status: "rejected";
      reason: "agent_writes_disabled" | "not_found" | "session_closed";
    }
  | {
      status: "rejected";
      reason: "too_large";
      field: "text" | "summary";
      bytes: number;
      maxBytes: number;
    }
  | {
      status: "rejected";
      reason: "not_bound" | "read_only";
      bound: string[];
    };
```

`saved` commits independently of turn completion. `conflict` carries current
content for reconciliation. Rejections identify frozen or deleted documents,
a session whose end already revoked its writes, a field above its limit, a
resource the render did not select, or a read-only binding. `bound` lists
the resources the save could have targeted. These outcomes let the model continue; malformed arguments
and operational failures are tool errors.

### Conflicts and retries

The host supplies the revision from the originating render. Every save and
retry within that model response uses it: another writer's edit causes a
conflict, as does a second save after the first succeeds. Reconcile in the
next model step; there is no automatic merge.

A committed save whose reply was lost can conflict on retry. Read current
content before writing again. Separately, **model-generation retries can
render again using newer memory**; they do not preserve the same projection.

Observed saves produce `memory.saved` [session events](/agents/events#memory)
with `resource`, `documentId`, `revision`, `bytes`. Delivery is best-effort: a
write can commit without a reply or event. Refresh documents when attaching,
reconnecting and completing work.

## Owner access

The project's **Memory** page shows documents, last writers and update times,
including resources retired from active code. Owner edits use revision checks.
Keep owner credentials in trusted application code.

Install the CLI, then [log in and link your project](/agents/quickstart):

```bash theme={null}
npm install -g @opencomputer/cli
```

Commands default to Development; add `--environment production` for
production.

List metadata:

```bash theme={null}
opencomputer memory list notes
```

Read a document:

```bash theme={null}
opencomputer memory show notes workshop
```

Create empty notes:

```bash theme={null}
opencomputer memory create notes workshop --title "Workshop"
```

Open existing text in your editor:

```bash theme={null}
opencomputer memory edit notes workshop
```

Create and edit accept `--text-file <path>`, `--text-stdin`, and
`--summary <text>`. Create also accepts `--frozen`. Add `--json` for
structured output: list follows all pages and returns `{ documents }`; show
returns the [document object](#documents).

### Disable agent writes

Freeze:

```bash theme={null}
opencomputer memory freeze notes workshop
```

Re-enable writes:

```bash theme={null}
opencomputer memory unfreeze notes workshop
```

Freeze sets `agentWrites: "disabled"`; after success, no later agent save can
commit. Earlier saves remain; reads and owner edits continue. Unfreeze enables
active bindings without reviving ended sessions or cancelling work.

Successful session end revokes its document-memory access. A failed or timed
out end has an uncertain outcome; freeze the document to block all agent
writes while resolving it. [Remote providers](/agents/memory-providers) have
a separate completion contract.

### Export saved notes

```bash theme={null}
opencomputer memory export --out ./memory
```

Export includes retired resources; repeat `--resource <id>` to restrict it.
Each `<out>/<resource>/<id>.json` contains current document fields. Reads are
individual: this is not a consistent snapshot or revision/session backup.
Credentials, conversation history and sandbox files are excluded.

### Delete a document

```bash theme={null}
opencomputer memory remove notes workshop
```

Deletion removes title, text and summary but reserves the ID against delayed
recreation. Collections omit it; existing document bindings fail their next
recall, and pending saves return `not_found`. Copies in history, tool results
and exports remain. Use a new ID for new notes.

## Management API

Use `x-api-key: <api-key>` on `https://app.opencomputer.dev`, as for the rest
of the [management API](/agents/api). Every route requires
`environment=development` or `environment=production` as a query parameter.
Below, `<p>` is the project ID and `<r>` the resource ID.

### Resource inventory

```text theme={null}
GET /api/managed-agents/projects/<p>/memory
```

```json theme={null}
{
  "resources": [
    {
      "id": "notes",
      "provider": {
        "kind": "document",
        "maxBytes": 8192
      },
      "declared": true,
      "documents": 2
    }
  ]
}
```

* `provider`: stored kind and current limit.
* `declared`: whether any active deployment in the environment declares it.
* `documents`: count of non-deleted documents.

Retired resources remain discoverable, editable and exportable. Removing
declarations neither revokes existing bindings nor deletes notes. New sessions
need a deployment declaring their resources.

Renaming an ID requires migration; reusing it addresses the same stored data.

### Documents

Paths are relative to this base; append `?environment=development`:

```text theme={null}
/api/managed-agents/projects/<p>/memory/<r>/documents
```

| Operation | Method/path | Success |
| - | - | - |
| List metadata | `GET` | `200` |
| Read | `GET /<id>` | `200` |
| Create | `PUT /<id>` | `201` |
| Replace text/summary | `PUT /<id>` | `200` |
| Change title/policy | `PATCH /<id>` | `200` |
| Delete | `DELETE /<id>` | `204`, empty body |

Create requires `If-None-Match: *` and a never-used ID. Other mutations require
`If-Match: "<revision>"`; checks and writes happen together. JSON bodies:

* **Create:** required `title`; optional `text`, `summary` default to `""`;
  `agentWrites` defaults to `"enabled"`.
* **Replace:** required `text`; omitted `summary` is preserved.
* **Patch:** `title`, `agentWrites`, or both. Omitted fields stay unchanged.

`agentWrites` accepts `"enabled"` or `"disabled"`. Unknown fields are rejected.
Read, create, replace and patch return the document and its quoted `ETag`:

```json theme={null}
{
  "id": "workshop",
  "title": "Workshop notes",
  "text": "Exercises must run on Node.js 22.",
  "summary": "Workshop runtime requirements.",
  "agentWrites": "enabled",
  "revision": "<opaque-revision>",
  "bytes": 33,
  "maxBytes": 8192,
  "updatedAt": "2026-09-10T12:00:00.000Z",
  "writer": { "kind": "owner" }
}
```

`bytes` counts UTF-8 text bytes; `maxBytes` is the current limit. The platform
sets `writer` to `{ kind: "owner" }` or `{ kind: "agent", sessionId }`.
Revision is opaque: retain `ETag` verbatim for `If-Match`. Delete returns no
new document ETag.

List returns `{ documents, nextCursor }`, omitting `text` from entries. Pass
`nextCursor` as the `cursor` query parameter until null. Order is descending
update time, then ascending ID. Pagination is live; concurrent edits can move
documents between pages. Re-list for a complete current inventory.

### Errors

Error bodies are `{ error: { code, message } }`:

| Status | Code | Meaning |
| - | - | - |
| `400` | `invalid_request` | Invalid input, environment or conditions |
| `404` | `not_found` / `project_not_found` | Missing/deleted target |
| `412` | `precondition_failed` | Stale revision or already-used create ID |
| `413` | `memory_limit_exceeded` | Field size limit |
| `428` | `precondition_required` | Missing condition header |

Authentication/authorization failures return `401`/`403`. On `412`, read the
latest document and reconcile.

Network/server errors can leave mutations committed without acknowledgement.
Read current state before retrying; conditional writes protect newer content
but do not replay the original response.

## Limits

| Item | Limit |
| - | - |
| Resource ID | 1–128 lowercase letters/digits, single hyphen separators |
| Document ID | 1–128 ASCII letters, digits, `-`, `_` |
| Document text | `maxBytes`: integer 1–16,384; default 8,192 UTF-8 bytes |
| Title | 1–240 UTF-8 bytes |
| Summary | 0–240 UTF-8 bytes |
| Mutation JSON body | 64 KiB |
| Bindings per session | 8 |
| Collection overview | 50 whole entries within 16 KiB |
| List page | 50 documents |

Field limits are separate. These are not token budgets: memory shares the
model context with instructions, history and tools, without silent truncation.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.