> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs-beta.getzep.com/v4/facts/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs-beta.getzep.com/_mcp/server. # Facts > Facts are precise, time-stamped relationships on a Context Graph. Bi-temporal valid_at/invalid_at timestamps let Zep track change and answer point-in-time queries. ## Overview Facts are time-stamped claims stored on edges that capture relationships about specific events. The `valid_at` and `invalid_at` fields define the temporal bounds that Zep has derived for a fact. Applications can use these fields for history and point-in-time retrieval. The fields do not establish that the source content or the derived fact is true. ## How Zep updates facts When incorporating new data, Zep looks for existing nodes and edges in the graph and decides whether to add new nodes/edges or to update existing ones. An update could mean updating an edge (for example, indicating the previous fact is no longer valid). Here's an example of how Zep might extract graph data from a chat message, and then update the graph once new information is available: ![graphiti intro slides](/_fern-files/zep-preview.docs.buildwithfern.com/204428cea99ae5c2c2055235e6cab2c0b5bc5aad3d7fdfbb1e3792cf4cd9e8fb/images/graphiti-graph-intro.gif) As shown in the example above, when Kendra initially loves Adidas shoes but later is angry that the shoes broke and states a preference for Puma shoes, Zep attempts to invalidate the fact that Kendra loves Adidas shoes and creates two new facts: "Kendra's Adidas shoes broke" and "Kendra likes Puma shoes". Zep also looks for dates in all ingested data, such as the timestamp on a chat message or an article's publication date, informing how Zep sets the edge attributes. This gives an agent temporal context for its task. ## The four fact timestamps Each fact stored on an edge includes four different timestamp attributes that track the lifecycle of that information: | Edge attribute | Example | | :-------------- | :---------------------------------------------- | | **created\_at** | The time Zep learned that the user got married | | **valid\_at** | The time the user got married | | **invalid\_at** | The time the user got divorced | | **expired\_at** | The time Zep learned that the user got divorced | The `valid_at` and `invalid_at` attributes for each fact are included in Zep's Context Block. Follow [Memory security best practices](/memory-security) when you send the block to your model: ```text # format: FACT (Date range: from - to) User account Emily0e62 has a suspended status due to payment failure. (2024-11-14 02:03:58+00:00 - present) ``` ## Edge names In addition to the fact body and timestamps, each edge has a **name** that identifies the relationship type. Edge names are SCREAMING\_SNAKE\_CASE labels like `WORKS_AT`, `LIVES_IN`, `OWNS`, or `PURCHASED`. Zep generates a name for each edge it extracts from your data. If you use Zep's [custom ontology feature](/customizing-graph-structure) to define custom edge types, the custom edge type is expressed through the edge name: when Zep classifies an edge as one of your custom types, the edge's `name` is set to the type key you registered. For example, if you register an edge type with key `RESTAURANT_VISIT`, every edge classified as that type will have `name = "RESTAURANT_VISIT"`. This is how you can tell — given an edge — whether it was matched to a custom type and which one. ## Adding or deleting facts Facts are generated as part of the ingestion process. If you follow the directions for [adding data to the graph](/adding-business-data), new facts will be created. Delete a fact by [deleting its edge](/deleting-data-from-the-graph). ## Retrieving facts Facts live on edges, so the SDK exposes them under `graph.edge`. List the edges of a graph, fetch an edge by UUID, or search a graph for facts. Each call takes the UUID of a graph. For a user graph, use the `graph_uuid` that `user.create` returns. Store this UUID in your application database next to your own user ID. ### List and fetch **`Python`** ```python Python from zep_cloud.client import Zep client = Zep(api_key=API_KEY) # The graph_uuid of the user, from your application database. graph_uuid = zep_graph_uuid # List the edges (facts) on a user's graph. # The pager fetches the next page when you iterate. edges = client.graph.edge.list(graph_uuid, limit=20) for edge in edges: print(f"[{edge.name}] {edge.fact}") # Fetch a single item by UUID. item = client.graph.edge.get(graph_uuid, edge_uuid) ``` **`TypeScript`** ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY }); // The graph UUID of the user, from your application database. const graphUuid = zepGraphUuid; // List the edges (facts) on a user's graph. // The pager fetches the next page when you iterate. const edges = await client.graph.edge.list(graphUuid, { limit: 20, body: {} }); for await (const edge of edges) { console.log(`[${edge.name}] ${edge.fact}`); } // Fetch a single item by UUID. const item = await client.graph.edge.get(graphUuid, edgeUuid); ``` **`Go`** ```go Go import ( "context" "fmt" zep "github.com/getzep/zep-go/v4" zepclient "github.com/getzep/zep-go/v4/client" "github.com/getzep/zep-go/v4/graph" "github.com/getzep/zep-go/v4/option" ) client := zepclient.NewClient(option.WithAPIKey(API_KEY)) // The graph UUID of the user, from your application database. graphUUID := zepGraphUUID // List the edges (facts) on a user's graph. // The iterator fetches the next page when it reaches the end of a page. edges, err := client.Graph.Edge.List( context.TODO(), graphUUID, &graph.EdgeListRequest{Limit: zep.Int(20)}, ) if err != nil { // handle error } iter := edges.Iterator() for iter.Next(context.TODO()) { edge := iter.Current() fmt.Printf("[%s] %s\n", *edge.Name, *edge.Fact) } if err := iter.Err(); err != nil { // handle error } // Fetch a single item by UUID. item, err := client.Graph.Edge.Get(context.TODO(), graphUUID, edgeUUID) ``` List methods use cursor pagination. The SDK pager fetches the next page when you iterate. Set `limit` to control the page size. For a graph that you create with `graph.create`, pass the `uuid` that `graph.create` returns. ### Search Facts are the default search target for [graph search](/searching-the-graph). Use `graph.search_edges` to return the facts most relevant to your query. The call returns one page of results: **`Python`** ```python Python results = client.graph.search_edges( graph_uuid, query="payment failures", limit=5, ) for edge in results.items or []: print(edge.name, edge.fact, edge.score) ``` **`TypeScript`** ```typescript TypeScript const results = await client.graph.searchEdges(graphUuid, { limit: 5, body: { query: "payment failures" }, }); for (const edge of results.data) { console.log(edge.name, edge.fact, edge.score); } ``` **`Go`** ```go Go results, err := client.Graph.SearchEdges(context.TODO(), graphUUID, &zep.GraphSearchEdgesRequest{ Limit: zep.Int(5), Body: &zep.SearchRequest{Query: "payment failures"}, }) if err != nil { // handle error } for _, edge := range results.Results { fmt.Println(*edge.Name, *edge.Fact, *edge.Score) } ``` ## Related context types Facts are one of several types of context Zep produces from a user's graph. Each fact lives on an edge between two [entities](/entities) and is extracted from one or more [episodes](/episodes). For durable, cross-entity patterns derived from many facts, see [observations](/observations). > Precise, time-stamped information capturing detailed relationships about specific events