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

# Storage Architecture

> What the self-hosted deployment actually stores, where, and what you can realistically swap.

<Warning>
  **There is no pluggable storage-driver abstraction.** No `StorageDriver` interface, no `storage_provider` config key, no YAML adapter format, and no S3/R2/Qdrant provider blocks exist in this codebase. Self-hosting means running the `v2-agent-state` edge function on **your own Supabase project** — Postgres and Supabase Storage are the storage layer, not one option among several.

  If you've seen documentation describing swappable storage adapters for this project, that describes a different project's plugin architecture.
</Warning>

## What actually gets stored, and where

Two Postgres tables plus one storage bucket, all inside your own Supabase project:

| Location                       | Holds                                                                                                                                       |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `public.agent_state_snapshots` | Snapshot metadata — `agent_id`, `sequence_number`, `parent_tx_id`, `policy_hash`, `client_payload_hash`, `byte_size`, status and timestamps |
| `public.agent_replication_log` | Differential replication blocks — `ciphertext` (BYTEA), `block_hash`, `merkle_root`, `sequence_number`, `expires_at`                        |
| `sovseal-rom` storage bucket   | Snapshot ciphertext payloads, at SHA-256-derived object paths                                                                               |

Row-Level Security scopes every row to its owning account. The schema lives in `supabase/migrations/` — read it directly rather than trusting a transcription, including this one.

## The blind-ciphertext contract

Whatever backs your deployment, the invariant holds and is enforced by the client, not the server:

* The server receives **only** encrypted bytes plus non-secret metadata: hashed agent IDs, sequence numbers, byte sizes, hashes, timestamps.
* Encryption and decryption keys never leave client devices. The server has no key material and no code path that would use one.
* Because content arrives already sealed, no storage backend can inspect it — that property comes from the client-side encryption boundary, not from a well-behaved driver.

<Note>
  The **embedding vectors** never reach the server at all under any configuration — they live only in the local LanceDB store on each device. What replicates is the encrypted `active_context` payload, not the vector index.
</Note>

## What you can realistically change

**Your own Supabase project.** This is the supported path, and it is the whole of self-hosting: your Postgres, your storage bucket, your region, your backup policy, your compliance boundary. See [Deploy Self-Hosted](/self-hosted/deploy).

**Your own Postgres behind Supabase.** Supabase projects can be pointed at external Postgres in some configurations — that is a Supabase-level concern, and sovseal neither knows nor cares which Postgres answers.

**Forking the function.** `supabase/functions/v2-agent-state/` is open source. If you need a genuinely different storage backend — S3 for payloads, a different database — you can fork and rewrite the persistence calls. There is no adapter seam designed for this, so you take on merge cost against upstream changes. It is a fork, not a configuration.

## What you cannot change without forking

* The storage **shape** — two tables plus a bucket, with the schema in `supabase/migrations/`.
* The **vector store** — LanceDB locally, IndexedDB in the extension. Not server-side, not swappable. See [Vector Stores](/components/vector-stores/overview).
* The **embedder** — fixed per surface (`Xenova/all-MiniLM-L6-v2` in `@sovseal/mcp-server`, `intfloat/multilingual-e5-small` in the browser extension). See [Embedding Model](/self-hosted/custom-embedders) for why this is deliberate.

## If you need something different

If a compliance requirement makes the Supabase-backed shape unworkable — a mandated on-premise database, a specific sovereign cloud — that is a real constraint worth raising at `enterprise@sovseal.com` rather than working around with a fork you then have to maintain.
