Claude Code's Org Memory: the Memory Stores REST API#

Companion to Claude Code v2.1.227. | Part of the Claude Code Version Tracker series. | Official Changelog

v2.1.227 added two env vars, CLAUDE_CODE_MEMORY_API_BASE_URL and CLAUDE_CODE_MEMORY_API_TOKEN, that point Claude Code's memory-sync client at a server. That server speaks the Managed Agents Memory Stores REST API. The v2.1.227 binary carries the SDK client for it and the full Markdown reference for it, under the managed-agents-2026-04-01 public-beta header. This post lists every route, payload field, and status code, then the env vars and gate that let you run it against a server you choose.

A memory store is a workspace-scoped set of small text files that survives across sessions. Sessions are otherwise ephemeral: when one ends, what the agent learned is gone. Attach a store and the agent reads and writes it with ordinary file tools; every mutation is kept as an immutable version, so you get an audit trail and point-in-time rollback.

Object model#

Three objects, each with its own ID prefix.

ObjectID prefixScopeNotes
Memory storememstore_...WorkspaceAttached to sessions via resources[]
Memorymem_...StoreOne text file, addressed by path; ≤ 100 KB each — prefer many small files
Memory versionmemver_...MemoryImmutable snapshot per mutation; operationcreated / modified / deleted

Endpoint reference#

Every call carries ?beta=true and the anthropic-beta: managed-agents-2026-04-01 header. The SDK sets the header automatically on client.beta.memory_stores.*.

ResourceSDK methodHTTPPath
StorescreatePOST/v1/memory_stores
listGET/v1/memory_stores
retrieveGET/v1/memory_stores/{memory_store_id}
updatePOST/v1/memory_stores/{memory_store_id}
deleteDELETE/v1/memory_stores/{memory_store_id}
archivePOST/v1/memory_stores/{memory_store_id}/archive
MemoriescreatePOST/v1/memory_stores/{memory_store_id}/memories
listGET/v1/memory_stores/{memory_store_id}/memories
retrieveGET/v1/memory_stores/{memory_store_id}/memories/{memory_id}
updatePOST/v1/memory_stores/{memory_store_id}/memories/{memory_id}
deleteDELETE/v1/memory_stores/{memory_store_id}/memories/{memory_id}
Memory versionslistGET/v1/memory_stores/{memory_store_id}/memory_versions
retrieveGET/v1/memory_stores/{memory_store_id}/memory_versions/{version_id}
redactPOST/v1/memory_stores/{memory_store_id}/memory_versions/{version_id}/redact

The binary's own "Raw HTTP base path" block lists the memory update as PATCH /v1/memory_stores/{id}/memories/{memory_id}; the compiled SDK client issues it as a POST. The SDK verb is what goes on the wire.

Create and attach a store#

create takes a name and a description; the description is fed to the agent, so it is written for the model, not for humans.

store = client.beta.memory_stores.create(
    name="User Preferences",
    description="Per-user preferences and project context.",
)
# store.id -> memstore_01Hx...

Stores support retrieve / update / list (with include_archived and created_at_{gte,lte} filters) / delete / archive. Archive is one-way: the store goes read-only, existing session attachments keep working, new sessions cannot reference it, and there is no unarchive.

A store attaches to a session through the resources[] array, at session-create time only — there is no add-after-create path for a memory store.

session = client.beta.sessions.create(
    agent=agent.id,
    environment_id=environment.id,
    resources=[
        {
            "type": "memory_store",
            "memory_store_id": store.id,
            "access": "read_write",   # or "read_only"; default read_write
            "instructions": "User preferences and project context. Check before any task.",
        }
    ],
)
FieldRequiredNotes
typeyes"memory_store"
memory_store_idyesmemstore_...
accessno"read_write" (default) or "read_only" — enforced at the filesystem level on the mount
instructionsnoPer-session guidance for this store, added to its name/description; ≤ 4,096 chars

A session takes at most 8 memory stores. Split them by owner or lifecycle — a read-only shared-reference store next to a read-write per-user store, for example.

How the agent sees it#

Each attached store mounts in the session container at /mnt/memory/<store-name>/. The agent uses the standard file tools (bash, read, write, edit, glob, grep); there are no dedicated memory tools. read_only makes the mount read-only at the filesystem level. A short description of each mount — name, path, instructions, access — is injected into the system prompt automatically, so the agent knows the store is there without being told. Writes the agent makes under the mount persist back to the store and produce versions, exactly like a host-side update.

Manage memories host-side#

Use these to seed a store, review it, or fix a bad memory out of band.

List returns Memory and MemoryPrefix entries — a MemoryPrefix (type: "memory_prefix", just a path) is a directory-like node. Scope with path_prefix (include the trailing slash: /notes/ matches /notes/a.md but not /notes_backup/old.md) and bound the walk with depth. view="full" includes content; the default "basic" returns metadata only — path, content_sha256, content_size_bytes, updated_at.

Create vs. update differ in how they address the memory:

OperationAddressed bySemantics
memories.create(store_id, path=, content=)PathCreate at path. 409 memory_path_conflict_error (with conflicting_memory_id) if the path is taken.
memories.update(mem_id, memory_store_id=, ...)mem_... IDChange content, path (rename), or both. Rename onto an occupied path returns the same 409.

Optimistic concurrency. update accepts a precondition; the only supported type is content_sha256. Read → modify → write back, passing the sha you read, and a concurrent writer that moved the memory first triggers 409 memory_precondition_failed_error — re-read and retry.

client.beta.memory_stores.memories.update(
    mem.id,
    memory_store_id=store.id,
    content="CORRECTED: 2-space indentation.",
    precondition={"type": "content_sha256", "content_sha256": mem.content_sha256},
)

Delete takes an optional expected_content_sha256 for a conditional delete.

Audit and rollback: memory versions#

Every mutation creates an immutable memver_... snapshot. create at a new path → created; an update or an agent-side write to the mount → modified; a deletedeleted. Each version records created_by — an actor with typesession_actor / api_actor / user_actor — and, after redaction, redacted_at and redacted_by.

list is newest-first and paginated, filterable by memory_id, operation, session_id, api_key_id, and created_at_{gte,lte}. retrieve returns one version.

Redact scrubs a historical version while keeping the audit trail: it clears content, content_sha256, content_size_bytes, and path, and leaves actor and timestamps in place. It is the path for a leaked secret, PII, or a user-deletion request.

client.beta.memory_stores.memory_versions.redact(version_id, memory_store_id=store.id)

Status codes and server-enforced limits#

The write path is validated server-side, and the errors are specific:

ConditionStatus / code
Path already occupied (create, or rename-onto)409 memory_path_conflict_error (+ conflicting_memory_id)
content_sha256 precondition mismatch409 memory_precondition_failed_error
Memory or store not found404
Content larger than 100 KB400 content_too_large — "content must be at most 102400 bytes"
Store at its memory-count or size limit400 store_full
Content looks like a credential400 content_secret
Write against an archived store400 store_archived

The credential check is real string-matching on write: "memory content appears to contain a credential or API key; remove it before writing. If the credential is real, rotate it." The reference is blunt about why — never store secrets in a memory store. A key written once is replayed verbatim into every later session that mounts the store; use vault environment-variable credentials instead, and if a secret already landed, delete the memory and redact the affected versions.

Point it at your own server#

Two env vars aim the memory-sync client, and both are grounded in the v2.1.227 binary:

VariableWhat It Does
CLAUDE_CODE_MEMORY_API_BASE_URLBase URL for the memory API instead of the default. Routes hang off /v1/memory_stores/… under the managed-agents-2026-04-01 beta.
CLAUDE_CODE_MEMORY_API_TOKENBearer token for that server. When set, the client sends Authorization: Bearer and skips its OAuth refresh. Treated as a credential and masked in logs, like CLAUDE_CODE_OAUTH_TOKEN and ANTHROPIC_API_KEY.
CLAUDE_CODE_DISABLE_ORG_MEMORYKill switch. Turns the whole org-memory sync off regardless of the above.

The sync path is gated by tengu_haze_glass and an allow_memory_sync capability; without both, the client reports no_oauth / no-auth and stays parked. Two user settings expose it in the UI: orgMemoryRead ("Synced project memory (this directory; applies next session)") and orgMemoryWrites ("Synced project memory writes"), and writes require reads to be enabled first — both apply on the next session, not the current one.

The client is a real sync engine, not a thin fetch wrapper. It carries maxConcurrentWrites, maxLineLength, stallTimeoutMs, and deadlineMs knobs, and a typed error set — parse_failed, write_failed, oversized_line, too_many_entries, stream_error, stream_truncated, count_mismatch, decrypt_errors. Its delete behaviour is selectable through tengu_mem_push_delete_mode (corroborate / immediate / never), so a remote deletion does not blindly wipe local state.

What this tells us#

Claude Code's org memory is not a bespoke feature bolted onto the CLI. It is a client for a first-class Managed Agents resource that sits next to /v1/agents, /v1/environments, and /v1/files in the same beta, with immutable versioning, optimistic concurrency, server-side secret scanning, and per-memory audit actors. The two env vars are the seam: point the base URL and token at your own implementation of these routes and Claude Code will sync against it. None of this is in the v2.1.227 changelog — the two env vars ship one release before any note names them, and the full API reference is compiled into the binary as documentation the CLI never surfaces.

This analysis is conducted for educational and research purposes under fair use principles. All trademarks and software referenced belong to their respective owners. This content is not intended to infringe on any intellectual property rights, circumvent any protections, or encourage unauthorized access to proprietary systems.

Sources#

  1. Managed Agents Memory Stores reference and SDK client, compiled into the Claude Code v2.1.227 binary (darwin-x64, published August 10, 2026).
  2. Claude Code Official Changelog.