Query memory with recall()
recall() is cognee's query API. It picks a search strategy, searches the
graph and (with a session) the session cache, and returns a list of tagged
results.
import cognee
results = await cognee.recall("Where was Einstein born?")
for r in results:
print(r.source, r.text) # e.g. "graph", "Einstein was born in Ulm."
Without datasets it searches every dataset the user can read. Pass
datasets=["research"] (names) or dataset_ids=[...] (UUIDs, which win) to
narrow it; that is also faster.
Use it
How the search type is picked
- An explicit
query_type=SearchType.X always wins.
- Otherwise, with no usable LLM key,
CHUNKS (plain vector search).
- Otherwise the router (
auto_route=True, the default). It is two regex
rules, first match wins, no LLM call:
- the whole query is one
"quoted phrase" → CHUNKS_LEXICAL
- mentions coding rules/standards/conventions or code-review guidelines
→
CODING_RULES
- Everything else →
HYBRID_COMPLETION.
A routed type (never a pinned one) that the backend rejects, or a routed
CHUNKS_LEXICAL / CODING_RULES that returns nothing, is retried once as
HYBRID_COMPLETION. The router never picks CYPHER.
from cognee import SearchType
await cognee.recall("What changed in v2?", query_type=SearchType.GRAPH_COMPLETION)
Search types
The full list is cognee/modules/search/types/SearchType.py; the
type-to-retriever table is cognee/modules/retrieval/README.md.
| Type | LLM? | Use for |
|---|
HYBRID_COMPLETION (default) | yes | General questions: document passages plus entity neighbourhoods, then an answer |
GRAPH_COMPLETION | yes | Answers from graph relationships |
GRAPH_COMPLETION_COT, _CONTEXT_EXTENSION, _DECOMPOSITION | yes | Harder multi-hop questions (more LLM calls) |
GRAPH_SUMMARY_COMPLETION | yes | Summarizes the retrieved graph edges at query time (extra LLM call), then answers |
RAG_COMPLETION | yes | Classic chunk RAG |
TRIPLET_COMPLETION | yes | Subject-predicate-object facts (needs triplet embedding) |
TEMPORAL | yes | Time questions; reads the Timestamp nodes the default pipeline extracts |
CHUNKS | no | Raw passages by vector similarity |
CHUNKS_LEXICAL | no | Keyword / exact-phrase match |
SUMMARIES | no | Document summaries |
CODE | no | Code-graph operations via code_query={...}; needs scope="code" in recall |
SKILLS | no | Discover skill playbooks; exactly one dataset |
CYPHER | no | Raw Cypher. On by default; ALLOW_CYPHER_QUERY=false disables it. It can write, so only pass user-authored queries deliberately |
NATURAL_LANGUAGE | yes | LLM writes Cypher, then runs it (same flag) |
GRAPH_REPORT | partly | Graph insight report: hubs, cross-set links, suggested questions |
FEELING_LUCKY | yes | An LLM picks the type |
AGENTIC_COMPLETION | yes | Multi-step loop with skills/tools; exactly one dataset. Use search() for its parameters |
Scope: which sources are searched
scope is one of, or a list of: graph, session, session_first,
trace, session_context, all, tools, code. all means graph +
session + trace + session_context; tools and code are never included
implicitly.
When scope is omitted:
| You pass | Sources |
|---|
session_id only | Session first; a session hit skips the graph |
session_id + datasets | Session and graph both contribute |
session_id + query_type | Graph only — pinning a type drops the session |
no session_id | Graph only |
Session and trace search is keyword overlap, not embeddings.
Filters and knobs
top_k=15: per dataset, not in total. The default HYBRID caps each lane
at min(top_k, 10); set chunks_top_k / entities_top_k /
facts_top_k in retriever_specific_config to go higher.
node_name=["AI"] (+ node_name_filter_operator="OR"|"AND"): restricts
graph/chunk/completion types to data remembered with that node_set.
SUMMARIES, CHUNKS_LEXICAL, GRAPH_REPORT, CYPHER, NATURAL_LANGUAGE, CODE and
SKILLS ignore it; CODING_RULES treats it as the rules node-set name.
system_prompt / system_prompt_path: change the answering prompt.
response_model=MyPydanticModel: structured answer, on r.structured.
include_references=True: attach the document chunks that support each
graph edge used (needs EDGE_EVIDENCE_ENABLED=true, the default).
only_context=True: return what the LLM would have received instead of
an answer. r.text is the rendered user prompt, r.system_prompt the
system prompt. Pin query_type when you use it.
retriever_specific_config={...}: retriever-only options. For the
agentic extras (skills, tools, max_iter) and node_type, call
cognee.search() instead, which takes them as parameters.
Reading the results
Each item is a Pydantic model with a source discriminator: graph,
session, trace, session_context, code, tools, skills, or
system. Graph items carry text (always renderable), search_type,
kind, score, dataset_id / dataset_name, metadata, raw, and
structured. A system item is a status
marker, not data (see "memory warming up" below).
When a query sounds procedural ("how do I…", "runbook", "steps to…") and
exactly one dataset is targeted, recall also runs a small SKILLS lookup
and appends hits with source="skills". Disable with
SKILL_GATE_ENABLED=false.
Pitfalls
- Permissions change what you get back. With no
datasets, recall
searches only datasets the user can read, so a user without grants gets
one source="system" memory_warming_up marker from a graph-only recall
(with only_context=True or RECALL_WARMUP_SHORTCIRCUIT=false it gets
[]; with session sources included only the graph lane is empty, and
session and trace hits still come back). Asking for a dataset id the user cannot read raises
PermissionDeniedError (HTTP 403). Dataset names resolve only among
the user's own datasets, so a name that is not theirs (even one shared
with them) raises DatasetNotFoundError; use dataset_ids for shared
datasets. See the cognee-permissions skill.
- "Memory warming up". On an empty graph, a graph-only recall (no
session sources, not
only_context) returns one source="system" item
with status="memory_warming_up" (or "build_failed" plus
error_message) instead of results; a multi-source recall just returns
no graph results. Wait for the
remember to finish, or check why it failed.
- Hybrid silently becomes graph completion when you pass
neighborhood_depth or feedback_influence > 0 (including a nonzero
DEFAULT_FEEDBACK_INFLUENCE), or the chunk collection is missing.
node_name stays on hybrid, which filters to that node set. search()
also defers for a custom node_type or node_name with node_type=None;
recall() has no node_type. wide_search_top_k and triplet_distance_penalty
with hybrid raise InvalidHybridSearchConfig; pin
GRAPH_COMPLETION to use them.
SKILLS and AGENTIC_COMPLETION need exactly one dataset. For
SKILLS, search() raises unless exactly one dataset is given.
recall() runs SKILLS per dataset with access control on (zero datasets
gives [], not an error) and raises only with access control off and not
exactly one dataset. For
AGENTIC_COMPLETION only search() checks it up front, so call it through
search() with one dataset.
code_query without scope="code" raises, and scope="tools" also
needs TOOL_CALLS_ENABLED=true.
- Latency. Most completion types make one LLM call; COT,
DECOMPOSITION, CONTEXT_EXTENSION, GRAPH_SUMMARY_COMPLETION, TEMPORAL,
FEELING_LUCKY (one call to pick the type, then the chosen type's) and
AGENTIC_COMPLETION (a loop of up to
max_iter, default 6) make more. NATURAL_LANGUAGE makes one (no answer call) and retries only on
an empty or failed query, up to 3 attempts. With CACHING and
AUTO_FEEDBACK on (defaults), each answered turn adds one analysis call,
even without a session_id. Set
AUTO_FEEDBACK=false for low-latency reads (see the cognee-performance
skill).
recall() or search()?
Use recall(). Drop to cognee.search() only for agentic parameters
(skills, tools, max_iter, node_type) as first-class arguments, raw
SearchResult objects, or a pinned type with no router. search() never
searches the session cache; its session_id only adds conversation history
to the prompt. Full guide: docs/recall-vs-search.md.
How it works
recall() resolves scope and search type, then calls the same authorized
search search() uses: datasets resolve through the permission layer with
read, one search per dataset runs concurrently, and results are
normalized and tagged.
- Entry point, scope and type resolution:
cognee/api/v1/recall/recall.py
- Router:
cognee/api/v1/recall/query_router.py
- Skill gate:
cognee/api/v1/recall/skill_gate.py
- Result types:
cognee/modules/recall/types/RecallResponse.py,
SearchResultItem.py
- Scope names:
cognee/memory/entries.py:normalize_scope
- Warm-up config (
RECALL_WARMUP_*): cognee/modules/recall/config.py
- Core search and fan-out:
cognee/modules/search/methods/search.py
- Hybrid fallback rules:
cognee/modules/search/methods/hybrid_deferral.py
- Registry:
cognee/modules/search/methods/get_search_type_retriever_instance.py
Examples in examples/guides/: recall_core.py,
hybrid_retrieval_recall.py, references_example.py, temporal_recall.py,
sessions.py.
Extending it
Adding a search type, per cognee/modules/retrieval/README.md:
- Write the retriever in
cognee/modules/retrieval/ (subclass
BaseRetriever or a completion base).
- Add the
SearchType member and its search_core_registry entry.
- Add a row to the README table. A unit test
(
cognee/tests/unit/modules/retrieval/retriever_readme_index_test.py)
fails if the table and registry disagree.
- Optional: add it to
SEARCH_TYPE_CHOICES in cognee/cli/config.py for
the CLI, or a regex rule to query_router.py for auto-routing. Never
route a type that can write.