AgentsOpen SourceFreeActiveMachine-verified· intermediate · ~15 min setup

Graphiti: A Temporal Graph for What Was True When

Stand up the bi-temporal context-graph engine behind Zep on a local FalkorDB, with indices built and ready for episodes.

by Shilpa Mitra· verified today· v1.0.0

Run this workflow

CI-verified, 2/2 fixtures passing.

Build this with your agent

One copy-paste hands Claude Code, Codex, or Cursor the full recipe, steps included, nothing to fetch.

Intended Use

Tracking facts that change over time: Graphiti invalidates rather than deletes, so 'what was true last month' is queryable. CI starts a real FalkorDB container, installs graphiti-core, connects, and builds indices and constraints, none of which needs a model (a dummy key proves it). Ingesting episodes runs an LLM, OpenAI by default, so it's fenced.

Not for

  • Setups without a graph database, Graphiti needs one (FalkorDB is the one-command Docker option)
  • Expecting CI to verify episode ingestion, that's the model-driven step

The Stack

Tested Against

graphiti-core@latestfalkordb@latest (Docker)python@3.12

Side effects & data flow

Network
PyPI + Docker Hub, install only
Writes
./.venv/, a throwaway FalkorDB container
Credentials
LLM key, for the fenced episode-ingest step only

Prerequisites

  • Docker
  • Python 3.10+
  • An OpenAI (or compatible) key for the fenced ingest step

Steps

  1. 1

    Start FalkorDB, install graphiti-core, connect, and build indices

    FalkorDB runs in one Docker command. CI then installs graphiti-core[falkordb], waits for the port, connects with FalkorDriver, and builds indices and constraints. A deliberately-dummy OPENAI_API_KEY proves no model is involved in this spine. The container is torn down either way.

    docker rm -f wf-falkordb >/dev/null 2>&1 || true
    docker run -d --name wf-falkordb -p 16379:6379 falkordb/falkordb:latest
    python3 -m venv .venv
    .venv/bin/pip install -q "graphiti-core[falkordb]"
    OPENAI_API_KEY="dummy-key-proves-no-model-call" .venv/bin/python - <<'EOF'
    import asyncio, socket, time
    
    # wait for FalkorDB to accept connections
    for _ in range(30):
        try:
            socket.create_connection(("localhost", 16379), timeout=1).close()
            break
        except OSError:
            time.sleep(1)
    else:
        raise SystemExit("FalkorDB never came up on :16379")
    
    from graphiti_core import Graphiti
    from graphiti_core.driver.falkordb_driver import FalkorDriver
    
    async def main():
        g = Graphiti(graph_driver=FalkorDriver(host="localhost", port=16379))
        await g.build_indices_and_constraints()
        print("graphiti OK: connected to FalkorDB and built indices (no model call)")
    
    asyncio.run(main())
    EOF
    rc=$?
    docker rm -f wf-falkordb >/dev/null 2>&1 || true
    exit $rc
  2. 2

    Ingest episodes (the model step, not checked by CI)

    Add episodes with a real key and Graphiti extracts entities and relations with an LLM (OpenAI by default, best with structured-output models). Non-deterministic, so CI never claims it.

Eval, 2 fixtures

Last passed: verified today
  • indices-builtcontainstimeout 900s · max $0

    Expected: graphiti OK: connected to FalkorDB and built indices (no model call)

  • clean-exitexit_codetimeout 900s · max $0

    Expected: 0

Results

Bi-temporal facts: when a fact changes the old one is invalidated, not deleted, so you can query any past point in time.

Did this work for you?

Our CI checks the setup runs. You tell us if the whole thing worked. Tell us straight.

Liked this workflow?

Get new verified workflows in WebAfterAI, three issues a week (Tue, Thu, Sat).