geshtu.io/cloud — managed hosting, oauth, email digests  ·  join the waitlist →
v0.1 · open source · agpl-3.0

Self-hosted shared memory for teams
using LLMs.

Connect Claude, Cursor, or Windsurf via MCP. Geshtu captures facts and decisions across every chat, scopes them per-project, and lets a teammate ask their AI for a digest of "what happened since Monday" in 30 seconds.

postgres + pgvector mcp · stdio local embeddings one docker compose
geshtu · sumerian · n. — "ear", "wisdom", "memory": the same word for all three. In Mesopotamian thought the ear was the organ of memory; to listen well was to remember. Five thousand years later, teams using LLMs still need somewhere to keep what they have heard.
claude desktop · geshtu mcp · api-core
5min
› clone to running
~€11/mo
› api spend, 5-person team
6
› mcp tools, no more
1024d
› bge-m3, local cpu
how it works

Memory, recorded as it happens.

Every message your team sends to an LLM passes through Geshtu. Facts and decisions are extracted, embedded, and scoped to the project. The next teammate's chat starts where the last one left off.

› step.01

You chat as usual

Open Claude, Cursor, or Windsurf. Geshtu sits behind MCP. No new UI, no copy-paste.

› step.02

It listens

Each message is captured, then a worker calls Claude Haiku to extract facts and decisions as structured JSON.

› step.03

It remembers

Facts are embedded with BGE-M3 locally, dedup'd against existing memory, and tied to the project they came from.

› step.04

A teammate catches up

"Catch me up since Friday." Geshtu hands them a cited digest in seconds — what changed, what was decided, what's open.

the schema

Four layers, each doing one thing well.

Most "AI memory" tools collapse everything into one bucket of "memories". Geshtu keeps facts, decisions, and summaries separate — because retrieving "what's true" and "what we chose" are different questions, and the answers age differently.

> layer.01 // source of truth

Raw log

Every message your team sends, untouched. Source of truth for everything else. Optional retention windows.

tbl: messages
> layer.02 // what is true

Facts

Extracted statements with embeddings, validity windows, and supersession links. Old facts don't vanish — they're marked outdated.

tbl: facts
> layer.03 // what we chose

Decisions

Explicit choices with the rationale stated, not inferred. Authored, dated, and reversible — first-class, separate from facts.

tbl: decisions
> layer.04 // where we left off

Summaries

End-of-session markdown: what happened, what's open, what's next. The seed for tomorrow's digest.

tbl: session_summaries
why it's different

Built around the team, not the user.

Most memory systems were designed for one user's relationship with one AI. Geshtu is designed for one team's relationship with one project — a different shape, with different requirements.

// spatial

MemPalace

file memories into rooms & drawers
  • Hierarchical, palace metaphor
  • Built for solo dev, large personal context
  • Cross-cutting queries fight the hierarchy
  • No team scope, no async handoff
// personal stream

Mem0 / Letta

flat list of facts about a user
  • One stream per user, per agent
  • Fast, well-understood, hosted-first
  • Decisions and facts collapsed into "memory"
  • No temporal validity, no rationale
// team event log ◉

Geshtu

structured journal of a project
  • Team is the primary entity, not the user
  • Facts, decisions, summaries — separate, first-class
  • Async digests as the headline feature
  • Decision rationale is a required field
  • Validity windows + supersession built in
  • Self-host on one box, AGPL forever
read the long version of why →
team protocol
"Every chat with an LLM starts cold. Multiply by 5 teammates and 3 tools, and your team spends an hour a day re-explaining context. Geshtu holds onto what you've heard — async, scoped, cited."
// from the README
what's inside

Boring stack. Sharp shape.

No Kubernetes, no dedicated vector DB, no auth library, no frontend framework. The simplicity is the product — every retrieval maps to one SQL filter against one of four tables.

MCP-native

Six tools, no more. Works in any MCP client — Claude Desktop, Cursor, Windsurf, Cline. Stable surface.

Hybrid search

pgvector HNSW + pg_trgm fused via Reciprocal Rank Fusion. Sub-10ms similarity over a team's lifetime memory.

Local embeddings

BGE-M3 on CPU. Multilingual. Free per call. Your message text never leaves your box for embedding.

Async digests

Three depths: quick (~300w), standard (~800w), deep (~2500w). Sonnet writes them. Cited and dated.

Project-scoped

Memory is partitioned per project from the schema up. One project's memory never leaks into another's.

Auditable

Every read is logged. Every fact links to the message and author it came from. GDPR export & purge built in.

Decision rationale

Why you chose Postgres, not just that you did. A required field, surfaced in every digest and search result.

Temporal validity

Facts have valid_from / valid_until / superseded_by. Old answers don't silently stay true.

One box, one compose

Postgres, Redis, FastAPI, Celery, MCP, Streamlit admin. Caddy out front. Five minutes from clone to running.

install

Five minutes to running.

Clone, set one API key, bring up the stack, paste a JSON snippet into your AI client. Done. Hetzner CPX21 (~€8/mo) handles a team up to 15 people.

1 bring up the stack
$ git clone https://github.com/crowditory/geshtu
$ cd geshtu && cp .env.example .env
# edit .env, set ANTHROPIC_API_KEY
$ docker compose up -d
$ docker compose exec api python -m geshtu.bootstrap \
    --team "My Team" \
    --admin-email "me@example.com" \
    --admin-name "Me"
# → prints tk_... drop into your llm client
2 wire your llm client
{
  "mcpServers": {
    "geshtu": {
      "command": "npx",
      "args": ["-y", "@geshtu/mcp"],
      "env": {
        "GESHTU_TOKEN": "tk_...",
        "GESHTU_URL": "http://localhost:3000"
      }
    }
  }
}
get started

Give your team a memory.

AGPL-3.0, no signup, no telemetry by default. Self-host today. Or join the cloud waitlist if you'd rather we run it.

$ docker compose up -d
# [+] running 6/6
postgres started
redis started
api started
worker started
mcp started
admin started
> memory layer is live