> 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/understand-telys/partitions-scope-key.md).

# Partitions & scopes

A collection is split into **partitions** by a single key column you name at create time. Partitions give isolation (one tenant or user can't see another's records) and speed (a scoped search walks only the matching partition). The sharp edge: `partition_by` is **not** composite — it names exactly one physical column. For a compound scope like *tenant + user*, compose a single string key with `scope_key(...)`.

## What `partition_by` does

`partition_by` names the physical partition-key column for the whole collection. Every record's metadata must carry a value under that name; the runtime groups records by it and can restrict a search to one value.

```python
from telys import Telys

db = Telys("./memory")
col = db.create_collection("notes", dim=384, partition_by="scope")
# every record now carries a "scope" value; searches can be pinned to one scope
```

## `partition_by` is a single column — not composite

Pass a list or tuple to `partition_by` and Telys uses **only the first element** as the physical key. It is not a composite key — the rest are silently ignored.

{% hint style="danger" %}
`partition_by=["tenant_id", "user_id"]` does **not** partition by both. Only `element[0]` (`"tenant_id"`) becomes the physical key; `"user_id"` is ignored. Records for different users under the same tenant land in the *same* partition, so a per-user scope would leak across users. Compose a single key with `scope_key(...)` instead.
{% endhint %}

```python
# WRONG — looks composite, is not. Only "tenant_id" is used.
col = db.create_collection("docs", dim=384, partition_by=["tenant_id", "user_id"])
```

## Compose one key with `scope_key`

`scope_key(*parts)` joins its arguments into one string with the unit-separator byte `\x1f` as delimiter. That byte is not something users type, so it won't collide with your data — a safe, reversible compound key.

```python
from telys import scope_key

scope_key("acme", "user_42")     # -> "acme\x1fuser_42"
```

`scope_key` is available as the top-level import above and as a handle method (`db.scope_key(...)`); they behave identically. The idiom: partition by a single column (say `"scope"`) and store a composed key in that column on every record.

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

db = Telys("./memory")
emb = AlgentaMultigramEmbedder()
col = db.create_collection(
    "notes", dim=emb.profile.dimension, partition_by="scope", embedder=emb
)

key = scope_key("acme", "user_42")

col.add_texts(
    ["remember to ship the beta"],
    ids=["m1"],
    metadata=[{"scope": key}],       # the composed key lives in the partition column
)
```

## Searching and listing within a scope

To keep a query inside one partition, pass `where=` with an `Eq` on the partition column (or a single-key dict). Only records whose partition key matches are considered:

```python
hits = col.search_text(
    "what did I need to ship?",
    top_k=5,
    where=Eq("scope", scope_key("acme", "user_42")),
)
```

The same filter scopes an id listing:

```python
col.ids(where=Eq("scope", scope_key("acme", "user_42")))   # ids in this scope only
```

{% hint style="info" %}
`Eq` (or a single-key dict) is the whole filter surface. `scope_key` is deterministic, so `Eq("scope", scope_key(...))` matches exactly the records you added with that key — reconstruct the key the same way when you query.
{% endhint %}

## Why partition at all

| Benefit                 | What it buys you                                                                                   |
| ----------------------- | -------------------------------------------------------------------------------------------------- |
| Tenant / user isolation | A scoped search can only return records from that scope — a hard boundary for multi-tenant memory. |
| Faster scoped search    | A partitioned query walks only the matching partition, not the whole collection.                   |
| Cleaner lifecycle       | You can list (`ids`) or reason about one scope's records without scanning everything.              |

Choose the partition column by your unit of isolation: one tenant → `partition_by="tenant_id"`; one user within a tenant → `partition_by="scope"` with `scope_key(tenant, user)`; one agent session → `scope_key(agent, session)`. The partition key is fixed for the collection's lifetime, so match the granularity to how you will query.

## 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>Filter results</strong></td><td>The hands-on recipe for scoping searches with Eq.</td><td><a href="/pages/f1kH8mnLEAKBG7sEkDOZ">/pages/f1kH8mnLEAKBG7sEkDOZ</a></td></tr><tr><td><strong>Metadata &#x26; filtering</strong></td><td>How filter_columns and Eq relate to the partition key.</td><td><a href="/pages/mCyhYY8XvfpJT4RScC5i">/pages/mCyhYY8XvfpJT4RScC5i</a></td></tr><tr><td><strong>Records, IDs &#x26; payloads</strong></td><td>Where the partition-key value lives inside a record.</td><td><a href="/pages/25a92W1qdHq0jNswnnSy">/pages/25a92W1qdHq0jNswnnSy</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/understand-telys/partitions-scope-key.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.
