Model or dataset
smaramwbc/statewave avatar
smaramwbc/statewave

Statewave review: compile-then-use memory for AI agents on Postgres

Open-source memory runtime for AI agents — reproducible, provenance-tagged context bundles instead of query-time retrieval. Apache-2.0, self-hosted on Postgres + pgvector, Python + TypeScript SDKs.

355 stars30 forksPythonApache-2.0

At a glance

What is it?
Statewave is an Apache-2.0 memory runtime that compiles raw agent episodes into typed, provenance-tagged memories and assembles deterministic context bundles. It is self-hosted on Postgres with pgvector, and its default heuristic compiler runs without any API key.
Who is it for?
Adopt Statewave if you are building a long-lived agent that needs auditable, repeatable context and you already run Postgres. Skip it if you want a hosted memory API or a drop-in RAG replacement.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Statewave is for, and who it is not for

The problem Statewave targets is stated plainly in its README: most AI applications have no memory, and bolting on a vector database or dumping chat logs into a prompt produces fragile context that degrades as it scales. Statewave's answer is a four-stage lifecycle around a subject identifier, which can be a user, an account, an agent, a repo, or any entity prefix you choose. Raw events are recorded as episodes, append-only. A compiler extracts typed memories with confidence scores. A retrieval step assembles a ranked, token-bounded context bundle. Governance covers subject timelines, provenance tracing, and deletion by subject.

The audience is narrow on purpose. The README states that Statewave is not a chatbot framework, not a vector database, not a RAG pipeline, and not a hosted service. It is infrastructure you run alongside your application. If your requirement is a managed memory API with someone else on call, this project is the wrong shape. If your requirement is that the same query against the same subject at the same point in time returns the same bytes, that determinism is the whole point of the design.

How compile-then-use differs from query-time retrieval

The mechanism is a pipeline rather than a search index. Episodes are ingested as they happen. Compilation happens once per subject change, producing typed memories. Bundle assembly then ranks those memories against a task and a token budget. The README describes the result as deterministic per subject and task, and claims idempotency at every step: recompiling a subject produces no duplicates, and reassembling a bundle for the same task at the same point in time returns the same bytes.

Provenance is the second half of the design. Every memory traces back to its source episodes, and receipts are content-hashed. State-assembly receipts are described as an immutable, ULID-addressable record of which memories influenced each bundle, with an HMAC-SHA256 signature and an embedded policy snapshot, plus a replay endpoint for asking what today's code would say with the original rules. That endpoint is the part worth scrutinising: it implies you can re-run assembly under a frozen policy, which matters when a memory's inclusion is later disputed.

Two compilers ship. The heuristic one is regex-based and fully local. The LLM compiler routes through any LiteLLM provider. The .env.example is explicit that these are not interchangeable at runtime: with the LLM compiler selected but no key reachable, compilation produces zero memories and does not fall back to the regex compiler. That is a silent-failure shape worth knowing before you deploy.

Installing Statewave and running the ingest, compile, use loop

The repository ships a docker-compose.yml that starts two services: a pgvector/pgvector:pg16 database and the API image statewavedev/statewave, published on port 8100 by default. The compose file reads a host .env if one exists, and injects connection wiring so the API reaches the database as `db` inside the compose network.

Start by copying the example environment file. The defaults run in demo mode with no API key, using the heuristic compiler and hash-based embeddings.

bash
cp .env.example .env
docker compose up -d

The .env.example comments state that every step of the getting-started guide works as written in this mode. Retrieval in demo mode is keyword and text only, with no semantic similarity, because the embedding provider is set to stub.

Once the API answers on port 8100, the README's quickstart shows the full loop. The client is a context manager, episodes are created with a subject, a source, a type and a payload, and the returned bundle exposes the assembled context as a string.

python
from statewave import StatewaveClient

with StatewaveClient("http://localhost:8100") as sw:
    sw.create_episode(subject_id="user-42", source="chat", type="message",
                      payload={"text": "Alice asked about pricing tiers"})
    sw.compile_memories("user-42")
    print(sw.get_context("user-42", task="answer pricing", max_tokens=1000).assembled_context)

To move past demo mode, the .env.example instructs you to comment out the two demo lines and uncomment the LiteLLM block, selecting a provider through the model identifier. The Python SDK lives at statewave-py and the TypeScript SDK at statewave-ts; the README also points to Docker and Helm paths for self-hosting.

Where the design puts pressure on you

The README links to a Limitations section, which is a fair signal that the authors know the edges. The most concrete constraint visible in the repository is the compiler choice. Demo mode is keyless and local, but its retrieval is keyword-only. Turning on semantic search means an embedding provider, and turning on LLM extraction means a reachable provider key. The failure mode when the key is absent is zero memories, not degraded memories. A pipeline that quietly compiles nothing will look healthy at the API layer.

The API process is CPU-only, and the README states that no GPU is required. GPUs enter the picture only if you self-host an LLM compiler or an embedding model. That is a real operational simplification, but it also means the hosted-provider path is where your latency and your data flow go, and the README points to a separate Privacy and Data Flow document rather than resolving that question inline.

Multi-tenancy is query-scoped through an X-Tenant-ID header, with per-tenant config and policies. Version 0.9 added region pinning, where a tenant pinned to a region gets a 403 from any process running elsewhere. Region pinning is enforcement at the process level, which is a different guarantee from database-level residency. If your compliance story depends on where bytes rest rather than where requests are refused, verify that against your own deployment topology.

Statewave against a vector store plus a retrieval loop

The obvious alternative is the stack the README argues against: a vector database such as pgvector alone, with your application embedding and retrieving chunks at query time. The difference is not the storage engine, since Statewave itself runs on Postgres with pgvector. The difference is when the work happens and what gets recorded.

In a query-time retrieval loop, the context you feed a model is assembled on each request from a similarity search. Two requests with the same inputs can return different neighbours depending on index state and embedding drift, and nothing in the response says which source documents produced which sentence. In Statewave, compilation happens on subject change and assembly is deterministic per subject and task, with receipts that trace memories back to episodes and a replay endpoint for re-running assembly under the original policy snapshot.

That buys auditability and repeatability at the cost of a lifecycle you now have to operate: episodes to ingest, compilations to trigger, bundles to assemble, policies to write. A team that only needs approximate recall over a document set, and has no requirement to explain why a particular fact appeared in a prompt, will find a plain pgvector table simpler and faster to ship. Statewave is for the case where the explanation is the requirement.

Project status, licence and the cost of upgrading

The repository is not archived, and the last push was on 2026-09-10. Releases are frequent: v1.3.0 on 2026-06-25, v1.4.0 on 2026-07-14, and v1.5.0 on 2026-08-30. The pyproject.toml carries the classifier Development Status :: 4 - Beta, so treat the API surface as still settling even though the cadence is steady.

Upgrade cost is dominated by the database schema. The repository includes alembic.ini and an alembic/ directory, and the Dockerfile notes that start.sh runs `alembic upgrade head` before uvicorn starts. Migrations are therefore applied automatically on container start, which makes upgrades convenient and rollbacks a thing you have to plan for yourself. The README does not document rollback.

Dependency pinning is tight, with upper bounds on FastAPI, pydantic, SQLAlchemy, asyncpg, alembic, pgvector, numpy and tiktoken. Two comments in pyproject.toml explain why numpy and httpx are declared explicitly: pgvector 0.5.0 dropped numpy as a transitive dependency, and httpx previously arrived only through the `llm` extra, so a core-only install had no httpx and webhook delivery raised ModuleNotFoundError. Those are the kinds of breakage that show up when you install without the extras, so match your install to the features you actually use.

The licence is Apache-2.0. That permits commercial use and modification, and it includes a patent grant. The repository also carries LICENSING.md, NOTICE.md and TRADEMARKS.md alongside LICENSE, which usually means trademark use is carved out separately from the code grant. Read those files before shipping a product that carries the Statewave name; this is a description of the files present, not legal advice.

Editorial conclusion

Adopt Statewave if you are building a long-lived agent that needs auditable, repeatable context and you already run Postgres. Skip it if you want a hosted memory API or a drop-in RAG replacement. Before committing, run the demo-mode quickstart, then read the repository's own Limitations section.

Frequently asked questions

Does Statewave require an API key to run?

No. The .env.example sets the heuristic compiler and a stub embedding provider by default, and states that no API key is required and every step of the getting-started guide works as written. That mode extracts memories locally but retrieval is keyword and text only, with no semantic similarity.

What happens if the LLM compiler is selected but no provider key is reachable?

The .env.example states that compilation produces zero memories and does not fall back to the regex compiler. Use the demo-mode settings for a keyless setup rather than selecting the LLM compiler without a working key.

What database does Statewave run on?

Postgres with pgvector. The bundled docker-compose.yml uses the pgvector/pgvector:pg16 image and the API connects to it through STATEWAVE_DATABASE_URL, which the compose file overrides to point at the `db` service inside the compose network.

Does Statewave need a GPU?

The README states that the API process is CPU-only and no GPU is required. GPUs only enter the picture if you self-host an LLM compiler or an embedding model rather than calling a hosted provider.

How are Statewave database migrations applied?

The Dockerfile notes that start.sh runs `alembic upgrade head` before uvicorn starts, and the repository includes alembic.ini and an alembic/ directory. The README does not document a rollback procedure.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. smaramwbc/statewave on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/smaramwbc-statewave.svg)](https://hysenlabs.com/projects/smaramwbc-statewave)