Building with Zep
This skill is the decision-and-workflow layer for building on Zep: how to
reason about Zep, scope graphs, ingest data, retrieve context, and evaluate
whether Zep delivers your use case. It is not an API reference or a full
best-practices manual — for exact, current details (method names, parameters,
limits, plan availability) and the complete best practices for any given
feature, query the zep-docs MCP server first — preferring to load the
whole relevant page (see
Documentation index for how to read pages vs. search). If
it is unavailable, use help.getzep.com and the
SDK/API reference. If this skill and the
live docs ever disagree, the live docs win (see Source authority).
Work backward from the end use case and the business value it must deliver.
Success is whether the agent receives complete context and produces
accurate answers for that use case — not whether the graph is perfect or the
ingested data is perfect.
Guidance here targets Zep V3 (SDK packages zep-cloud for
Python/TypeScript, github.com/getzep/zep-go/v3 for Go). Ignore the legacy V2
Memory API. Zep is a paid product; some features are plan-gated — confirm
availability in the docs.
Conceptual overview
Zep builds temporal Context Graphs. You control the data that goes in and
the context retrieved out. A graph is a substrate that fuses many data
sources — conversations, emails, Slack, documents, transcripts, user
interactions, business data — into one time-aware picture, and Zep supports
many graphs with governance for enterprise scale (many graphs, sources,
agents, and humans, with security and control over creation, usage, and
retrieval).
The mental model: Zep is not a chat-log store and not a vector database. It
extracts structured, time-aware knowledge from whatever you feed it, fuses it
into the graph, and returns the slice that matters for the current moment. That
sets it apart from the tools you might otherwise reach for:
- vs. a store per data type — chat, documents, JSON, and business events all
fuse into one graph per subject; you don't stand up and stitch together a
separate store for each source.
- vs. plain vector search — retrieval is hybrid (semantic + keyword +
graph traversal, then reranked), not similarity alone, so it captures exact
terms and relationships, not just conceptual matches.
- vs. static GraphRAG — Zep is built for change: it ingests streaming,
frequently-updated data incrementally and time-stamps every fact (see the
bitemporal model below), whereas GraphRAG targets one-time summarization of
static documents. Reach for Zep when knowledge evolves.
Two kinds of graph. A user graph is a specialization of a standalone graph:
anything a standalone graph can do, a user graph can do too. Only some features
are user-graph-only — flagged (user graphs only) below; everything else
applies to every graph.
- Standalone graph — the base graph type (
graph_id), for shared or domain
knowledge (knowledge bases, product/runbook data). See
Graph overview.
- User graph — a standalone graph specialized for a user: auto-created
per user, the home of agent memory (an agent remembering prior conversations
with that user). Adds user-only features — a user node, a user
summary, and threads — and fuses all of that user's threads and business
data. See Users and user graphs.
An integration with Zep can use one or both kinds of graph. The developer
integrating Zep decides which graphs exist and what data feeds each. Access to
graphs is determined in the application layer: at retrieval time the
application decides which graph(s) a given request reads from — for example,
granting a user access to their own user graph and a companywide standalone
graph. See Architecture patterns.
How an episode is processed. Each ingested artifact (an "episode") is
processed asynchronously: Zep extracts the entities mentioned, extracts the
facts/relationships between them, deduplicates the new entities and
facts against what is already in the graph, and invalidates any facts the
new data supersedes (e.g. a changed preference — the old fact is marked invalid
but kept as history).
Bitemporal model. Facts carry validity timestamps (valid/invalid/created/
expired), so you can ask what is true now or what was true at a past date.
Context types (what ingestion creates, what retrieval returns): episodes, entities, facts, thread
summaries, the user summary, and observations. Each captures a different value;
auto search finds the most relevant artifacts across all of them. A useful
contrast: entity/node summaries give depth (a narrative rolling up one
entity's history) while facts give breadth (granular, individually-dated
claims) — good retrieval draws on both. See
Context types.
Architectural philosophy and invariants
- Test end to end for your use case. Zep's many choices (scoping, ontology,
retrieval) rarely have one "correct" setting; what matters is whether
the whole pipeline delivers complete context and accurate answers for
your use case, not whether any single part looks right in isolation. Tune and
validate against an end-to-end evaluation, not a "perfect" graph — several
trade-offs below (under-merging, recall over precision) only make sense through
this lens. See Evaluating Zep.
- Zep vs. your application. Zep manages the graph (extraction, dedup,
retrieval). The application controls what data is sent, which graphs
are retrieved from, and how the agent uses the context Zep returns
(prompt, model, logic). Retrieving from one vs. many graphs is an
application-layer decision.
- Zep does not infer beyond the data provided; it is only as good as the data
it receives. If context was never sent to Zep, Zep cannot surface it — a
possible cause of "missing" context is that it was never ingested.
- Deduplication philosophy — prefer under- to over-merging. Wrongly merging
two distinct entities is worse than failing to merge two that are the same,
because unmerged duplicates are both still retrievable, so the agent still
gets complete context. This is a concrete reason not to chase a "perfect"
graph — what matters is complete retrieval when you test end to end for
your use case.
- Dedup needs context. Threads automatically use prior messages as
extraction context;
graph.add does not. Episodes with pronouns or bare
first names (e.g. multiple "John"s with no last name) deduplicate poorly —
pre-process ambiguous data with stable identifiers (full names, IDs).
- Retrieval philosophy — favor recall over precision. Retrieve broadly and
let the downstream LLM ignore what is irrelevant; missing relevant context is
worse than including some extra. See Retrieval philosophy.
- Ingestion is asynchronous. Added data is processed before it becomes
retrievable (seconds or more). Design for eventual availability rather than
reading back immediately; check status when it matters via
Check ingestion status.
Submit all episodes without polling between adds — for
thread.add_messages, graph.add, batch, or zep-ingest alike — and
poll only once, on the last episode, when you need retrievability.
Expected wait time scales with total episode count in that graph.
Implementation: scope → ingest → retrieve
Implementing Zep has four steps — scope → ingest → retrieve → evaluate.
Evaluation has its own section below; the choices for the first three follow.
These are cross-cutting decisions; confirm exact signatures and limits in the
docs (see the index) rather than guessing.
1. Scope your graphs and data sources
- Choose user graphs (per-user memory) vs. standalone graphs (shared or
domain knowledge). Use separate graphs wherever you need hard data
separation — per user, per team, per tenant.
- Decide which data sources feed which graphs. One graph can hold many sources;
you can also have many graphs.
- Zep threads apply only to user graphs. A Zep thread represents a
conversation between the user and the agent; it records that conversation
history and ingests it into the user graph. Note the available episode/data
types (message, text, JSON). Standalone graphs have no first-class thread
support, but can still ingest arbitrary text — e.g. Slack or email — via
graph.add, or via zep-ingest when
those sources are already on disk (as text/JSON/episodes, not as a Zep
thread).
2. Ingest data into graphs
Choose an ingestion path by how the data arrives (see
Adding context):
| What you are adding |
Use |
| A message in a live conversation, as your agent sends and receives it |
thread.add_messages in the Zep SDK |
| Historical data on disk you are loading for the first time: documents, transcripts, email, Slack exports, or past conversations |
zep-ingest |
| A recurring export that lands files on disk (hourly or nightly dump, ETL output) |
zep-ingest |
| An individual document, API response, or webhook payload your application already holds in memory |
graph.add |
zep-ingest is a Python package for building ingestion pipelines: it
prepares and loads existing on-disk data into Zep in a defined order
(canonicalize identities and timestamps, validate, submit, monitor). Prefer it
for backfills and recurring folder/glob imports. It is a convenience layer over
the Zep SDK — calling graph.add or the
Batch API directly remains fully
supported. Do not use it for live chat turns (thread.add_messages) or for
typical in-memory / webhook payloads (graph.add is simpler). For loaders,
transforms, preview, submission, and monitoring details, read
Create an ingestion pipeline — do not
invent package APIs from memory.
Prepare the data. Anytime you design an ingestion pipeline (SDK or
zep-ingest), read
Prepare data for ingestion
and follow those best practices (entity identity, source context, event time,
and related guidance). Also attach
episode metadata
(such as source) at ingest when you need episode-metadata filtering on
search; chunk oversized documents per
Chunking.
Seed vs. stream. Decide between backfilling initial/historical data
(zep-ingest, or batch ingestion
for large volumes) and live/streaming updates (thread.add_messages /
graph.add).
Multi-graph backfills — enqueue everything, then wait once. Graphs do
not share a processing queue; one graph finishing extraction is not a
prerequisite for another to accept data. For a backfill into multiple graphs
(user and/or standalone), create all destinations and configure
ontology/instructions first — ontology is not retroactive — then submit all
episodes to every graph without waiting on another graph's processed status.
Use the Batch API or zep-ingest
with method="auto" or "batch". Waiting for graph A to finish before even
sending to graph B is a common backfill anti-pattern. After all submits are
queued, wait or poll once (in parallel per graph if you like) until the facts
you need are searchable — only when you are about to search or demo, not after
every file or graph. Within a single graph, enqueue all sources together too;
do not finish one source before submitting the next unless you have a real
dependency (e.g. seed nodes/triples before episodes that must pin to those
UUIDs).
Customize extraction (iterate, don't front-load). Rule of thumb:
ontology defines the shape of the graph (which entity/edge types exist);
instructions define how to interpret your domain — don't conflate them.
- Custom ontology —
your entity/edge types. Model entity types as nouns and edge types as
verbs/relationships, and start with a few generic types rather than
modeling everything up front (custom attributes are advanced and often
unnecessary). Sharpens extraction and enables type-filtered retrieval.
- Custom instructions —
describe your domain (terminology, concepts) so Zep interprets data better
on ingest. Not for defining types — that is the ontology's job.
- User summary instructions
(user graphs only) — steer what the always-on user summary captures.
3. Provide retrieval to agents
- Choose the context surface:
- Default Context Block (user graphs only) —
thread.get_user_context;
returns whole-user-graph context, relevance driven by the most recent thread
messages. Best for most conversational agents.
- Context templates (user graphs only) — automatic relevance, your fixed
layout/sections. See Context templates.
- Advanced/manual construction — run searches and assemble the string
yourself; the only context surface for standalone graphs, and used for
custom blocks on any graph. See
Advanced construction.
- Search with
graph.search: scope="auto" (recommended entry point for
standalone/non-thread queries, spans all context types) or a specific scope
(edges, nodes, episodes, observations, thread_summaries) with rerankers and
filters (metadata, timestamp, entity/edge type, property). See
Searching the graph.
- Decide how the agent retrieves: expose search as a tool call (LLM
decides when) vs. deterministic/programmatic retrieval on every turn.
- Decide how many graphs to read (one versus many, using parallel graph
searches) — an application-layer decision. See
Architecture patterns.
Evaluating Zep
- Anchor to the end business task and evaluate end-to-end, not each part
in isolation. See Evaluate Zep for your use case.
- Two distinct measures:
- Context completeness — did Zep provide the context needed? (Zep's job.)
- Answer accuracy — did your agent use that context to produce the correct
result? (Your LLM/prompt's job, assuming context is complete.)
- Diagnose with them:
- Completeness high, accuracy low → fix the agent (prompt, model,
logic), not Zep.
- Completeness low → accuracy will be low too. Localize the failure: is it
ingestion or retrieval? First check whether the needed information is in the
graph at all — read/export the graph
(edges, entities, observations) and inspect the episodes (the raw data
that was sent).
- Not in the episodes → the data was never sent to Zep; fix what your
application ingests. Not a Zep problem.
- In the episodes but not in derived artifacts → tune ingestion (custom
instructions, ontology, pre-processing the data).
- In the derived artifacts but not in the retrieved context → tune
retrieval (search scope, rerankers, filters, context assembly).
- This is why under-deduplication is acceptable (see philosophy above): an
imperfect graph can still yield complete retrieval, which is what the
end-to-end evaluation actually measures.
- Zep provides an evaluation harness to help measure context completeness
and answer accuracy — but you supply a gold dataset: the kinds of
questions you want your agent to answer, paired with the correct answers.
See the full guidance in
Evaluate Zep for your use case.
Documentation index
The zep-docs MCP server is the source for exact, current details and best
practices — query it before relying on memory, and refer to the
documentation before implementing any feature. The pages below are curated
entry points ("read X to do Y"), grouped into foundational concepts, pages that
apply to all graphs, and the smaller sets that are user-graph-only or
standalone-graph-only.
How to retrieve — read a page (preferred), or search. Prefer loading a whole
page over searching. The server exposes two mechanisms:
- Read a whole page (preferred). Load a full doc page in one shot as an MCP
resource —
zep-docs://<slug>, where <slug> is the page's
help.getzep.com path (everything after the domain, no leading slash). E.g.
https://help.getzep.com/searching-the-graph →
zep-docs://searching-the-graph; nested paths keep their slashes. Every page
linked below is reachable at its zep-docs://<slug> resource by this rule;
discover the full list with your client's resource-listing capability (both
Claude Code and Codex expose MCP resources — Codex via list_mcp_resources /
read_mcp_resource). Prefer this whenever you implement, verify, or debug a
specific feature — you get the complete, current page, not fragments — and it
needs only the MCP connection, so it works even when the agent has no general
web access.
- Fallbacks if the client can't read MCP resources or a resource errors:
fetch the identical markdown at
https://help.getzep.com/<slug>.md (the
resource is just a cached proxy to that file), or the rendered page at
https://help.getzep.com/<slug>. Both require web access to
help.getzep.com.
- Search the docs (discovery). Use the
search_documentation tool
(served by zep-docs; params: query, and optional max_results, 1–10,
default 5) when you don't know where something is documented, whether it exists
at all, or you want a broad look. It returns reranked text chunks with no
page URLs, so use it to find what to read, then load that page in full via
its zep-docs://<slug> resource.
Foundational concepts
All graphs
User graphs only
Standalone graphs only
Reference and governance
- SDK / API reference: https://help.getzep.com/sdk-reference — confirm exact
signatures, parameters, and limits here or via the
zep-docs MCP.
- Docs MCP server setup: https://help.getzep.com/docs-mcp-server.
- Governance (enterprise):
- Security & compliance — the hub
for Zep's security posture: SOC 2 Type II, HIPAA BAAs, access controls,
audit/API logging, and BYOK/BYOC deployment options.
- RBAC — role-based access
control. Governs human teammates' access to the Zep dashboard via account-
and project-scoped roles, so each person gets the right level of access.
- ABAC — attribute-based
access control. Scopes an individual API key to a subset of a project's
actions and data (by action, and by data class via ingestion metadata) to
enforce least privilege — useful when each agent authenticates with its own key.
- BYOK — bring your own key. Encrypt
data at rest with your own AWS KMS key, keeping full control including revocation.
Source authority and validation
- Query the
zep-docs MCP server first for anything that must be exact or
current — method names, parameters, limits, plan availability, newer features.
Prefer loading the whole relevant page via its zep-docs://<slug> resource;
use the search_documentation tool to find the right page or check whether
something exists (see Documentation index for both). It
covers the guides and the SDK/API reference.
- Fallback if resources or the MCP are unavailable: fetch the page markdown at
https://help.getzep.com/<slug>.md, else the guides at https://help.getzep.com
and the SDK/API reference at https://help.getzep.com/sdk-reference.
- The live docs win on conflict. Treat this skill's summaries as stale if
they disagree with current, version-matched documentation. Verify
version-sensitive code against the SDK reference and, when available, the
installed SDK's types/source.
- Validate behavior, not just plausibility. Don't stop at code that looks
right — confirm ingestion completed, retrieval returns the expected context,
and (per Evaluating Zep) the end use case actually improves.
1---2name: building-with-zep3description: Guide for building, designing, reviewing, evaluating, and troubleshooting applications that use Zep — agent memory built on temporal Context Graphs, for use cases needing low-latency retrieval, one or many users and agents, multi-source ingestion, and governance. Use whenever you write or design code that integrates Zep — adding memory or long-term context to an agent or chatbot, ingesting chat/business/document/JSON data into a Context Graph, retrieving a Context Block or searching the graph, choosing between user graphs and standalone graphs, scoping graphs, defining a custom ontology or custom instructions, or deciding how to evaluate and tune Zep for a use case. Triggers on requests like "add memory to my agent", "integrate Zep", "store this in Zep", "search the Zep graph", "set up a Zep ontology", "how should I structure my Zep graphs", "why is Zep not returning the right context", "help me evaluate Zep", or "make my agent remember users".4---56# Building with Zep78This skill is the **decision-and-workflow layer** for building on Zep: how to9reason about Zep, scope graphs, ingest data, retrieve context, and evaluate10whether Zep delivers your use case. It is **not** an API reference or a full11best-practices manual — for exact, current details (method names, parameters,12limits, plan availability) and the complete best practices for any given13feature, query the **`zep-docs` MCP server** first — preferring to load the14whole relevant page (see15[Documentation index](#documentation-index) for how to read pages vs. search). If16it is unavailable, use [help.getzep.com](https://help.getzep.com) and the17[SDK/API reference](https://help.getzep.com/sdk-reference). If this skill and the18live docs ever disagree, **the live docs win** (see [Source authority](#source-authority-and-validation)).1920Work backward from the **end use case and the business value** it must deliver.21Success is whether the agent receives **complete context** and produces22**accurate answers** for that use case — not whether the graph is perfect or the23ingested data is perfect.2425> Guidance here targets **Zep V3** (SDK packages `zep-cloud` for26> Python/TypeScript, `github.com/getzep/zep-go/v3` for Go). Ignore the legacy V227> `Memory` API. Zep is a paid product; some features are plan-gated — confirm28> availability in the docs.2930## Conceptual overview3132Zep builds **temporal Context Graphs**. *You* control the data that goes in and33the context retrieved out. A graph is a substrate that **fuses many data34sources** — conversations, emails, Slack, documents, transcripts, user35interactions, business data — into one time-aware picture, and Zep supports36**many graphs with governance** for enterprise scale (many graphs, sources,37agents, and humans, with security and control over creation, usage, and38retrieval).3940The mental model: **Zep is not a chat-log store and not a vector database.** It41extracts structured, time-aware knowledge from whatever you feed it, fuses it42into the graph, and returns the slice that matters for the current moment. That43sets it apart from the tools you might otherwise reach for:4445- **vs. a store per data type** — chat, documents, JSON, and business events all46 fuse into *one* graph per subject; you don't stand up and stitch together a47 separate store for each source.48- **vs. plain vector search** — retrieval is **hybrid** (semantic + keyword +49 graph traversal, then reranked), not similarity alone, so it captures exact50 terms and relationships, not just conceptual matches.51- **vs. static GraphRAG** — Zep is built for **change**: it ingests streaming,52 frequently-updated data incrementally and time-stamps every fact (see the53 bitemporal model below), whereas GraphRAG targets one-time summarization of54 static documents. Reach for Zep when knowledge evolves.5556Two kinds of graph. A **user graph is a specialization of a standalone graph**:57anything a standalone graph can do, a user graph can do too. Only some features58are **user-graph-only** — flagged **(user graphs only)** below; everything else59applies to every graph.6061- **Standalone graph** — the base graph type (`graph_id`), for shared or domain62 knowledge (knowledge bases, product/runbook data). See63 [Graph overview](https://help.getzep.com/graph-overview).64- **User graph** — a standalone graph **specialized for a user**: auto-created65 per user, the home of agent memory (an agent remembering prior conversations66 with that user). Adds user-only features — a **user node**, a **user67 summary**, and **threads** — and fuses all of that user's threads and business68 data. See [Users and user graphs](https://help.getzep.com/users-and-user-graphs).6970An integration with Zep can use **one or both** kinds of graph. The developer71integrating Zep decides which graphs exist and what data feeds each. Access to72graphs is determined in the **application layer**: at retrieval time the73application decides which graph(s) a given request reads from — for example,74granting a user access to their own user graph *and* a companywide standalone75graph. See [Architecture patterns](https://help.getzep.com/architecture-patterns).7677**How an episode is processed.** Each ingested artifact (an "episode") is78processed asynchronously: Zep extracts the **entities** mentioned, extracts the79**facts/relationships** between them, **deduplicates** the new entities and80facts against what is already in the graph, and **invalidates** any facts the81new data supersedes (e.g. a changed preference — the old fact is marked invalid82but kept as history).8384**Bitemporal model.** Facts carry validity timestamps (valid/invalid/created/85expired), so you can ask what is true *now* or what was true at a past date.8687**Context types** (what ingestion creates, what retrieval returns): episodes, entities, facts, thread88summaries, the user summary, and observations. Each captures a different value;89**auto** search finds the most relevant artifacts across all of them. A useful90contrast: **entity/node summaries** give *depth* (a narrative rolling up one91entity's history) while **facts** give *breadth* (granular, individually-dated92claims) — good retrieval draws on both. See93[Context types](https://help.getzep.com/context-types).9495## Architectural philosophy and invariants9697- **Test end to end for your use case.** Zep's many choices (scoping, ontology,98 retrieval) rarely have one "correct" setting; what matters is whether99 the whole pipeline delivers **complete context and accurate answers** for100 *your* use case, not whether any single part looks right in isolation. Tune and101 validate against an **end-to-end evaluation**, not a "perfect" graph — several102 trade-offs below (under-merging, recall over precision) only make sense through103 this lens. See [Evaluating Zep](#evaluating-zep).104- **Zep vs. your application.** Zep manages the graph (extraction, dedup,105 retrieval). The application controls **what data is sent**, **which graphs106 are retrieved from**, and **how the agent uses the context Zep returns**107 (prompt, model, logic). Retrieving from one vs. many graphs is an108 application-layer decision.109- **Zep does not infer beyond the data provided; it is only as good as the data110 it receives.** If context was never sent to Zep, Zep cannot surface it — a111 possible cause of "missing" context is that it was never ingested.112- **Deduplication philosophy — prefer under- to over-merging.** Wrongly merging113 two distinct entities is worse than failing to merge two that are the same,114 because unmerged duplicates are *both* still retrievable, so the agent still115 gets complete context. This is a concrete reason not to chase a "perfect"116 graph — what matters is complete retrieval when you **test end to end** for117 your use case.118- **Dedup needs context.** Threads automatically use prior messages as119 extraction context; `graph.add` does **not**. Episodes with pronouns or bare120 first names (e.g. multiple "John"s with no last name) deduplicate poorly —121 pre-process ambiguous data with stable identifiers (full names, IDs).122- **Retrieval philosophy — favor recall over precision.** Retrieve broadly and123 let the downstream LLM ignore what is irrelevant; missing relevant context is124 worse than including some extra. See [Retrieval philosophy](https://help.getzep.com/retrieval-philosophy).125- **Ingestion is asynchronous.** Added data is processed before it becomes126 retrievable (seconds or more). Design for eventual availability rather than127 reading back immediately; check status when it matters via128 [Check ingestion status](https://help.getzep.com/check-data-ingestion-status).129 **Submit all episodes without polling between adds** — for130 `thread.add_messages`, `graph.add`, batch, or `zep-ingest` alike — and131 **poll only once, on the last episode**, when you need retrievability.132 Expected wait time scales with total episode count in that graph.133134## Implementation: scope → ingest → retrieve135136Implementing Zep has four steps — **scope → ingest → retrieve → evaluate**.137Evaluation has its own section below; the choices for the first three follow.138These are cross-cutting decisions; confirm exact signatures and limits in the139docs (see the [index](#documentation-index)) rather than guessing.140141### 1. Scope your graphs and data sources142143- Choose **user graphs** (per-user memory) vs. **standalone graphs** (shared or144 domain knowledge). Use **separate graphs wherever you need hard data145 separation** — per user, per team, per tenant.146- Decide which data sources feed which graphs. One graph can hold many sources;147 you can also have many graphs.148- **Zep threads apply only to user graphs.** A Zep thread represents a149 conversation between the user and the agent; it records that conversation150 history *and* ingests it into the user graph. Note the available episode/data151 types (message, text, JSON). Standalone graphs have no first-class thread152 support, but can still ingest arbitrary text — e.g. Slack or email — via153 `graph.add`, or via [`zep-ingest`](https://help.getzep.com/zep-ingest) when154 those sources are already on disk (as text/JSON/episodes, not as a Zep155 thread).156157### 2. Ingest data into graphs158159- **Choose an ingestion path** by how the data arrives (see160 [Adding context](https://help.getzep.com/adding-context)):161162 | What you are adding | Use |163 | --- | --- |164 | A message in a live conversation, as your agent sends and receives it | [`thread.add_messages`](https://help.getzep.com/adding-messages) in the Zep SDK |165 | Historical data on disk you are loading for the first time: documents, transcripts, email, Slack exports, or past conversations | [`zep-ingest`](https://help.getzep.com/zep-ingest) |166 | A recurring export that lands files on disk (hourly or nightly dump, ETL output) | [`zep-ingest`](https://help.getzep.com/zep-ingest) |167 | An individual document, API response, or webhook payload your application already holds in memory | [`graph.add`](https://help.getzep.com/adding-business-data) |168169- **`zep-ingest`** is a Python package for building **ingestion pipelines**: it170 prepares and loads existing on-disk data into Zep in a defined order171 (canonicalize identities and timestamps, validate, submit, monitor). Prefer it172 for backfills and recurring folder/glob imports. It is a convenience layer over173 the Zep SDK — calling `graph.add` or the174 [Batch API](https://help.getzep.com/adding-batch-data) directly remains fully175 supported. Do **not** use it for live chat turns (`thread.add_messages`) or for176 typical in-memory / webhook payloads (`graph.add` is simpler). For loaders,177 transforms, preview, submission, and monitoring details, read178 [Create an ingestion pipeline](https://help.getzep.com/zep-ingest) — do not179 invent package APIs from memory.180- **Prepare the data.** Anytime you design an ingestion pipeline (SDK or181 `zep-ingest`), **read**182 [Prepare data for ingestion](https://help.getzep.com/prepare-data-for-ingestion)183 and follow those best practices (entity identity, source context, event time,184 and related guidance). Also attach185 [**episode metadata**](https://help.getzep.com/adding-business-data#episode-metadata)186 (such as `source`) at ingest when you need episode-metadata filtering on187 search; chunk oversized documents per188 [Chunking](https://help.getzep.com/chunking-large-documents).189- **Seed vs. stream.** Decide between backfilling initial/historical data190 (`zep-ingest`, or [batch ingestion](https://help.getzep.com/adding-batch-data)191 for large volumes) and live/streaming updates (`thread.add_messages` /192 `graph.add`).193- **Multi-graph backfills — enqueue everything, then wait once.** Graphs do194 not share a processing queue; one graph finishing extraction is not a195 prerequisite for another to accept data. For a backfill into multiple graphs196 (user and/or standalone), create all destinations and configure197 ontology/instructions first — ontology is not retroactive — then **submit all198 episodes to every graph without waiting on another graph's processed status**.199 Use the [Batch API](https://help.getzep.com/adding-batch-data) or `zep-ingest`200 with `method="auto"` or `"batch"`. Waiting for graph A to finish before even201 *sending* to graph B is a common backfill anti-pattern. After all submits are202 queued, wait or poll once (in parallel per graph if you like) until the facts203 you need are searchable — only when you are about to search or demo, not after204 every file or graph. Within a single graph, enqueue all sources together too;205 do not finish one source before submitting the next unless you have a real206 dependency (e.g. seed nodes/triples before episodes that must pin to those207 UUIDs).208- **Customize extraction (iterate, don't front-load).** Rule of thumb:209 **ontology defines the *shape* of the graph (which entity/edge types exist);210 instructions define *how to interpret* your domain** — don't conflate them.211 - [Custom ontology](https://help.getzep.com/customizing-graph-structure) —212 your entity/edge types. Model entity types as **nouns** and edge types as213 **verbs/relationships**, and start with a few generic types rather than214 modeling everything up front (custom attributes are advanced and often215 unnecessary). Sharpens extraction and enables type-filtered retrieval.216 - [Custom instructions](https://help.getzep.com/custom-instructions) —217 describe your domain (terminology, concepts) so Zep interprets data better218 on ingest. Not for defining types — that is the ontology's job.219 - [User summary instructions](https://help.getzep.com/user-summary-instructions)220 **(user graphs only)** — steer what the always-on user summary captures.221222### 3. Provide retrieval to agents223224- **Choose the context surface:**225 - *Default Context Block* **(user graphs only)** — `thread.get_user_context`;226 returns whole-user-graph context, relevance driven by the most recent thread227 messages. Best for most conversational agents.228 - *Context templates* **(user graphs only)** — automatic relevance, your fixed229 layout/sections. See [Context templates](https://help.getzep.com/context-templates).230 - *Advanced/manual construction* — run searches and assemble the string231 yourself; the **only** context surface for standalone graphs, and used for232 custom blocks on any graph. See233 [Advanced construction](https://help.getzep.com/advanced-context-block-construction).234- **Search** with `graph.search`: `scope="auto"` (recommended entry point for235 standalone/non-thread queries, spans all context types) or a specific scope236 (edges, nodes, episodes, observations, thread_summaries) with rerankers and237 **filters** (metadata, timestamp, entity/edge type, property). See238 [Searching the graph](https://help.getzep.com/searching-the-graph).239- **Decide how the agent retrieves:** expose search as a **tool call** (LLM240 decides when) vs. **deterministic/programmatic** retrieval on every turn.241- **Decide how many graphs** to read (one versus many, using parallel graph242 searches) — an application-layer decision. See243 [Architecture patterns](https://help.getzep.com/architecture-patterns).244245## Evaluating Zep246247- **Anchor to the end business task** and evaluate **end-to-end**, not each part248 in isolation. See [Evaluate Zep for your use case](https://help.getzep.com/evaluate-zep-for-your-use-case).249- **Two distinct measures:**250 - *Context completeness* — did Zep provide the context needed? (Zep's job.)251 - *Answer accuracy* — did your agent use that context to produce the correct252 result? (Your LLM/prompt's job, assuming context is complete.)253- **Diagnose with them:**254 - Completeness **high**, accuracy **low** → fix the **agent** (prompt, model,255 logic), not Zep.256 - Completeness **low** → accuracy will be low too. Localize the failure: is it257 ingestion or retrieval? First check whether the needed information is in the258 graph **at all** — [read/export the graph](https://help.getzep.com/reading-data-from-the-graph)259 (edges, entities, observations) and inspect the **episodes** (the raw data260 that was sent).261 - Not in the episodes → the data was **never sent** to Zep; fix what your262 application ingests. Not a Zep problem.263 - In the episodes but not in derived artifacts → tune **ingestion** (custom264 instructions, ontology, pre-processing the data).265 - In the derived artifacts but not in the retrieved context → tune266 **retrieval** (search scope, rerankers, filters, context assembly).267- This is why under-deduplication is acceptable (see philosophy above): an268 imperfect graph can still yield complete retrieval, which is what the269 end-to-end evaluation actually measures.270- Zep provides an **evaluation harness** to help measure context completeness271 and answer accuracy — but you supply a **gold dataset**: the kinds of272 questions you want your agent to answer, paired with the correct answers.273 See the full guidance in274 [Evaluate Zep for your use case](https://help.getzep.com/evaluate-zep-for-your-use-case).275276## Documentation index277278The `zep-docs` MCP server is the source for exact, current details and **best279practices** — query it before relying on memory, and **refer to the280documentation before implementing any feature**. The pages below are curated281entry points ("read X to do Y"), grouped into foundational concepts, pages that282apply to all graphs, and the smaller sets that are user-graph-only or283standalone-graph-only.284285**How to retrieve — read a page (preferred), or search.** Prefer loading a whole286page over searching. The server exposes two mechanisms:2872881. **Read a whole page (preferred).** Load a full doc page in one shot as an MCP289 **resource** — `zep-docs://<slug>`, where `<slug>` is the page's290 `help.getzep.com` path (everything after the domain, no leading slash). E.g.291 `https://help.getzep.com/searching-the-graph` →292 `zep-docs://searching-the-graph`; nested paths keep their slashes. Every page293 linked below is reachable at its `zep-docs://<slug>` resource by this rule;294 discover the full list with your client's resource-listing capability (both295 Claude Code and Codex expose MCP resources — Codex via `list_mcp_resources` /296 `read_mcp_resource`). **Prefer this whenever you implement, verify, or debug a297 specific feature** — you get the complete, current page, not fragments — and it298 needs only the MCP connection, so it works even when the agent has no general299 web access.300 - *Fallbacks* if the client can't read MCP resources or a resource errors:301 fetch the identical markdown at `https://help.getzep.com/<slug>.md` (the302 resource is just a cached proxy to that file), or the rendered page at303 `https://help.getzep.com/<slug>`. Both require web access to304 `help.getzep.com`.3052. **Search the docs (discovery).** Use the **`search_documentation`** tool306 (served by `zep-docs`; params: `query`, and optional `max_results`, 1–10,307 default 5) when you don't know where something is documented, whether it exists308 at all, or you want a broad look. It returns reranked text chunks with **no309 page URLs**, so use it to find *what* to read, then load that page in full via310 its `zep-docs://<slug>` resource.311312**Foundational concepts**313314| Read | To |315|------|----|316| [Key concepts](https://help.getzep.com/concepts) | Understand graphs, entities, facts, episodes |317| [Architecture patterns](https://help.getzep.com/architecture-patterns) | Scope graphs and choose one-vs-many-graph retrieval |318| [Context types](https://help.getzep.com/context-types) | Understand each context type and auto search |319| [Retrieval philosophy](https://help.getzep.com/retrieval-philosophy) | Understand recall-over-precision retrieval |320321**All graphs**322323| Read | To |324|------|----|325| [Adding context](https://help.getzep.com/adding-context) | Choose among `thread.add_messages`, `zep-ingest`, and `graph.add` |326| [Create an ingestion pipeline](https://help.getzep.com/zep-ingest) | Backfills and on-disk imports with `zep-ingest` |327| [Adding business data](https://help.getzep.com/adding-business-data) | Individual documents/JSON/API payloads (`graph.add`) |328| [Batch ingestion](https://help.getzep.com/adding-batch-data) | Large imports / the transport `zep-ingest` submits through |329| [Prepare data for ingestion](https://help.getzep.com/prepare-data-for-ingestion) | Best practices — **read before designing any ingestion pipeline** |330| [Chunking](https://help.getzep.com/chunking-large-documents) | Split large documents to fit size limits |331| [Check ingestion status](https://help.getzep.com/check-data-ingestion-status) | Handle asynchronous processing |332| [Webhooks](https://help.getzep.com/webhooks) | Receive pushed events (episode processed, batch completed) instead of polling |333| [Customizing graph structure](https://help.getzep.com/customizing-graph-structure) | Define a custom ontology (entity/edge types) |334| [Custom instructions](https://help.getzep.com/custom-instructions) | Steer domain interpretation on ingest |335| [Searching the graph](https://help.getzep.com/searching-the-graph) | Scoped search, filters, rerankers |336| [Assembling context](https://help.getzep.com/assembling-context) · [Advanced construction](https://help.getzep.com/advanced-context-block-construction) | Build custom context blocks (the only context surface for standalone graphs) |337| [Manually updating the graph](https://help.getzep.com/adding-fact-triplets) | Add nodes/fact triplets and update existing edges, nodes, and facts by UUID |338| [Reading data](https://help.getzep.com/reading-data-from-the-graph) · [Deleting data](https://help.getzep.com/deleting-data-from-the-graph) | Inspect or remove graph data |339| [Cloning graphs](https://help.getzep.com/cloning-graphs) | Copy a graph (e.g. for testing) |340| [Evaluate Zep for your use case](https://help.getzep.com/evaluate-zep-for-your-use-case) | Benchmark completeness vs. accuracy |341| [Performance best practices](https://help.getzep.com/performance) | Reduce latency and optimize production performance (SDK client reuse, cache warming, concise search) |342343**User graphs only**344345| Read | To |346|------|----|347| [Quick start](https://help.getzep.com/quick-start-guide) | Stand up the basic loop (the user-graph quick start) |348| [Users and user graphs](https://help.getzep.com/users-and-user-graphs) | Create users and per-user memory |349| [Threads](https://help.getzep.com/threads) | Record conversations and ingest into the user graph |350| [Retrieving context](https://help.getzep.com/retrieving-context) | Get the default Context Block |351| [Context templates](https://help.getzep.com/context-templates) | Fixed custom layout with automatic relevance |352| [User summary](https://help.getzep.com/user-summary) · [summary instructions](https://help.getzep.com/user-summary-instructions) | Shape the always-on user baseline |353| [Add user business data](https://help.getzep.com/how-to-add-user-specific-business-data-to-user-graphs) | Add non-chat data to a user graph |354355**Standalone graphs only**356357| Read | To |358|------|----|359| [Give your agent domain knowledge](https://help.getzep.com/give-your-agent-domain-knowledge) | Stand up the basic loop (the standalone-graph quick start) |360| [Graph overview](https://help.getzep.com/graph-overview) · [Create graph](https://help.getzep.com/create-graph) | Create and manage standalone graphs |361362**Reference and governance**363364- SDK / API reference: <https://help.getzep.com/sdk-reference> — confirm exact365 signatures, parameters, and limits here or via the `zep-docs` MCP.366- Docs MCP server setup: <https://help.getzep.com/docs-mcp-server>.367- Governance (enterprise):368 - [Security & compliance](https://help.getzep.com/security-compliance) — the hub369 for Zep's security posture: SOC 2 Type II, HIPAA BAAs, access controls,370 audit/API logging, and BYOK/BYOC deployment options.371 - [RBAC](https://help.getzep.com/role-based-access-control) — role-based access372 control. Governs **human** teammates' access to the Zep dashboard via account-373 and project-scoped roles, so each person gets the right level of access.374 - [ABAC](https://help.getzep.com/attribute-based-access-control) — attribute-based375 access control. Scopes an individual **API key** to a subset of a project's376 actions and data (by action, and by data class via ingestion metadata) to377 enforce least privilege — useful when each agent authenticates with its own key.378 - [BYOK](https://help.getzep.com/bring-your-own-key) — bring your own key. Encrypt379 data at rest with your own AWS KMS key, keeping full control including revocation.380381## Source authority and validation382383- **Query the `zep-docs` MCP server first** for anything that must be exact or384 current — method names, parameters, limits, plan availability, newer features.385 Prefer loading the whole relevant page via its **`zep-docs://<slug>` resource**;386 use the **`search_documentation`** tool to find the right page or check whether387 something exists (see [Documentation index](#documentation-index) for both). It388 covers the guides and the SDK/API reference.389- **Fallback if resources or the MCP are unavailable:** fetch the page markdown at390 `https://help.getzep.com/<slug>.md`, else the guides at <https://help.getzep.com>391 and the SDK/API reference at <https://help.getzep.com/sdk-reference>.392- **The live docs win on conflict.** Treat this skill's summaries as stale if393 they disagree with current, version-matched documentation. Verify394 version-sensitive code against the SDK reference and, when available, the395 installed SDK's types/source.396- **Validate behavior, not just plausibility.** Don't stop at code that looks397 right — confirm ingestion completed, retrieval returns the expected context,398 and (per [Evaluating Zep](#evaluating-zep)) the end use case actually improves.