> ## 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.

# SDK Configuration

> Customize SDK behavior for your environment.

## Overview

The Synap SDK is configured via the `SDKConfig` object, which controls storage, credentials, caching, timeouts, retries, and logging. Sensible defaults are provided for all fields, so you only need to override what matters for your environment.

## SDKConfig Reference

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

config = SDKConfig(
    storage_path=None,                    # Default: SDK-managed local directory (cache only)
    cache_backend="sqlite",              # "sqlite" or None
    session_timeout_minutes=30,           # Range: 5-1440
    timeouts=TimeoutConfig(),             # Connection and read timeouts
    retry_policy=RetryPolicy(),           # Retry behavior for transient errors
    log_level="WARNING",                  # DEBUG, INFO, WARNING, ERROR
    grpc_host=None,                       # Override the real-time stream host
    grpc_port=None,                       # Override the real-time stream port
    grpc_use_tls=None                     # None = TLS on; False = plaintext
)
```

### Field Reference

At a glance, `SDKConfig` accepts:

* `storage_path`: directory for the local SQLite cache and transient state. Defaults to an SDK-managed directory. The API key is never written here; it is read from `SYNAP_API_KEY` (or the `api_key=` constructor argument) on each start. See [Storage Path](#storage-path).
* `cache_backend`: `"sqlite"` (default) for on-disk caching, or `None` to disable it. See [Cache Backend](#cache-backend).
* `session_timeout_minutes`: how long a session stays active before re-authentication. Default `30`, valid range `5` to `1440`. See [Session Timeout](#session-timeout).
* `timeouts`: a [TimeoutConfig](#timeoutconfig) for per-operation network timeouts.
* `retry_policy`: a [RetryPolicy](#retrypolicy) for transient-error retries, or `None` to disable retries.
* `log_level`: logging verbosity, one of `"DEBUG"`, `"INFO"`, `"WARNING"` (default), `"ERROR"`. See [Log Level](#log-level).
* `grpc_host` / `grpc_port` / `grpc_use_tls`: endpoint overrides for the real-time anticipation stream. Only needed for self-hosted or local deployments. See [gRPC Connection](#grpc-connection).

<Card title="Full parameter reference →" icon="book" href="/sdk-reference/lifecycle/configure">
  The complete field list, types, accepted ranges, and the `configure()` rules (including the `logger` override).
</Card>

## TimeoutConfig

Controls how long the SDK waits for individual network operations.

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

timeouts = TimeoutConfig(
    connect=5.0,       # Seconds to establish TCP connection
    read=30.0,         # Seconds to wait for response data
    write=10.0,        # Seconds to wait for request upload
    stream_idle=60.0   # Seconds of inactivity before reconnecting the event stream
)
```

<ParamField body="connect" type="float" default="5.0">
  Maximum time in seconds to establish a TCP connection to Synap Cloud. Increase this if your network has high latency or unreliable DNS resolution.
</ParamField>

<ParamField body="read" type="float" default="30.0">
  Maximum time in seconds to wait for a complete response after sending a request. This should be higher than your expected query latency. For compaction of very large conversations, you may need to increase this.
</ParamField>

<ParamField body="write" type="float" default="10.0">
  Maximum time in seconds to upload request data. Relevant for large batch ingestion payloads. Increase if you are sending very large documents.
</ParamField>

<ParamField body="stream_idle" type="float" default="60.0">
  Maximum idle time in seconds for the SDK's real-time event stream (used by `sdk.instance.listen()`). If no data is received within this window, the stream is considered stale and reconnected. Increase for low-traffic instances where events are infrequent.
</ParamField>

## gRPC Connection

These three fields point the real-time anticipation stream ([`instance.listen()`](/sdk-reference/instance/listen)) at a specific endpoint. Leave them unset for Synap Cloud; the defaults are correct and TLS is on.

```python theme={null}
config = SDKConfig(
    grpc_host="localhost",   # Default: Synap Cloud
    grpc_port=50051,         # Default: Synap Cloud
    grpc_use_tls=False,      # Default: None (TLS on)
)
```

<ParamField body="grpc_host" type="string | None" default="None">
  Hostname for the real-time stream. `None` uses the Synap Cloud endpoint. Set this when running against a self-hosted or local Synap deployment.
</ParamField>

<ParamField body="grpc_port" type="int | None" default="None">
  Port for the real-time stream, commonly `50051` for local deployments. `None` uses the Synap Cloud default.
</ParamField>

<ParamField body="grpc_use_tls" type="bool | None" default="None">
  `None` uses the transport default (TLS **on**). Set to `False` only for a plaintext endpoint, such as a local container. Never disable TLS against a remote host.
</ParamField>

<Note>
  These fields affect only the streaming transport. REST calls use the separate `api_base_url`. Point both at the same deployment or the SDK will authenticate against one environment and stream against another.
</Note>

### Caching and async ingestion

Ingestion is asynchronous: memories from a turn are not immediately retrievable. If you fetch right after writing, an empty result is a legitimate response, and with `cache_backend="sqlite"` the local read cache will hold onto that empty result for its TTL, so later turns keep seeing nothing.

For live agents that ingest and retrieve in the same loop, disable the local read cache:

```python theme={null}
config = SDKConfig(cache_backend=None)
```

The anticipation cache is unaffected and keeps working: the server pushes fresh bundles, so it invalidates correctly on its own.

## RetryPolicy

Controls automatic retry behavior for transient errors.

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

retry_policy = RetryPolicy(
    max_attempts=3,            # Total attempts (1 initial + 2 retries)
    backoff_base=1.0,          # Base delay in seconds
    backoff_max=10.0,          # Maximum delay cap
    backoff_jitter=True,       # Add randomized jitter
    retryable_errors=[         # Which error types to retry
        "NetworkTimeoutError",
        "RateLimitError",
        "ServiceUnavailableError",
        "SynapTransientError"
    ]
)
```

<ParamField body="max_attempts" type="int" default="3">
  The total number of attempts including the initial request. Setting this to `1` means no retries (only the initial attempt). Setting to `5` means up to 4 retries after the initial failure.
</ParamField>

<ParamField body="backoff_base" type="float" default="1.0">
  The base delay in seconds for exponential backoff. The delay for attempt N is `backoff_base * 2^(N-2)`, capped at `backoff_max`. A higher base means longer waits between retries, which is gentler on rate-limited endpoints.
</ParamField>

<ParamField body="backoff_max" type="float" default="10.0">
  The maximum delay in seconds between retry attempts. Prevents exponential backoff from growing unbounded for high `max_attempts` values.
</ParamField>

<ParamField body="backoff_jitter" type="bool" default="True">
  When enabled, adds a random component to the backoff delay. This prevents the "thundering herd" problem where multiple SDK instances retry at the exact same time after a shared failure. Strongly recommended for production deployments.
</ParamField>

<ParamField body="retryable_errors" type="List[str]" default="[&#x22;NetworkTimeoutError&#x22;, &#x22;RateLimitError&#x22;, &#x22;ServiceUnavailableError&#x22;, &#x22;SynapTransientError&#x22;]">
  The list of error type names that should be automatically retried. Only errors in this list trigger the retry policy. All other errors are raised immediately.

  For `RateLimitError`, the SDK uses the server-provided `retry_after_seconds` value instead of the exponential backoff calculation.
</ParamField>

## Storage Path

The `storage_path` directory holds the local SQLite cache and transient state. The SDK sets restrictive filesystem permissions on this directory on creation. The API key is never stored here; it comes from `SYNAP_API_KEY` or the `api_key=` constructor argument.

### When to Override

| Scenario                        | Recommended `storage_path`                                             |
| ------------------------------- | ---------------------------------------------------------------------- |
| Standard deployment             | `None` (use SDK default)                                               |
| Docker container                | `/var/lib/synap/` mapped to a persistent volume (optional, cache only) |
| Serverless function             | Disable the cache (`cache_backend=None`)                               |
| Multiple instances on same host | `/var/lib/synap/<instance_id>/`                                        |
| Testing                         | `/tmp/synap-test/`                                                     |

## Credentials

The SDK reads the API key on every start. There are exactly two sources:

| Source                               | Description                                                 |
| ------------------------------------ | ----------------------------------------------------------- |
| `api_key="..."` constructor argument | Passed directly to `MaximemSynapSDK(...)`                   |
| `SYNAP_API_KEY` environment variable | Read automatically when the constructor argument is omitted |

The SDK uses your API key for every call. The instance ID is resolved automatically from the API key; you do not need to set it manually.

## Cache Backend

### SQLite (Default, Recommended)

```python theme={null}
config = SDKConfig(cache_backend="sqlite")
```

The SQLite cache stores recent retrieval results locally, enabling sub-millisecond cache hits for repeated queries. The cache respects TTL values from the server (`ttl_seconds` in response metadata) and evicts stale entries automatically.

Benefits:

* Sub-millisecond cache hits for repeated context fetches
* Persists across SDK restarts (within TTL)
* Automatic size management and TTL-based eviction
* Zero configuration (SQLite is bundled with Python)

### Disabled

```python theme={null}
config = SDKConfig(cache_backend=None)
```

Disables local caching entirely. Every `conversation.context.fetch()` call goes to Synap Cloud. Use this when:

* You need guaranteed freshness on every call
* You are running in a read-only filesystem (and cannot use a RAM-backed path)
* You are debugging cache-related issues

## Session Timeout

```python theme={null}
config = SDKConfig(session_timeout_minutes=60)
```

The session timeout controls how long the SDK's authenticated session remains valid before re-authentication is required. The valid range is 5 to 1440 minutes (24 hours).

| Setting       | Value          | Use Case                                            |
| ------------- | -------------- | --------------------------------------------------- |
| Short session | 5-15 min       | High-security environments, compliance requirements |
| Default       | 30 min         | General-purpose applications                        |
| Long session  | 60-120 min     | Long-running batch processes                        |
| Maximum       | 1440 min (24h) | Background workers, data pipelines                  |

## Log Level

The SDK uses Python's standard `logging` module. The log level controls verbosity of the `synap` logger.

```python theme={null}
config = SDKConfig(log_level="DEBUG")
```

| Level     | What is Logged                                                                                               |
| --------- | ------------------------------------------------------------------------------------------------------------ |
| `DEBUG`   | All internal operations: request/response bodies, cache lookups, retry decisions, credential rotation timing |
| `INFO`    | Initialization, connection events, credential rotation, compaction triggers                                  |
| `WARNING` | Deprecation notices, approaching rate limits, cache size warnings                                            |
| `ERROR`   | Failed operations that could not be retried, authentication failures, data corruption                        |

<Warning>
  The `DEBUG` level may log sensitive information including request payloads. Do not use `DEBUG` in production environments where logs may be exposed to unauthorized parties.
</Warning>

## Using `configure()`

The `configure()` method allows you to update individual configuration fields after constructing the SDK but before calling `initialize()`.

```python theme={null}
sdk = MaximemSynapSDK(
    api_key="synap_your_key_here"
)

# Override specific fields without constructing a full SDKConfig
sdk.configure(log_level="DEBUG")
sdk.configure(session_timeout_minutes=120)
sdk.configure(cache_backend=None)

await sdk.initialize()
```

<Warning>
  Calling `configure()` after `initialize()` raises `InvalidInputError('Cannot reconfigure after initialization')`.
</Warning>

## Environment Variables

A small set of connection settings can come from the environment. Everything else must be set in code via `SDKConfig`; pass it to the constructor (or `configure()`) before `initialize()`.

| Variable            | Sets                                           |
| ------------------- | ---------------------------------------------- |
| `SYNAP_API_KEY`     | API key, when no `api_key=` argument is passed |
| `SYNAP_BASE_URL`    | `api_base_url`, the REST endpoint              |
| `SYNAP_INSTANCE_ID` | `instance_id`, when no argument is passed      |

<Note>
  Explicit configuration always wins. Each variable is consulted only when the corresponding `SDKConfig` field is left as `None`, so setting a value in code makes the environment variable inert.
</Note>

```python theme={null}
import os
from maximem_synap import MaximemSynapSDK, SDKConfig

sdk = MaximemSynapSDK(
    api_key=os.environ["SYNAP_API_KEY"],
    config=SDKConfig(log_level=os.environ.get("LOG_LEVEL", "WARNING")),
)
```

## Common Configurations

<AccordionGroup>
  <Accordion title="Development">
    Verbose logging, short timeouts, and aggressive retries for fast feedback during development.

    ```python theme={null}
    from maximem_synap import SDKConfig, TimeoutConfig, RetryPolicy

    dev_config = SDKConfig(
        storage_path="/tmp/synap-dev",  # Temporary path for dev
        cache_backend="sqlite",
        session_timeout_minutes=120,
        timeouts=TimeoutConfig(
            connect=3.0,
            read=15.0,
            write=5.0,
            stream_idle=30.0
        ),
        retry_policy=RetryPolicy(
            max_attempts=2,
            backoff_base=0.5,
            backoff_max=3.0
        ),
        log_level="DEBUG"
    )
    ```
  </Accordion>

  <Accordion title="Production">
    Conservative timeouts, standard retries with jitter, minimal logging, and persistent storage.

    ```python theme={null}
    from maximem_synap import SDKConfig, TimeoutConfig, RetryPolicy

    prod_config = SDKConfig(
        storage_path="/var/lib/synap",
        cache_backend="sqlite",
        session_timeout_minutes=30,
        timeouts=TimeoutConfig(
            connect=10.0,
            read=30.0,
            write=10.0,
            stream_idle=120.0
        ),
        retry_policy=RetryPolicy(
            max_attempts=3,
            backoff_base=1.0,
            backoff_max=10.0,
            backoff_jitter=True
        ),
        log_level="WARNING"
    )
    ```
  </Accordion>

  <Accordion title="Testing">
    Isolated storage, disabled caching for deterministic tests, no retries for immediate failure feedback.

    ```python theme={null}
    from maximem_synap import SDKConfig, TimeoutConfig

    test_config = SDKConfig(
        storage_path="/tmp/synap-test",
        cache_backend=None,          # No caching for deterministic tests
        session_timeout_minutes=5,
        timeouts=TimeoutConfig(
            connect=2.0,
            read=5.0,
            write=3.0,
            stream_idle=10.0
        ),
        retry_policy=None,           # No retries: fail fast in tests
        log_level="DEBUG"
    )

    # Use _force_new to bypass singleton caching in tests
    sdk = MaximemSynapSDK(
        api_key="synap_test_key",
        config=test_config,
        _force_new=True
    )
    ```
  </Accordion>

  <Accordion title="High-Throughput">
    Optimized for batch ingestion workloads with generous timeouts, higher retry limits, and long sessions.

    ```python theme={null}
    from maximem_synap import SDKConfig, TimeoutConfig, RetryPolicy

    throughput_config = SDKConfig(
        storage_path="/var/lib/synap",
        cache_backend="sqlite",
        session_timeout_minutes=1440,  # 24 hours for long batch jobs
        timeouts=TimeoutConfig(
            connect=15.0,
            read=60.0,               # Long reads for large batch responses
            write=30.0,              # Long writes for large batch payloads
            stream_idle=300.0        # 5 min idle for streaming
        ),
        retry_policy=RetryPolicy(
            max_attempts=5,
            backoff_base=2.0,
            backoff_max=30.0,
            backoff_jitter=True
        ),
        log_level="INFO"
    )
    ```
  </Accordion>
</AccordionGroup>

## Full Configuration Example

Putting it all together with explicit values for every field:

```python theme={null}
from maximem_synap import MaximemSynapSDK, SDKConfig, TimeoutConfig, RetryPolicy

sdk = MaximemSynapSDK(
    api_key="synap_your_key_here",
    config=SDKConfig(
        storage_path="/var/lib/myapp/synap",
        cache_backend="sqlite",
        session_timeout_minutes=60,
        timeouts=TimeoutConfig(
            connect=10.0,
            read=30.0,
            write=10.0,
            stream_idle=120.0
        ),
        retry_policy=RetryPolicy(
            max_attempts=3,
            backoff_base=1.0,
            backoff_max=10.0,
            backoff_jitter=True,
            retryable_errors=[
                "NetworkTimeoutError",
                "RateLimitError",
                "ServiceUnavailableError",
                "SynapTransientError"
            ]
        ),
        log_level="WARNING"
    )
)

await sdk.initialize()
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Initializing the SDK" icon="play" href="/sdk/initialization">
    Learn the full initialization lifecycle with configuration.
  </Card>

  <Card title="API Error Reference" icon="alert-triangle" href="/sdk-reference/errors">
    Understand how retry policies interact with the error hierarchy.
  </Card>

  <Card title="Production Checklist" icon="check" href="/guides/production-checklist">
    Review configuration best practices before going live.
  </Card>

  <Card title="Ingesting Memories" icon="upload" href="/sdk/ingestion">
    Start ingesting data with your configured SDK.
  </Card>
</CardGroup>
