cognify() is a legacy operation. In Cognee v1.0, most users should use remember() instead, which replaces the add() + cognify() + memify() workflow with a single call.What is the cognify operation
The.cognify operation takes the ingested data with Add and turns plain text into structured knowledge: chunks, embeddings, summaries, nodes, and edges that live in Cognee’s vector and graph stores. It prepares your data for downstream operations like Search.
- Transforms ingested data: builds chunks, embeddings, and summaries
- Graph creation: extracts entities and relationships to form a knowledge graph
- Vector indexing: makes everything searchable via embeddings
- Dataset-scoped: runs per dataset, respecting ownership and permissions
.cognify can be run multiple times as the dataset grows, and Cognee will skip what’s already processed. Read more about Incremental loading in Examples and detailsWhat happens under the hood
The.cognify pipeline is made of six ordered Tasks, plus two optional tasks you can switch on. Each task takes the output of the previous one and moves your data closer to becoming a searchable knowledge graph.
- Classify documents — wrap each ingested file as a
Documentobject with metadata and optional node sets - Check permissions — enforce that you have write access to the target dataset
- Extract chunks — split documents into smaller pieces (paragraphs, sections)
- Extract graph — use LLMs to identify entities and relationships, inserting them into the graph DB
- Summarize text — generate summaries for each chunk, stored as
TextSummaryDataPoints - Add data points — embed nodes and summaries, write them into the vector store, and update graph edges
- Record provenance (opt-in, off by default) — append an audit-ledger entry for every document, chunk, entity, and relationship this run produced. Enable it with
PROVENANCE_TRACKING=true; when it is off, the pipeline is exactly the tasks above. See Provenance ledger. - Detect contradictions (opt-in, off by default) — compare the facts this run touched against the facts already stored around them and record each conflict as a
contradictsedge. Enable it withCONTRADICTION_DETECTION=true; when it is off, the pipeline is exactly the tasks above. See Contradiction detection.
After cognify finishes
When.cognify completes for a dataset:
- DocumentChunks exist in memory as the granular breakdown of your files
- Summaries are stored and indexed in the vector database for semantic search
- Knowledge graph nodes and edges are committed to the graph database
- Dataset metadata is updated with token counts and pipeline status
contradictsedges may also be present if you enabled contradiction detection — each one records the two conflicting facts, the reason, and a confidence score- Your dataset is now query-ready: you can run Search or graph queries immediately
Because
cognify() calls the LLM for entity extraction and summarization, it can fail when the configured LLM provider (or LiteLLM proxy) reports that its token budget is exhausted. In that case it raises LLMPaymentRequiredError, which the API surfaces as HTTP 402 (Payment Required) with body {"error": "Token budget exhausted", "detail": "..."}. This error is terminal — Cognee does not retry budget-exhaustion failures — so treat a 402 as final for the request and prompt the user to top up their token budget rather than reissuing the call.Examples and details
Pipeline tasks (detailed)
Pipeline tasks (detailed)
-
Classify documents
- Turns raw
Datarows intoDocumentobjects - Chooses the right document type (PDF, text, image, audio, etc.)
- Attaches metadata and optional node sets
- Turns raw
-
Check permissions
- Verifies that the user has write access to the dataset
-
Extract chunks
- Splits documents into
DocumentChunks using a chunker - You can customize the chunk size and strategy — see Chunkers for details
- Updates token counts in the relational DB
- Splits documents into
-
Extract graph
- Calls the LLM to extract entities and relationships
- Deduplicates nodes and edges, commits to the graph DB
-
Summarize text
- Generates concise summaries per chunk
- Stores them as
TextSummaryDataPoints for vector search
-
Add data points
- Converts summaries and other DataPoints into graph + vector nodes
- Embeds them in the vector store, persists in the graph DB
-
Record provenance (opt-in — set
PROVENANCE_TRACKING=true)- Runs right after Add data points, where node ids are persisted and stable, and before the contradiction check, so the ledger never depends on contradiction edges
- Appends document → chunk → entity → relationship lineage entries to the append-only
provenance_entriestable in the relational DB, one chained transaction per task invocation - Every entry carries a SHA-256 checksum linking it to the previous one, so
verify_chain()detects deletion, reordering, and single-field edits - Fail-safe: it returns its input unchanged and swallows its own errors, so it can never break ingestion — which also means a failed batch is silently absent from the ledger
- Read entries back through
ProvenanceManager, and note the migration requirement — see Provenance ledger
-
Detect contradictions (opt-in — set
CONTRADICTION_DETECTION=true)- Runs last, so both the new facts and the already-stored ones are persisted and comparable
- Gathers the facts one hop from the entities this run touched (structural edges such as
containsandmade_fromare skipped) and asks the LLM which pairs conflict - Logs a warning per conflict and writes a
contradictsedge carryingfirst_fact,second_fact,reason, andconfidence - Non-destructive and fail-safe: it only adds edges and swallows its own errors, so it can never break ingestion
- Tunable with
CONTRADICTION_CONFIDENCE_THRESHOLD(default0.5) andCONTRADICTION_MAX_FACTS(default500) — see Contradiction detection
Default extraction prompts
Default extraction prompts
Cognee ships with several built-in system prompts for entity and relationship extraction, stored in Or configure it at runtime via
cognee/infrastructure/llm/prompts/. The active prompt is controlled by the GRAPH_PROMPT_PATH environment variable (default: generate_graph_prompt.txt).To switch to a different built-in prompt, set the environment variable:
cognee.config:If you need to use a custom prompt, refer to our Custom Prompts guide
Datasets and permissions
Datasets and permissions
- Cognify always runs on a dataset
- You must have write access to the target dataset
- Permissions are enforced at pipeline start
- Each dataset maintains its own cognify status and token counts
Incremental loading and deduplication
Incremental loading and deduplication
incremental_loading=True is the default on cognee.add(), cognee.cognify(), and update(), as is its companion data_cache=True. The per-item skip runs whenever either flag is on, so disabling deduplication means passing both as False. Failure behavior is controlled by an environment variable, not a function parameter — see When a data item fails below.The two flags give you two layers of deduplication:Layer 1 — content-hash deduplication in add()Before cognify() runs, add() already deduplicates by content hash within the dataset. Re-adding unchanged content is skipped at ingestion time, while changed content hashes differently and becomes a new record with its own id — the previous record stays. To replace a document’s content while keeping its id, use update().For the full behavior and scenario table, see Hash-based deduplication on the Add page.Layer 2 — pipeline-status tracking in cognify()Before processing each data item, cognify() checks a pipeline_status field on the record. If the status for the cognify_pipeline in the current dataset is already COMPLETED, the item is skipped entirely — no LLM calls, no re-embedding, no graph writes.Common usage patterns:
Appending new data to an existing dataset
Appending new data to an existing dataset
You can grow a dataset over time without reprocessing what’s already there:
Forcing a full reprocess
Forcing a full reprocess
To reprocess everything regardless of status, pass both skip flags as This bypasses the pipeline-status check but does not re-ingest files — use
False — the skip runs whenever either one is on:cognee.datasets.empty_dataset() first if you also need to clear the stored data.Re-ingesting a source that keeps growing
Re-ingesting a source that keeps growing
For a table, database, or CSV that gains rows between runs, two independent settings decide what happens. The
write_disposition you pass to dlt ingestion decides what the staged snapshot contains on a re-run; incremental_loading / data_cache decide whether Cognee looks at that snapshot at all. write_disposition alone is not enough: a plain re-run is skipped before the grown snapshot is ever compared (see Re-Ingesting a Source), so turn off both skip flags on add() to force the ingestion layer to look:cognify() can keep its defaults: add() clears the record’s pipeline_status whenever the content hash changed, so the grown source is reprocessed while every unchanged document in the dataset is still skipped. Note that append also disables orphan cleanup, so rows deleted upstream stay in the graph.When a data item fails
When a data item fails
Deduplication never suppresses errors, and the behavior is not a function parameter: it is the
RAISE_INCREMENTAL_LOADING_ERRORS environment variable, default true.In both modes the
add() / cognify() call returns a PipelineRunErrored run info rather than raising. A failed cognify() run also rolls back its partial artifacts so the next run resumes cleanly — see Crash recovery and stuck pipelines for how the rollback is scoped; add() has no rollback step. Cases where deduplication cannot identify rows are logged as warnings rather than raised: duplicate primary keys within a dlt table are reported and the last row loaded wins for foreign-key targeting.Batching for faster processing
Batching for faster processing
Two batching parameters control how much work Cognee runs at once during ingestion and graph building:For new workflows, prefer remember(). It is the current API and accepts these batching controls for permanent-memory ingestion. Use
add() and cognify() directly only when you need lower-level control over ingestion and graph building as separate legacy steps.data_per_batch is the outer concurrency limit. Cognee schedules the data items in a dataset and uses a semaphore so at most this many items are processed at the same time. The default of 20 is a deliberate concurrency cap — pushing many more items through the pipeline at once overwhelms it regardless of backend. On the default SQLite backend there is an additional, sharper constraint to know about before raising it: every in-flight item writes its own Data row, and at high concurrency the parallel read-then-write transactions hit WAL snapshot-upgrade conflicts that fail immediately with database is locked, bypassing busy_timeout. Deployments on Postgres are not subject to that particular failure. Raise data_per_batch explicitly when you want more ingestion concurrency, and lower it if your deployment is memory-constrained or your model provider’s rate limits are tight.chunks_per_batch is the inner chunk-task batch size. In the default Cognify pipeline, Cognee passes it as batch_size to the graph extraction/summarization task and to add_data_points. If you do not pass it directly, Cognee checks the chunks_per_batch value from CognifyConfig; when that is unset, the default Cognify pipeline uses 2000.Where to configure them- Pass
data_per_batchandchunks_per_batchto permanent-memoryremember()for the current API path. - Use legacy
add()/cognify()only when you intentionally split ingestion and graph building;data_per_batchapplies to both, whilechunks_per_batchapplies tocognify(). - For the legacy
/api/v1/cognifyendpoint, both values are accepted in the JSON request body. - For
/api/v1/remember,chunks_per_batchis exposed as a multipart form field. The current remember endpoint does not exposedata_per_batchas a form field, so tunedata_per_batchthrough the Python SDK or the lower-level Cognify API when you need that control.
Larger batches can improve throughput by keeping the pipeline, model provider, and databases busier, but they also increase memory pressure and can hit LLM, embedding, or database rate limits sooner. The best values depend on document size, chunk count, model/provider limits, embedding batch behavior, graph/vector database capacity, and the CPU/RAM available to the Cognee process.
How entity and relationship names are determined
How entity and relationship names are determined
During the Extract graph step, Cognee asks the LLM to turn each chunk into graph nodes and edges. The names and types in that graph are inferred from your content rather than fixed in advance.
The extraction prompt instructs the model to:
- Capture entities, names, nouns, and implied mentions exhaustively
- Form relationships as
(start_node, relationship_name, end_node)triplets using explicit and inferred connections - Avoid duplicates and overly generic terms
id the model returns is only a local handle, used to wire up that chunk’s edges. The identity of the stored node is derived from its name (normalized to lowercase, with spaces turned into underscores and apostrophes stripped), so every mention of the same name — across chunks, across documents, and across later .cognify runs — resolves to the same Entity node instead of creating a duplicate.Three consequences worth knowing:- If a single extracted chunk graph contains several distinct nodes that share one name, they are not merged: each gets a deterministic chunk-scoped id so they stay separate.
- An extracted edge whose endpoint is not among that chunk’s extracted nodes is dropped, rather than creating a placeholder node for the missing endpoint.
- Entity nodes written before Cognee moved to name-derived ids keep their old ids, so re-running
.cognifyover data that is already in the graph can create a second node alongside the existing one. Re-process those datasets from scratch if you need the ids to line up.
If you need tighter control over naming, use an OWL ontology or a custom graph model. See Ontologies and Custom Graph Model.
Inspect extracted graph schema
Inspect extracted graph schema
Once To explore the same graph visually, use the Graph Visualization guide.
.cognify finishes, the graph schema is inspectable because the extracted node types and relationship names now exist in the graph store.Python SDK
Use the graph engine directly to inspect the stored nodes and edges:get_graph_data() returns:- Nodes as
(node_id: str, properties: dict) - Edges as
(source_id: str, target_id: str, relationship_name: str, properties: dict)
HTTP server mode
When you run the Cognee HTTP server, you can inspect graph data through the dataset graph endpoint:Re-cognify after schema changes
Re-cognify after schema changes
If you update your data model (e.g., add new entity fields or relationships) and want to reprocess existing data:
-
Delete the dataset first, then re-add and re-cognify:
- Alternatively, use Memify for additive enrichment — it runs extraction and enrichment tasks over the existing graph without re-ingesting data. This is useful when you want to add new derived facts without reprocessing from scratch.
Final outcome
Final outcome
- Vector database contains embeddings for summaries and nodes
- Graph database contains entities and relationships
- Relational database tracks token counts and pipeline run status
- Your dataset is now ready for Search (semantic or graph-based)
Checking indexing status
Checking indexing status
If you are using the current v1.0 API, see Remember for the recommended indexing-status workflow built around
remember() and recall().If you are working directly with legacy .cognify() or the MCP cognify_status tool, the same dataset status primitives still apply:cognee.datasets.get_status([dataset_id])GET /api/v1/datasets/status?dataset=<dataset-uuid>GET /api/v1/activity/pipeline-runs?dataset_id=<dataset-uuid>
cognify_status(dataset_name="main_dataset") provides a text summary of recent cognify runs.LLM call count and cost estimation
LLM call count and cost estimation
The default cognify pipeline makes 2 LLM calls per chunk:When With typical defaults (e.g.,
- Graph extraction — identifies entities and relationships from the chunk text
- Summarization — generates a concise summary of the chunk
chunk_size:chunk_size is not set explicitly, Cognee auto-calculates it as:gpt-4o-mini + text-embedding-3-small) this usually falls in the 1 024 – 8 192 token range. See Chunkers for details.Example estimates at chunk_size = 1024:Tips for reducing API usage
- Increase
chunk_size— fewer, larger chunks mean fewer calls: - Skip summarization — use a custom pipeline that omits the
summarize_texttask, reducing calls to 1 per chunk. - Pace requests from the start — Cognee already turns the RPM limiter on by itself once a provider reports overload (see Rate Limiting), but you can set
LLM_RATE_LIMIT_ENABLED=trueto pace every call from the first request and avoid bursting your provider quota when processing many chunks in parallel.
Concurrent search while cognify is running
Concurrent search while cognify is running
You can run Seeing this error means two processes are writing to the same embedded vector store. Route all writes through one Cognee process, or switch to an external vector store such as PGVector — see the single-process callout in remember.
search while a cognify pipeline is active — there is no global lock that blocks one from the other.Cognee’s locks are session-level: they serialize short read-modify-write operations (such as update_qa or add_feedback) within the same (session_id, operation) pair. They do not apply across cognify and search.Within a single process, the default LanceDB vector store uses an asyncio lock per adapter instance to serialize concurrent write coroutines, so interleaved searches and writes within the same worker are safe.Across multiple processes, sharing the same LanceDB data directory is not supported — Cognee’s embedded stores are single-process. If two workers do open the same directory, LanceDB’s commit-conflict detection surfaces errors like:For single-process deployments (the default), concurrent search during cognify works without any special configuration.
Add
First bring data into Cognee
Search
Query embeddings or graph structures built by Cognify
Memify
Enrich your graph with derived facts after cognify