Temporal Knowledge Graph: How AI Agents Know What Is True Now
A temporal knowledge graph is a knowledge graph in which every fact carries time: when it was true in the world, and when the system learned it. When a new fact contradicts an old one, the old fact is closed rather than deleted. An AI agent can then ask what is true now, and an auditor can ask what the agent knew on any given day.
That one property decides whether an agent answers from the current state of your business or from whatever passage looks most like the question.
The problem: similar is not current
Take a customer whose contact person changed in June. The March email names Jana Keller, the June ticket names Tom Berger. A vector search for “who is the contact at Acme” returns both passages, because both are similar to the question. The model then picks one, usually the one that reads more confident, and nothing in the retrieved text says which is still true.
Documents do not expire. Facts do. Every system that feeds an agent from chat, tickets, wiki and CRM runs into this within weeks, because those sources are full of decisions that were later revised.
How it works: facts with two clocks
A temporal knowledge graph stores three kinds of things:
- Entities are the nodes: a customer, a person, a project, a system.
- Facts are the edges between entities, written in plain language, such as “Tom Berger is Acme’s contact for the rollout”.
- Episodes are the raw inputs the facts were extracted from: a ticket comment, a meeting note, a CRM change. Every fact points back to its episodes.
Each fact carries two time axes. Valid time says when the fact held in the world. Transaction time says when the system recorded it, and when the system stopped treating it as current. A model with both axes is called bi-temporal. In Graphiti, every fact edge carries four timestamps for exactly this: valid_at and invalid_at for the world, created_at and expired_at for the system.
When the June ticket arrives, the graph does not overwrite anything. It adds the new fact and closes the old one:
| Fact | valid_at | invalid_at | Source |
|---|---|---|---|
| Jana Keller is Acme’s contact for the rollout | 2026-03-04 | 2026-06-03 | Email, 4 March |
| Tom Berger is Acme’s contact for the rollout | 2026-06-03 | open | Jira comment, 3 June |
A query for the current state returns the second row. A query as of 1 May returns the first. Both answers carry their source, so a person can open the email or the ticket and check.
Temporal knowledge graph, vector RAG and GraphRAG compared
| Vector RAG | GraphRAG-style knowledge graph | Temporal knowledge graph | |
|---|---|---|---|
| Unit of knowledge | Text chunk | Entities, relations, community summaries | Entities, facts with validity windows, episodes |
| New data | Embed and append | Batch indexing pipeline | Incremental, one episode at a time |
| Contradicting sources | Need metadata and conflict rules | Need explicit temporal modeling | Validity windows support conflict handling |
| “What was true in May?” | Possible with retained versions and date filters | Requires a history model | Supported when the relevant history is retained |
| Provenance | Chunk to document | Summaries to source text | Fact to episode to source system |
| Main cost | Embeddings | Extraction and summaries at index time | Extraction and reconciliation during ingestion |
Microsoft’s GraphRAG builds community summaries over a document collection and suits questions about the collection as a whole. A temporal knowledge graph suits questions about the current state of things that keep changing: customers, projects, systems, decisions.
The table compares common implementations. RAG is an architectural pattern and can include a graph. Azure AI Search, for example, documents metadata filters for vector retrieval.
How Graphiti builds it
Graphiti is an open-source framework for temporal knowledge graphs from Zep, under the Apache-2.0 license, at version 0.30.2 in September 2026 with about 30,800 GitHub stars. The parts that matter for an agent:
- Episodes in, facts out. You add an episode (text, a message or JSON) with a reference time. A language model extracts entities and facts, resolves them against what the graph already knows, and closes facts the new episode contradicts. Entity and edge types can be prescribed with Pydantic models or left to emerge from the data.
- Hybrid search without a model on the read path. Retrieval combines embeddings, BM25 keyword search and graph traversal, with optional reranking by graph distance, and returns facts rather than a generated summary.
- Backends. Neo4j 5.26 or newer, FalkorDB 1.1.2 or newer, and Amazon Neptune. The Kuzu driver is deprecated because the upstream project is no longer maintained.
- Models. OpenAI by default, with clients for Azure OpenAI, Anthropic, Google Gemini and Groq, and any OpenAI-compatible endpoint such as Ollama or vLLM. The README is explicit that Graphiti works best with models that support structured output, and that smaller models cause ingestion failures.
- Two defaults to know. Anonymous telemetry is on by default and switches off with
GRAPHITI_TELEMETRY_ENABLED=false. The official MCP server exposes write and delete tools, including one that clears a whole group.
A minimal round trip:
import asyncio
from datetime import datetime, timezone
from graphiti_core import Graphiti
from graphiti_core.nodes import EpisodeType
async def main():
graphiti = Graphiti("bolt://localhost:7687", "neo4j", "password")
await graphiti.build_indices_and_constraints()
await graphiti.add_episode(
name="jira-comment-4711",
episode_body="From today Tom Berger is Acme's contact for the rollout. "
"Jana Keller moved to procurement.",
source=EpisodeType.text,
source_description="Jira comment",
reference_time=datetime(2026, 6, 3, tzinfo=timezone.utc),
)
for edge in await graphiti.search("Who is Acme's contact for the rollout?"):
print(edge.fact, edge.valid_at, edge.invalid_at)
await graphiti.close()
asyncio.run(main())
How Graphiti compares with Mem0 is in Graphiti vs Mem0, and what running it takes is in Graphiti in production.
What it costs to run
The read side is cheap. The write side is where the cost sits: every episode means model calls for extraction and for resolving entities and facts against the existing graph, and that context grows with the graph. Graphiti’s own issue tracker has threads on high ingestion cost and on resolution prompts that grow with the number of nodes. Plan for it:
- Batch what can wait. A nightly ingest of a wiki space costs the same as a live one and is easier to watch.
- Keep concurrency low at first. Graphiti defaults to low concurrency to stay under provider rate limits; raise it once you know your quota.
- Pick the extraction model for structured output, not for price alone. A cheap model that returns malformed JSON costs more in retries and dropped facts than a mid-range model that follows the schema.
- Set the embedding width explicitly. A local embedder such as
nomic-embed-textreturns 768 dimensions, while graphiti-core defaults to 1,024 unlessEMBEDDING_DIMsays otherwise, and a mismatch corrupts every vector it writes without an error.
When a temporal knowledge graph is the wrong tool
- Static reference text such as manuals and policies: plain retrieval is simpler and cheaper.
- Memory inside one conversation: the context window already holds it.
- Numbers and aggregates: a warehouse answers “revenue per quarter” better than any graph of facts.
Use one when facts change, when two sources can disagree, and when someone will ask “since when” or “who said so”.
Three rules from running them
I run temporal knowledge graphs in two settings: a company’s operational context layer on its own cloud tenant, and my own working graphs on FalkorDB, with a single-file LadybugDB graph on my laptop. Three rules came out of both:
- The agent proposes, a person approves. A record from a system of record, with its own source id, can land automatically. An interpretation, such as “this customer is at risk”, waits in a queue for a person. Writes go through a separate command, never through the tools the agent reads with.
- Nothing generates on the read path. The agent gets facts with their validity window and their source, and the model only phrases the answer. That keeps answers checkable and reads fast.
- Pin what you read with to what you wrote with. Keep reader and writer on the same graphiti-core version, and take query embeddings from the same embedding model, served the same way, that built the index. In my graphs, a reader one patch version behind the writer returned no results at all, without an error, and the same embedding model served by two different Ollama builds produced vectors with a cosine similarity of only 0.80 to each other, enough to lose matches.
Those rules are built into Graphiti Local, the open-source interface I maintain: six read-only MCP tools, a kg command line, and a write path that waits for a person. In client work they become the context layer for AI agents: the same kind of graph, fed from the systems a company already runs, on its own tenant.
Graphiti Local is an independent community project built on Graphiti. It is not affiliated with or endorsed by Zep. Versions and counts as of 11 September 2026.
Frequently asked questions
What is a temporal knowledge graph?
A knowledge graph in which every fact carries time: when it was true in the world and when the system recorded it. A contradicting fact closes the old one instead of deleting it, so you can ask what is true now and what was true on any earlier date.
How is a temporal knowledge graph different from a static knowledge graph?
A temporal graph explicitly models validity over time. A graph without that model can still retain history using snapshots, events or versioned properties. Incremental updates are an implementation choice, not exclusive to temporal graphs.
Is a knowledge graph better than RAG for AI agents?
A temporal graph is useful when relationships, validity periods and the history of decisions matter. RAG can also use timestamps, metadata filters, source attribution and reranking. Similarity alone does not establish which conflicting claim is current; neither approach guarantees truth without reliable sources and evaluated update rules. Test both on your actual questions.
Is Graphiti open source?
Yes. Graphiti is Zep's framework for temporal knowledge graphs, released under the Apache-2.0 license and at version 0.30 in September 2026. It runs on Neo4j, FalkorDB or Amazon Neptune. Zep Cloud is the vendor's managed service built on it.
Does a temporal knowledge graph need a language model?
No. Structured facts can be imported with deterministic code. Graphiti uses language models for its unstructured episode extraction and reconciliation pipeline. Retrieval can also call embedding or reranking models, depending on configuration; a generated answer is a separate step.
Can a temporal knowledge graph run inside the EU or fully on premises?
Compute, storage and the graph run in your cloud tenant. Model and embedding endpoints are selected and verified separately. For an EU requirement, the deployment review records the exact model, version, deployment type, processing location and connected services. Self-hosted inference is an option when data must remain inside your network.
Your agents answer from whatever the retriever finds, and too often that is last quarter's truth. I build the context layer they answer and act from: a temporal knowledge graph that keeps every fact with its source and the time it held, reads with each person's own permissions, and writes nothing without a person's approval. On your own tenant, billed by the hour, step by step.