Graphiti Without Neo4j: One Embedded File, Ollama, No API Key
Last tested: September 2026, graphiti-core 0.30.1, LadybugDB 0.19, Ollama with qwen2.5:7b and nomic-embed-text.
Graphiti’s quickstart assumes a graph database server and an OpenAI key. For agent memory on one machine, both are optional, and the choice that remains is which embedded file backend to use. It matters more than it looks, because it decides whether your agent can keep reading while new facts are written.
Which embedded backend Graphiti can use
Graphiti can run without Neo4j or Docker on an embedded backend that keeps the graph in a local file. Kuzu is deprecated upstream. FalkorDB Lite is maintained but allows one process per file. LadybugDB, the maintained Kuzu fork, allows one writer plus many read-only readers, which is what an agent that reads during ingest needs.
| Backend | Install | State | Concurrent access |
|---|---|---|---|
| Kuzu | graphiti-core[kuzu] | Deprecated, upstream unmaintained | Do not start new work |
| FalkorDB Lite | graphiti-core[falkordblite], Python 3.12+ | Maintained | One process per file |
| LadybugDB | ladybug through the Kuzu driver | Maintained Kuzu fork | One read-write open plus read-only opens |
LadybugDB has no driver of its own in Graphiti. It is a continuation of Kuzu, so it runs through the Kuzu driver once the package answers to the old name:
import sys
import ladybug
sys.modules.setdefault("kuzu", ladybug) # Graphiti imports the predecessor by its old name
from graphiti_core import Graphiti
from graphiti_core.driver.kuzu_driver import KuzuDriver
driver = KuzuDriver(db="graph.ladybug")
graphiti = Graphiti(graph_driver=driver)
One trap on this path: the Kuzu driver declares its full-text indexes, but its build_indices_and_constraints does nothing, so the indexes are never created and every hybrid search fails with a Binder exception. Create them yourself on the first read-write open. Graphiti Local does this in its setup command and refuses a read-only open without them.
The writer should not be the agent
An embedded file makes the write path visible, because only one process may hold it for writing. I use that constraint as the design: readers open the file read-only, and the one read-write open is a command a person runs.
In Graphiti Local the MCP server exposes six tools, all reads. When an agent learns something, it files a proposal outside the graph file. Nothing reaches the graph until a person approves it and runs the drain. A 7B model turning a meeting note into three confident, wrong entities is the reason: a bad answer can be retried, a bad memory keeps coming back.
Before 0.3.0 the server held the write lock and locked every other command out of its own database. Opening readers read-only fixed that; the server picks up what the drain wrote without a restart.
Try the read path in 10 seconds
uvx --from git+https://github.com/renezander030/graphiti-local kg-demo
On a clean directory this took 10 seconds and installed 54 packages. It answers a question against a small synthetic graph with keyword search only, so no model is contacted and nothing needs Ollama. The full local setup:
git clone https://github.com/renezander030/graphiti-local.git && cd graphiti-local
uv sync --frozen
ollama pull qwen2.5:7b && ollama pull nomic-embed-text
export GRAPHITI_LOCAL_CONFIG="$PWD/config/ollama.example.yaml"
export KG_WORKSPACE_DIR="$PWD/workspace/local-demo"
export KG_LADYBUG_PATH="$KG_WORKSPACE_DIR/graph.ladybug"
uv run --frozen kg-ladybug-setup --database "$KG_LADYBUG_PATH" --apply
uv run --frozen kg doctor
uv run --frozen kg-ingest examples/local_memory_demo.jsonl --apply
uv run --frozen kg ask "Which database does Aurora Analytics use?" example
What it costs on a laptop
Measured on an Apple M5 with 32 GiB on the shipped synthetic fixture, excluding model and dependency downloads:
| Step | Seconds |
|---|---|
| Database setup | 1.3 |
kg doctor | 0.5 |
| Ingest (local extraction) | 34.4 |
| Query | 1.3 |
| Approve and apply an update | 44.7 |
Retrieval is fast enough for an agent loop. Extraction is a local model producing structured output, and it is the step to batch or run overnight.
Your embedder is part of your data
Vectors from one embedder are not comparable to vectors from another, even under the same model name. In my own graphs, nomic-embed-text on a second Ollama build scored 0.80 cosine against stored vectors where the original scored 1.00. Nothing errors; every search ranks a little worse. Graphiti Local records which embedder wrote the database, and an ingest with a different one exits 2.
The width is the second silent failure: nomic-embed-text returns 768 dimensions, not the 1536 an OpenAI default assumes. kg doctor probes the endpoint and fails when the configured width disagrees.
When an embedded file is the wrong choice
- Several users or tenants in one deployment. An embedded file is one graph and cannot enforce a boundary between groups. Use one file per user, or FalkorDB or Neo4j when a real tenant boundary is required.
- Agents that must write directly. By design they cannot here.
- Bulk ingestion. A local model is the floor on extraction speed.
- A long-lived dependency on the Kuzu driver. LadybugDB rides a driver Graphiti has marked deprecated. Graphiti Local pins graphiti-core for that reason; check the pin before you upgrade.
If you try the setup, the repository has an issue template for setup results, blocked ones included. The full-text index fix above came out of exactly that kind of report. For server backends, read Graphiti in production; for the concepts, the temporal knowledge graph guide.
Changelog
- 2026-09-23: First version, from Graphiti Local 0.4.1 and the local demo measurements.
Graphiti Local is my independent open-source project built on Graphiti. It is not affiliated with or endorsed by Zep.