> ## Documentation Index
> Fetch the complete documentation index at: https://docs.maximem.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Agno

> Drop-in InMemoryDb replacement that routes Agno user memories through Synap.

Swap Agno's in-memory database for a Synap-backed one. Agents that use `enable_user_memories=True` keep working without code changes. They just gain a persistent, semantically searchable memory store.

<Note>
  Requires Python 3.11+.
</Note>

## Overview

This guide shows how to add Synap to an Agno application to build agents that:

* Persist user memories across processes and deployments
* Retrieve memories semantically rather than by raw key lookup
* Serve many users from a single database instance, scoped per-call by `user_id`

The Synap Agno integration ships a single class: a subclass of Agno's `InMemoryDb` that routes memory operations through Synap.

| Class     | Agno interface        | Purpose                                      |
| --------- | --------------------- | -------------------------------------------- |
| `SynapDb` | `InMemoryDb` subclass | Persistent user-memory store backed by Synap |

## Setup

Install the package alongside Agno:

<CodeGroup>
  ```bash pip theme={null}
  pip install maximem-synap-agno agno
  ```

  ```bash uv theme={null}
  uv add maximem-synap-agno agno
  # pip-compatible (existing venv): uv pip install maximem-synap-agno agno
  ```
</CodeGroup>

<Note>
  The pip package is `maximem-synap-agno`, but the import drops the `maximem-` prefix and uses underscores: `from synap_agno import ...`.
</Note>

Configure your API key. Generate one from the [Synap Dashboard](https://synap.maximem.ai).

```bash .env theme={null}
SYNAP_API_KEY=synap_your_key_here
OPENAI_API_KEY=your-openai-api-key
```

Initialize the SDK once at application startup:

```python theme={null}
from maximem_synap import MaximemSynapSDK

sdk = MaximemSynapSDK()
await sdk.initialize()
```

See [SDK Initialization](/sdk/initialization) for the full lifecycle and configuration options.

## Basic integration

The smallest useful integration constructs a `SynapDb`, hands it to an `Agent`, and turns on `enable_user_memories`. Each `agent.run(..., user_id=...)` call now reads and writes against Synap rather than a process-local dict:

```python theme={null}
# pip install maximem-synap-agno agno
from maximem_synap import MaximemSynapSDK
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from synap_agno import SynapDb

sdk = MaximemSynapSDK()
await sdk.initialize()

db = SynapDb(sdk=sdk, customer_id="acme")   # customer_id is optional

agent = Agent(
    db=db,
    model=OpenAIChat(id="gpt-4o-mini"),
    enable_user_memories=True,
)

agent.run("Remember that I prefer async communication", user_id="alice")
reply = agent.run("What are my communication preferences?", user_id="alice")
```

Notice that `user_id` is supplied per call. `SynapDb` is constructed once and serves all users in the process. The `customer_id` (organization scope) is fixed at construction. **Memory reads degrade gracefully** on Synap outages; writes raise so silent data loss is impossible.

***

## Core concepts

### SynapDb

`SynapDb` extends Agno's `InMemoryDb` and overrides the four user-memory methods. Everything else (session state, non-memory storage) is inherited unchanged, so existing Agno code continues to work:

```python theme={null}
from synap_agno import SynapDb

db = SynapDb(
    sdk=sdk,
    customer_id="acme",   # optional, required for B2B instances
)
```

The overridden methods map to Synap as follows:

| Method                                | Behavior                                          |
| ------------------------------------- | ------------------------------------------------- |
| `upsert_user_memory(user_id, memory)` | Writes a new or updated memory to Synap           |
| `get_user_memory(user_id, memory_id)` | Fetches a specific memory by ID                   |
| `get_user_memories(user_id, query)`   | Retrieves the user's memories via semantic search |
| `get_all_memory_topics(user_id)`      | Returns unique memory topics via a broad search   |

### Per-call user scoping

Agno passes `user_id` as a runtime argument to every memory call rather than baking it into the database. That means one `SynapDb` instance can serve any number of users:

```python theme={null}
db = SynapDb(sdk=sdk, customer_id="acme")
agent = Agent(db=db, model=OpenAIChat(id="gpt-4o-mini"), enable_user_memories=True)

for user_id in ["alice", "bob", "carol"]:
    agent.run("What do you remember about me?", user_id=user_id)
```

Each call hits Synap with its own `user_id` scope, so memories never leak between users, even though the database object is shared.

***

## Complete example: long-lived agent serving many users

The pattern below is what most production Agno deployments end up with: one `SynapDb` and one `Agent` at module load, and a thin handler that supplies `user_id` per request:

```python theme={null}
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from synap_agno import SynapDb


# Define once at startup
db = SynapDb(sdk=sdk, customer_id="acme")

agent = Agent(
    db=db,
    model=OpenAIChat(id="gpt-4o-mini"),
    enable_user_memories=True,
    description=(
        "You are a personal assistant with long-term memory. "
        "Recall the user's preferences and decisions whenever they ask. "
        "When the user shares a new fact, write it down."
    ),
)


# Per-request handler: user_id varies, db/agent do not
async def handle_request(user_id: str, message: str) -> str:
    return agent.run(message, user_id=user_id).content


# Usage
await handle_request("alice", "I prefer email over Slack for updates.")
await handle_request("bob", "Remind me what timezone I'm in, it's Pacific.")
reply = await handle_request("alice", "How should you contact me?")
# → "Over email, since that's your preferred channel."
```

Three things to notice in this pattern:

1. **One `SynapDb`, many users.** The database is constructed once; `user_id` is the per-call scope.
2. **The `customer_id` is the tenant boundary.** All users sharing a `SynapDb` instance are inside the same `customer_id`. For cross-tenant services, build a separate `SynapDb` per tenant.
3. **Agno's behavior is unchanged.** `enable_user_memories`, `description`, and run signatures all work exactly as in vanilla Agno; you've only swapped the storage layer.

***

## Advanced patterns

### Multi-tenant scoping

`SynapDb` takes the customer-tenant scope at construction (`customer_id`) and the user scope per call (`user_id`). `customer_id` is required on B2B Synap instances and ignored on single-tenant ones. See [Memory Scopes](/concepts/memory-scopes).

```python theme={null}
# Single-tenant instance
db = SynapDb(sdk=sdk)

# Multi-tenant: one db per customer
db_acme = SynapDb(sdk=sdk, customer_id="acme")
db_initech = SynapDb(sdk=sdk, customer_id="initech")
```

For services that serve many tenants, route requests to the matching `SynapDb` rather than mixing tenants on one instance.

### Memory topic discovery

`get_all_memory_topics` is implemented as a broad Synap search and returns unique topics across the user's memory pool. Useful for building UIs that let a user browse what's been remembered about them, or for prompt enrichment ("Here are the topics we've discussed: ...").

### Failure semantics

The integration follows the Synap-wide contract:

* **`get_user_memory` / `get_user_memories` degrade gracefully**: return empty results and log an error if Synap is unreachable.
* **`upsert_user_memory` surfaces failures**: raises `SynapIntegrationError` so the agent and caller know persistence failed.

This is by design: read failures shouldn't break a user-facing answer, but silent write failures would let memory drift away from reality.

***

## Going further

* [Patterns overview](/patterns/overview): reusable memory patterns across frameworks.
* [Cookbook overview](/cookbook/overview): end-to-end worked examples.

***

## Next steps

<CardGroup cols={2}>
  <Card title="Google ADK" icon="google" href="/integrations/google-adk">
    `FunctionTool` factory for Google ADK agents.
  </Card>

  <Card title="OpenAI Agents" icon="robot" href="/integrations/openai-agents">
    Function tools for the OpenAI Agents SDK.
  </Card>

  <Card title="Memory Scopes" icon="layer-group" href="/concepts/memory-scopes">
    How `user_id` and `customer_id` interact across reads and writes.
  </Card>

  <Card title="Ingestion" icon="upload" href="/sdk/ingestion">
    Direct ingestion API for pipelines that need finer control than `upsert_user_memory`.
  </Card>
</CardGroup>
