# Persistent Agent Memory
URL: /docs/cookbooks/persistent-agent-memory

An agent that remembers things about a customer across separate sandbox sessions, via @alineo-labs/memory.



<CookbookMeta difficulty="Advanced" time="~10 min" primitives="[&#x22;@alineo-labs/memory&#x22;, &#x22;resourceRef&#x22;, &#x22;remember()&#x22;]" />

A support agent that remembers things about a customer across sessions — not within one
conversation (Pi already keeps that), but across separate sandbox sessions entirely, backed by a
real, persisted `@alineo-labs/memory` store.

## Setup [#setup]

<Steps>
  <Step>
    Start OpenSandbox in Docker (one-time setup):

    ```bash
    bunx alineo-cli init
    ```
  </Step>

  <Step>
    Get a free API key from [build.nvidia.com](https://build.nvidia.com) and export it:

    ```bash
    export NVIDIA_API_KEY=...
    ```
  </Step>
</Steps>

## Run it [#run-it]

<CookbookPlayground
  cwd="cookbooks/persistent-agent-memory"
  repoHref="https://github.com/DrejT/alineo/tree/main/cookbooks/persistent-agent-memory"
  commands="[
  { command: &#x22;bun install&#x22; },
  { command: &#x22;bun start&#x22; },
]"
  output="`── session 1 (sandboxId: a1b2c3) ──
Working-memory profile set: { plan: &#x22;pro&#x22;, name: &#x22;Jordan&#x22; }
remember(): &#x22;upgraded to Pro on the 3rd&#x22; — sourceRef verified against the ledger ✔

── session 2 (sandboxId: d4e5f6 — a brand-new sandbox) ──
buildContextSnippet() → &#x22;Jordan is on the Pro plan. Upgraded on the 3rd (verified).&#x22;
Agent: &#x22;Hi Jordan — since you're on Pro, you already have access to that feature.&#x22;`"
/>

## What it does [#what-it-does]

<Steps>
  <Step>
    **Session 1** — loads `agents/support-agent.json` via `Alineo.start()`, wired with a `Memory`
    instance backed by `@alineo-labs/sqlite-memory` (a real file: `./.alineo/agent-memory.db`). Sets
    a working-memory profile (`plan`, `name`), runs a command, and `remember()`s a fact tagged with a
    `sourceRef` pointing at the real ledger entry that command produced — so it comes back
    `verified: true`, not just claimed. Prompts the agent, then closes the sandbox.
  </Step>

  <Step>
    **Session 2** — calls `Alineo.start()` again with the **same spec** and the **same `Memory`
    instance**. This creates a brand-new sandbox (a different `sandboxId` — you'll see it in the
    output) with none of session 1's container state. Everything recalled — the working-memory
    profile, the verified fact — comes back purely because `agent.resourceRef` (which defaults to the
    agent's own `name`) is the same resource as session 1's, not because anything about the sandbox
    itself was preserved.
  </Step>

  <Step>
    Uses `buildContextSnippet()` to assemble what's known about the customer into a plain-text block,
    prepended to the second session's prompt — so the agent's reply is grounded in real memory, not
    asked to guess.
  </Step>
</Steps>

<Callout title="The point">
  Sandboxes are already durable — `sb.checkpoint()`/`resume()` preserve container state within one
  logical session. What this recipe shows is a different kind of durability: memory that survives
  past the sandbox session it was learned in entirely, addressed by a stable identity
  (`resourceRef`) instead of a `sandboxId`.
</Callout>

<Accordions>
  <Accordion title="Where to go next">
    * [`examples/memory-basics`](https://github.com/DrejT/alineo/tree/main/examples/memory-basics) —
      every `@alineo-labs/memory` capability demonstrated standalone, no OpenSandbox needed:
      compaction, `SchemaWorkingMemory`, `episodicTree()`, `Memory.fork()` (which `Alineo.spawn()`
      calls automatically — not exercised in this recipe, since it needs a second agent spec and a
      `spawnDepth` budget beyond what this recipe's scope covers), and team access control.
    * [`@alineo-labs/memory`'s own README](https://github.com/DrejT/alineo/tree/main/packages/memory)
      for the full API.
  </Accordion>

  <Accordion title="Notes on the embedding provider">
    The embedding call in `index.ts` (`nvidiaEmbeddings()`) is inlined rather than imported from
    `@alineo-labs/model-providers`, since that package is private to this repo's own dashboard app —
    not meant to be depended on from a cookbook someone copies out of this repo. Swap it for any
    `EmbeddingProvider` (a different provider's API, a local model) with no other changes needed.
  </Accordion>
</Accordions>
