Haijun Platform Docs
ID

Each Managed Agents session starts with a fresh context by default. When a session ends, any state the agent built up is gone. Memory stores let the agent carry information across sessions: user preferences, project conventions, prior mistakes, and domain context.

Note: Don't combine agent-memory-2026-07-22 with managed-agents-2026-04-01 on a memory store request: sending both returns a 400 error. If your code sets beta headers explicitly, replace managed-agents-2026-04-01 with agent-memory-2026-07-22 on memory store calls rather than adding a second value. Session endpoints, including attaching a memory store to a session, still use managed-agents-2026-04-01. GET /v1/memory_stores/{memory_store_id}/memories behaves the same under either header: results come back in a stable, server-defined order, and path_prefix and depth apply the same way.

Overview

A memory store is a workspace-scoped collection of text documents optimized for Haijun. When you attach a store to a session, it is mounted as a directory inside the session's sandbox. The agent reads and writes it with the same file tools it uses for the rest of the filesystem, and a note describing each mount is automatically added to the system prompt, telling the agent where to look. The agent toolset is required for these interactions; make sure to enable it during agent creation. On self-hosted sandboxes, that directory is not a live mount. Instead, the SDK's environment worker downloads each attached store into your sandbox before the agent's tools run and keeps that copy in sync with the store.

Each memory in a store is addressed by a path and can be read and edited directly through the API or the Haijun Console, allowing for tuning, importing, and exporting.

Every change to a memory creates an immutable memory version, giving you an audit trail and point-in-time recovery for everything the agent writes.

Create a memory store

Give the store a name and a description. The description is passed to the agent, telling it what the store contains.

bash
  curl -s https://haijun.my.id/v1/memory_stores \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: agent-memory-2026-07-22" \
    -H "content-type: application/json" \
    -d '{"name": "User Preferences", "description": "Per-user preferences and project context."}'
bash
    ant apply memory_store.yaml
yaml
      # yaml-language-server: $schema=https://platform.juglow.my.id/schemas/ant/beta/memory_store.json
      name: User Preferences
      description: Per-user preferences and project context.
python
  store = client.beta.memory_stores.create(
      name="User Preferences",
      description="Per-user preferences and project context.",
  )
  print(store.id)  # memstore_01Hx...
typescript
  const store = await client.beta.memoryStores.create({
    name: "User Preferences",
    description: "Per-user preferences and project context."
  });
  console.log(store.id); // memstore_01Hx...
csharp
  var store = await client.Beta.MemoryStores.Create(new()
  {
      Name = "User Preferences",
      Description = "Per-user preferences and project context.",
  });
  Console.WriteLine(store.ID);  // memstore_01Hx...
go
  store, err := client.Beta.MemoryStores.New(ctx, juglow.BetaMemoryStoreNewParams{
  	Name:        "User Preferences",
  	Description: juglow.String("Per-user preferences and project context."),
  })
  if err != nil {
  	panic(err)
  }
  fmt.Println(store.ID) // memstore_01Hx...
java
  var store = client.beta().memoryStores().create(
      MemoryStoreCreateParams.builder()
          .name("User Preferences")
          .description("Per-user preferences and project context.")
          .build()
  );
  IO.println(store.id());  // memstore_01Hx...
php
  use Juglow\Client;

  $client = new Client();

  $store = $client->beta->memoryStores->create(
      name: 'User Preferences',
      description: 'Per-user preferences and project context.',
  );
  echo "{$store->id}\n"; // memstore_01Hx...
ruby
  require "juglow"

  client = Juglow::Client.new

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

The memory store id (memstore_...) is what you pass when attaching the store to a session.

Seed it with content (optional)

Pre-load a store with reference material before any agent runs:

bash
  curl -s "https://haijun.my.id/v1/memory_stores/$store_id/memories" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: agent-memory-2026-07-22" \
    -H "content-type: application/json" \
    -d '{"path": "/formatting_standards.md", "content": "All reports use GAAP formatting. Dates are ISO-8601..."}' > /dev/null
bash
  ant beta:memory-stores:memories create \
    --memory-store-id "$store_id" \
    --path "/formatting_standards.md" \
    --content "All reports use GAAP formatting. Dates are ISO-8601..." \
    > /dev/null
python
  client.beta.memory_stores.memories.create(
      store.id,
      path="/formatting_standards.md",
      content="All reports use GAAP formatting. Dates are ISO-8601...",
  )
typescript
  await client.beta.memoryStores.memories.create(store.id, {
    path: "/formatting_standards.md",
    content: "All reports use GAAP formatting. Dates are ISO-8601..."
  });
csharp
  await client.Beta.MemoryStores.Memories.Create(store.ID, new()
  {
      Path = "/formatting_standards.md",
      Content = "All reports use GAAP formatting. Dates are ISO-8601...",
  });
go
  _, err = client.Beta.MemoryStores.Memories.New(ctx, store.ID, juglow.BetaMemoryStoreMemoryNewParams{
  	Path:    "/formatting_standards.md",
  	Content: juglow.String("All reports use GAAP formatting. Dates are ISO-8601..."),
  })
  if err != nil {
  	panic(err)
  }
java
  client.beta().memoryStores().memories().create(
      store.id(),
      MemoryCreateParams.builder()
          .path("/formatting_standards.md")
          .content("All reports use GAAP formatting. Dates are ISO-8601...")
          .build()
  );
php
  $client->beta->memoryStores->memories->create(
      $store->id,
      path: '/formatting_standards.md',
      content: 'All reports use GAAP formatting. Dates are ISO-8601...',
  );
ruby
  client.beta.memory_stores.memories.create(
    store.id,
    path: "/formatting_standards.md",
    content: "All reports use GAAP formatting. Dates are ISO-8601..."
  )

Tip: Individual memories within the store are capped at 100 kB (\~25k tokens). A store holds a maximum of 10,000 memories. Structure memory as many small focused files, not a few large ones.

Attach a memory store to a session

Memory stores are attached in the session's resources[] array when the session is created. Unlike file resources, memory stores can only be attached at session creation time; adding or removing one from a running session is not supported. You attach memory stores the same way for sessions on cloud and self-hosted environments; self-hosted environments accept only memory_store resources.

Optionally include instructions to provide session-specific guidance for how the agent should use this store. It is shown to the agent alongside the store's name and description, and is capped at 4,096 characters.

You can configure access as well. It defaults to read_write (shown explicitly in the following example), but read_only is also supported.

bash
  curl -s https://haijun.my.id/v1/sessions \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: managed-agents-2026-04-01" \
    -H "content-type: application/json" \
    --data @- <<EOF
  {
    "agent": "$agent_id",
    "environment_id": "$environment_id",
    "resources": [
      {
        "type": "memory_store",
        "memory_store_id": "$store_id",
        "access": "read_write",
        "instructions": "User preferences and project context. Check before starting any task."
      }
    ]
  }
  EOF
bash
  ant beta:sessions create <<YAML
  agent: $agent_id
  environment_id: $environment_id
  resources:
    - type: memory_store
      memory_store_id: $store_id
      access: read_write
      instructions: User preferences and project context. Check before starting any task.
  YAML
python
  session = client.beta.sessions.create(
      agent=agent.id,
      environment_id=environment.id,
      resources=[
          {
              "type": "memory_store",
              "memory_store_id": store.id,
              "access": "read_write",
              "instructions": "User preferences and project context. Check before starting any task.",
          }
      ],
  )
typescript
  const session = await client.beta.sessions.create({
    agent: agent.id,
    environment_id: environment.id,
    resources: [
      {
        type: "memory_store",
        memory_store_id: store.id,
        access: "read_write",
        instructions: "User preferences and project context. Check before starting any task."
      }
    ]
  });
csharp
  var session = await client.Beta.Sessions.Create(new()
  {
      Agent = agent.ID,
      EnvironmentID = environment.ID,
      Resources =
      [
          new BetaManagedAgentsMemoryStoreResourceParam
          {
              Type = "memory_store",
              MemoryStoreID = store.ID,
              Access = "read_write",
              Instructions = "User preferences and project context. Check before starting any task.",
          },
      ],
  });
go
  session, err := client.Beta.Sessions.New(ctx, juglow.BetaSessionNewParams{
  	Agent: juglow.BetaSessionNewParamsAgentUnion{
  		OfString: juglow.String(agent.ID),
  	},
  	EnvironmentID: environment.ID,
  	Resources: []juglow.BetaSessionNewParamsResourceUnion{{
  		OfMemoryStore: &juglow.BetaManagedAgentsMemoryStoreResourceParam{
  			Type:          juglow.BetaManagedAgentsMemoryStoreResourceParamTypeMemoryStore,
  			MemoryStoreID: store.ID,
  			Access:        juglow.BetaManagedAgentsMemoryStoreResourceParamAccessReadWrite,
  			Instructions:  juglow.String("User preferences and project context. Check before starting any task."),
  		},
  	}},
  })
  if err != nil {
  	panic(err)
  }
java
  var session = client.beta().sessions().create(
      SessionCreateParams.builder()
          .agent(agent.id())
          .environmentId(environment.id())
          .addResource(
              BetaManagedAgentsMemoryStoreResourceParam.builder()
                  .type(BetaManagedAgentsMemoryStoreResourceParam.Type.MEMORY_STORE)
                  .memoryStoreId(store.id())
                  .access(BetaManagedAgentsMemoryStoreResourceParam.Access.READ_WRITE)
                  .instructions("User preferences and project context. Check before starting any task.")
                  .build()
          )
          .build()
  );
php
  $session = $client->beta->sessions->create(
      agent: $agent->id,
      environmentID: $environment->id,
      resources: [
          [
              'type' => 'memory_store',
              'memory_store_id' => $store->id,
              'access' => 'read_write',
              'instructions' => 'User preferences and project context. Check before starting any task.',
          ],
      ],
  );
ruby
  session = client.beta.sessions.create(
    agent: agent.id,
    environment_id: environment.id,
    resources: [
      {
        type: "memory_store",
        memory_store_id: store.id,
        access: "read_write",
        instructions: "User preferences and project context. Check before starting any task."
      }
    ]
  )

Warning: Memory stores attach with read_write access by default. If the agent processes untrusted input (user-supplied prompts, fetched web content, or third-party tool output), a successful prompt injection could write malicious content into the store. Later sessions then read that content as trusted memory. Use read_only for reference material, shared lookups, and any store the agent does not need to modify.

A maximum of 8 memory stores are supported per session. Attach multiple stores when different parts of memory have different owners or access rules. Common reasons:

  • Shared reference material: one read-only store attached to many sessions (standards, conventions, domain knowledge), kept separate from each session's own read-write store.
  • Mapping to your product's structure: one store per end user, per team, or per project, while sharing a single agent configuration.
  • Different lifecycles: a store that outlives any single session, or one you want to archive on its own schedule.

How the agent accesses memory

Each attached store is mounted inside the session's sandbox as a directory under /mnt/memory/. The directory name is the store's display name sanitized to a filesystem-safe slug (lowercased; non-alphanumeric runs become a single hyphen), so a store named "Demo Memory" mounts at /mnt/memory/demo-memory/. The exact path is returned in the mount_path field on the session's memory-store resource; read it from there rather than constructing it yourself. The agent reads and writes the store with the standard agent toolset. Writes under the mount path are persisted back to the store and stay in sync across sessions that share it; writes to any other path under /mnt/memory/ fail, because the sandbox mounts that parent directory read-only. A short description of each mount (display name, mount path, access mode, store description, and any instructions) is automatically added to the system prompt.

access is enforced at the filesystem level: a read_only mount rejects writes, while writes to a read_write mount produce memory versions attributed to the session.

Note: On self-hosted sandboxes, each store's directory is a local copy that the SDK worker manages rather than a live mount. The worker reconciles each copy with its store after tool calls, at most once per sync interval (15 seconds by default), and once more when the session ends. The agent's write and edit tools change only the local copy; the worker uploads those changes at its next sync, so another session running on a self-hosted sandbox sees a change only after both workers have synced. Paths under /mnt/memory/ outside the store directories are not scratch space there: the worker's file tools refuse to write to them, and anything a shell command writes there is never synced to a store. For a read_only store, the worker's write and edit tools refuse changes under that directory and the worker never uploads anything from it. To learn how the worker resolves write conflicts, and what the bash tool can still change in a read-only store's local copy, see Read-only stores and conflicts.

The agent's reads and writes appear in the event stream as ordinary agent.tool_use and agent.tool_result events for whichever tool touched the mount.

View and edit memories

Memory stores can be managed directly through the API. Use this for building review workflows, correcting bad memories, or seeding stores before any session runs.

List memories

List the memories in a store. Results are returned in a stable, server-defined order.

  • path_prefix scopes the list to one directory. It must end with / and matches whole path segments, so path_prefix=/notes/ returns /notes/todo.md but not /notes-archive/todo.md.
  • depth controls how deep the listing goes below path_prefix: omit it (or pass 0) to list the whole subtree, or pass 1 to list only the immediate children. Other values return a 400 error.
bash
  curl -s "https://haijun.my.id/v1/memory_stores/$store_id/memories?path_prefix=/" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: agent-memory-2026-07-22"
bash
  ant beta:memory-stores:memories list \
    --memory-store-id "$store_id" \
    --path-prefix "/"
python
  page = client.beta.memory_stores.memories.list(
      store.id,
      path_prefix="/",
  )
  for item in page.data:
      print(item.type, item.path)
typescript
  const page = await client.beta.memoryStores.memories.list(store.id, {
    path_prefix: "/"
  });
  for (const item of page.data) {
    console.log(item.type, item.path);
  }
csharp
  var page = await client.Beta.MemoryStores.Memories.List(store.ID, new()
  {
      PathPrefix = "/",
  });
  await foreach (var item in page.Paginate())
  {
      var line = item.Match(m => $"memory  {m.Path}", p => $"memory_prefix  {p.Path}");
      Console.WriteLine(line);
  }
go
  page, err := client.Beta.MemoryStores.Memories.List(ctx, store.ID, juglow.BetaMemoryStoreMemoryListParams{
  	PathPrefix: juglow.String("/"),
  })
  if err != nil {
  	panic(err)
  }
  for _, item := range page.Data {
  	fmt.Println(item.Type, item.Path)
  }
java
  var page = client.beta().memoryStores().memories().list(
      store.id(),
      MemoryListParams.builder()
          .pathPrefix("/")
          .build()
  );
  for (var item : page.data()) {
      item.memory().ifPresent(m -> IO.println("memory  " + m.path()));
      item.memoryPrefix().ifPresent(p -> IO.println("memory_prefix  " + p.path()));
  }
php
  $page = $client->beta->memoryStores->memories->list(
      $store->id,
      pathPrefix: '/',
  );
  foreach ($page->data as $item) {
      echo "{$item->type}  {$item->path}\n";
  }
ruby
  page = client.beta.memory_stores.memories.list(
    store.id,
    path_prefix: "/"
  )
  page.data.each do |entry|
    puts "#{entry.type}  #{entry.path}"
  end

See the List memories reference for full parameters and response schema.

Read a memory

Fetching an individual memory returns the full content.

bash
  curl -s "https://haijun.my.id/v1/memory_stores/$store_id/memories/$mem_id" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: agent-memory-2026-07-22"
bash
  ant beta:memory-stores:memories retrieve \
    --memory-store-id "$store_id" \
    --memory-id "$mem_id"
python
  retrieved = client.beta.memory_stores.memories.retrieve(
      mem.id,
      memory_store_id=store.id,
  )
  print(retrieved.content)
typescript
  const retrieved = await client.beta.memoryStores.memories.retrieve(mem.id, {
    memory_store_id: store.id
  });
  console.log(retrieved.content);
csharp
  var retrieved = await client.Beta.MemoryStores.Memories.Retrieve(mem.ID, new()
  {
      MemoryStoreID = store.ID,
  });
  Console.WriteLine(retrieved.Content);
go
  retrieved, err := client.Beta.MemoryStores.Memories.Get(ctx, mem.ID, juglow.BetaMemoryStoreMemoryGetParams{
  	MemoryStoreID: store.ID,
  })
  if err != nil {
  	panic(err)
  }
  fmt.Println(retrieved.Content)
java
  var retrieved = client.beta().memoryStores().memories().retrieve(
      mem.id(),
      MemoryRetrieveParams.builder().memoryStoreId(store.id()).build()
  );
  IO.println(retrieved.content().orElseThrow());
php
  $retrieved = $client->beta->memoryStores->memories->retrieve($mem->id, memoryStoreID: $store->id);
  echo "{$retrieved->content}\n";
ruby
  retrieved = client.beta.memory_stores.memories.retrieve(
    mem.id,
    memory_store_id: store.id
  )
  puts retrieved.content

See the Retrieve a memory reference for full parameters and response schema.

Create a memory

memories.create creates a memory at a given path. Create does not overwrite; to change an existing memory, use memories.update.

bash
  curl -s "https://haijun.my.id/v1/memory_stores/$store_id/memories" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: agent-memory-2026-07-22" \
    -H "content-type: application/json" \
    -d '{"path": "/preferences/formatting.md", "content": "Always use tabs, not spaces."}'
bash
  ant beta:memory-stores:memories create \
    --memory-store-id "$store_id" \
    --path "/preferences/formatting.md" \
    --content "Always use tabs, not spaces."
python
  mem = client.beta.memory_stores.memories.create(
      store.id,
      path="/preferences/formatting.md",
      content="Always use tabs, not spaces.",
  )
typescript
  const mem = await client.beta.memoryStores.memories.create(store.id, {
    path: "/preferences/formatting.md",
    content: "Always use tabs, not spaces."
  });
csharp
  var mem = await client.Beta.MemoryStores.Memories.Create(store.ID, new()
  {
      Path = "/preferences/formatting.md",
      Content = "Always use tabs, not spaces.",
  });
go
  mem, err := client.Beta.MemoryStores.Memories.New(ctx, store.ID, juglow.BetaMemoryStoreMemoryNewParams{
  	Path:    "/preferences/formatting.md",
  	Content: juglow.String("Always use tabs, not spaces."),
  })
  if err != nil {
  	panic(err)
  }
java
  var mem = client.beta().memoryStores().memories().create(
      store.id(),
      MemoryCreateParams.builder()
          .path("/preferences/formatting.md")
          .content("Always use tabs, not spaces.")
          .build()
  );
php
  $mem = $client->beta->memoryStores->memories->create(
      $store->id,
      path: '/preferences/formatting.md',
      content: 'Always use tabs, not spaces.',
  );
ruby
  mem = client.beta.memory_stores.memories.create(
    store.id,
    path: "/preferences/formatting.md",
    content: "Always use tabs, not spaces."
  )

See the Create a memory reference for full parameters and response schema.

Update a memory

memories.update modifies an existing memory by ID. You can change content, path (a rename), or both. The example renames a memory to an archive path:

bash
  curl -s -X POST "https://haijun.my.id/v1/memory_stores/$store_id/memories/$mem_id" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: agent-memory-2026-07-22" \
    -H "content-type: application/json" \
    -d '{"path": "/archive/2026_q1_formatting.md"}' > /dev/null
bash
  ant beta:memory-stores:memories update \
    --memory-store-id "$store_id" \
    --memory-id "$mem_id" \
    --path "/archive/2026_q1_formatting.md" \
    > /dev/null
python
  client.beta.memory_stores.memories.update(
      mem.id,
      memory_store_id=store.id,
      path="/archive/2026_q1_formatting.md",
  )
typescript
  await client.beta.memoryStores.memories.update(mem.id, {
    memory_store_id: store.id,
    path: "/archive/2026_q1_formatting.md"
  });
csharp
  await client.Beta.MemoryStores.Memories.Update(mem.ID, new()
  {
      MemoryStoreID = store.ID,
      Path = "/archive/2026_q1_formatting.md",
  });
go
  _, err = client.Beta.MemoryStores.Memories.Update(ctx, mem.ID, juglow.BetaMemoryStoreMemoryUpdateParams{
  	MemoryStoreID: store.ID,
  	Path:          juglow.String("/archive/2026_q1_formatting.md"),
  })
  if err != nil {
  	panic(err)
  }
java
  client.beta().memoryStores().memories().update(
      mem.id(),
      MemoryUpdateParams.builder()
          .memoryStoreId(store.id())
          .path("/archive/2026_q1_formatting.md")
          .build()
  );
php
  $client->beta->memoryStores->memories->update(
      $mem->id,
      memoryStoreID: $store->id,
      path: '/archive/2026_q1_formatting.md',
  );
ruby
  client.beta.memory_stores.memories.update(
    mem.id,
    memory_store_id: store.id,
    path: "/archive/2026_q1_formatting.md"
  )

See the Update a memory reference for full parameters and response schema.

Safe content edits (optimistic concurrency)

To avoid clobbering a concurrent write, pass a content_sha256 precondition. The update only applies if the stored content hash still matches the one you read; on mismatch, re-read the memory and retry against the fresh state.

bash
  curl -s -X POST "https://haijun.my.id/v1/memory_stores/$store_id/memories/$mem_id" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: agent-memory-2026-07-22" \
    -H "content-type: application/json" \
    --data @- > /dev/null <<EOF
  {
    "content": "CORRECTED: Always use 2-space indentation.",
    "precondition": {"type": "content_sha256", "content_sha256": "$mem_sha"}
  }
  EOF
bash
  ant beta:memory-stores:memories update \
    --memory-store-id "$store_id" \
    --memory-id "$mem_id" \
    --content "CORRECTED: Always use 2-space indentation." \
    --precondition "{type: content_sha256, content_sha256: $mem_sha}" \
    > /dev/null
python
  client.beta.memory_stores.memories.update(
      memory_id=mem.id,
      memory_store_id=store.id,
      content="CORRECTED: Always use 2-space indentation.",
      precondition={"type": "content_sha256", "content_sha256": mem.content_sha256},
  )
typescript
  await client.beta.memoryStores.memories.update(mem.id, {
    memory_store_id: store.id,
    content: "CORRECTED: Always use 2-space indentation.",
    precondition: { type: "content_sha256", content_sha256: mem.content_sha256 }
  });
csharp
  await client.Beta.MemoryStores.Memories.Update(mem.ID, new()
  {
      MemoryStoreID = store.ID,
      Content = "CORRECTED: Always use 2-space indentation.",
      Precondition = new BetaManagedAgentsPrecondition
      {
          Type = "content_sha256",
          ContentSha256 = mem.ContentSha256,
      },
  });
go
  _, err = client.Beta.MemoryStores.Memories.Update(ctx, mem.ID, juglow.BetaMemoryStoreMemoryUpdateParams{
  	MemoryStoreID: store.ID,
  	Content:       juglow.String("CORRECTED: Always use 2-space indentation."),
  	Precondition: juglow.BetaManagedAgentsPreconditionParam{
  		Type:          juglow.BetaManagedAgentsPreconditionTypeContentSha256,
  		ContentSha256: juglow.String(mem.ContentSha256),
  	},
  })
  if err != nil {
  	panic(err)
  }
java
  client.beta().memoryStores().memories().update(
      mem.id(),
      MemoryUpdateParams.builder()
          .memoryStoreId(store.id())
          .content("CORRECTED: Always use 2-space indentation.")
          .precondition(
              BetaManagedAgentsPrecondition.builder()
                  .type(BetaManagedAgentsPrecondition.Type.CONTENT_SHA256)
                  .contentSha256(mem.contentSha256())
                  .build()
          )
          .build()
  );
php
  $client->beta->memoryStores->memories->update(
      $mem->id,
      memoryStoreID: $store->id,
      content: 'CORRECTED: Always use 2-space indentation.',
      precondition: ['type' => 'content_sha256', 'content_sha256' => $mem->contentSha256],
  );
ruby
  client.beta.memory_stores.memories.update(
    mem.id,
    memory_store_id: store.id,
    content: "CORRECTED: Always use 2-space indentation.",
    precondition: {type: "content_sha256", content_sha256: mem.content_sha256}
  )

Delete a memory

bash
  curl -s -X DELETE "https://haijun.my.id/v1/memory_stores/$store_id/memories/$mem_id" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: agent-memory-2026-07-22" > /dev/null
bash
  ant beta:memory-stores:memories delete \
    --memory-store-id "$store_id" \
    --memory-id "$mem_id" \
    > /dev/null
python
  client.beta.memory_stores.memories.delete(
      mem.id,
      memory_store_id=store.id,
  )
typescript
  await client.beta.memoryStores.memories.delete(mem.id, {
    memory_store_id: store.id
  });
csharp
  await client.Beta.MemoryStores.Memories.Delete(mem.ID, new()
  {
      MemoryStoreID = store.ID,
  });
go
  _, err = client.Beta.MemoryStores.Memories.Delete(ctx, mem.ID, juglow.BetaMemoryStoreMemoryDeleteParams{
  	MemoryStoreID: store.ID,
  })
  if err != nil {
  	panic(err)
  }
java
  client.beta().memoryStores().memories().delete(
      mem.id(),
      MemoryDeleteParams.builder().memoryStoreId(store.id()).build()
  );
php
  $client->beta->memoryStores->memories->delete($mem->id, memoryStoreID: $store->id);
ruby
  client.beta.memory_stores.memories.delete(
    mem.id,
    memory_store_id: store.id
  )

See the Delete a memory reference for full parameters and response schema.

Audit memory changes

Every mutation to a memory creates an immutable memory version (memver_...). Use the version endpoints to audit who changed what and when, to inspect or restore a prior snapshot, and to scrub sensitive content out of history with redact.

Versions belong to the store (not the individual memory) and are not deleted when the memory itself is deleted, so the audit trail also covers deleted memories, subject to the retention described below. Versions are retained for 30 days after they are written; however, the recent versions of a live memory are always kept regardless of age, so memories that change infrequently might retain history beyond 30 days. The live memories.retrieve call always returns the latest version; the version endpoints give you the retained history.

There is no dedicated restore endpoint; to roll back, retrieve the version you want and write its content back with memories.update (or memories.create if the parent memory has been deleted, provided the version you want is still retained).

Past memory versions might be deleted after 30 days. To preserve memory history for longer, export versions through the API.

List versions

List version history for a store, newest first. The example filters to a single memory's history:

bash
  curl -s "https://haijun.my.id/v1/memory_stores/$store_id/memory_versions?memory_id=$mem_id" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: agent-memory-2026-07-22"
bash
  ant beta:memory-stores:memory-versions list \
    --memory-store-id "$store_id" \
    --memory-id "$mem_id" \
    --format json
python
  versions = client.beta.memory_stores.memory_versions.list(
      store.id,
      memory_id=mem.id,
  )
  for version in versions:
      print(f"{version.id}: {version.operation}")

  version_id = versions.data[1].id
typescript
  const versions = await client.beta.memoryStores.memoryVersions.list(store.id, {
    memory_id: mem.id
  });
  for await (const v of versions) {
    console.log(`${v.id}: ${v.operation}`);
  }

  const versionId = versions.data[1].id;
csharp
  var versions = await client.Beta.MemoryStores.MemoryVersions.List(store.ID, new()
  {
      MemoryID = mem.ID,
  });
  var versionIds = new List<string>();
  await foreach (var v in versions.Paginate())
  {
      Console.WriteLine($"{v.ID}: {v.Operation.Raw()}");
      versionIds.Add(v.ID);
  }

  var versionId = versionIds[1];
go
  versions := client.Beta.MemoryStores.MemoryVersions.ListAutoPaging(ctx, store.ID, juglow.BetaMemoryStoreMemoryVersionListParams{
  	MemoryID: juglow.String(mem.ID),
  })
  for versions.Next() {
  	v := versions.Current()
  	fmt.Printf("%s: %s\n", v.ID, v.Operation)
  }
  if err := versions.Err(); err != nil {
  	panic(err)
  }

  vpage, err := client.Beta.MemoryStores.MemoryVersions.List(ctx, store.ID, juglow.BetaMemoryStoreMemoryVersionListParams{
  	MemoryID: juglow.String(mem.ID),
  })
  if err != nil {
  	panic(err)
  }
  versionID := vpage.Data[1].ID
java
  var versions = client.beta().memoryStores().memoryVersions().list(
      store.id(),
      MemoryVersionListParams.builder().memoryId(mem.id()).build()
  );
  for (var v : versions.autoPager()) {
      IO.println(v.id() + ": " + v.operation());
  }

  var versionId = versions.data().get(1).id();
php
  $versions = $client->beta->memoryStores->memoryVersions->list(
      $store->id,
      memoryID: $mem->id,
  );
  foreach ($versions->pagingEachItem() as $v) {
      echo "{$v->id}: {$v->operation}\n";
  }

  $versionId = $versions->data[1]->id;
ruby
  versions = client.beta.memory_stores.memory_versions.list(
    store.id,
    memory_id: mem.id
  )
  versions.auto_paging_each do |version|
    puts "#{version.id}: #{version.operation}"
  end

  version_id = versions.data[1].id

See the List memory versions reference for full parameters and response schema.

Retrieve a version

Fetching an individual version returns the same fields as the list response plus the full content body.

bash
  curl -s "https://haijun.my.id/v1/memory_stores/$store_id/memory_versions/$version_id" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: agent-memory-2026-07-22"
bash
  ant beta:memory-stores:memory-versions retrieve \
    --memory-store-id "$store_id" \
    --memory-version-id "$version_id"
python
  version = client.beta.memory_stores.memory_versions.retrieve(
      version_id,
      memory_store_id=store.id,
  )
  print(version.content)
typescript
  const version = await client.beta.memoryStores.memoryVersions.retrieve(versionId, {
    memory_store_id: store.id
  });
  console.log(version.content);
csharp
  var version = await client.Beta.MemoryStores.MemoryVersions.Retrieve(versionId, new()
  {
      MemoryStoreID = store.ID,
  });
  Console.WriteLine(version.Content);
go
  version, err := client.Beta.MemoryStores.MemoryVersions.Get(ctx, versionID, juglow.BetaMemoryStoreMemoryVersionGetParams{
  	MemoryStoreID: store.ID,
  })
  if err != nil {
  	panic(err)
  }
  fmt.Println(version.Content)
java
  var version = client.beta().memoryStores().memoryVersions().retrieve(
      versionId,
      MemoryVersionRetrieveParams.builder().memoryStoreId(store.id()).build()
  );
  IO.println(version.content().orElseThrow());
php
  $version = $client->beta->memoryStores->memoryVersions->retrieve(
      $versionId,
      memoryStoreID: $store->id,
  );
  echo "{$version->content}\n";
ruby
  version = client.beta.memory_stores.memory_versions.retrieve(
    version_id,
    memory_store_id: store.id
  )
  puts version.content

See the Retrieve a memory version reference for full parameters and response schema.

Redact a version

Redact scrubs content out of a historical version while preserving the audit trail (who did what, when). Use it for compliance workflows such as removing leaked secrets, PII, or user deletion requests.

A version that is the current head of a live memory cannot be redacted. Write a new version first (or delete the memory), then redact the old one.

bash
  curl -s -X POST "https://haijun.my.id/v1/memory_stores/$store_id/memory_versions/$version_id/redact" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: agent-memory-2026-07-22" \
    -H "content-type: application/json" \
    -d '{}'
bash
  ant beta:memory-stores:memory-versions redact \
    --memory-store-id "$store_id" \
    --memory-version-id "$version_id"
python
  client.beta.memory_stores.memory_versions.redact(
      version_id,
      memory_store_id=store.id,
  )
typescript
  await client.beta.memoryStores.memoryVersions.redact(versionId, {
    memory_store_id: store.id
  });
csharp
  await client.Beta.MemoryStores.MemoryVersions.Redact(versionId, new()
  {
      MemoryStoreID = store.ID,
  });
go
  _, err = client.Beta.MemoryStores.MemoryVersions.Redact(ctx, versionID, juglow.BetaMemoryStoreMemoryVersionRedactParams{
  	MemoryStoreID: store.ID,
  })
  if err != nil {
  	panic(err)
  }
java
  client.beta().memoryStores().memoryVersions().redact(
      versionId,
      MemoryVersionRedactParams.builder().memoryStoreId(store.id()).build()
  );
php
  $client->beta->memoryStores->memoryVersions->redact(
      $versionId,
      memoryStoreID: $store->id,
  );
ruby
  client.beta.memory_stores.memory_versions.redact(
    version_id,
    memory_store_id: store.id
  )

See the Redact a memory version reference for full parameters and response schema.

Manage memory stores

In addition to create, memory stores support retrieve, update, list, archive, and delete.

List stores

List stores in the workspace. Archived stores are excluded by default; pass include_archived: true to include them.

bash
  curl -s "https://haijun.my.id/v1/memory_stores?include_archived=true" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: agent-memory-2026-07-22"
bash
  ant beta:memory-stores list --include-archived
python
  for memory_store in client.beta.memory_stores.list(include_archived=True):
      print(memory_store.id, memory_store.name, memory_store.archived_at)
typescript
  for await (const s of client.beta.memoryStores.list({ include_archived: true })) {
    console.log(s.id, s.name, s.archived_at);
  }
csharp
  var stores = await client.Beta.MemoryStores.List(new() { IncludeArchived = true });
  await foreach (var s in stores.Paginate())
  {
      Console.WriteLine($"{s.ID} {s.Name} {s.ArchivedAt}");
  }
go
  stores := client.Beta.MemoryStores.ListAutoPaging(ctx, juglow.BetaMemoryStoreListParams{
  	IncludeArchived: juglow.Bool(true),
  })
  for stores.Next() {
  	s := stores.Current()
  	fmt.Println(s.ID, s.Name, s.ArchivedAt)
  }
  if err := stores.Err(); err != nil {
  	panic(err)
  }
java
  for (var s : client.beta().memoryStores().list(
      MemoryStoreListParams.builder().includeArchived(true).build()
  ).autoPager()) {
      IO.println(s.id() + " " + s.name() + " " + s.archivedAt());
  }
php
  foreach ($client->beta->memoryStores->list(includeArchived: true)->pagingEachItem() as $s) {
      // archivedAt is only set on archived stores.
      $archivedAt = isset($s->archivedAt) ? $s->archivedAt->format(DATE_ATOM) : '';
      echo "{$s->id} {$s->name} {$archivedAt}\n";
  }
ruby
  client.beta.memory_stores.list(include_archived: true).auto_paging_each do |memory_store|
    puts "#{memory_store.id} #{memory_store.name} #{memory_store.archived_at}"
  end

See the List memory stores reference for full parameters and response schema.

Archive a store

Archiving makes a store read-only and prevents it from being attached to new sessions. Archiving is one-way; there is no unarchive.

bash
  curl -s -X POST "https://haijun.my.id/v1/memory_stores/$store_id/archive" \
    -H "x-api-key: $JUGLOW_API_KEY" \
    -H "juglow-version: 2023-06-01" \
    -H "juglow-beta: agent-memory-2026-07-22" > /dev/null
bash
  ant beta:memory-stores archive --memory-store-id "$store_id"
python
  client.beta.memory_stores.archive(store.id)
typescript
  await client.beta.memoryStores.archive(store.id);
csharp
  await client.Beta.MemoryStores.Archive(store.ID);
go
  _, err = client.Beta.MemoryStores.Archive(ctx, store.ID, juglow.BetaMemoryStoreArchiveParams{})
  if err != nil {
  	panic(err)
  }
java
  client.beta().memoryStores().archive(store.id());
php
  $client->beta->memoryStores->archive($store->id);
ruby
  client.beta.memory_stores.archive(store.id)

See the Archive a memory store reference for full parameters and response schema.

To permanently remove a store along with all of its memories and versions, use memory_stores.delete.

Best practices for memory management

When a store reaches its 10,000-memory limit, writes to new memories fail: both direct memories.create calls and the agent's file writes to unmapped paths. Existing memories remain readable and editable. The following practices help you stay well under the limit and recover gracefully if you reach it.

  • Use focused stores. Rather than one large general-purpose store, use smaller purpose-built stores: one per user, one for shared domain knowledge, and one for project-specific context. Each store has its own 10,000-memory limit, so keeping stores scoped reduces the chance any single one fills up.
  • Condense or prune before the store fills up. Delete stale or redundant memories with memories.delete. You can also run a dreaming session, which consolidates fragmented content into a separate new output store rather than modifying the original. Switch your sessions over to that output store, then archive or delete the original.
  • Attach a new store when it makes sense. If a store has grown beyond its useful scope, attach a fresh one for new content and attach the original with read_only access. The agent can read from both while only writing to the new one.
  • Limit write access where appropriate. Sessions that only read shared reference material don't need read_write. Keeping write access scoped to sessions that actually add new memories makes it easier to track where growth is coming from.
On this page
OverviewCreate a memory storeSeed it with content (optional)Attach a memory store to a sessionHow the agent accesses memoryView and edit memoriesList memoriesRead a memoryCreate a memoryUpdate a memorySafe content edits (optimistic concurrency)Delete a memoryAudit memory changesList versionsRetrieve a versionRedact a versionManage memory storesList storesArchive a storeBest practices for memory management