Your data, your ops — the same epistemic memory graph, fully self-managed.
Prefer zero-ops? Try hosted →
What you get: a multi-writer-safe FalkorDB graph (AOF on the sidecar) behind the daemon, the MCP server, and the same Tortoise onboarding instructions your agent reads. The MCP tool names are identical to hosted — only the transport differs (self-hosted HTTP vs Streamable HTTP).
Clone the repo (Docker is the recommended path — no local Python needed):
git clone https://github.com/daniel-ospina/tortoise.git && cd tortoise
No Docker? pip install tortoise-graph (or pip install -e . from the repo) — Python 3.12+ — and use the embedded path below, which is single-agent eval only.
The repo's docker-compose.yml starts the daemon plus a FalkorDB sidecar (AOF on, named volume, healthcheck) — the multi-writer path for teams and production:
docker compose up -d ✔ daemon ready → http://localhost:8000 (MCP at /mcp) ✔ FalkorDB sidecar healthy (127.0.0.1:6379, requirepass)
Set a strong TORTOISE_API_KEY in docker-compose.yml before exposing beyond localhost. Host-side tools can reach the sidecar directly with TORTOISE_DB_URI=docker://:falkordb@localhost:6379/tortoise.
Durability, plainly: AOF on the sidecar survives a process or container crash (≤1 s of lost writes) — it does not survive losing the volume or the host. Durability is the store's persistence plus an off-box copy, so the off-box backup target is a setup decision, not a silent default: in docker-compose.yml, fill all five of R2_ACCOUNT_ID / R2_ACCESS_KEY_ID / R2_SECRET_ACCESS_KEY / R2_BUCKET / TORTOISE_BACKUP_KEY to declare a target, or set TORTOISE_OFFBOX_BACKUP_DECLINED=1 to decline one explicitly. Leave both unset and the daemon still serves — and reports the single local copy loudly at startup. The full posture, with what has actually been verified: docs/durability-posture.md.
⚠️ Declaring the complete target arms the daemon's off-box backup driver: it sweeps this deployment's graph to that target every hour (configurable) with the read-back-verified logical dump, and logs every failed run. The first archive appears after the first interval, and the posture doc states the recovery path's verification status — read it before relying on the target.
Run tortoise onboard from your repo — it chains init → index → demo → doctor automatically (resolves the same DB target as your daemon):
tortoise onboard Step 1/5: Ensure Tortoise SDK is installed ✅ Tortoise installed Step 2/5: Initialize graph ✅ graph ready Step 3/5: Index repository Found 42 markdown files. Indexing… Step 4/5: First memory demo ✅ demo points created Step 5/5: Health check ✅ doctor OK Onboarding complete. Next: connect your agent (step 4) tortoise setup — configure per-role memory
Idempotent — re-running skips already-done steps. When it finishes, it prints the served onboarding instructions URL — hand that document to your agent to complete setup.
Docker path (recommended): point your agent at the daemon:
claude mcp add --transport http tortoise http://localhost:8000/mcp # writes local scope (~/.claude.json, private); or the project-scope .mcp.json block — committable, no key here (a local daemon needs none), and it stays Pending approval until you start claude in the project and allow the prompt (or run /mcp)
Stdio path (same durable sidecar): if you prefer stdio transport, point the harness at the sidecar (requires the Docker sidecar from step 2 running):
No Docker / single-agent eval: run python -m tortoise.mcp_server with TORTOISE_DB_PATH set — embedded FalkorDBLite is single-writer, eval only; concurrent writers lose data, so one agent only.
Configure how Tortoise filters memory per role:
tortoise setup --role developer # researcher | strategist | developer
Or run tortoise setup interactively — it walks through episodic / epistemic / semantic / procedural / working memory per role.
| You are… | Use… | Why |
|---|---|---|
| One agent, experimenting / laptop eval | Embedded (no Docker, tortoise init) | Zero deps, single-writer only — safe for one agent |
| A team / multiple agents | Docker compose sidecar (step 2) | Multi-writer: verified to 5 concurrent writer processes with no lost writes |
| Production / HA | Docker compose or managed Cloud | AOF + a declared off-box target + ops; embedded is eval only |
Embedded FalkorDBLite is AOF-durable for a single process since #915, but concurrent writers lose data — that is the boundary, and it is not negotiable for team deployments.
What each path actually sustains — write concurrency, request rate limits, graph-size caps, retrieval latency, storage footprint per element, and belief-propagation cost. Every published number names the committed artifact or code symbol it comes from.
Measured today: the Docker path is verified to 5 concurrent writer processes on one graph with no lost writes; embedded is single-writer; the hosted per-key limit is 100 requests/min. The full page, with sources: docs/capacity.md.
tortoise_health, and report the harness-connected checkpoint. Read them at
app.premiselabs.co/skills/tortoise-onboarding/SKILL.md
(they are a document your agent reads — never an installed skill; the archived onboarding
prompt was superseded by this document, M8) or run
tortoise onboard and copy the URL it prints.