Model or dataset
alash3al/stash avatar
alash3al/stash

Stash: a Postgres-backed memory layer for MCP agents

Stash — persistent memory layer for AI agents. Episodes, facts, and working context stored in Postgres. MCP server included. Self-hosted, single binary, no cloud required.

768 stars48 forksGoApache-2.0

At a glance

What is it?
Stash stores episodes, facts and working context in Postgres with pgvector and exposes them to any MCP-compatible client over SSE. The design is legible and self-hostable, but the README undersells the operational and cost surface, and the hosted version is a separate codebase.
Who is it for?
Adopt Stash if you already run Postgres, want agent memory to stay inside your own network, and are willing to point STASH_EMBEDDING_MODEL and STASH_REASONER_MODEL at a provider you trust. Do not adopt it if you need a hosted SLA, if your agent runtime cannot speak MCP over SSE, or if you cannot absorb a recurring token bill for consolidation.
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 93 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

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

DEEP OPEN-SOURCE ANALYSIS

The problem Stash targets: agents that forget between sessions

Every LLM session starts from an empty context window. If you want an agent to recall that a user prefers Go over Python, that a deployment failed last Tuesday, or that a particular vendor integration was abandoned, you have to re-supply that information on every call. Most teams solve this by pasting a growing blob of text into the system prompt, which works until the blob outgrows the context window or the cost of re-sending it becomes noticeable. Stash takes the opposite position: memory belongs in a database, not in a prompt. The README frames it as a cognitive layer between the agent and the world, and the pitch is aimed at people running MCP-compatible clients such as Claude Desktop, Cursor, Windsurf, Cline or Continue. If your agent stack already speaks MCP over SSE, Stash slots in as a server. If it does not, Stash is not the tool you need, because the README does not describe any other integration path.

Episodes, facts and a 9-stage consolidation pipeline

The architecture has two layers. The first is storage: episodes, facts and working context live in Postgres with pgvector for embeddings. The second is transformation. The README describes a 9-stage consolidation pipeline that turns raw observations into structured knowledge: facts, relationships, causal links, patterns, contradictions, goal tracking, failure patterns and hypothesis verification. Each stage only processes data new since the last run, which is the detail that makes the pipeline viable at all. Without incremental processing, every consolidation pass would re-read the entire episode table and re-pay for it. The README also states that consolidation runs in the background alongside the MCP server, which is why the docker compose command is described as bringing up "Postgres + pgvector, migrations, MCP server with background consolidation" in one step. What the README does not specify is the scheduling interval, the retry behaviour when the reasoner model returns an error, or how contradictions are resolved once detected. Those are the parts of a memory system that determine whether it stays trustworthy after a month of use, and they are not documented here.

Getting it running: docker compose and the .env keys that matter

The quick start is four commands. Clone the repository, copy .env.example to .env, edit it with your API key and model, then run docker compose up. The README says this brings up Postgres with pgvector, runs migrations, and starts the MCP server with background consolidation. The server then exposes an SSE endpoint at http://localhost:8080/sse. Client configuration is a small JSON block per tool. For Cursor it goes in ~/.cursor/mcp.json, for Claude Desktop in claude_desktop_config.json, for OpenCode in ~/.config/opencode/config.json with a slightly different shape (a type field set to remote and an enabled flag), and for Windsurf in ~/.codeium/windsurf/mcp_config.json. The environment keys the README names are STASH_OPENAI_API_KEY, STASH_OPENAI_BASE_URL, STASH_EMBEDDING_MODEL, STASH_REASONER_MODEL and STASH_VECTOR_DIM. The Atlas Cloud example sets the base URL to https://api.atlascloud.ai/v1, the embedding model to text-embedding-3-small, the reasoner to deepseek-ai/DeepSeek-V3-0324 and the vector dimension to 1536. That last key is the one to get right before the first run, because changing an embedding model later means the stored vectors no longer match the query vectors. There is also a documented fully local path using Ollama, described in docs/LOCAL_OLLAMA.md, for private embeddings and reasoning.

What the README does not tell you about operating Stash

Two gaps stand out. First, the consolidation pipeline needs a chat-capable reasoning model, and the README is explicit that Stash needs "a chat-capable reasoning model for consolidation". That means every consolidation run spends tokens on a model you pay for, separate from whatever your agent already spends. The README gives no estimate of how many calls a given volume of episodes produces, so the only way to find out is to run it and watch your provider dashboard. Second, the vector dimension is fixed at configuration time. If you set STASH_VECTOR_DIM to 1536 and later switch to an embedding model with a different output size, the existing rows in pgvector are the wrong shape. The README does not describe a migration path for that case, so treat the embedding model choice as a decision you make once. A third, smaller issue: the SSE endpoint is exposed at localhost without any mention of authentication in the README. If you bind that port to a network interface rather than loopback, you are responsible for whatever sits in front of it.

Stash versus plain retrieval over your own database

The obvious alternative is not another memory product. It is a table of notes, an embedding column and a retrieval function you write yourself. The difference in approach is where the intelligence sits. A hand-rolled retrieval layer returns the nearest chunks to a query and stops. Stash runs consolidation on top of storage, so the stored material is transformed before it is ever queried: episodes become facts, facts become relationships, and the pipeline claims to detect contradictions and track goals. That transformation is the product. It is also the cost centre, because it requires a reasoning model on a schedule. If your use case is "find the three notes most similar to this question", a pgvector query and a small script will do it with no reasoning model in the loop and no pipeline to monitor. If your use case is "notice that the user changed their mind about a vendor three weeks ago", the transformation layer is doing work you would otherwise have to write and maintain yourself. The honest framing is that Stash trades a recurring inference bill for code you would otherwise own.

The hosted version is a different codebase, not a deployment of this one

The README states plainly that usestash.io is a hosted, multi-tenant version written from scratch, sharing no code with this repository, and that feature sets differ in both directions. That is an unusually direct disclosure and it matters for anyone evaluating the open source project as a path to the hosted product. Migrating from self-hosted Stash to the cloud is not a deployment change; it is a move between two implementations with overlapping ideas. The cloud version is described as free while in beta. For teams that want the memory behaviour without running Postgres, the cloud is the only documented option, but the README gives no migration tooling and no compatibility guarantee. Plan accordingly: pick one and stay there, or expect to re-import your data by hand.

Licence, maintenance and what to verify before you commit

Stash is Apache-2.0. That covers the Go code and the MCP server, and it permits commercial use and modification. It does not cover the embedding or reasoning models you configure, which carry their own terms, and it does not cover the hosted service. On maintenance: the release history shows v0.2.9 in early May 2026, then v0.2.10 and v0.2.11 within a day of each other in late May, and the last push to main was in mid June 2026. The v0.2.9 release is titled "Consolidation Quality & MCP Setup Docs", which suggests the consolidation stage and the setup documentation are still moving. The version number is 0.2.x, so expect interface and configuration changes between releases. Pin a tag rather than tracking main if you are deploying this anywhere that matters. The single-binary, self-hosted claim holds for the server, but the surrounding stack is Postgres with pgvector plus an external inference provider, so the operational surface is larger than the phrase suggests.

Editorial conclusion

Adopt Stash if you already run Postgres, want agent memory to stay inside your own network, and are willing to point STASH_EMBEDDING_MODEL and STASH_REASONER_MODEL at a provider you trust. Do not adopt it if you need a hosted SLA, if your agent runtime cannot speak MCP over SSE, or if you cannot absorb a recurring token bill for consolidation. Before committing, verify three things: the vector dimension in .env matches the embedding model you chose, the consolidation job actually runs after docker compose up (check the container logs), and the licence terms of the models you configure. Apache-2.0 covers Stash itself, not the inference you plug into it.

Official sources

  1. alash3al/stash on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Community notes

Community notes