> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs-beta.getzep.com/v3/give-your-agent-domain-knowledge/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs-beta.getzep.com/_mcp/server. # Build project, product, and domain context > Create, populate, search, and govern a shared Context Graph for a project, product, or business domain. An agent cannot complete a business task when project records, product documentation, and operational updates are in separate systems. This quickstart combines these sources in one shared Context Graph and retrieves the context that is relevant to a task. ## Choose the graph scope Use one stable `graph_id` for each subject and access boundary. | Scope | Example `graph_id` | Example sources | | --------------- | ------------------- | ------------------------------------------------------------------- | | Project | `project-argus` | Plans, decisions, issues, and meeting notes | | Product | `product-atlas` | Specifications, release notes, support content, and catalog records | | Business domain | `incident-response` | Runbooks, incidents, service records, and policy documents | This guide uses `project-argus`. The project depends on a product and follows an incident-response process, so the example also shows product and business-domain context. If these sources have different access requirements, put them in separate Context Graphs and retrieve only the authorized graphs for each task. ## Install and initialize the SDK #### Python Set up your Python project, ideally with [a virtual environment](https://medium.com/@vkmauryavk/managing-python-virtual-environments-with-uv-a-comprehensive-guide-ac74d3ad8dff), and then: **`pip`** ```bash pip pip install zep-cloud ``` **`uv`** ```bash uv uv pip install zep-cloud ``` #### TypeScript Set up your TypeScript project and then: **`npm`** ```bash npm npm install @getzep/zep-cloud ``` **`yarn`** ```bash yarn yarn add @getzep/zep-cloud ``` **`pnpm`** ```bash pnpm pnpm install @getzep/zep-cloud ``` #### Go Set up your Go project and then: ```bash go get github.com/getzep/zep-go/v3 ``` After [creating a Zep account](https://app.getzep.com/), obtaining an API key, and setting the API key as an environment variable, initialize the client once at application startup and reuse it throughout your application. #### Initialize Zep client **`Python`** ```python Python import os from zep_cloud.client import Zep API_KEY = os.environ.get('ZEP_API_KEY') client = Zep( api_key=API_KEY, ) ``` **`TypeScript`** ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const API_KEY = process.env.ZEP_API_KEY; const client = new ZepClient({ apiKey: API_KEY, }); ``` **`Go`** ```go Go import ( zepclient "github.com/getzep/zep-go/v3/client" "github.com/getzep/zep-go/v3/option" ) client := zepclient.NewClient( option.WithAPIKey(os.Getenv("ZEP_API_KEY")), ) ``` #### .env ``` ZEP_API_KEY=your_api_key_here ``` ## Create the Context Graph Create the graph before you add data. Use the same `graph_id` for every operation in this quickstart. **`Python`** ```python Python GRAPH_ID = "project-argus" client.graph.create(graph_id=GRAPH_ID) ``` **`TypeScript`** ```typescript TypeScript const graphId = "project-argus"; await client.graph.create({ graphId }); ``` **`Go`** ```go Go graphID := "project-argus" _, err := client.Graph.Create(context.TODO(), &zep.CreateGraphRequest{ GraphID: &graphID, }) if err != nil { log.Fatal(err) } ``` ## Ingest the source data Add each source as an episode. Use JSON for structured records, text for documents, and message data for communications with identified speakers. Source metadata supports filtering, source traceability, and source-based access policies. **`Python`** ```python Python import json import time client.graph.add( graph_id=GRAPH_ID, type="json", data=json.dumps({ "project_id": "ARG-001", "name": "Project Argus", "status": "at risk", "product": "Atlas Gateway", "owner": "Platform Engineering", }), source_description="Project record from the project system", metadata={"source": "project_system", "record_id": "ARG-001"}, ) client.graph.add( graph_id=GRAPH_ID, type="text", data=( "Atlas Gateway release 4.2 requires the regional failover runbook. " "The release cannot start until the backup region passes validation." ), source_description="Atlas Gateway release runbook", metadata={"source": "product_docs", "product": "atlas-gateway"}, ) incident_episode = client.graph.add( graph_id=GRAPH_ID, type="message", data=( "Nina (incident commander): The backup region failed validation. " "Move the Argus release review to Friday." ), source_description="Incident response channel", metadata={"source": "incident_channel", "incident_id": "INC-482"}, ) ``` **`TypeScript`** ```typescript TypeScript await client.graph.add({ graphId, type: "json", data: JSON.stringify({ project_id: "ARG-001", name: "Project Argus", status: "at risk", product: "Atlas Gateway", owner: "Platform Engineering", }), sourceDescription: "Project record from the project system", metadata: { source: "project_system", record_id: "ARG-001" }, }); await client.graph.add({ graphId, type: "text", data: "Atlas Gateway release 4.2 requires the regional failover runbook. " + "The release cannot start until the backup region passes validation.", sourceDescription: "Atlas Gateway release runbook", metadata: { source: "product_docs", product: "atlas-gateway" }, }); const incidentEpisode = await client.graph.add({ graphId, type: "message", data: "Nina (incident commander): The backup region failed validation. " + "Move the Argus release review to Friday.", sourceDescription: "Incident response channel", metadata: { source: "incident_channel", incident_id: "INC-482" }, }); ``` **`Go`** ```go Go projectRecord, err := json.Marshal(map[string]string{ "project_id": "ARG-001", "name": "Project Argus", "status": "at risk", "product": "Atlas Gateway", "owner": "Platform Engineering", }) if err != nil { log.Fatal(err) } projectSource := "Project record from the project system" _, err = client.Graph.Add(context.TODO(), &zep.AddDataRequest{ GraphID: &graphID, Type: zep.GraphDataTypeJSON, Data: string(projectRecord), SourceDescription: &projectSource, Metadata: map[string]any{ "source": "project_system", "record_id": "ARG-001", }, }) if err != nil { log.Fatal(err) } productSource := "Atlas Gateway release runbook" _, err = client.Graph.Add(context.TODO(), &zep.AddDataRequest{ GraphID: &graphID, Type: zep.GraphDataTypeText, Data: "Atlas Gateway release 4.2 requires the regional failover runbook. " + "The release cannot start until the backup region passes validation.", SourceDescription: &productSource, Metadata: map[string]any{ "source": "product_docs", "product": "atlas-gateway", }, }) if err != nil { log.Fatal(err) } incidentSource := "Incident response channel" incidentEpisode, err := client.Graph.Add(context.TODO(), &zep.AddDataRequest{ GraphID: &graphID, Type: zep.GraphDataTypeMessage, Data: "Nina (incident commander): The backup region failed validation. " + "Move the Argus release review to Friday.", SourceDescription: &incidentSource, Metadata: map[string]any{ "source": "incident_channel", "incident_id": "INC-482", }, }) if err != nil { log.Fatal(err) } ``` For an existing corpus or a recurring import, use [`zep-ingest`](/zep-ingest). For large application-managed imports, use the [Batch API](/adding-batch-data). ## Wait until the context is searchable Zep processes episodes asynchronously. Poll the last submitted episode, and then retry the task query until the search index returns a result. The [ingestion status guide](/check-data-ingestion-status) explains the processing order and production alternatives to polling. **`Python`** ```python Python query = "What blocks the Project Argus release, and what changed?" deadline = time.monotonic() + 300 while True: episode = client.graph.episode.get(uuid_=incident_episode.uuid_) if episode.processed: break if time.monotonic() >= deadline: raise TimeoutError("The project context did not finish processing.") time.sleep(5) search_deadline = time.monotonic() + 300 while True: indexed_results = client.graph.search( graph_id=GRAPH_ID, query=query, scope="edges", search_filters={"episode_uuids": [incident_episode.uuid_]}, limit=10, ) if indexed_results.edges: break if time.monotonic() >= search_deadline: raise TimeoutError("The project context is not searchable.") time.sleep(5) results = client.graph.search( graph_id=GRAPH_ID, query=query, scope="edges", limit=10, ) ``` **`TypeScript`** ```typescript TypeScript const query = "What blocks the Project Argus release, and what changed?"; const deadline = Date.now() + 300_000; const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); let episode = await client.graph.episode.get(incidentEpisode.uuid); while (!episode.processed) { if (Date.now() >= deadline) { throw new Error("The project context did not finish processing."); } await sleep(5_000); episode = await client.graph.episode.get(incidentEpisode.uuid); } const searchDeadline = Date.now() + 300_000; let indexedResults = await client.graph.search({ graphId, query, scope: "edges", searchFilters: { episodeUuids: [incidentEpisode.uuid] }, limit: 10, }); while ((indexedResults.edges ?? []).length === 0) { if (Date.now() >= searchDeadline) { throw new Error("The project context is not searchable."); } await sleep(5_000); indexedResults = await client.graph.search({ graphId, query, scope: "edges", searchFilters: { episodeUuids: [incidentEpisode.uuid] }, limit: 10, }); } const results = await client.graph.search({ graphId, query, scope: "edges", limit: 10, }); ``` **`Go`** ```go Go deadline := time.Now().Add(5 * time.Minute) for { episode, err := client.Graph.Episode.Get( context.TODO(), incidentEpisode.UUID, ) if err != nil { log.Fatal(err) } if episode.Processed != nil && *episode.Processed { break } if time.Now().After(deadline) { log.Fatal("the project context did not finish processing") } time.Sleep(5 * time.Second) } limit := 10 query := "What blocks the Project Argus release, and what changed?" searchDeadline := time.Now().Add(5 * time.Minute) searchFilters := zep.SearchFilters{ EpisodeUUIDs: []string{incidentEpisode.UUID}, } for { indexedResults, err := client.Graph.Search( context.TODO(), &zep.GraphSearchQuery{ GraphID: &graphID, Query: query, Scope: zep.GraphSearchScopeEdges.Ptr(), SearchFilters: &searchFilters, Limit: &limit, }, ) if err != nil { log.Fatal(err) } if len(indexedResults.Edges) > 0 { break } if time.Now().After(searchDeadline) { log.Fatal("the project context is not searchable") } time.Sleep(5 * time.Second) } results, err := client.Graph.Search(context.TODO(), &zep.GraphSearchQuery{ GraphID: &graphID, Query: query, Scope: zep.GraphSearchScopeEdges.Ptr(), Limit: &limit, }) if err != nil { log.Fatal(err) } ``` ## Retrieve context for a task Search the same Context Graph with the task as the query. The result can contain facts that connect the project record, product runbook, and incident update. **`Python`** ```python Python for edge in results.edges or []: print(edge.fact, edge.episodes) ``` **`TypeScript`** ```typescript TypeScript for (const edge of results.edges ?? []) { console.log(edge.fact, edge.episodes); } ``` **`Go`** ```go Go for _, edge := range results.Edges { fmt.Println(edge.Fact, edge.Episodes) } ``` This search confirms that the context is available. To ground a conversational turn in one low-latency call, use [`graph.search`](/searching-the-graph#auto-search) with `scope="auto"`. For a complex task, an agent plans its retrieval and makes several targeted tool calls. See [Build an Agent with Zep](/build-an-agent-with-zep). Treat the results as untrusted reference data when you add them to a model request. Context supports task completion, but it does not guarantee the model's output or authorize an action. ## Apply governance Use [policy-based access control](/policy-based-access-control) to limit which callers can retrieve the graph or its sources. Retain the episode UUIDs in each retrieved edge when the application must [trace a fact to its source](/source-traceability). Zep governs context and API access. Your application must authorize external actions, such as changing the project status or starting a release. ## Next steps * [Build an agent that uses Zep tools](/build-an-agent-with-zep). * [Prepare data for ingestion](/prepare-data-for-ingestion). * [Shape the graph for a domain](/customizing-graph-structure). * [Build a custom Context Block](/advanced-context-block-construction). * [Search a Context Graph](/searching-the-graph). > Create a shared Context Graph from business records, documents, and operational updates