Release Notes — graphiti-core 0.29.0
Summary
0.29.0 is the first of two releases focused on making ingestion meaningfully cheaper and the search pipeline easier to evolve. The headline changes:
Cheaper ingestion. A new combined node + edge extraction path lets a single LLM call cover what previously took two, and node/edge extraction can now batch multiple episodes into one prompt. Timestamp resolution (valid_at / invalid_at) has also been split into its own step so it doesn't compete with structural fact extraction.
Search pipeline rework. A large internal restructure of graphiti_core/search/search.py lays the groundwork for upcoming search and reranker changes — no public API changes, but tracing coverage is much improved.
New saga abstraction. A summarize_saga(saga_id) API on Graphiti, backed by SagaNode and a refreshed prompt, gives a first-class way to roll up multi-episode narratives.
Quality-of-life. A fact_triple episode type, episode_metadata for filtering, safer attribute merging that no longer clobbers first-class fields, and a podcast example that runs against an embedded FalkorDB with no external DB.
How this affects developers
Defaults are unchanged. Combined extraction is opt-in via use_combined_extraction=True on extract_nodes_and_edges_bulk. Existing ingestion code keeps working as-is.
Episode indices are now 0-based. If you parse [Episode N] headers or rely on episode_indices from extraction results, update your offsets accordingly.
Kuzu users — schema migration required. RelatesToNode_ now expects a reference_time TIMESTAMP column. New databases get it automatically; existing stores need a one-time ALTER TABLE RelatesToNode_ ADD reference_time TIMESTAMP.
Custom attributes are now safer to set. Attribute dicts on nodes/edges no longer overwrite first-class fields (uuid, group_id, created_at, timestamps). If you were depending on that overwrite behavior, you'll need to set those fields directly.
New public surface to know about: Graphiti.summarize_saga(saga_id), the fact_triple episode type, and EpisodicNode.episode_metadata for custom filtering keys.
Highlights
Efficiency: fewer, smarter LLM calls during ingestion
Combined node + edge extraction (feature-flagged). A single LLM call can now produce both nodes and edges for an episode. Pass use_combined_extraction=True to extract_nodes_and_edges_bulk to opt in; default behavior is unchanged. Backed by a new prompts/extract_nodes_and_edges.py and utils/maintenance/combined_extraction.py.
Multi-episode batched extraction. _extract_and_resolve_nodes and extract_edges now accept a list of episodes, build a shared prompt with [Episode N] headers (new concatenate_episodes helper), and attach episode_indices to each extracted node/edge so callers can map results back to their source episode.
Decoupled timestamp resolution. New extract_timestamps / extract_timestamps_batch prompts let valid_at / invalid_at be resolved in a dedicated post-extraction step, so structural fact extraction is no longer entangled with date parsing.
Architecture
Search pipeline rework. Major restructure of graphiti_core/search/search.py (~1k lines changed) and new tracing test coverage, paving the way for upcoming search/reranker changes.
Sagas. New summarize_saga(saga_id) API on Graphiti, plus a refreshed summarize_sagas prompt and supporting helpers (saga_get_previous_episode_uuid, saga_get_episode_contents).
fact_triple episode type and an episode_metadata dict on EpisodicNode for customer-defined filtering keys.
Safer attribute merging on edges and nodes — first-class fields (uuid, group_id, created_at, timestamps) are no longer overwritten when an attribute dict happens to contain a matching key.
reference_time preserved through bulk edge save, and added as a column on the Kuzu RelatesToNode schema. Existing Kuzu users may need a one-time ALTER TABLE RelatesToNode ADD reference_time TIMESTAMP.
Prompt refinements
Dedup (nodes & edges): tightened scope, looser two-entity rule in the combined extraction path.
Fact extraction: detail-preservation rule, broader entity capture for qualified objects.
Refreshed summarize_sagas prompt.
Examples / DX
examples/podcast/podcast_runner.py now runs against an embedded FalkorDB (falkordblite) with no external database, and exercises edge + node hybrid search post-ingest.
Notable internal changes
Driver tweaks in graph_operations.py and record_parsers.py.
Episode indexing is now 0-based (was 1-based in the first iteration of multi-episode extraction).
pytest bumped to 9.0.3 in server/ and mcp_server/.
Lockfile and dependency refreshes (uv group, voyageai, groq, google-genai, uvicorn, pyright, pytest-asyncio).
Coming next
The next release will continue this architectural track — expect the combined extraction path to graduate toward the default ingestion mode, additional batching across edge resolution and dedup, and follow-on search-pipeline changes building on the rework that landed here.