Self-hosted
Team Server
One shared knowledge graph for your whole team — on your own infrastructure. No data leaves your network.
Overview
The Team Server is the Waystone API backed by a multi-writer PostgreSQL + pgvector graph. Each team member's Claude Code session injects the team's context every prompt and writes new decisions back to the same graph, automatically. You run it; nothing leaves your network.
- Shared memory — a teammate's decision shows up in your next session.
- Self-hosted — your hardware, your Postgres, your data.
- Drop-in — the same
query/extract/ hooks, just pointed at the server.
Quickstart
No clone, no build — pull the published image:
curl -O https://unbidden.ai/team-server/docker-compose.yml
curl -o .env https://unbidden.ai/team-server/env.example
# edit .env (see below), then:
docker compose up -d # Postgres (pgvector) + the API, ready in ~30s
curl localhost:8000/v1/health
(Prefer to build from source? git clone https://github.com/Unbidden-AI/waystone and use the repo's root docker-compose.yml instead.) docker compose up brings up two services: db (pgvector/pgvector:pg16, data in a named volume) and server (ghcr.io/unbidden-ai/waystone-server). The Postgres schema is created automatically on first use — no migration step.
In .env, set one auth value plus the LLM key:
- Bought a license? Paste it as
WAYSTONE_LICENSE=<token>— that alone enables per-seat mode (issue keys below). Nothing else to flip. - Just want one shared key? Set
WAYSTONE_API_KEYinstead (any strong random string). LLM_API_KEY(+ optionalLLM_BASE_URL,LLM_MODEL) — the OpenAI-compatible endpoint the server uses to extract facts (defaults target Gemini 2.5 Flash).
The server refuses to start if you set neither a license nor a shared key — it never comes up unauthenticated.
Connect a client
In each member's ~/.waystone/config.yaml:
backend: remote
api_url: http://<server-host>:8000
api_key: <the WAYSTONE_API_KEY you set>
That's it. Now:
- The UserPromptSubmit hook injects shared context from the team graph on every prompt (fail-open, capped at ~8s so a slow server never blocks you).
- Extraction is routed to the server — assistant turns and decisions land in the shared graph automatically.
waystone query,extract,show,export, andinitall operate against the Team Server.
Use backend: local to force a machine back to its private SQLite graph even if api_url is set.
Per-seat licensing
If you set WAYSTONE_LICENSE in the quickstart, the server is already in per-seat mode — just hand out keys with the team CLI:
docker compose exec server waystone team issue alice@acme.com
docker compose exec server waystone team members # who has a seat
docker compose exec server waystone team license # seats used / total
docker compose exec server waystone team revoke bob@acme.com # free a seat
Licenses are Ed25519-signed tokens verified locally — no phone-home. An airgapped server stays correctly licensed. Seats are enforced offline; a tampered or expired license never grants seats (fail-closed). Without a license you get 3 trial seats to evaluate; a license raises the cap.
Notes & ops
- Data lives in the
waystone-pgdatavolume. Back it up withdocker compose exec db pg_dump -U waystone waystone > backup.sql. - Upgrades: image deploy →
docker compose pull && docker compose up -d; source build →git pull && docker compose up -d --build. Schema migrations are additive, so rolling forward is safe. - TLS / public exposure: put the server behind a reverse proxy or a private network (e.g. Tailscale) — the bearer key is the only gate.
- Tenancy: each
projectis an isolated tenant inside the one Postgres graph.
Full reference (env vars, compose file, examples): docs/team-server.md on GitHub →