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

# Custom Memory Storage

By default, Charm uses **local file-backed memory** (`runtime.memory.provider: local`). On the cloud runner, workspace files are persisted under a managed workspace path (backed by cloud storage for serverless/daemon workloads).

For Redis, PostgreSQL, or other backends, install a **memory plugin** or use the built-in `supabase` provider where configured.

## Configuring a provider

```yaml theme={"theme":{"light":"min-light","dark":"min-dark"}}
runtime:
  adapter:
    type: langchain
    entry_point: src.main:agent
  memory:
    provider: redis
    config:
      url: "redis://localhost:6379/0"
```

The cloud runner sets `CHARM_MEMORY_PROVIDER` from this block so runtime code can resolve the active backend.

Built-in provider names today:

| Provider          | Source                                    |
| ----------------- | ----------------------------------------- |
| `local` (default) | Core — file-backed                        |
| `supabase`        | Core — when Supabase memory is configured |
| Custom names      | `charm.memory` entry points               |

### Underlying Checkpoint Mechanism

When using an external provider like `supabase`, Charm leverages thread identifiers (`thread_id`) and checkpoint namespaces to continuously sync state to the database. Upon waking up or migrating across devices, the runtime automatically queries the most recent state checkpoint. This architecture provides zero-downtime perception and seamless cross-device continuity without additional developer overhead.

## Creating a memory plugin

### 1. Implement `BaseMemoryStore`

```python theme={"theme":{"light":"min-light","dark":"min-dark"}}
from typing import Any, Dict, List
import json
import redis
from charm.core.storage import BaseMemoryStore

class RedisMemory(BaseMemoryStore):
    def __init__(self, config: Dict[str, Any]):
        super().__init__(config)
        self.client = redis.Redis.from_url(
            self.config.get("url", "redis://localhost:6379/0")
        )

    def load_messages(self, thread_id: str) -> List[Dict[str, Any]]:
        raw = self.client.get(f"charm:memory:{thread_id}")
        return json.loads(raw) if raw else []

    def save_messages(self, thread_id: str, messages: List[Dict[str, Any]]) -> None:
        self.client.set(f"charm:memory:{thread_id}", json.dumps(messages))

    def get_langgraph_checkpointer(self) -> Any:
        return None
```

### 2. Register via entry points

```toml theme={"theme":{"light":"min-light","dark":"min-dark"}}
[project.entry-points."charm.memory"]
redis = "charm_memory_redis.store:RedisMemory"
```

### 3. Use in `charm.yaml`

```yaml theme={"theme":{"light":"min-light","dark":"min-dark"}}
runtime:
  memory:
    provider: redis
    config:
      url: "${REDIS_URL}"
```

## Using memory from agent code

```python theme={"theme":{"light":"min-light","dark":"min-dark"}}
import os
from charm.core.storage import StorageManager

def agent(inputs):
    thread_id = inputs.get("__charm_thread_id__", "default")
    provider = os.getenv("CHARM_MEMORY_PROVIDER", "local")

    store = StorageManager.get_provider(provider, {})
    history = store.load_messages(thread_id)

    history.append({"role": "user", "content": str(inputs)})
    store.save_messages(thread_id, history)

    return {"status": "success", "output": f"Turns: {len(history)}"}
```

`StorageManager` caches the active provider for the process. Pass the same `config` dict shape as `runtime.memory.config` when constructing plugins that need connection settings.

## Cloud deployment

Unlike heavy adapters, **Memory plugins are typically lightweight** (e.g. `redis`, `pymongo`). This means the Charm Cloud Runner can install them dynamically at boot time without timing out.

**You do NOT need a `custom_image` to use most Memory Providers!**

1. Add the package to your agent's `requirements.txt`:

```txt theme={"theme":{"light":"min-light","dark":"min-dark"}}
charm-memory-redis
```

2. Enable it in `charm.yaml`:

```yaml theme={"theme":{"light":"min-light","dark":"min-dark"}}
runtime:
  memory:
    provider: redis
    config:
      url: "${REDIS_URL}"
```

3. Ensure **`policies.allow_internet_access`** (or network policy) allows reaching your database.
4. Provide connection secrets via environment variables — not in committed `charm.yaml`.

If your memory plugin requires heavy native packages (e.g. `psycopg2-binary` takes longer), you should bake it into a `runtime.custom_image` instead.

If the configured plugin is not found at runtime, Charm **falls back to local file memory** and logs a warning.

## Share with the Community

Once your memory provider is working and published to PyPI, you can list it in the official **Charm Store**!

Submit a Pull Request to the [charm-community-plugin](https://github.com/CharmAIOS/charm-community-plugin) repository to add your package to `memory/registry.json`. Your integration will immediately appear on the [Plugins](/plugins) page for other developers to discover.

## Related

* [Extensibility Overview](/guides/extensibility)
* [Custom Runtimes](/guides/custom-runtimes)
* [Threads](/platform/threads)
