> For the complete documentation index, see [llms.txt](https://docs.telys.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.telys.ai/quickstarts/quickstart-agent-memory.md).

# Agent memory

LLM agents forget everything between calls. Telys gives them durable, on-device memory: store what the user says, then recall the relevant pieces before the next reply. This page builds that loop in a few lines of Python, keeping each user and session isolated with `scope_key`.

{% hint style="info" %}
This assumes Telys is installed and you are signed in (`pipx install telys` then `telys login`). New to Telys? Start with the [Quickstart: your first collection](/quickstarts/quickstart-first-collection.md). The examples need the signed runtime and native kernel, both installed by `telys login`.
{% endhint %}

## Isolate memory with scope keys

A collection's `partition_by` field is its physical partition key. Give each user+session its own partition by putting a composed key in that field. `scope_key` joins its parts into one stable string (with a `\x1f` separator), so `scope_key("alice", "session-42")` and `scope_key("bob", "session-42")` never collide.

```python
from telys import scope_key

print(repr(scope_key("alice", "session-42")))
```

**Expected output:**

```
'alice\x1fsession-42'
```

{% hint style="warning" %}
`partition_by` is a single physical key, not a composite. If you pass a list or tuple, only element `[0]` is used. Compose multiple parts into one string with `scope_key(...)`. See [Partitions & scope keys](/understand-telys/partitions-scope-key.md).
{% endhint %}

{% stepper %}
{% step %}

#### Create the memory collection

Partition by `scope` — the field that holds each `scope_key` value.

```python
from telys import Telys, Eq, scope_key
from telys.embedding import AlgentaMultigramEmbedder

t = Telys("./agent-memory")
emb = AlgentaMultigramEmbedder()

memory = t.create_collection(
    "chat",
    dim=emb.profile.dimension,
    partition_by="scope",
    embedder=emb,
)
```

{% endstep %}

{% step %}

#### Wrap remember and recall

Two helpers are all an agent needs. `remember` uses `upsert_texts`, so re-running a turn replaces it instead of raising `KeyError`. `recall` scopes the search to one partition with `where=Eq("scope", scope)`, so a user only ever reads their own memory.

```python
def remember(scope, turn_id, text, role="turn"):
    memory.upsert_texts(
        [text],
        ids=[f"{scope}:{turn_id}"],
        metadata=[{"scope": scope, "role": role}],
    )

def recall(scope, query, k=3):
    hits = memory.search_text(
        query,
        top_k=k,
        where=Eq("scope", scope),
    )
    return hits["ids"]
```

Prefixing each id with its `scope` keeps ids unique across users in one collection.
{% endstep %}

{% step %}

#### Store turns, then recall

Store a few turns for one user+session, persist, then ask a question that should surface the relevant memory.

```python
# one user, one session -> one partition
scope = scope_key("alice", "session-42")

for turn_id, text in [
    ("t1", "I prefer metric units."),
    ("t2", "I'm planning a trip to Kyoto in October."),
    ("t3", "My budget for the trip is 2000 dollars."),
]:
    remember(scope, turn_id, text)

memory.save()

# later, before the agent answers, recall the relevant memory
print(recall(scope, "how much can I spend on the trip?"))
```

**Expected result:**

```
['alice\x1fsession-42:t3', 'alice\x1fsession-42:t2', 'alice\x1fsession-42:t1']
```

The budget turn (`t3`) ranks first, the trip turn (`t2`) next. Feed those recalled strings into the model's prompt as context for the reply.
{% endstep %}

{% step %}

#### Update a fact

When the user changes their mind, upsert the same id to replace the stored fact in place. `upsert_texts` inserts or replaces; `save()` commits it.

```python
remember(scope, "t1", "I now prefer imperial units.")  # replaces t1
memory.save()

print(recall(scope, "which units do I like?", k=1))
```

**Expected result:**

```
['alice\x1fsession-42:t1']
```

Recall the same id and you get the updated fact. Because every write and read is scoped, `scope_key("bob", "session-42")` sees an empty memory — one agent's users never leak into another's.
{% endstep %}
{% endstepper %}

{% hint style="success" %}
Prefer no Python? The MCP path is the zero-code alternative: run `telys mcp install` and your MCP client (Claude Desktop, Cursor) gets `telys_add` and `telys_search` tools over a shared memory directory — the agent stores and recalls memory itself. See [MCP overview](/mcp/overview.md).
{% endhint %}

## Next steps

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>MCP overview</strong></td><td>Give an agent memory tools with no application code at all.</td><td><a href="/pages/ubMgZcamUs49e9HJGixL">/pages/ubMgZcamUs49e9HJGixL</a></td></tr><tr><td><strong>Agent long-term memory</strong></td><td>The full recipe: retention, summarization, and multi-session recall.</td><td><a href="/pages/QYbY40mZFZxkolWKKL7V">/pages/QYbY40mZFZxkolWKKL7V</a></td></tr><tr><td><strong>Partitions &#x26; scope keys</strong></td><td>How partitioning and scope_key isolate and speed up recall.</td><td><a href="/pages/Rv5cBr1GHyWvxVC7AeIF">/pages/Rv5cBr1GHyWvxVC7AeIF</a></td></tr><tr><td><strong>Update records</strong></td><td>upsert_texts vs update_texts, and when to use each.</td><td><a href="/pages/IEihttmP8r8zxpFDyjgd">/pages/IEihttmP8r8zxpFDyjgd</a></td></tr></tbody></table>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.telys.ai/quickstarts/quickstart-agent-memory.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
