{"owner":"topoteretes","repo":"cognee","hasSkills":true,"totalSkillsCount":71,"totalTokensCount":45284,"categories":["anthropic-skill","root-instruction","claude-rule","plugin-manifest"],"hasMcp":false,"mcpConfig":null,"found":[".agents/skills/cognee-docker/SKILL.md",".agents/skills/cognee-forget/SKILL.md",".agents/skills/cognee-community/SKILL.md",".agents/skills/cognee-cli/SKILL.md",".agents/skills/cognee-custom-pipelines/SKILL.md",".agents/skills/cognee-custom-graph-models/SKILL.md","cognee/skill.md",".agents/skills/cognee-install/SKILL.md",".agents/skills/cognee-integrations/SKILL.md",".agents/skills/cognee-ingestion/SKILL.md",".agents/skills/cognee-migrations/SKILL.md",".agents/skills/cognee-improve-sessions/SKILL.md",".agents/skills/cognee-performance/SKILL.md",".agents/skills/cognee-permissions/SKILL.md",".agents/skills/cognee-recall/SKILL.md",".agents/skills/cognee-server/SKILL.md",".agents/skills/company-brain-company-qa/SKILL.md",".agents/skills/company-brain-follow-up-agent/SKILL.md",".agents/skills/personalized-email/SKILL.md",".agents/skills/self-hosted-companion/SKILL.md","examples/demos/feedback/skill_feedback_loop/skills/diff-risk-explainer/SKILL.md","examples/demos/feedback/skill_feedback_loop/skills/pr-comment-evaluator/SKILL.md","examples/demos/feedback/skill_feedback_loop/skills/skill-feedback-writer/SKILL.md","AGENTS.md","CLAUDE.md","evals/README.md","tools/spec_extras.json","cognee_db_workers/ladybug_extensions/README.md","evals/old/hotpot_50_corpus.json","evals/old/hotpot_50_qa_pairs.json","catalog/entries/packages/qdrant.yaml","catalog/entries/packages/weaviate.yaml","evals/old/cognee_01042025/aggregate_metrics_v_deepeval.json","evals/old/cognee_01042025/aggregate_metrics_v_direct_llm.json","evals/old/cognee_01042025/metrics_output_cognee.json","evals/old/cognee_01042025/metrics_output_cognee_direct_llm.json","evals/old/cognee_01042025/metrics_output_cognee_human_eval.json","evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10.json","evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short.json","evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short_deepeval.json","evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10.json","evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10_short.json","evals/old/comparative_eval/README.md","evals/old/comparative_eval/hotpot_50_corpus.json","evals/old/comparative_eval/hotpot_50_qa_pairs.json","evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk.json","evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk_direct_llm.json","evals/old/falkor_01042025/metrics_output_falkor_graph_sdk_human_eval.json","evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk.json","evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk_direct_llm.json","evals/old/graphiti_01042025/aggregate_metrics_graphiti.json","evals/old/graphiti_01042025/aggregate_metrics_graphiti_direct_llm.json","evals/old/graphiti_01042025/metrics_output_graphiti.json","evals/old/graphiti_01042025/metrics_output_graphiti_direct_llm.json","evals/old/graphiti_01042025/metrics_output_graphiti_huma_eval.json","evals/old/graphiti_updated/hotpot_qa_graphiti_results_old.json","evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics.json","evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics_direct_llm.json","evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics.json","evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics_direct_llm.json","evals/old/hotpot_qa_24_2025/README.md","evals/old/hotpot_qa_24_2025/benchmark_summary_cognee.json","evals/old/hotpot_qa_24_2025/benchmark_summary_competition.json","evals/old/mem0_01042025/aggregate_metrics_mem0.json","evals/old/mem0_01042025/aggregate_metrics_mem0_direct_llm.json","evals/old/mem0_01042025/metrics_output_mem0.json","evals/old/mem0_01042025/metrics_output_mem0_direct_llm.json","evals/old/mem0_01042025/metrics_output_mem0_human_eval.json","evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_corpus.json","evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_instance_filter.json","evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_qa_pairs.json"],"skills":{".agents/skills/cognee-docker/SKILL.md":"---\nname: cognee-docker\ndescription: Use when the user wants to run cognee with Docker or docker compose — trying it out from the prebuilt image, starting the API server in a container, or bringing up the full stack (UI, MCP, Postgres, Neo4j) with compose profiles.\n---\n\n# Start cognee from the Docker image\n\n## Fastest path: prebuilt image, one file\n\nFor a local try-out, do NOT clone or build anything. Follow\n`docs/minimal-docker-compose.md`: save this as `docker-compose.yml` in an\nempty directory:\n\n```yaml\nservices:\n  cognee:\n    image: cognee/cognee:main\n    ports:\n      - \"8000:8000\"\n    environment:\n      LLM_API_KEY: ${LLM_API_KEY:?set LLM_API_KEY to your OpenAI API key}\n      # Single-user try-out: no auth, shared local databases.\n      ENABLE_BACKEND_ACCESS_CONTROL: \"false\"\n```\n\nThen:\n\n```bash\nexport LLM_API_KEY=\"sk-...\"   # OpenAI key (default LLM + embedding provider)\ndocker compose up\ncurl http://localhost:8000/health\n```\n\nInteractive API reference: http://localhost:8000/docs. First requests:\n\n```bash\necho \"Cognee turns documents into AI memory.\" > note.txt\n# remember = ingest + build the graph in one call (multipart form)\ncurl -X POST http://localhost:8000/api/v1/remember -F \"data=@note.txt\" -F \"datasetName=main_dataset\"\n# recall = query it (JSON)\ncurl -X POST http://localhost:8000/api/v1/recall -H \"Content-Type: application/json\" \\\n  -d '{\"query\": \"What does Cognee do?\", \"datasets\": [\"main_dataset\"]}'\n```\n\n`/api/v1/recall` takes the question as `query`. Omit `search_type` (or pass\n`null`) and the query is auto-routed by the same rule-based router the SDK\n`recall()` uses, with `HYBRID_COMPLETION` as the fallback; pass a value such as\n`\"search_type\": \"GRAPH_COMPLETION\"` to pin a strategy. The rule table is in\n`docs/recall-vs-search.md`.\n\nRequest DTOs accept both `snake_case` and `camelCase` for every field\n(`alias_generator=to_camel` + `populate_by_name` in `cognee/api/DTO.py`), so\n`search_type` and `searchType` are equally valid.\n\nThe legacy `/api/v1/add` + `/api/v1/cognify` + `/api/v1/search` endpoints still\nexist and are what `remember`/`recall` call underneath; use them only when you\nneed a single stage on its own. `/api/v1/improve` and `/api/v1/forget` complete\nthe memory API.\n\nData lives inside the container by default. To persist it, set\n`DATA_ROOT_DIRECTORY=/cognee-data/data` and\n`SYSTEM_ROOT_DIRECTORY=/cognee-data/system` and mount a named volume at\n`/cognee-data` (full example in `docs/minimal-docker-compose.md`).\n\n## Full stack from the repo\n\nThe repository's `docker-compose.yml` builds from source and adds opt-in\nprofiles. From the repo root (needs a `.env` with at least `LLM_API_KEY`;\ncopy `.env.template`):\n\n```bash\ndocker compose up                                  # API server only, port 8000\ndocker compose --profile ui up                     # + frontend on port 3000\ndocker compose --profile mcp up                    # + MCP server on port 8001\ndocker compose --profile postgres --profile neo4j up   # + databases\n```\n\nPostgres profile: pgvector/pg17, user/password/db `cognee`/`cognee`/`cognee_db`\non 5432. Neo4j profile: `neo4j`/`pleaseletmein` on 7474/7687. When cognee runs\nin a container and the database on the host, use `DB_HOST=host.docker.internal`.\n\n## Gotchas\n\n- With `ENABLE_BACKEND_ACCESS_CONTROL` unset (defaults to true), every API\n  call requires authentication — the single-user try-out sets it to `false`.\n- The image defaults to OpenAI for both LLM and embeddings; configuring only\n  one of them leaves the other on OpenAI, so keep a valid OpenAI key or\n  configure both (see the cognee-integrations skill).\n",".agents/skills/cognee-forget/SKILL.md":"---\nname: cognee-forget\ndescription: Use when removing data from cognee memory with forget() in the SDK, HTTP API, or CLI — finding which dataset and document hold the content to delete (listing datasets and data items, reading raw content), choosing between deleting one document, a whole dataset, or only the graph/vector memory, and doing it safely.\n---\n\n# Remove data with forget()\n\n`forget()` is cognee's one deletion API. It removes one document, a whole\ndataset, or only the derived memory (graph + vectors) while keeping the raw\nfiles. Deletion cannot be undone, so the workflow is always **find, read,\nconfirm, then delete**.\n\n> **Hard limits for agents**\n> - Delete only what the user asked to forget. Identify it by reading the\n>   content first; never guess from a file name alone.\n> - Confirm the exact items with the user before deleting, unless they\n>   already named exact ids.\n> - The widest deletion you may run is `forget(everything=True)`, and only\n>   when the user explicitly asks to wipe all of their memory. Never use any\n>   other reset or wipe mechanism to delete data.\n\n## Use it\n\n### 1. Find the dataset\n\n```python\nimport cognee\n\ndatasets = await cognee.datasets.list_datasets()  # datasets the user can read\nfor ds in datasets:\n    print(ds.id, ds.name)\n```\n\nHTTP: `GET /api/v1/datasets`. CLI: `cognee-cli datasets list`.\n\n### 2. List its documents\n\n```python\nitems = await cognee.datasets.list_data(dataset_id)  # all Data rows, oldest first\nfor item in items:\n    print(item.id, item.name, item.extension, item.created_at)\n```\n\nHTTP: `GET /api/v1/datasets/{dataset_id}/data?limit=100&offset=0` (limit up\nto 1000; `GET .../data/count` for the total; example:\n`examples/python/dataset_data_pagination.py`). CLI:\n`cognee-cli datasets data <dataset_uuid>`.\n\nEach item has `id`, `name`, `created_at`, `extension`, `mime_type`,\n`raw_data_location`, `dataset_id`, `label`, `external_metadata` (including\nany `node_set`), and `data_size`.\n\n### 3. Read the content before deciding\n\nNames are often `text_<hash>.txt`, so read the content to find what the user\nmeans.\n\n- HTTP: `GET /api/v1/datasets/{dataset_id}/data/{data_id}/raw` returns the\n  stored file (404 if it is gone).\n- SDK: there is no \"get raw\" helper; open the stored location:\n\n```python\nfrom cognee.infrastructure.files.utils.open_data_file import open_data_file\n\nasync with open_data_file(item.raw_data_location, mode=\"rb\") as f:\n    preview = f.read(2000).decode(\"utf-8\", errors=\"replace\")\n```\n\nJudge matches by meaning, not only by keywords, and show the user the\ncandidates (name + a short preview) before deleting.\n\n### 4. Delete\n\n| Goal | Call | What remains |\n|---|---|---|\n| One document | `forget(data_id=..., dataset_id=...)` (or `dataset=\"name\"`) | Nothing of that document; shared entities stay while another document still references them |\n| A whole dataset | `forget(dataset=\"name\")` or `forget(dataset_id=...)` | The dataset is deleted outright: the record, its data rows, graph and vector stores, and attributed sessions |\n| Rebuild a dataset's graph later | `forget(dataset=\"name\", memory_only=True)` | Raw files and data rows; graph, vectors, sessions and pipeline status are reset, so the data can be re-processed |\n| One document's memory only | `forget(dataset=\"name\", data_id=..., memory_only=True)` | That document's raw file and row |\n| Every dataset the user can delete | `forget(everything=True)` | Nothing, in any dataset the user has `delete` on in the current tenant (shared ones included). Only on explicit request (see the hard limits) |\n\nReturn values: `{\"data_id\", \"dataset_id\", \"status\"}` for a document,\n`{\"dataset_id\", \"status\"}` for a dataset (plus `data_records_reset` with\n`memory_only`), `{\"datasets_removed\", \"status\"}` for everything\n(`datasets_removed` counts the datasets the user can *read*, not the delete\nset).\n\n**HTTP:** `POST /api/v1/forget` with a JSON body; camelCase and snake_case\nkeys both work: `{\"datasetId\": \"...\", \"dataId\": \"...\"}`,\n`{\"dataset\": \"name\", \"memoryOnly\": true}`, `{\"everything\": true}`. Invalid\ncombinations return 422.\n\n**CLI:** `cognee-cli forget --dataset NAME | --dataset-id UUID\n[--data-id UUID] [--memory-only]`, or `--everything` / `--all`. The CLI\n**does not ask for confirmation**; confirm with the user first.\n\n## Pitfalls\n\n- **A `data_id` that is not in the dataset returns success and deletes\n  nothing.** The delete path treats an unknown id as a custom-graph-model\n  delete. Always take the id from `list_data` for that same dataset, and\n  check it is still listed afterwards if it matters.\n- **Pass either `dataset` or `dataset_id`, not both** (`ValueError`).\n  `data_id` and `memory_only` both need a dataset.\n- **`memory_only` is ignored when `everything=True`** in the SDK (the CLI\n  rejects the combination). `everything=True` always deletes everything.\n- **Not found and not allowed look the same.** An unknown dataset name and\n  one the user cannot delete both raise `DatasetNotFoundError`. Deleting\n  needs the `delete` permission on the dataset (see the `cognee-permissions`\n  skill). `everything=True` deletes every dataset the user has `delete`\n  permission on in the current tenant, including datasets shared to them\n  with delete rights, not only the ones they own.\n- **Sessions that cited deleted data are invalidated** so recall stops\n  returning answers built on it. Agent-trace entries are not invalidated.\n- **Changing a document is not a delete.** To replace a document's content,\n  use `cognee.update(data_id=..., data=..., dataset_id=...)`, which keeps its\n  id and re-extracts only the changed parts.\n- `cognee.delete()` is deprecated; use `forget()`.\n\n## How it works\n\n`forget()` resolves the dataset with the `delete` permission, then:\n\n- **One document** → `datasets.delete_data()`: takes the dataset lock,\n  deletes the graph nodes and edges the document owns, the matching vectors\n  and edge evidence, invalidates sessions that cited them, then deletes the\n  `Data` row. Ownership is tracked per document (source-refs on graph\n  elements), so an entity shared by two documents survives until both are\n  deleted. Raw files are reference-counted by storage location.\n- **A dataset** → `datasets.empty_dataset()`.\n- **`memory_only`** → drops the dataset's graph/vector memory and resets its\n  pipeline status, leaving raw data for a rebuild.\n- **`everything`** → `datasets.delete_all()` over every dataset the user has\n  `delete` on in the current tenant, plus a full prune of the session cache\n  (when caching or usage logging is on). This wipes **every user's**\n  sessions (Redis FLUSHDB / the whole fs cache / all SQL cache tables), not\n  just this user's.\n\nKey files:\n\n- `cognee/api/v1/forget/forget.py` (SDK), `routers/get_forget_router.py`\n  (HTTP), `cognee/cli/commands/forget_command.py` (CLI)\n- `cognee/api/v1/datasets/datasets.py` (`list_datasets`, `list_data`,\n  `delete_data`, `empty_dataset`, `delete_all`)\n- `cognee/api/v1/datasets/routers/get_datasets_router.py` (list, count, raw)\n- `cognee/infrastructure/databases/provenance/source_refs.py` (per-document\n  ownership of graph elements)\n- `cognee/infrastructure/files/utils/open_data_file.py`\n\n## Extending it\n\n- Anything new that writes graph nodes or edges for a document must record\n  its source-refs, or `forget(data_id=...)` cannot find and remove it.\n- Anything new that stores per-document data outside the graph (like edge\n  evidence) needs a cleanup step in the delete path and in `memory_only`.\n- Unit tests for `forget()` are in `cognee/tests/unit/api/v1/forget/`\n  (argument validation, the HTTP endpoint, `memory_only`); cover both the\n  document and the `memory_only` paths for new deletion behaviour.\n",".agents/skills/cognee-community/SKILL.md":"---\nname: cognee-community\ndescription: Use when the user needs something that ships outside cognee core — community database adapters (Qdrant, Milvus, Weaviate, Redis, Pinecone, FalkorDB, Memgraph, DuckDB, NetworkX, …), data-source connectors (Slack, Gmail, Notion, Confluence, Google Drive), custom tasks/pipelines/retrievers (Exa, ScrapeGraph, codify), Keywords AI observability — or wants to contribute a package to the cognee-community repo.\n---\n\n# Use and contribute cognee-community packages\n\nCommunity-maintained plugins live in a separate monorepo:\nhttps://github.com/topoteretes/cognee-community. Everything installable is\nunder `packages/`; `experimental/` holds demos (n8n nodes, dlt demos,\nbauplan, tower) that are not published packages. Each package publishes to\nPyPI as `cognee-community-<family>-<kind>-<name>` and imports as the same\nname with underscores.\n\n## Package families\n\n| Family | Packages |\n|---|---|\n| Vector adapters | azureaisearch, milvus, moss, opengauss, opensearch, pinecone, qdrant, redis, singlestore, turbopuffer, valkey, weaviate |\n| Graph adapters | arcadedb, memgraph, networkx, pggraph, spanner, turbopuffer, turingdb |\n| Hybrid (graph+vector in one DB) | arcadedb, duckdb, falkordb, helixdb |\n| Connectors (data sources) | confluence, gmail, google-drive, notion, slack |\n| Tasks / pipelines / retrievers | codify_tasks, codify_pipeline, code_retriever, exa_tasks, scrapegraph_tasks |\n| Observability | keywordsai (`MONITORING_TOOL=keywordsai` + `KEYWORDSAI_API_KEY`) |\n\n## Using a database adapter\n\nInstall, then **import the package's `register` module before cognee touches\nany engine** — registration is what makes the provider name valid:\n\n```python\nuv pip install cognee-community-vector-adapter-qdrant\n```\n\n```python\nimport cognee\nfrom cognee import config\nfrom cognee_community_vector_adapter_qdrant import register  # noqa: F401\n\nconfig.set_vector_db_config(\n    {\n        \"vector_db_provider\": \"qdrant\",\n        \"vector_db_url\": \"http://localhost:6333\",\n        \"vector_db_key\": \"...\",\n        \"vector_dataset_database_handler\": \"qdrant\",  # only if the adapter ships one\n    }\n)\n```\n\nThe `register.py` calls `use_vector_adapter(name, AdapterClass)` /\n`use_graph_adapter(...)`. Setting `VECTOR_DB_PROVIDER`/`GRAPH_DATABASE_PROVIDER`\nto a community name **without** the register import raises \"Unsupported\nvector database provider\". Hybrid adapters (e.g. falkordb) register as both\ngraph and vector — set both configs to the same provider name.\n\n**Multi-tenancy caveat**: with `ENABLE_BACKEND_ACCESS_CONTROL=true` (the\ndefault), both backends must have a dataset-database handler or cognee raises\n`EnvironmentError`. Community adapters that ship one (registered via\n`use_dataset_database_handler` in their `register.py`): qdrant, moss,\nsinglestore, turbopuffer (vector + graph), falkordb, arcadedb, helixdb. All\nother community adapters need `ENABLE_BACKEND_ACCESS_CONTROL=false`.\n\n## Using a connector\n\nConnectors expose a `dlt` source you hand straight to `remember()`; they\nreuse core's DLT ingestion path, so snapshot sync and forget-on-delete work\nwith no core changes:\n\n```python\nfrom cognee_community_connector_slack import slack_export_source\n\nawait cognee.remember(\n    slack_export_source(\"/path/to/slack-export\"),\n    dataset_name=\"team-slack-export\",  # use a dedicated dataset\n    max_rows_per_table=0,\n)\n```\n\nSame shape for gmail (\"ask my inbox\"), notion, confluence, and google-drive\n(incremental, forget-on-delete). Each package README documents its\ncredentials; always give a connector its own dataset.\n\n## Verifying an install\n\nEvery package has `examples/example.py` (run `uv run python examples/example.py`\nfrom the package dir) and a `tests/` directory. An LLM API key is still\nrequired (`LLM_API_KEY`, OpenAI by default).\n\n## Contributing a package\n\n- **Branch from `main`** — unlike the core repo, cognee-community does not\n  use a `dev` branch.\n- Follow the existing structure: package dir under `packages/<family>/<name>/`\n  with `pyproject.toml`, a `README.md` (install + usage), `examples/example.py`,\n  and `tests/` that go beyond the example.\n- New DB adapters implement `VectorDBInterface` / `GraphDBInterface` from\n  core, expose a `register.py`, and should run the shared conformance tests\n  in `packages/shared/contract_suite/` (vector_contract.py / graph_contract.py).\n- Add a handler via `use_dataset_database_handler(...)` if the backend can\n  isolate per user+dataset — that's what makes it work with access control on.\n- Name it `cognee-community-<family>-<kind>-<name>` and add it to the tables\n  in the repo README. Lint config is the repo-root `ruff.toml`.\n",".agents/skills/cognee-cli/SKILL.md":"---\nname: cognee-cli\ndescription: Use when the user wants to drive cognee from the terminal with cognee-cli — remember/recall/forget/improve memory commands, managing datasets and config, or database migrations.\n---\n\n# Use the cognee CLI\n\n`cognee-cli` ships with the package (entry point in `cognee/cli/_cognee.py`;\neach command lives in `cognee/cli/commands/`). Every command has\n`--help` for its flags, but only a few (`demo`, `eval`, `serve`,\n`push`, `upgrade`, `downgrade`, `stamp`, and `search` with one CODE example)\ninclude usage examples — for the memory commands use the examples\nin this file. Needs `LLM_API_KEY` configured, same as the SDK.\n\n## Core flow\n\nThe memory commands are the primary surface as of cognee 1.x:\n\n```bash\ncognee-cli remember \"Your text here\"         # also accepts file paths / URLs\ncognee-cli remember ./docs --dataset-name my_project\ncognee-cli recall \"Your question\"            # query the graph\ncognee-cli recall \"keyword\" --query-type CHUNKS\ncognee-cli forget --all                      # wipe local state\n```\n\n`remember` is ingest + graph build in one step (`add` + `cognify` under the\nhood); `--background`/`-b` runs the cognify stage in the background, and\n`--dry-run` estimates LLM tokens/cost without ingesting. `recall` takes\n`--datasets`/`-d`, `--top-k`/`-k` (default 10), and `--session-id`/`-s`.\n\n`forget` targets `--dataset`, `--dataset-id`, `--data-id` (needs a dataset), or\n`--everything`/`--all` — one unified command replacing the older `delete` and\nempty-dataset paths. `--memory-only` (with a dataset) drops the graph and\nvectors but keeps the raw files, so the data can be rebuilt.\n\n> **`forget --all` does not ask for confirmation.** It deletes every dataset\n> immediately, even on a non-interactive stdin. The legacy `delete --all`\n> prompts `Delete ALL data from cognee? [y/N]` first, so switching to `forget`\n> silently drops that safety net — script it with care.\n\n`--query-type` accepts 10 of the SDK's 20 `SearchType` values — the list in\n`cognee/cli/config.py:SEARCH_TYPE_CHOICES`: HYBRID_COMPLETION, GRAPH_COMPLETION,\nRAG_COMPLETION, CHUNKS, CHUNKS_LEXICAL, SUMMARIES, CODE, CYPHER, GRAPH_REPORT,\nSKILLS. The rest (TEMPORAL, GRAPH_COMPLETION_COT,\nAGENTIC_COMPLETION, NATURAL_LANGUAGE, …) are SDK-only, e.g.\n`cognee.recall(q, query_type=SearchType.TEMPORAL)`.\n\nWhen `--query-type` is omitted the CLI uses `HYBRID_COMPLETION`\n(`DEFAULT_SEARCH_TYPE`), whereas the SDK's `cognee.recall()` auto-routes\nbetween search types. `--top-k` defaults to 10 on the CLI and 15 in the SDK.\n\n## Session memory and enrichment\n\nSession entries are currently written from the SDK — `cognee.remember(...,\nsession_id=\"chat_1\")` — not the CLI (`cognee-cli remember` has no session\nflag). The CLI side of session memory is reading and bridging:\n\n```bash\ncognee-cli recall \"question\" -s chat_1       # session cache first: without -d/-t\n                                             # this searches the session directly\ncognee-cli sessions get                      # retrieve session Q&A history\ncognee-cli improve -d my_project -s chat_1   # bridge session content into the graph\ncognee-cli improve -d my_project             # enrich/index the graph (no session)\ncognee-cli feedback ...                      # attach feedback to results\n```\n\n`improve` also takes `--feedback-alpha` (learning rate in\n(0, 1]; default `IMPROVE_FEEDBACK_ALPHA`, 0.1), `--build-global-context-index`,\n`--build-truth-subspace` (both opt-in stages; the truth subspace needs\n`-s`), and `--background`/`-b` (`--node-name` is deprecated: it warns and is\nignored). It prints one line per stage — name, status\n(`completed` / `already_completed` / `skipped` / `errored`) and the skip\nreason (e.g. `no_session_ids`, `lock_held`, `opt_in_disabled`).\n`remember`/`improve` build their graphs through `cognify()`, so cognify-level\nsettings (e.g. `PROVENANCE_TRACKING=true`) apply to them too.\n\n## Legacy / lower-level commands\n\n`add`, `cognify`, `search`, and `delete` still ship and are what the\nmemory commands call underneath. Use them only to drive a single stage in\nisolation; prefer `remember`/`recall`/`forget`/`improve` otherwise.\n\n```bash\ncognee-cli add \"text\" && cognee-cli cognify  # what `remember` does in one step\ncognee-cli search \"question\"                 # `recall` minus routing/scope/session sources\ncognee-cli delete --all                      # superseded by `forget --all`\n```\n\n## Management\n\n```bash\ncognee-cli datasets list                     # dataset operations\ncognee-cli config get [key] [--show-secrets] # view one/all settings (API keys masked by default)\ncognee-cli config set <key> <value>          # set + persist to ./.env in the cwd\ncognee-cli config unset <key>                # reset a key to its default (also persisted)\ncognee-cli -ui                               # launch API server + UI (see cognee-server skill)\ncognee-cli serve --url http://localhost:8000 # connect CLI/SDK to a running instance\n```\n\n## Database migrations\n\ncognee has two migration chains: the relational schema (Alembic, in\n`cognee/alembic/`) and the graph/vector data chain (slugs registered in\n`cognee/modules/migrations/registry.py`). Both run automatically — at API\nserver startup and on the first write (`remember`, `add`, `cognify`,\n`improve`, …) in an SDK/CLI process — unless `ENABLE_AUTO_MIGRATIONS=false`.\nSo you rarely need these commands; they are for inspecting state, disabled\nauto-migration, and rollbacks. There is no `migrate` command.\n\n```bash\ncognee-cli current                    # stamped revision per database (per dataset\n                                      # with access control on)\ncognee-cli history                    # the data-migration chain, newest first\ncognee-cli upgrade                    # relational to head, then data chain to head\ncognee-cli upgrade <slug>             # data chain up to and including <slug>\ncognee-cli upgrade --alembic <rev>    # pin the relational (Alembic) target\ncognee-cli downgrade <slug|base>      # REWRITES DATA; revision is required,\n                                      # prompts unless --force; --dataset <uuid>\n                                      # (repeatable) limits it\ncognee-cli stamp <head|base|slug>     # set the stored revision WITHOUT running\n                                      # anything; prompts unless --force;\n                                      # --dataset <uuid> (repeatable) limits it\n```\n\nThe positional revision is always a **data-chain slug**; the relational\ntarget goes through `--alembic`. `downgrade` leaves the relational schema\nalone unless you pass `--alembic`. `upgrade` runs even when\n`ENABLE_AUTO_MIGRATIONS=false`. `--alembic-path` (or `COGNEE_ALEMBIC_PATH`)\npoints at a custom Alembic scripts directory.\n\n## Gotchas\n\n- The CLI initializes cognee lazily; the first command in a fresh environment\n  is slow (DB + model setup), later ones are fast.\n- `remember` (and `add`) without `--dataset-name` targets the default dataset\n  `main_dataset`; `recall`/`search` operate across your accessible datasets\n  unless a dataset is given.\n- `forget` refuses to run bare — pass `--dataset`, `--dataset-id`, `--data-id`\n  (with a dataset), or `--everything`/`--all`.\n- Session commands (`recall -s`, `sessions get`, `improve -s`) require\n  `CACHING=true` (the default) — with it off, session reads return nothing and\n  SDK session writes raise. To cut read latency and token cost while keeping\n  session memory, `cognee-cli config set AUTO_FEEDBACK false` — by default\n  cognee makes one structured-output LLM call per answered query to self-tune\n  its memory.\n- `config set`/`config unset` write to the `.env` file in whatever directory\n  you run the command from (creating it if missing). `config reset` (reset\n  *all* keys) is still not implemented.\n- **Which `.env` actually wins is not always the cwd one.** At import, cognee\n  calls `dotenv.load_dotenv(override=True)`, which resolves relative to the\n  *cognee package location*, not your working directory. In a source/editable\n  checkout (`uv pip install -e .`) a `.env` at the repo root therefore shadows\n  the `.env` in the directory you ran from — and because `override=True`, it\n  also beats variables you `export`ed. Symptom: `config set` appears to do\n  nothing, or the CLI connects to a backend you thought you had overridden.\n  To test against different settings, move the repo `.env` aside, or set\n  values programmatically after import (`cognee.config.set_*`). (Under\n  `python -c` the cwd `.env` does win, because dotenv falls back to the cwd\n  when `__main__` has no `__file__` — which is why the same command can\n  behave differently as a script vs. `-c`.)\n",".agents/skills/cognee-custom-pipelines/SKILL.md":"---\nname: cognee-custom-pipelines\ndescription: Use when building your own cognee processing — writing custom tasks, chaining them into a pipeline with run_custom_pipeline or the lightweight run_pipeline (from cognee.pipelines import run_pipeline), storing custom DataPoints with add_data_points, running custom enrichment over the existing graph, checking pipeline run status, or debugging how data flows between tasks (batch_size, data_per_batch, ctx, Drop, enriches).\n---\n\n# Custom tasks and pipelines\n\nEverything cognee does runs as a **pipeline**: an ordered list of **tasks**,\neach a plain Python function whose output feeds the next one. `remember()`\nis the right tool for ordinary ingestion. Build a pipeline when you need\nprocessing cognee does not ship: your own extraction, your own node types,\nor a post-processing step over the graph.\n\n```python\nimport cognee\nfrom cognee.modules.pipelines import Task\nfrom cognee.tasks.storage import add_data_points\nfrom cognee.low_level import DataPoint\n\n\nclass Person(DataPoint):\n    name: str\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nasync def extract_people(data_items: list) -> list[Person]:\n    people = []\n    for item in data_items:  # always a list, see below\n        text = item if isinstance(item, str) else \"\"\n        people += [Person(name=n.strip()) for n in text.split(\",\") if n.strip()]\n    return people\n\n\nresult = await cognee.run_custom_pipeline(\n    tasks=[\n        Task(extract_people, needs_llm=False),\n        Task(add_data_points, needs_llm=False),  # store in graph + vector DBs\n    ],\n    data=[\"Ada Lovelace, Alan Turing\"],\n    dataset=\"people\",\n)\n```\n\n## Use it\n\n### Pick the runner\n\nThere are three, and two share the name `run_pipeline`:\n\n| Runner | Import | Use it for |\n|---|---|---|\n| `cognee.run_custom_pipeline(...)` | `cognee` | The normal choice: runs your tasks against a dataset with permissions, a per-dataset lock, run records, and status |\n| Full orchestrator `run_pipeline(tasks=..., data=..., datasets=...)` | `cognee.modules.pipelines` | What `run_custom_pipeline` and `cognify` call; yields `PipelineRunInfo` |\n| Lightweight `run_pipeline([...], data=...)` | `from cognee.pipelines import run_pipeline` (after `import cognee`, the attribute `cognee.pipelines.run_pipeline` is the orchestrator) | Quick chains of `task()` specs with no permissions, locks, run rows, or migrations; returns the last step's outputs |\n\n`cognee.run_custom_pipeline(tasks, data=None, dataset=\"main_dataset\",\nuser=None, incremental_loading=False, data_per_batch=20,\nrun_in_background=False, pipeline_name=\"custom_pipeline\", data_cache=False,\n...)` returns `{dataset_id: PipelineRunInfo}` (the started run when\n`run_in_background=True`). With `data=None` it runs over the dataset's\nexisting documents (`Data` rows).\n\n### Write a task\n\n```python\nfrom cognee.modules.pipelines import Task\nfrom cognee.modules.pipelines.models import PipelineContext\nfrom cognee.modules.pipelines.tasks.task import task_summary\nfrom cognee.pipelines import Drop\n\n\n@task_summary(\"Tagged {n} chunk(s)\")\nasync def tag_chunks(chunks: list, ctx: PipelineContext = None, label: str = \"x\"):\n    for chunk in chunks:\n        chunk.metadata[\"label\"] = label\n    return chunks  # or yield per item; return/yield Drop to discard\n\n\ntag = Task(tag_chunks, label=\"reviewed\", batch_size=10, needs_llm=False)\n```\n\n- A task is an `async def`, a generator, an async generator, or a plain\n  `def`. Extra `Task(fn, *args, **kwargs)` arguments are passed after the\n  pipeline data.\n- `needs_llm=False` on tasks that never call an LLM lets an LLM-free\n  pipeline skip the LLM connection check.\n- `ctx` (injected by the parameter **name** `ctx`) carries `user`,\n  `data_item`, `dataset`, `pipeline_run_id`, `pipeline_name`, and `extras`.\n- `task.with_config(batch_size=..., **kwargs)` returns a modified copy.\n\n### How data flows\n\n- **Each document runs the whole chain on its own** with `run_custom_pipeline`\n  or the orchestrator, and the first task receives it as a **one-element\n  list** (`[data_item]`), not the bare item. The lightweight `run_pipeline`\n  passes `data` to the first task unchanged.\n- **`data_per_batch`** (default 20) is how many documents run at the same\n  time. It is a concurrency limit, not a batch size.\n- **`batch_size` belongs to the consumer.** A task's `batch_size` decides how\n  the *previous* task's generator output is grouped before it is passed in.\n  Generator tasks always hand over lists; a coroutine or function hands over\n  its single return value.\n- **Streaming:** each upstream result goes down the chain immediately, so a\n  downstream task can run many times per document.\n- **`enriches=True`:** if the task returns `None`, its input is passed on\n  unchanged (coroutines and functions only, not generators).\n- **`Drop`:** returning or yielding it removes that item from the stream.\n- Every `DataPoint` passing through is stamped automatically with where it\n  came from (`source_pipeline`, `source_task`, `source_user`, …).\n\n### Store results\n\n`add_data_points(data_points, custom_edges=None, graph_only=False)` writes a list of `DataPoint`s to the graph and indexes\ntheir `index_fields` in the vector DB. It returns the same list, so it can\nsit mid-chain. Give every node type `identity_fields` so repeated runs merge\ninstead of duplicating (see the `cognee-custom-graph-models` skill).\n\n### Work on the existing graph\n\n`cognee.memify`, `cognee-cli memify`, `POST /api/v1/memify` and `improve()`'s\n`extraction_tasks` / `enrichment_tasks` are deprecated and removed in the next\nrelease. Run a post-processing step over the\ngraph with `run_custom_pipeline`: the task reads the graph itself, and one\nplaceholder item as `data` makes the chain run once instead of once per\ndocument.\n\n```python\nfrom cognee.infrastructure.databases.graph import get_graph_engine\n\n\nasync def enrich_graph(_items: list):\n    graph = await get_graph_engine()  # the dataset's graph inside the pipeline\n    nodes, edges = await graph.get_graph_data()\n    return [...]  # new DataPoints for add_data_points\n\n\nawait cognee.run_custom_pipeline(\n    tasks=[Task(enrich_graph, needs_llm=False), Task(add_data_points, needs_llm=False)],\n    data=[{}],\n    dataset=\"people\",\n)\n```\n\nFor cognee's own enrichment (session bridging, feedback weights, conflict\nreview, global context index) call `improve()`.\n\n### Check status\n\n```python\nstatus = await cognee.datasets.get_status([dataset_id], pipeline_names=[\"custom_pipeline\"])\n```\n\nWithout `pipeline_names` it reports only `cognify_pipeline`. It returns\n`{str(dataset_id): PipelineRunStatus}` (`{str(dataset_id): {pipeline_name:\nstatus}}` for several `pipeline_names`): `DATASET_PROCESSING_STARTED`,\n`_COMPLETED`, or `_ERRORED` (`_INITIATED` exists only on legacy rows). The value `run_custom_pipeline`\nreturns per dataset is a `PipelineRunInfo` instead, whose class names the\noutcome: `PipelineRunCompleted`, `PipelineRunAlreadyCompleted`,\n`PipelineRunErrored`, and so on.\n\n## Pitfalls\n\n- **Wrong `run_pipeline`.** The one imported via\n  `from cognee.pipelines import run_pipeline` wants `task()`\n  specs *called* (`extract()`, not `extract`) and raises `TypeError`\n  otherwise; the orchestrator in `cognee.modules.pipelines` wants `Task`\n  objects and raises `WrongTaskTypeError` otherwise.\n- **`run_custom_pipeline` accepts only `Task` objects** despite its type hint;\n  string task names are not resolved.\n- **Some callables are rejected** by `Task` (`ValueError: Unsupported task\n  type`): bound methods and `functools.partial`s of a plain (non-generator)\n  sync function, and callable objects (instances with `__call__`). Generator\n  and async variants, plain functions, and lambdas work. When in doubt, wrap it\n  in a plain `def` / `async def`.\n- **`run_custom_pipeline` does not run database migrations.** On an existing\n  database, run `await cognee.run_migrations()` (or any `remember()` first).\n- **Nodes duplicate on every run** when a DataPoint has no\n  `identity_fields` (or `Dedup()` fields). `examples/guides/custom_data_models.py`\n  and `examples/guides/custom_tasks_and_pipelines.py` have this bug; don't\n  copy it.\n\n## How it works\n\n`run_custom_pipeline` → orchestrator `run_pipeline` (checks write\npermission, takes the per-dataset lock, records a `PipelineRun`) →\n`run_tasks` (a semaphore of `data_per_batch`, one chain per document) →\n`run_tasks_base` (streams each task's output into the next, batching by the\nconsumer's `batch_size`, injecting `ctx`, stamping provenance).\n\n- Package overview and the runner semantics: `cognee/modules/pipelines/__init__.py`\n- `Task`, `task()`, `TaskSpec`, `BoundTask`, `@task_summary`: `cognee/modules/pipelines/tasks/task.py`\n- Orchestrator: `cognee/modules/pipelines/operations/pipeline.py`; execution:\n  `run_tasks.py`, `run_tasks_base.py`, `run_tasks_data_item.py`\n- Lightweight runner: `cognee/modules/pipelines/operations/run_pipeline.py`,\n  exported from `cognee/pipelines/`\n- Context: `cognee/modules/pipelines/models/PipelineContext.py`\n- `run_custom_pipeline`: `cognee/modules/run_custom_pipeline/run_custom_pipeline.py`\n- Storage: `cognee/tasks/storage/add_data_points.py`\n- Index of all shipped tasks: `cognee/tasks/README.md`\n\nExamples:\n\n- `examples/demos/custom_pipelines/custom_pipeline_single_object_example.py`:\n  the best reference. It runs over added documents, does LLM extraction into\n  typed DataPoints, then recalls. Its models declare identity with `Dedup()`\n  (the `Annotated` alternative to `metadata[\"identity_fields\"]`).\n- `examples/demos/custom_pipelines/organizational_hierarchy/`: low-level\n  `run_tasks`, no LLM, dedup via `identity_fields`, status polling.\n- `examples/demos/custom_pipelines/custom_cognify_pipeline_example.py`:\n  rebuilds add + cognify from the default task list.\n\n## Extending it\n\n- **A new shipped task:** put it in the `cognee/tasks/` subpackage for its\n  stage, export it from that package's `__init__.py`, follow the template in\n  `cognee/tasks/README.md`, and add a unit test under `cognee/tests/unit/tasks/`.\n- Pipeline tests: `cognee/tests/unit/modules/pipelines/` (runner semantics,\n  context, provenance, rollback) and `cognee/tests/unit/pipelines/` (the\n  lightweight API).\n",".agents/skills/cognee-custom-graph-models/SKILL.md":"---\nname: cognee-custom-graph-models\ndescription: Use when defining the shape of cognee's knowledge graph with graph_model= — writing DataPoint node classes, choosing identity and index fields so nodes merge and are searchable, declaring typed Edge fields and FromIdentity references, building a model from a JSON schema, or debugging duplicated nodes, missing edges, or InvalidReferenceTypeError.\n---\n\n# Custom graph models\n\nBy default cognee extracts a generic `KnowledgeGraph` of entities and\nrelationships. Pass your own model with `graph_model=` and the LLM fills\nyour node and edge types instead.\n\n```python\nfrom typing import Annotated, Literal\nimport cognee\nfrom cognee.low_level import DataPoint, Edge, FromIdentity\n\n\nclass Role(DataPoint):\n    name: str\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nclass Person(DataPoint):\n    name: str\n    is_a: Annotated[Role, FromIdentity()] | None = None  # reference by name\n    reports_to: list[Edge[\"Person\", \"Person\"]] = []  # edge owned by Person\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nclass PeopleGraph(DataPoint):  # the root the LLM fills\n    people: list[Person]\n    friends_with: list[Edge[Person, Person]] = []\n    family: list[Edge[Person, Person, Literal[\"married_to\", \"sibling_of\"]]] = []\n    metadata: dict = {\"index_fields\": [], \"transparent\": True}\n\n\nawait cognee.remember(text, graph_model=PeopleGraph, custom_prompt=\"Extract every person...\")\n```\n\nFull example: `examples/guides/custom_graph_model.py`.\n\n## Use it\n\n### Nodes: DataPoint classes\n\nEvery node type subclasses `DataPoint` (`from cognee.low_level import\nDataPoint`). Its fields become:\n\n- **Node properties:** scalars, strings, dicts, and anything that is not a\n  DataPoint.\n- **Edges named after the field:** a field holding a DataPoint or a list of\n  DataPoints. `members: list[Person]` becomes `members` edges.\n\n`dict[str, Person]`, sets and plain tuples are stored as properties, not\nedges.\n\n### Identity and search: `metadata`\n\n| Key | What it does |\n|---|---|\n| `identity_fields` | The node id is derived from these field values (normalized: lowercased, spaces to `_`, apostrophes removed). The same entity from two chunks or two runs becomes **one node**. |\n| `index_fields` | Each field gets a vector collection named `<ClassName>_<field>`, so recall can find the node. |\n| `transparent` | The node is not stored; its children take its place. Use it for a root container like `PeopleGraph`. |\n\n**Without `identity_fields` every node gets a random id, so the same person\nis duplicated in every chunk and every run.** Set it on every node type that\nrepresents a real-world entity.\n\n**Write `metadata` explicitly**, as in the examples above. There is also an\nannotation shortcut (`from cognee.infrastructure.engine import Dedup,\nEmbeddable`; `name: Annotated[str, Embeddable(), Dedup()]`), but today only\nhalf of it works:\n\n- `Dedup()` works: ids are derived from the marked fields.\n- `Embeddable()` does not index. The markers update the class-level\n  default, but each instance still carries `{\"index_fields\": []}`, and\n  indexing reads the instance, so no vector collection is created and\n  recall cannot find the node.\n\nMarkers are also ignored entirely when the class declares `metadata`\nitself.\n\n### Typed edges: `list[Edge[Source, Target, Name]]`\n\nThe LLM answers edges as flat rows of identity strings (`source`, `target`),\nand cognee resolves them to the extracted nodes. The third parameter\ncontrols the relationship name:\n\n| Declaration | Relationship name |\n|---|---|\n| `list[Edge[Person, Person]]` | The field name (`friends_with`) |\n| `list[Edge[Person, Person, Literal[\"a\", \"b\"]]]` | The LLM picks one value |\n| `list[Edge[Person, Person, str]]` | Free-form from the LLM, normalized |\n\n- **Where to declare:** on the root model for relationships with no obvious\n  owner, or on the owning node. On the owner, endpoints of the owner's own\n  type must be strings (`Edge[\"Person\", \"Person\"]`), because the class is\n  not defined yet inside its own body.\n- **Always a list:** `Edge[...]` or `Edge[...] | None` on its own raises.\n- **Both endpoint types need exactly one `identity_fields` entry.**\n\n### References: `Annotated[Target, FromIdentity()]`\n\nInstead of a nested object, the LLM answers the identity string of a node\n(`is_a: \"engineer\"`), and cognee links to that node. Supported spellings:\n`Target`, `Target | None`, `list[Target]`, `list[Target] | None`.\nAnything else raises `InvalidReferenceTypeError`. The target needs exactly\none identity field, and its other required fields need defaults.\n\n### Edge values you build by hand\n\n`Edge(source=..., target=..., relationship_type=..., weight=...,\nproperties={...})`. An omitted `source` falls back to the node declaring the\nfield; on a parametrized field that node must be the declared `Source`\ntype, or it raises. On a root container, always pass `source=`. The tuple\nform `(Edge(weight=0.8), target_node)` attaches edge properties to a plain\nDataPoint field (`examples/guides/custom_data_models.py`).\n\n### From JSON instead of Python\n\n- `cognee.low_level.graph_model_from_spec(spec)`: a small entity/relation\n  spec (names, fields, `one`/`many` relations) compiled to DataPoint\n  classes, with identity and index on `name` by default. Example:\n  `examples/guides/graph_model_from_json.py`.\n- `cognee.low_level.graph_schema_to_graph_model(json_schema)`: a JSON\n  Schema (needs a top-level `title`; only internal `#` refs).\n- HTTP: `POST /api/v1/remember` takes a `graph_model` form field (JSON\n  schema string); `POST /api/v1/cognify` takes a `graphModel` JSON object.\n  `POST /api/v1/llm/infer-schema` proposes a schema from sample text.\n\nNeither JSON path can express typed `Edge` fields or `FromIdentity`; use\nPython classes for those.\n\n## Pitfalls\n\n- **Duplicated nodes** → missing `identity_fields`.\n- **Node never shows up in recall** → no `index_fields`, or the recalling\n  process never imported the model class (graph completion searches the\n  collections of DataPoint classes loaded in that process).\n- **Edge rows silently missing** → an unresolved row is dropped with a\n  warning. Endpoints resolve by **exact type** against nodes extracted from\n  the same chunk: a subclass instance does not match where its base is\n  declared, and a node from another chunk or an earlier run is not a\n  candidate.\n- **`InvalidReferenceTypeError`, \"declares Edge in a shape the LLM\n  extraction cannot fill\"** → an unsupported `FromIdentity` or `Edge`\n  spelling. These are raised when the model is converted during\n  extraction, not at class definition, so they appear mid-pipeline.\n- **String endpoints resolve only to the owning model itself or a\n  module-level class.** A string naming another class defined inside a\n  function raises `InvalidReferenceTypeError`, so define models at module\n  level.\n- **Field names that collide with DataPoint's own fields** (`id`, `type`,\n  `version`, `metadata`, `created_at`, `belongs_to_set`, …) are stripped\n  from what the LLM sees. Rename them.\n- **A subclass that overrides `metadata`** replaces the parent's entirely.\n  Dropping `identity_fields` only logs a warning. A subclass also hashes ids\n  under its own class name.\n- **Write a `custom_prompt`.** Without one the generic knowledge-graph\n  prompt is used; your schema reaches the LLM only as structured output.\n- **Not with GLiNER.** `extractor=\"gliner_demo\"` (alias `\"gliner\"`) raises\n  with a custom `graph_model`, and so does the default `GRAPH_EXTRACTOR=auto`\n  when no LLM key is configured (it resolves to `gliner_demo`).\n- **Remote mode drops it.** After `cognee.serve(url)`, `remember()` and\n  `cognify()` do not forward `graph_model`; the server builds a generic\n  graph.\n- A custom model skips the generic path's ontology resolution, per-graph\n  node dedup. Summaries still run.\n\n## How it works\n\n`extract_content_graph` converts a DataPoint model into a plain Pydantic\nmodel for the LLM: infrastructure fields and `metadata` are stripped, typed\nedge fields become row lists (`FriendsWithEdge` with `source`/`target`\nstrings), and `FromIdentity` fields become strings. The answer is converted\nback into DataPoint instances with ids from `identity_fields`, edge rows are\nresolved against the nodes in that answer, and the result is attached to the\nchunk (`chunk.contains`) and stored by `add_data_points`. Ownership is\nrecorded per document, so `forget(data_id=...)` removes a custom-model\ndocument's nodes while shared nodes survive.\n\n- LLM boundary, both directions: `cognee/shared/llm_graph_model.py`\n- DataPoint, metadata, ids: `cognee/infrastructure/engine/models/DataPoint.py`\n- Markers: `cognee/infrastructure/engine/models/FieldAnnotations.py`\n- Edge: `cognee/infrastructure/engine/models/Edge.py`\n- Property vs edge decision: `cognee/modules/graph/utils/field_edges.py`\n- Custom-model branch of extraction: `cognee/tasks/graph/extract_graph_from_data.py`\n- JSON schema / spec paths: `cognee/shared/graph_model_utils.py`,\n  `cognee/modules/graph_models/`\n- Vector collections: `cognee/tasks/storage/index_data_points.py`\n\n## Extending it\n\n- Tests for the LLM round trip: `cognee/tests/unit/modules/graph/test_content_graph_to_data_point.py`.\n  Edge typing: `cognee/tests/unit/interfaces/graph/test_typed_edge_model.py`,\n  `test_typed_edges_graph.py`. Identity: `cognee/tests/unit/infrastructure/engine/test_identity_fields.py`.\n  Property vs edge: `cognee/tests/unit/modules/graph/test_field_edges.py`.\n- Deletion of custom-model nodes: `cognee/tests/test_delete_custom_graph.py`.\n- A new `Edge` or `FromIdentity` spelling must be handled in both directions\n  in `llm_graph_model.py`, and rejected with `InvalidReferenceTypeError`\n  when unsupported, never silently accepted.\n","cognee/skill.md":"---\nname: cognee\ndescription: >\n  Use this skill whenever the user asks about Cognee, AI memory, persistent agent memory,\n  self-improving agents, agents learning from feedback, knowledge graphs, graph-based RAG,\n  long-term memory for agents, short-term memory for agents, personalization, personas,\n  temporal search, temporal knowledge graphs, ontology-based extraction, ontology grounding,\n  feedback, Cypher search, natural-language graph search, chunk search, RAG search, cross-session memory,\n  session feedback, feedback loops, session based memory, redis based memory, knowledge promotion.\n  Also use when the user describes the workflow such as:\n  \"turn documents into a knowledge graph\", \"build memory from files\", \"search my graph\",\n  \"extract entities and relations\", \"sync data into a graph\", \"update graph memory\",\n  \"store memories for an agent\", \"help my agent learn over time\", \"visualize a knowledge\n  graph built from documents\", \"let the agent learn\", \"adaptive agents\", \"personalized agents\",\n  \"session based personalization\", \"find important ontologies\", \"find custom pydantic models\",\n  \"isolate agentic behaviour\", \"add permission control to retrieval\", \"reduce context bloating\".\n---\n\n# Cognee\n\nUse this skill for **Cognee-specific Python API help** and for mapping user goals to the right\nCognee workflow.\n\n## When to apply this skill\n\nApply this skill whenever the user wants to do any of the following with Cognee:\n\n- ingest text, files, URLs, repos, or datasets\n- build or rebuild a knowledge graph\n- search documents, chunks, summaries, triplets, or graph context\n- choose a `SearchType`\n- enrich an existing graph with `improve`\n- define custom graph extraction models or `DataPoint` types\n- run custom task pipelines\n- configure LLM, graph DB, vector DB, or storage settings\n- tag and scope memory with `node_set` / NodeSets\n- build persistent memory for agents across sessions\n- create feedback loops or self-improving agent workflows\n- work with temporal extraction, ontologies, Cypher, or natural-language graph queries\n- manage datasets, sessions, feedback, deletion, updates, or visualization\n\nIf the user's intent is \"store information in memory and query it later\", prefer Cognee's\nmemory API: **remember -> recall** (plus **improve** to enrich and **forget** to delete).\n\n## Core workflow\n\n```python\nimport cognee\n\n# Store: ingest + build the graph (+ improve, because self_improvement=True by default)\nawait cognee.remember(\n    \"Your text, file path, URL, or list of inputs\",\n    dataset_name=\"main\",\n)\n\n# Query: recall picks a search strategy automatically (rule-based, no LLM call)\nresults = await cognee.recall(\"What are the key insights?\", datasets=[\"main\"])\nfor r in results:\n    print(r.source, r)  # each result is tagged \"graph\" / \"session\" / ...\n```\n\n`remember()` runs `add()` + `cognify()` and then `improve()` underneath. `recall()` wraps\n`search()` and adds routing, session memory as a source, and `source`-tagged results.\n\n## Default guidance\n\nWhen helping with Cognee:\n\n1. Start with the **simplest working path** unless the user explicitly asks for advanced\n   configuration.\n2. Prefer the memory API:\n   - `remember(...)` to store (ingest + graph build)\n   - `recall(...)` to query\n   - `improve(...)` to enrich or index an existing graph, and to bridge sessions into it\n   - `forget(...)` to delete\n3. Treat Cognee APIs as **async**.\n4. Use `dataset_name` / `datasets` to keep work organized when the user has multiple sources.\n5. Use `node_set` when the user wants lightweight tagging, project scoping, per-user memory\n   buckets, or subgraph filtering.\n6. Pass `query_type=SearchType.X` to `recall()` only when the user needs a specific strategy;\n   otherwise let it route.\n7. Recommend advanced features only when they match the task:\n   - `session_id` for fast short-term memory and conversation continuity\n   - `graph_model=` for schema-shaped extraction, `DataPoint` types for direct insertion\n   - `extractor=\"gliner_demo\"` for LLM-free graph extraction\n   - custom pipelines for non-default task orchestration\n   - feedback loops for retrieval improvement\n   - visualization tools for graph inspection\n\n## When to drop to the low-level operations\n\n`add()`, `cognify()` and `search()` still ship; the memory API calls them. Reach for\nthem only when `remember`/`recall` cannot express the job:\n\n- `cognify(datasets=[\"a\", \"b\"])` or `datasets=None` processes several datasets at once;\n  `remember()` always targets exactly one dataset.\n- Rebuilding a graph over data already in the DB (after `forget(memory_only=True)`, or with a\n  new `graph_model` / ontology) is `cognify()` only; `remember()` always runs `add()` first.\n- `search()` takes the agentic extras as first-class parameters (`skills`, `tools`, `max_iter`,\n  `code_query`, `node_type`) and returns raw `SearchResult` objects instead of tagged dicts.\n- `add()` is a staging area: use it to ingest now and `cognify()` later.\n- `prune.prune_system(metadata=True)` also drops the relational DB (users, ACLs, dataset\n  registry); `forget()` never touches those. Use prune only for full test teardown.\n\n`cognee.delete()` is deprecated in favour of `forget()`. Full comparison of the two query\nfunctions: `docs/recall-vs-search.md`.\n\n## Common tasks\n\n### Store data\n\n`remember()` accepts text, file paths, URLs, directories, git repository URLs, binary streams,\nor lists of these.\n\n```python\nawait cognee.remember(\"notes.md\", dataset_name=\"research\")\nawait cognee.remember(\"https://example.com\", dataset_name=\"research\")\nawait cognee.remember([\"paper.pdf\", \"summary.txt\"], dataset_name=\"research\")\n```\n\nUse `node_set` when the user wants data grouped into logical memory buckets.\n\n```python\nawait cognee.remember(\n    \"Customer prefers concise weekly summaries and Slack delivery.\",\n    dataset_name=\"customer_success\",\n    node_set=[\"preferences\", \"customer_123\", \"weekly_reports\"],\n)\n```\n\nUseful options:\n\n```python\nawait cognee.remember(\n    \"...\",\n    dataset_name=\"research\",\n    self_improvement=False,  # skip the improve() stage (faster)\n    run_in_background=True,  # return immediately; poll the pipeline status\n    chunk_size=1024,\n    custom_prompt=\"Extract companies, products, and partnerships.\",\n    extractor=\"gliner_demo\",  # LLM-free extraction; needs cognee[gliner]\n    dry_run=True,  # estimate LLM tokens/cost without ingesting\n)\nawait cognee.remember(\"./my_repo\", dataset_name=\"code\")  # code graph, no LLM\nawait cognee.remember(\"./skills\", dataset_name=\"ops\", content_type=\"skills\")  # SKILL.md playbooks\n```\n\n### Query memory\n\n```python\nfrom cognee import SearchType\n\nresults = await cognee.recall(\"What changed in Q1 2024?\", datasets=[\"research\"], top_k=10)\n\n# Pin a strategy when the user needs one\nresults = await cognee.recall(\n    \"What changed in Q1 2024?\",\n    query_type=SearchType.TEMPORAL,\n    datasets=[\"research\"],\n)\n\n# Answers with evidence, or validated into a Pydantic model\nresults = await cognee.recall(\"...\", include_references=True)\nresults = await cognee.recall(\"...\", response_model=MyAnswerModel)\n\n# Retrieval context only, no LLM completion (pin query_type here)\ncontext = await cognee.recall(\"...\", query_type=SearchType.GRAPH_COMPLETION, only_context=True)\n```\n\n### Scope retrieval with NodeSets\n\nUse NodeSets when the user wants to search only a subset of memory such as one project, one\ncustomer, one user, or one workflow.\n\n```python\nresults = await cognee.recall(\n    \"What are this customer's reporting preferences?\",\n    datasets=[\"customer_success\"],\n    node_name=[\"preferences\", \"customer_123\"],\n)\n```\n\n### Enrich an existing graph\n\nUse `improve()` when the user wants to improve or extend an already-built graph without\nre-ingesting. Without `session_ids` it runs only the graph-wide stages (opt-in conflict review\nand global context indexing); with them it also applies feedback weights, persists session Q&A,\nand distills session lessons into the graph.\n\n```python\nawait cognee.improve(dataset=\"research\")\nawait cognee.improve(dataset=\"research\", session_ids=[\"chat_1\"])\nawait cognee.improve(dataset=\"research\", build_global_context_index=True)\n```\n\n### Delete data\n\n`forget()` is the single deletion entry point.\n\n```python\nawait cognee.forget(data_id=data_id, dataset_id=dataset_id)  # one document\nawait cognee.forget(dataset=\"research\")  # a dataset: raw data + graph + vectors\nawait cognee.forget(dataset=\"research\", memory_only=True)  # graph + vectors only, keep raw files\nawait cognee.forget(everything=True)  # everything the current user owns\n```\n\n### Update a document in place\n\n```python\nawait cognee.update(data_id=data_id, data=\"Updated content\", dataset_id=dataset_id)\n```\n\nThe document keeps its `data_id`; only the chunks the edit touched are re-extracted.\n\n### Create domain-specific structures\n\nPass a `DataPoint`-derived Pydantic model as `graph_model` and the LLM fills it instead of the\ngeneric knowledge graph:\n\n```python\nfrom cognee.infrastructure.engine import DataPoint\n\n\nclass Person(DataPoint):\n    name: str\n    role: str\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nclass Company(DataPoint):\n    name: str\n    employs: list[Person] = []  # a DataPoint field becomes an edge named after the field\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nawait cognee.remember(\"...\", dataset_name=\"org\", graph_model=Company)\n```\n\nInsert structured Python objects directly, bypassing text extraction:\n\n```python\nfrom cognee.tasks.storage import add_data_points\n\nawait add_data_points([Person(name=\"Ada\", role=\"Engineer\")])\n```\n\nSee `examples/guides/custom_graph_model.py` and `examples/guides/custom_data_models.py`.\n\n### Run custom pipelines\n\nUse `run_custom_pipeline(...)` when the user needs explicit sequential task control.\n\n```python\nfrom cognee.modules.pipelines.tasks.task import Task\n\n\nasync def my_task(data):\n    return data\n\n\nawait cognee.run_custom_pipeline(\n    tasks=[Task(my_task)],\n    data=\"input\",\n    dataset=\"research\",\n)\n```\n\n## DataPoints\n\nA `DataPoint` is the **atomic unit of knowledge** in Cognee.\n\nUse this concept whenever the user asks how Cognee represents structured data internally or how\nto insert graph objects directly.\n\nKey ideas:\n\n- A `DataPoint` is a Pydantic model that represents one meaningful unit of information.\n- When inserted, DataPoints become graph nodes; fields holding other DataPoints become edges.\n- `metadata = {\"index_fields\": [...]}` controls which fields are embedded for semantic search.\n- `metadata = {\"identity_fields\": [...]}` makes the node id deterministic so repeated inserts\n  merge instead of duplicating.\n\nUse `DataPoint` when the user wants:\n\n- schema-shaped memory\n- exact control over graph structure\n- programmatic relationship creation\n- custom domain entities such as papers, customers, incidents, policies, products, or workflows\n\nPrefer plain `remember(...)` for unstructured documents. Prefer `graph_model=` when the text\nshould be extracted into a schema. Prefer `DataPoint` models plus `add_data_points(...)` when the\nuser already has structured Python objects.\n\n## NodeSets\n\nUse NodeSets when the user wants a lightweight way to **tag, group, and scope memory**.\n\nA NodeSet starts as a list of tags passed through `node_set=[...]` to `remember(...)`; after the\ngraph is built those tags are first-class graph nodes, and `recall(node_name=[...])` restricts\nretrieval to them.\n\n### Good NodeSet patterns\n\n- per customer: `[\"customer_123\"]`\n- per workflow: `[\"support_bot\", \"refund_flow\"]`\n- per topic: `[\"contracts\", \"vendor_risk\"]`\n- per environment: `[\"prod\", \"staging\"]`\n- per user memory: `[\"user_42\", \"preferences\"]`\n\n### Example\n\n```python\nawait cognee.remember(\n    [\n        \"Alice prefers terse answers and email follow-ups.\",\n        \"Alice escalates billing issues to finance first.\",\n        \"Bob prefers detailed technical explanations.\",\n    ],\n    dataset_name=\"agent_memory\",\n    node_set=[\"crm\", \"user_profiles\"],\n)\n\nresults = await cognee.recall(\n    \"How should I respond to Alice?\",\n    datasets=[\"agent_memory\"],\n    node_name=[\"crm\", \"user_profiles\"],\n)\n```\n\nUse NodeSets by default whenever the user says things like:\n\n- \"scope memory by customer\"\n- \"separate projects without making separate databases\"\n- \"let the agent search only its own memories\"\n- \"group facts by workflow or team\"\n\n## SearchType selection guide\n\n`recall()` routes automatically when `query_type` is omitted. When the user needs a specific\nstrategy, pick from `cognee.SearchType` (all 20 values):\n\nCompletion types (an LLM writes the answer):\n\n- `HYBRID_COMPLETION`: document passages plus entity neighbourhoods; the default when routing is off\n- `GRAPH_COMPLETION`: graph traversal + completion; the best general graph-aware Q&A\n- `GRAPH_COMPLETION_COT`: deeper chain-of-thought reasoning over graph context\n- `GRAPH_COMPLETION_CONTEXT_EXTENSION`: broader graph context retrieval\n- `GRAPH_COMPLETION_DECOMPOSITION`: splits the question into sub-queries first\n- `GRAPH_SUMMARY_COMPLETION`: graph context + pre-computed summaries\n- `RAG_COMPLETION`: traditional RAG over document chunks\n- `TEMPORAL`: time-aware graph search\n- `AGENTIC_COMPLETION`: multi-step loop that can load `skills` and call `tools`\n\nRetrieval-only types (no LLM call):\n\n- `CHUNKS`: semantic retrieval over chunks\n- `CHUNKS_LEXICAL`: exact-term / keyword (BM25) matching\n- `SUMMARIES`: pre-computed document summaries\n- `SKILLS`: discover SKILL.md playbooks (metadata only; exactly one dataset)\n- `CODE`: deterministic code-graph operations via `code_query` (callers, paths, impact analysis)\n\nOther:\n\n- `CYPHER`: raw Cypher, off by default (`ALLOW_CYPHER_QUERY=true` enables it; not on the Postgres demo graph)\n- `NATURAL_LANGUAGE`: natural language to graph query, off by default (same `ALLOW_CYPHER_QUERY=true` flag)\n- `CODING_RULES`: retrieve stored coding rules\n- `GRAPH_REPORT`: graph insight report (hubs, cross-source links, suggested questions)\n- `FEELING_LUCKY`: let Cognee choose\n\nThe CLI exposes 10 of these (`cognee-cli recall --query-type`); the rest are SDK-only.\n\n## Sessions, feedback, and self-improvement\n\nCognee has two memory tiers:\n\n- **Permanent memory**: `remember(...)` without `session_id` — the knowledge graph.\n- **Session memory**: `remember(..., session_id=...)` — a fast session cache written without an\n  LLM call. `recall(..., session_id=...)` searches it first and falls through to the graph.\n  Requires `CACHING=true` (the default).\n\n```python\n# Short-term: store a turn in the session cache, recall it instantly\nawait cognee.remember(\"User wants weekly summaries on Fridays.\", session_id=\"chat_1\")\nresults = await cognee.recall(\"when does the user want summaries?\", session_id=\"chat_1\")\n\n# Long-term: bridge the session into the permanent graph\nawait cognee.improve(dataset=\"main_dataset\", session_ids=[\"chat_1\"])\n```\n\n`remember(..., session_id=...)` with `self_improvement=True` (default) bridges into the graph\nin the background, so the explicit `improve()` call is only needed for control over timing.\n\n### Feedback\n\nFeedback is attached to a session Q&A entry and later folded into retrieval weights by\n`improve()`:\n\n```python\nfrom cognee import FeedbackEntry\n\n# Rate an earlier answer (qa_id is the entry_id returned by the remember() that stored it)\nawait cognee.remember(\n    FeedbackEntry(qa_id=qa_id, feedback_score=5, feedback_text=\"Captured the key themes.\"),\n    session_id=\"chat_1\",\n)\n# Equivalent helper API\nawait cognee.session.add_feedback(session_id=\"chat_1\", qa_id=qa_id, feedback_score=5)\nhistory = await cognee.session.get_session(session_id=\"chat_1\")\n```\n\nWith `AUTO_FEEDBACK=true` (default) every answered turn is also analysed for implicit feedback\nby one structured-output LLM call. Set `AUTO_FEEDBACK=false` for low-latency reads.\n\n### Wrap an agent\n\n`@cognee.agent_memory` records an agent function's calls as session traces and recalls context\nbefore each call. See `examples/guides/agent_memory_quickstart.py`.\n\n## Agentic workflows and feedback-driven improvement\n\nUse Cognee as the **memory layer for agent systems** that need to improve over time through\nbetter recall, better reuse of prior work, and better retrieval of successful past behavior.\n\nThe key idea is simple:\n\n- keep the **agent workflow itself constant**\n- keep the **prompt and tools constant**\n- change only what the agent can remember and retrieve\n\n\"Improvement\" comes from **memory reuse and retrieval quality**, not from changing the model.\n\n### General agent loop\n\n1. **Observe** — capture inputs, events, preferences, outcomes, errors, decisions.\n2. **Store** — `remember(...)` them, with `session_id` for the active run and without it for\n   durable facts.\n3. **Organize** — use datasets and NodeSets to separate memory by customer, workflow, team,\n   agent, or topic.\n4. **Recall before acting** — `recall(...)` before planning, tool use, synthesis, or response\n   generation.\n5. **Capture feedback** — `FeedbackEntry` / `session.add_feedback` for what worked and what\n   did not.\n6. **Consolidate** — `improve(dataset, session_ids=[...])` so session history and lessons become\n   long-term graph memory.\n7. **Reuse** — future runs benefit from richer context and more informed retrieval.\n\n### Minimal example pattern\n\n```python\nimport cognee\n\n# 1) Store a durable observation\nawait cognee.remember(\n    \"Customer 123 prefers concise status updates and Slack notifications.\",\n    dataset_name=\"agent_memory\",\n    node_set=[\"customer_123\", \"preferences\", \"support_agent\"],\n)\n\n# 2) Recall before acting, inside a session\ncontext = await cognee.recall(\n    \"What should I know before replying to customer 123?\",\n    datasets=[\"agent_memory\"],\n    session_id=\"support-session-123\",\n)\n\n# 3) Continue work in the same session\nanswer = await cognee.recall(\n    \"Draft the best reply for customer 123.\",\n    datasets=[\"agent_memory\"],\n    session_id=\"support-session-123\",\n)\n\n# 4) Consolidate the session into long-term memory later\nawait cognee.improve(dataset=\"agent_memory\", session_ids=[\"support-session-123\"])\n```\n\n### Best default explanation\n\nIf the user asks how Cognee helps agents improve over time:\n\n**Cognee lets agents improve by remembering more useful things, organizing them into searchable\ngraph memory, and reusing successful past work in future runs.**\n\n## Configuration help\n\nUse Cognee config helpers or environment variables when the user needs provider or backend setup.\n\n```python\ncognee.config.set_llm_provider(\"openai\")\ncognee.config.set_llm_model(\"gpt-5-mini\")\ncognee.config.set_llm_api_key(\"sk-...\")\n```\n\nEnvironment variables (`.env`): `LLM_API_KEY`, `LLM_MODEL`, `LLM_PROVIDER`, `EMBEDDING_*`,\n`GRAPH_DATABASE_PROVIDER` (ladybug default, neo4j, neptune, postgres_demo), `VECTOR_DB_PROVIDER`\n(lancedb default, pgvector, turso), `DB_PROVIDER` (sqlite default, postgres), `CACHE_BACKEND`.\nIf only the LLM or only embeddings are configured, the other defaults to OpenAI.\n\n## Dataset and lifecycle operations\n\n```python\ndatasets = await cognee.datasets.list_datasets()\ndata = await cognee.datasets.list_data(dataset_id)\nawait cognee.forget(dataset=\"research\")  # preferred over datasets.empty_dataset / delete_all\n```\n\n## Visualization\n\n`visualize_graph` renders a **bounded subgraph** by default (seed nodes + a k-hop neighborhood,\ncapped at `max_nodes`) instead of the whole graph.\n\n```python\n# Default: bounded subgraph. Seed by a query, explicit ids, or a recall result;\n# with none of those, the highest-degree nodes seed a representative view.\nawait cognee.visualize_graph(\"/path/to/output.html\")\nawait cognee.visualize_graph(\"/path/to/output.html\", query=\"What relates to Python?\")\nawait cognee.visualize_graph(\"/path/to/output.html\", seed_node_ids=[\"node-id-1\"])\nawait cognee.visualize_graph(\"/path/to/output.html\", recall_result=recall_output)\n\n# Legacy whole-graph render.\nawait cognee.visualize_graph(\"/path/to/output.html\", full=True)\n\nawait cognee.start_visualization_server(port=8080)\nawait cognee.start_ui()\n```\n\nCaps: `neighborhood_depth=2`, `neighborhood_seed_top_k=10`, `max_nodes=500`.\nSee `examples/guides/graph_visualization.py`.\n\n## Full reset (tests only)\n\n`forget(everything=True)` removes the user's data and memory. To also drop users, ACLs and the\ndataset registry — full test teardown — use prune:\n\n```python\nawait cognee.prune.prune_data()\nawait cognee.prune.prune_system(graph=True, vector=True, metadata=True, cache=True)\n```\n\n## Important behavior notes\n\n- Cognee APIs are **async**.\n- Prefer **remember -> recall** (+ `improve`, `forget`) unless the user needs one low-level stage.\n- Use `node_set` early when the user may later need scoped retrieval.\n- Use `session_id` for short-term memory and conversation continuity; `improve(session_ids=...)`\n  to make it permanent.\n- Use `graph_model=` or `DataPoint` types only when the user needs schema-shaped extraction.\n- Use `CYPHER` only when Cypher querying is enabled in config.\n- Keep examples minimal and runnable.\n\n## Do not overcomplicate\n\nDo not jump straight to advanced backends, ontology configuration, or custom pipelines unless the\nuser asks for them or the problem clearly requires them. Prefer the smallest correct Cognee\nsolution first, then extend it.\n",".agents/skills/cognee-install/SKILL.md":"---\nname: cognee-install\ndescription: Use when the user wants to install cognee and run their first remember → recall flow with the Python SDK — fresh setup, virtual env, extras selection, or a minimal working example.\n---\n\n# Install and run cognee\n\n## Install\n\nRequires Python 3.10–3.14. Prefer uv:\n\n```bash\nuv venv && source .venv/bin/activate\nuv pip install cognee            # from PyPI\n# or, working inside this repo:\nuv pip install -e .\n```\n\nAdd extras only when needed — examples: `cognee[postgres]`, `cognee[neo4j]`,\n`cognee[docling]` (office/HTML document parsing, slim), `cognee[docs]`\n(unstructured), `cognee[anthropic]`, `cognee[ollama]`, `cognee[aws]`. The full\nlist is in `pyproject.toml` under `[project.optional-dependencies]`.\n\n## Configure\n\nThe only required setting is an LLM API key. Create `.env` in the working\ndirectory (or export the variable):\n\n```bash\nLLM_API_KEY=\"your_openai_api_key\"\n```\n\nDefaults need no services: SQLite (relational), LanceDB (vector), and Ladybug\n(graph), all stored locally. OpenAI is the default LLM and embedding provider —\nif you configure a different LLM but not embeddings (or vice versa), the other\nsilently stays on OpenAI. For other providers and databases use the\ncognee-integrations skill.\n\n## First run\n\nAs of cognee 1.x the memory API — `remember`, `recall`, `forget`, `improve` —\nis the primary surface. All SDK functions are async. Minimal end-to-end script:\n\n```python\nimport asyncio\nimport cognee\n\n\nasync def main():\n    await cognee.remember(\"Cognee turns documents into AI memory.\")\n    results = await cognee.recall(\"What does cognee do?\")\n    print(results)\n\n\nasyncio.run(main())\n```\n\n`remember()` is the whole ingestion path in one call — it runs `add()` +\n`cognify()`, then `improve()` to index the graph (`self_improvement=True` by\ndefault). It accepts text, file paths, URLs, and binary streams, with an\noptional `dataset_name=\"my_project\"`; pass `datasets=[\"my_project\"]` to\n`recall()` to stay inside one dataset.\n\n`recall()` auto-routes the query to a search strategy by default. Pass\n`query_type=SearchType.CHUNKS` (etc.) to pin one, or `auto_route=False` to\nfall back to `GRAPH_COMPLETION`.\n\nSession memory is the other half of the API — `remember(..., session_id=\"chat_1\")`\nwrites to a fast session cache rather than running add+cognify inline, and\n`recall(..., session_id=\"chat_1\")` reads it back (session hits short-circuit the\ngraph search). With the default `self_improvement=True` it still bridges that\ndata into the permanent graph in the background; `improve(dataset=...,\nsession_ids=[...])` does the same explicitly. Session memory runs on the\nsession cache, which is on by default (`CACHING=true`); setting\n`CACHING=false` disables it entirely and makes `remember(session_id=...)`\nraise.\n\nStart with `examples/advanced_guides/remember_recall_improve_example.py`, which walks\nthrough permanent memory, session memory, and the sync between them.\n\nThe `add()` / `cognify()` / `search()` primitives still exist and\nare what `remember`/`recall`/`improve` call underneath — reach for them when you\nneed to drive a stage in isolation (e.g. custom pipeline tasks), not for\nordinary ingestion. `cognee.delete` is formally deprecated (since 0.3.9);\n`forget()` is the v1 replacement, unifying the old delete/empty_dataset\npaths behind one call. When to use `recall()` versus the low-level `search()`\nis covered in `docs/recall-vs-search.md`.\n\n## Verify / troubleshoot\n\n- `cognee-cli remember \"hello\" && cognee-cli recall \"hello\"` exercises the same\n  flow from the shell.\n- To wipe local state during experiments: `cognee-cli forget --all` (or\n  `await cognee.forget(everything=True)`).\n- Reads slow or spending tokens on every query → set `AUTO_FEEDBACK=false`\n  (keep `CACHING=true`); by default cognee makes one structured-output LLM\n  call per answered query to self-tune its memory.\n- Structured LLM output errors usually mean the model/provider needs an\n  explicit instructor mode: `LLM_INSTRUCTOR_MODE=\"json_schema_mode\"`.\n",".agents/skills/cognee-integrations/SKILL.md":"---\nname: cognee-integrations\ndescription: Use when the user wants to connect cognee to external services — switching LLM or embedding providers (OpenAI, Azure, Gemini, Anthropic, Ollama, OpenRouter), changing databases (Postgres, PGVector, Neo4j, Neptune, Turso), S3 storage, or the MCP server for IDE integration.\n---\n\n# Set up cognee integrations\n\nAll integration config is environment variables (`.env`). The authoritative,\nalways-current list with commented examples is `.env.template` at the repo\nroot — check it before inventing variable names. Install the matching extra\nbefore switching a backend (e.g. `pip install cognee[postgres]`).\n\n## LLM providers\n\nDefault is OpenAI (`LLM_API_KEY` is all you need). To switch, set\n`LLM_PROVIDER`, `LLM_MODEL`, `LLM_API_KEY`, and (where relevant)\n`LLM_ENDPOINT` / `LLM_API_VERSION`:\n\n- **Azure OpenAI**: `LLM_PROVIDER=azure`, `LLM_MODEL=azure/gpt-4o-mini`, endpoint + api version required.\n- **Gemini** (no extra needed): `LLM_PROVIDER=gemini`, `LLM_MODEL=gemini/gemini-2.0-flash-exp`.\n- **Anthropic** (`cognee[anthropic]`): `LLM_PROVIDER=anthropic`, model e.g. `claude-3-5-sonnet-20241022`.\n- **Ollama, local** (`cognee[ollama]`): `LLM_PROVIDER=ollama`, `LLM_ENDPOINT=http://localhost:11434/v1`, and set the embedding block + `HUGGINGFACE_TOKENIZER` too.\n- **Custom / OpenRouter / vLLM**: `LLM_PROVIDER=custom` with the provider's OpenAI-compatible endpoint.\n- **AWS Bedrock** (`cognee[aws]`): `LLM_PROVIDER=bedrock` + AWS credentials/region.\n\n**The classic trap**: LLM and embeddings are configured independently\n(`EMBEDDING_PROVIDER`, `EMBEDDING_MODEL`, `EMBEDDING_ENDPOINT`,\n`EMBEDDING_API_KEY`). Configuring only one leaves the other on OpenAI —\neither keep a valid OpenAI key or configure both.\n\n## Databases\n\n- **Relational** (`DB_PROVIDER`): sqlite (default) or postgres\n  (`cognee[postgres]`; host/port/user/password/name via `DB_*` vars).\n- **Vector** (`VECTOR_DB_PROVIDER`): lancedb (default), pgvector\n  (`cognee[postgres]`, needs `VECTOR_DB_URL`), neptune_analytics\n  (`cognee[neptune]`), turso (`cognee[turso]`). Anything else (ChromaDB,\n  Qdrant, Weaviate, Milvus, …) lives in community adapters — install from\n  https://github.com/topoteretes/cognee-community and register with\n  `use_vector_adapter` before use; setting `VECTOR_DB_PROVIDER` alone raises\n  \"Unsupported vector database provider\".\n- **Graph** (`GRAPH_DATABASE_PROVIDER`): ladybug (default), neo4j\n  (`cognee[neo4j]`, bolt URL + credentials), neptune (`cognee[neptune]`),\n  ladybug-remote, postgres (no raw Cypher / natural-language search).\n\nThe repo `docker-compose.yml` ships ready-to-use `postgres` (pgvector) and\n`neo4j` profiles with matching default credentials. From a container, reach\nhost services with `DB_HOST=host.docker.internal`.\n\n## Storage, cache, and the rest\n\n- **S3 storage** (`cognee[aws]`): `STORAGE_BACKEND=s3` + bucket/credentials,\n  and point `DATA_ROOT_DIRECTORY`/`SYSTEM_ROOT_DIRECTORY` at `s3://` paths.\n- **Session cache**: `CACHE_BACKEND` = sqlite (default) | postgres | redis | fs | tapes.\n- **Ontologies**: `ONTOLOGY_FILE_PATH` to an OWL file, resolver/matching via\n  `ONTOLOGY_RESOLVER` / `MATCHING_STRATEGY`.\n\n## MCP server (IDE integration)\n\n`docker compose --profile mcp up` starts the MCP server on port 8001\n(Streamable HTTP at `http://localhost:8001/mcp`), built from `cognee-mcp/`. Point Cursor / Claude Desktop /\nClaude Code at it to use cognee memory from the IDE. Configure its `DB_*` env\nto match the main service so both see the same data.\n\n## After changing providers mid-project\n\nEmbeddings from different models are not comparable — after switching the\nembedding provider or model, reset local state (`cognee-cli forget --all` or\n`await cognee.forget(everything=True)`) and re-ingest with `remember()`.\n\nTo drop just the graph and vectors while keeping the ingested files, use\n`await cognee.forget(dataset=\"my_project\", memory_only=True)` — the dataset can\nthen be rebuilt under the new embedding model without re-uploading anything.\n",".agents/skills/cognee-ingestion/SKILL.md":"---\nname: cognee-ingestion\ndescription: Use when putting data into cognee memory with remember() — choosing inputs (text, files, folders, URLs, repos, databases), datasets and node_sets, loaders, ontologies, the graph extractor (LLM or GLiNER), chunking, dry-run cost estimates, or when remember() raises on a keyword argument.\n---\n\n# Ingest data with remember()\n\n`remember()` is cognee's ingestion API. One call stores the data, builds the\nknowledge graph, and enriches it. Use it for all ingestion; every option in\nthis skill is a `remember()` argument unless it says otherwise.\n\n```python\nimport cognee\n\nresult = await cognee.remember(\"Einstein was born in Ulm.\")  # text\nresult = await cognee.remember(\n    [\"./notes.md\", \"./report.pdf\"],  # files\n    dataset_name=\"research\",\n)\nprint(result.status, result.dataset_id)  # \"completed\", UUID\n```\n\nAll cognee functions are async. Without `dataset_name` data goes to\n`main_dataset`. Needs `LLM_API_KEY` unless you use the GLiNER extractor\n(below).\n\n## Use it\n\n### Inputs\n\n`data` accepts a string, a list of strings, file paths (absolute, `file://`,\n`s3://`), http(s) URLs, binary streams, or a list mixing them.\n\n- **URLs** are fetched and scraped (needs `ALLOW_HTTP_REQUESTS=true`, the\n  default).\n- **Folders** are ingested file by file. A folder that looks like a code\n  project, or a GitHub/GitLab URL, becomes one code repository (needs `git`\n  on PATH).\n- **Code files** (`.py`, `.ts`, `.go`, …) go down the code-graph route: a\n  deterministic graph, no LLM calls, searchable only with\n  `SearchType.CODE`. To index a whole repository explicitly, pass\n  `content_type=\"code\"`.\n- **Databases and dlt sources**: a SQL connection string, a dlt\n  `DltResource` / `DltSource`, or a CSV. dlt is a core dependency, so no\n  extra is needed (`cognee[dlt]` is an empty compatibility extra). Options: `primary_key` (default `\"id\"`),\n  `write_disposition` (`\"replace\"` default, or `\"append\"`), `query`,\n  `max_rows_per_table`.\n- **Skill playbooks** (`SKILL.md` files): `content_type=\"skills\"`; ingests\n  into the target dataset (default `main_dataset`), so pass `dataset_name`\n  to keep skills in their own dataset.\n\n### Where the data goes\n\n| Argument | What it does |\n|---|---|\n| `dataset_name` / `dataset_id` | Target dataset. `dataset_id` wins. A dataset is the unit of permissions and isolation. |\n| `node_set=[\"AI\", \"FinTech\"]` | Tags the data so recall can filter to it later with `recall(..., node_name=[\"AI\"])`. With `session_id` it pins the session's node set instead (first write wins, a different set later is a 409); `improve()` carries it into the graph. See the `cognee-improve-sessions` skill. |\n| `session_id=\"chat_1\"` | Writes to the fast session cache instead of the graph; `improve()` bridges it into the graph in the background. See the `cognee-improve-sessions` skill. Requires `CACHING=true`. |\n\n### How the graph is built\n\n| Argument | What it does |\n|---|---|\n| `extractor` | `\"llm\"` or `\"gliner_demo\"` (alias `\"gliner\"`). Default is `GRAPH_EXTRACTOR=auto`: the LLM when an API key is configured, otherwise GLiNER. |\n| `graph_model=MyModel` | Extract into your own DataPoint model instead of the generic `KnowledgeGraph`. See the `cognee-custom-graph-models` skill. |\n| `custom_prompt` | Replaces the entity-extraction prompt (ignored by GLiNER). |\n| `config={\"ontology_config\": {...}}` | Ground entities in an OWL ontology (below). |\n| `chunk_size`, `chunker` | Max tokens per chunk (default: derived from the embedding and LLM limits) and the chunker class (default `TextChunker`). |\n| `preferred_loaders` | Choose a loader per file type (below). |\n| `self_improvement` | Default `True`: runs `improve()` after the graph is built. Its outcome is on `result.improve` / `result.improve_error`; a failed improve never fails the remember. |\n| `run_in_background=True` | Returns immediately with `status=\"running\"`; `await result` to wait. |\n\n### Ontologies\n\n```python\nfrom cognee.modules.ontology.rdf_xml.RDFLibOntologyResolver import RDFLibOntologyResolver\n\nconfig = {\n    \"ontology_config\": {\n        \"ontology_resolver\": RDFLibOntologyResolver(ontology_file=\"./my.owl\"),\n        # \"ontology_mode\": \"strict\",   # drop entities with no ontology match\n    }\n}\nawait cognee.remember(texts, config=config)\n```\n\nOr set `ONTOLOGY_FILE_PATH` (plus `ONTOLOGY_MODE`, `MATCHING_STRATEGY`) in\n`.env`. `annotate` (default) only enriches; `strict` drops entities that\nmatch no ontology class or individual. It prunes only the graph, chunk text\nis still stored. Strict mode with an empty or missing ontology file is a hard\nerror. Over HTTP, upload the ontology to `/api/v1/ontologies` and pass its\n`ontology_key` to `POST /api/v1/remember`. Example:\n`examples/guides/ontology_quickstart.py`.\n\n### Loaders\n\nEach file is claimed by the first loader that accepts it. Default order:\ncode, text, pypdf, image, audio, video, dlt_csv, csv, unstructured,\nadvanced_pdf, docling. Names: `text_loader`, `code_loader`, `csv_loader`,\n`dlt_csv_loader`, `pypdf_loader`, `image_loader`, `audio_loader`,\n`video_loader`, `unstructured_loader`, `advanced_pdf_loader`,\n`docling_loader`, `beautiful_soup_loader`.\n\n```python\n# Treat a code file as a plain document (chunking + LLM extraction):\nawait cognee.remember(\"./script.py\", preferred_loaders={\"text_loader\": {}})\n```\n\nOffice formats (DOCX, PPTX, …) need the `docs` (unstructured) or `docling`\nextra. A preferred loader that is not installed is skipped with only an info\nlog, so check the extra is installed when a file comes out wrong.\n\n### Check the cost first\n\n`dry_run=True` returns a token and cost estimate without ingesting anything\nor calling the LLM. It excludes the calls `improve()` makes. Not supported\nwith GLiNER, sessions, or a remote instance.\n\n`dry_run=\"presort\"` on a folder returns a `PresortReport` (junk, duplicates,\nversion candidates, possible personal data, proposed dataset groups). Apply\nit with `await cognee.remember(report)`, or pass `auto_apply=True`.\n\n### Without an LLM: GLiNER\n\n`extractor=\"gliner\"` builds the graph and summaries with a local GLiNER2\nmodel, with no LLM call (embeddings still run). Install\n`pip install \"cognee[gliner]\"`; the model (about 750 MB) downloads on first use.\nIt cannot be combined with a custom `graph_model`, `dry_run`, `session_id`,\nor a remote instance.\n\n> **For production:** the open-source GLiNER extractor is a demo. cognee's\n> enterprise GLiNER extraction is more accurate and covers more labels. The\n> same goes for the Postgres graph adapter (`postgres_demo`). Contact\n> social@cognee.ai.\n\n## Pitfalls\n\n- **Unknown keyword arguments raise.** `remember()` forwards kwargs through\n  a fixed allow-list and raises `TypeError: Unexpected keyword arguments`\n  for anything else. These real options are not on it yet:\n\n  | Option | Workaround through remember() |\n  |---|---|\n  | `ontology_file_path` | `config={\"ontology_config\": ...}` or `ONTOLOGY_FILE_PATH` (above) |\n  | `chunk_attachment` | None yet. Only `cognee.cognify()` accepts it. |\n  | `extraction_rules` | Pass it through the loader: `preferred_loaders={\"beautiful_soup_loader\": {\"extraction_rules\": {...}}}` (works in `remember()` and `add()`). Needs the `scraping` extra: without it the loader is not registered and the rules are silently ignored |\n  | `tavily_config`, `soup_crawler_config` | Not honoured by `add()` or `remember()`; only the `cognee/tasks/web_scraper` tasks use them |\n  | `column_value_columns` (dlt) | None yet. Only `cognee.add()` accepts it. |\n\n  If a user needs one with no workaround, say so plainly: the option exists\n  on the lower-level `add()` / `cognify()` but not on `remember()` yet.\n- **Changed files raise `DocumentUpdateRequiredError`.** Re-remembering the\n  same path (or the same filename for an upload) with different content is\n  an update, not a new document. Use\n  `cognee.update(data_id=..., data=..., dataset_id=...)`, which re-extracts\n  only the changed chunks and keeps the document's id. Identical content is\n  a no-op.\n- **`content_type` is strict.** Only `None`, `\"skills\"`, or `\"code\"`.\n  `\"code\"` rejects `session_id` and needs repository paths or git URLs;\n  `\"skills\"` ingests into the target dataset like any other call (default\n  `main_dataset`); pass `dataset_name` to keep skills in their own dataset.\n- **Session mode needs `CACHING=true`**, and `extractor` cannot be combined\n  with `session_id`.\n- **Remote mode.** After `cognee.serve(url)`, calls go to the server:\n  `extractor` and `session_ids` raise, and other options the client does not\n  forward (including `graph_model`, `node_set`, and ontology `config`) are\n  dropped without an error.\n- **Every remember runs `improve()`** unless `self_improvement=False` or\n  `IMPROVE_AUTO_ENABLED=false`. In scripts, call\n  `await cognee.wait_for_background_tasks()` before exiting.\n\n## How it works\n\n`remember(data)` runs `add()` (store raw data and create `Data` rows), then\n`cognify()` (classify documents, chunk, extract the graph and summaries,\nstore in graph and vector DBs), then `improve()`. `remember(data,\nsession_id=...)` writes to the session cache instead.\n\n- Entry point and kwarg routing: `cognee/api/v1/remember/remember.py`\n  (`RememberKwargs`, `_ADD_ONLY` / `_COGNIFY_ONLY` / `_SHARED`)\n- Storage: `cognee/api/v1/add/add.py`, `cognee/tasks/ingestion/ingest_data.py`\n- Graph build: `cognee/api/v1/cognify/cognify.py`,\n  `cognee/tasks/graph/extract_graph_from_data.py`,\n  `cognee/tasks/storage/add_data_points.py`\n- Extractor choice: `cognee/modules/cognify/config.py:resolve_extractor`;\n  GLiNER package: `cognee/tasks/graph/gliner_demo/`\n- Ontologies: `cognee/modules/ontology/`\n- Loaders: `cognee/infrastructure/loaders/` (`supported_loaders.py`,\n  `LoaderEngine.py`)\n- dlt: `cognee/tasks/ingestion/resolve_dlt_sources.py`\n\nExamples in `examples/guides/`: `simple_cognee_example.py`,\n`nodeset_grouping_example.py`, `ontology_quickstart.py`,\n`gliner_demo_llm_free_cognify.py`, `no_llm_remember_recall.py`,\n`temporal_recall.py`, `presort_downloads.py`,\n`web_url_content_ingestion_example.py`, `code_graph_example.py`.\n\n## Extending it\n\n- **New remember() option:** add it to `RememberKwargs` and to the matching\n  routing set in `remember.py`. An option on `add()`/`cognify()` that is not\n  in a routing set raises `TypeError` from `remember()`.\n- **New loader:** implement `LoaderInterface`\n  (`cognee/infrastructure/loaders/LoaderInterface.py`), register it in\n  `supported_loaders.py` (extras-gated loaders go under `external/`), and\n  add it to the priority list in `LoaderEngine.py` if it should run by\n  default.\n- **New cognify task:** see the `cognee-custom-pipelines` skill and\n  `cognee/tasks/README.md`.\n",".agents/skills/cognee-migrations/SKILL.md":"---\nname: cognee-migrations\ndescription: Use when dealing with cognee database migrations — understanding when they run automatically, checking or repairing migration state with cognee-cli upgrade/downgrade/stamp/current, a write blocked by a failed migration, authoring a new Alembic (relational schema) revision or a graph/vector data migration, or moving data between systems (relational DB import, memory export/import).\n---\n\n# Database migrations\n\ncognee has **two migration chains**, run together:\n\n| Chain | Changes | Lives in | Revision stored in |\n|---|---|---|---|\n| **Relational schema** (Alembic) | Tables and columns of the relational DB (users, datasets, ACLs, pipeline runs, …) | `cognee/alembic/` (`alembic.ini` is in `cognee/`) | `alembic_version` table |\n| **Graph/vector data** | Cross-store data rewrites (re-keying node ids, adding graph columns) across graph DB, vector DB and relational ledger | `cognee/modules/migrations/` (`registry.py`, `versions/`) | Per dataset: `dataset_database.migration_revision` (access control on). Globally: `global_database_version.global_migration_revision` (access control off) |\n\n## Use it\n\n### They run by themselves\n\n`run_migrations()` applies the relational chain first, then the data chain.\nIt runs:\n\n- at API server startup (and in the Docker `entrypoint.sh` before gunicorn);\n- on the first write in an SDK or CLI process (`remember`, `add`, `cognify`,\n  `improve`, memory imports), once per process;\n- when you call `await cognee.run_migrations()`.\n\nA fresh database is built by running the whole chain (no stamping). At\nhead, the first run in each process still does a no-op Alembic upgrade plus\na scan of the per-database revision rows; later calls in the same process\nare skipped by an in-memory flag. `ENABLE_AUTO_MIGRATIONS=false`\nturns off all automatic runs; then run `cognee-cli upgrade` yourself.\n\nConcurrent processes are serialized by a migration lock: a Postgres advisory\nlock (works across hosts) or a file lock next to the SQLite DB (one host\nonly).\n\n### Check and repair\n\n```bash\ncognee-cli current                   # stamped revision per database, and the last failure\ncognee-cli history                   # the data chain, newest first\ncognee-cli upgrade                   # relational to head, then data chain to head\ncognee-cli upgrade <slug>            # data chain up to and including <slug>\ncognee-cli upgrade --alembic <rev>   # pin the relational target\ncognee-cli downgrade <slug|base> [--dataset UUID ...] [--alembic REV] [--force]\ncognee-cli stamp <head|base|slug> [--dataset UUID ...] [--force]\n```\n\n- The positional revision is always a **data-chain slug**; relational\n  targets go through `--alembic`.\n- `downgrade` rewrites data and asks for confirmation. It only reverts\n  spans where every migration defines a `down()`, and leaves the relational\n  schema alone unless you pass `--alembic`.\n- `stamp` changes only the stored data-chain revision, without running\n  anything. Use `stamp base --dataset <id>` and then `upgrade` when a\n  database's data drifted from its stamp (for example after restoring a\n  backup); the chain is idempotent and converges it.\n- `upgrade` runs even with `ENABLE_AUTO_MIGRATIONS=false`.\n\n### A write is blocked\n\nIf a dataset's data migration failed, writes to that dataset are refused\nuntil it succeeds (with access control off, any failure blocks all writes).\nThe server still starts. Run `cognee-cli current` to see the error, fix the\ncause, then `cognee-cli upgrade`. A failed run is retried on the next start\nor write.\n\n### Moving data between systems (not schema migrations)\n\n| Goal | Use |\n|---|---|\n| Turn an existing relational database into a graph | `migrate_relational_database(graph_db, schema)` (`cognee/tasks/ingestion/migrate_relational_database.py`), with the source DB set by `MIGRATION_DB_PROVIDER` / `_PATH` / `_NAME` / `_HOST` / `_PORT` / `_USERNAME` / `_PASSWORD`. Examples: `examples/demos/ingestion_and_migration/` |\n| Back up a dataset, or move it to another cognee instance | A COGX archive, see below |\n| Export a dataset's graph for other tools | `await cognee.export(dataset, format=...)`: `\"json\"`, `\"graphml\"` or `\"cypher\"` write a file (one way: cognee can't import them back); `\"pydantic\"` (default) returns typed DataPoint objects in memory |\n| Import from another memory system (Mem0, Zep/Graphiti, Letta, LangMem) | Build a `MemorySource` (`cognee/modules/migration/sources/`) and pass it to `await cognee.remember(source, dataset_name=...)` |\n\nThere is no tool that moves a whole deployment from one database backend to\nanother.\n\n#### COGX archives\n\nCOGX (Cognee eXchange, `cognee/modules/migration/cogx.py`) is cognee's\nportable memory format and the only export format cognee can import back.\nAn archive is a directory with a `manifest.json` (COGX version, source\nsystem, the dataset's data-migration revision) and one JSONL file per record\nkind (`documents`, `episodes`, `entities`, `facts`, `memories`,\n`memory_blocks`), plus `nodes.jsonl` with the raw graph nodes. The Mem0,\nZep, Letta and LangMem importers also translate into COGX records first.\n\nUse it to back up and restore a dataset, or to copy one to another cognee\ninstance:\n\n```python\nfrom cognee.migration import COGXArchiveSource\n\nawait cognee.export(\"my_dataset\", format=\"cogx\", destination=\"backup_cogx\")\nawait cognee.remember(COGXArchiveSource(\"backup_cogx\"), dataset_name=\"my_dataset\")\n```\n\n- A restore defaults to `mode=\"preserve\"`: the archived graph is written\n  back as-is, with no LLM calls. `mode=\"hybrid\"` also re-cognifies the raw\n  content; `mode=\"re-derive\"` ignores the archived graph and extracts again\n  (costs LLM tokens).\n- `cognee.push()` / `cognee-cli push` does the same to Cognee Cloud: it\n  exports to COGX, packs it as a `.cogx.tar.gz` and uploads it, and the\n  receiving instance restores it (preserve mode unless you pass `mode=`).\n- `export(..., include_permissions=True)` also writes `permissions.json`\n  with the dataset owner and ACL grants, **including password hashes**, so\n  the restore recreates working accounts. Treat that archive as a secret.\n- An archive written by a newer major COGX version is rejected with a\n  `ValueError`; upgrade cognee on the importing side.\n\n## Pitfalls\n\n- **Never regenerate `cognee/alembic/frozen_schema.py`.** It is the\n  certified base schema the initial revision builds from, pinned by\n  `cognee/tests/unit/test_frozen_schema_seal.py`. Schema changes ship as\n  new revisions at head.\n- **Never hand-type an Alembic revision id.** Hand-typed patterns\n  (`a1b2c3d4e5f6`, …) already collided with a downstream chain that vendors\n  this one (`b2c3d4e5f6a7`). Generate ids with `alembic revision`.\n- **Never rename, remove, or reorder a data-chain entry.** The slug is what\n  deployed databases store; an unknown stored slug disables the chain for\n  that database.\n- **A model change and its migration land together.** CI's \"Migration/Model\n  Lockstep Guard\" fails otherwise.\n- **The relational schema cannot be downgraded below the data-bookkeeping\n  revisions** unless the data chain goes to `base` in the same call.\n- `alembic.ini` is always the packaged one; `COGNEE_ALEMBIC_PATH` or\n  `--alembic-path` only changes the scripts directory (for vendored chains).\n\n## How it works\n\n`run_migrations()` (`cognee/modules/migrations/startup.py`) takes the\nmigration lock, decides fresh vs existing (a `users` or `alembic_version`\ntable exists), runs Alembic in-process on a worker thread, then walks the\ndata chain per database with `runner.run_database_migrations`, stamping\nafter every step. After the chain, it syncs vector-adapter storage when the\nrecorded `cognee_version` differs from the library's\n(`versions/adapter_storage_migration.py`, not a chain entry).\n\n- Relational: `cognee/alembic.ini`, `cognee/alembic/env.py`,\n  `cognee/alembic/versions/`, `cognee/alembic/frozen_schema.py`\n- Data chain: `cognee/modules/migrations/` (`README.md` is the authoring\n  contract; `registry.py`, `migration.py`, `runner.py`, `startup.py`,\n  `versions/`)\n- CLI: `cognee/cli/commands/migrate_command.py`\n\n## Extending it\n\n### A new Alembic revision\n\n```bash\ncd cognee                              # the directory with alembic.ini\nuv run alembic revision -m \"add foo to data\"\n```\n\nThe DB URL comes from the live relational engine, so your normal `.env`\nsettings apply. Follow the recent revisions (for example\n`versions/e7f9a1c3d5b8_add_data_dataset_created_index.py`):\n\n- **Idempotent and guarded:** inspect first (`sa.inspect(op.get_bind())`)\n  and skip when the table is missing or the column/index already exists.\n- **Branch on dialect** (`conn.dialect.name == \"postgresql\"`) for\n  Postgres-only SQL. For Postgres enums use `postgresql.ENUM(...,\n  create_type=False)` and create the type up front with `checkfirst`.\n- **SQLite cannot drop or alter columns in place:** use\n  `op.batch_alter_table(...)`.\n- **Indexes:** plain `CREATE INDEX IF NOT EXISTS` inside the migration\n  transaction, not `CONCURRENTLY` (which releases the version-row lock and\n  lets concurrent workers into the same build). Repair invalid Postgres\n  indexes via `pg_index.indisvalid`.\n- A new model module outside the usual import path must be imported in\n  `cognee/alembic/env.py`, or autogenerate will not see it.\n\n### A new data migration\n\nRead `cognee/modules/migrations/README.md` first. In short:\n\n1. Write a module in `cognee/modules/migrations/versions/` with\n   `async def migrate(context)` (and optionally `async def downgrade(context)`);\n   step 2 registers them as `up=` / `down=`.\n2. Append `Migration(slug=..., cognee_version=..., up=..., down_revision=<previous slug>, down=...)`\n   to `MIGRATIONS` in `registry.py`. The chain is validated at import\n   (linear, unique slugs).\n3. Make it idempotent and cheap on empty stores, and crash-safe: re-key\n   derived stores (vectors, ledger) first and rename in the graph last.\n4. Freeze private copies of any logic you depend on; never import live\n   models that may change later.\n\n### Tests\n\n- `cognee/tests/e2e/migrations/test_migration_model_lockstep.py` (+\n  `schema_baseline.json`): the lockstep CI job.\n- `cognee/tests/unit/test_run_migrations.py`: single Alembic head, startup\n  behaviour.\n- `cognee/tests/unit/test_frozen_schema_seal.py`: frozen schema fingerprint.\n- `cognee/tests/unit/modules/migrations/`: data-chain unit tests.\n- `cognee/tests/migrations/test_migration_lockstep.py`: data chain against\n  real stores (seed, down, up, verify).\n",".agents/skills/cognee-improve-sessions/SKILL.md":"---\nname: cognee-improve-sessions\ndescription: Use when working with cognee's session memory or improve() — storing conversation turns, agent traces and feedback with session_id, bridging sessions into the permanent graph, reading an ImproveResult, understanding why an improve stage was skipped, already_completed or lock_held, or tuning the IMPROVE_* settings.\n---\n\n# Session memory and improve()\n\ncognee has two kinds of memory:\n\n- **Session memory**: a fast cache of conversation turns, agent traces, and\n  feedback, keyed by `session_id`. Writing is instant, with no LLM\n  extraction.\n- **The permanent graph**: what `remember()` builds without a session.\n\n`improve()` connects them. It bridges session content into the graph and\nenriches the graph itself. `remember()` calls it automatically, so most\nusers never call it directly.\n\n```python\nimport cognee\n\n# Session write: returns immediately; improve() bridges it in the background\nawait cognee.remember(\"User prefers dark mode.\", session_id=\"chat_1\")\n\n# Session-aware query: session cache first, then the graph\nresults = await cognee.recall(\"What does the user prefer?\", session_id=\"chat_1\")\n\n# Bridge sessions into a dataset's graph explicitly\nresult = await cognee.improve(dataset=\"main_dataset\", session_ids=[\"chat_1\"])\nprint(result.status, result.stage_summary())\n\nawait cognee.wait_for_background_tasks()  # before a script exits\n```\n\n## Use it\n\n### Writing session memory\n\n| What | How |\n|---|---|\n| A fact or note | `remember(text, session_id=...)` (stored as a Q&A entry with the text as the answer) |\n| A Q&A turn | `recall(query, session_id=...)` with a completion search type saves the turn itself; or `remember(cognee.QAEntry(question=..., answer=...), session_id=...)` |\n| An agent step | `remember(cognee.TraceEntry(origin_function=..., status=\"success\", ...), session_id=...)`, or the `@cognee.agent_memory(save_session_traces=True)` decorator |\n| Pin a session to a project / node set | `node_set=[...]` on the first `QAEntry`/`TraceEntry` (or as a kwarg on any session `remember`) pins it; later writes repeat or omit it, a different set raises `cognee.SessionNodeSetConflictError` (HTTP 409). `improve()` keeps the set on everything it bridges, so `recall(node_name=[...])` scopes to the project |\n| Feedback on an answer | `remember(cognee.FeedbackEntry(qa_id=..., feedback_score=...), session_id=...)` or `cognee.session.add_feedback(session_id, qa_id, feedback_text=..., feedback_score=...)` |\n| Read a session | `cognee.session.get_session(session_id, last_n=...)` |\n\nRequirements: `CACHING=true` (default). The cache backend is\n`CACHE_BACKEND`, one of `sqlite` (default), `postgres`, `redis`, `fs`,\n`tapes`. Sessions expire after `SESSION_TTL_SECONDS` (default 7 days).\n\n### What improve() does: nine stages, in order\n\nEvery run goes through the same ordered stages\n(`cognee/modules/improve/registry.py`). Each stage checks a gate before it\nspends any LLM or embedding cost, and reports one `StageResult`.\n\n| # | Stage | What it does | Runs when |\n|---|---|---|---|\n| 1 | `feedback_weights` | Adjusts the weight of graph elements that rated answers used | `session_ids` given; adapter supports feedback weights |\n| 2 | `persist_session_qa` | Turns session Q&A into graph content (node set `user_sessions_from_cache`) | `session_ids` given. **The only fatal stage** |\n| 3 | `persist_agent_traces` | Turns agent-trace feedback into graph content | `session_ids` given |\n| 4 | `extract_agent_context` | Drafts agent-profile lessons from traces | `session_ids`, `CACHING` + `AUTO_FEEDBACK`, an LLM |\n| 5 | `distill_sessions` | Distills session learnings into the graph | `session_ids`, an LLM |\n| 6 | `update_user_preferences` | Folds rated turns into per-user preferences | `session_ids`, `PERSONALIZATION_ENABLED=true` (default false) |\n| 7 | `build_truth_subspace` | Builds the truth subspace from distilled learnings | `session_ids`, `build_truth_subspace=True`, a Ladybug graph |\n| 8 | `review_conflicts` | Reviews dated source facts, stores conflicts and rewrites Entity descriptions | `review_conflicts=True` or `IMPROVE_REVIEW_CONFLICTS=true`, an LLM, edge evidence |\n| 9 | `global_context_index` | Bucket and root summaries for global questions | `build_global_context_index=True`, an LLM |\n\nStages 1–7 need `session_ids`; 8–9 work on the graph alone. The order\nmatters: 4 feeds 5, 5 feeds 7, and 7 runs before 8.\n\n`extraction_tasks` / `enrichment_tasks` are deprecated and removed in the next\nrelease: they still run, as a `custom_tasks` stage after the others, scoped by\n`node_name`, `data`, `node_type`, `vector_db_config` and `graph_db_config`.\nWithout custom tasks those options are ignored. Both cases warn with a\n`FutureWarning`; use `run_custom_pipeline()` instead.\n\n### Reading the result\n\n`improve()` returns an `ImproveResult`, and so do `POST /api/v1/improve`, the\nCLI, and `RememberResult.improve`.\n\n- `result.status`: `completed`, `errored` (any stage errored), `skipped`\n  (every stage skipped), or `running` (background, not finished).\n- `result.stages`: one `StageResult` per stage, with `stage`, `status`\n  (`completed` / `already_completed` / `skipped` / `errored`), `reason`,\n  `error`, `counts`, `duration_ms`.\n- `result.stage(\"distill_sessions\")`, `result.stage_summary()`,\n  `result.lock_held`, `result.rerun_requested`, `result.rerun_passes`.\n- `await result.wait()` finishes a background run (no-op otherwise).\n\n**Skip and no-op reasons:**\n\n| Reason | Meaning / fix |\n|---|---|\n| `no_session_ids` | Session stage, no `session_ids` passed |\n| `disabled_by_config` | Listed in `IMPROVE_STAGES_DISABLED` |\n| `opt_in_disabled` | Pass `build_truth_subspace=True` / `review_conflicts=True` / `build_global_context_index=True` |\n| `personalization_disabled` | Set `PERSONALIZATION_ENABLED=true` |\n| `auto_feedback_disabled` | Stage 4 needs `CACHING=true` and `AUTO_FEEDBACK=true` |\n| `no_llm_configured` | Stages 4, 5, 8, 9 draft text with an LLM; none configured |\n| `edge_evidence_disabled` | Conflict review needs `EDGE_EVIDENCE_ENABLED=true` |\n| `backend_unsupported` | The graph adapter lacks the feature (feedback weights, truth subspace) |\n| `session_manager_unavailable` | The session cache is not reachable |\n| `lock_held` | Another improve for the same dataset or session is running (below) |\n| `aborted_by_fatal_stage` | Stage 2 failed, so the rest did not run |\n| `budget_exhausted` | An earlier stage failed because the LLM budget is exhausted (a 402); the rest would fail the same way. Top up, then run improve again |\n| `no_new_entries`, `no_new_trace_steps`, `no_new_facts`, `no_writes_since_last_improve` | With status `already_completed`: nothing new since the last run |\n\n### How remember() triggers improve\n\n- **Without a session:** `add`, then `cognify`, then a foreground `improve()`.\n  Its outcome is on `result.improve` / `result.improve_error`. A failed\n  improve never marks the remember as errored.\n- **With `session_id`:** the text is cached, then a background\n  `improve(dataset, session_ids=[session_id])` starts if the debounce allows\n  it. `result.improve` fills in only after `await result` or\n  `wait_for_background_tasks()`.\n- `self_improvement=False` turns it off per call; `IMPROVE_AUTO_ENABLED=false`\n  turns it off everywhere and overrides `self_improvement=True`.\n- An application embedding cognee can decline one automatic improve before it\n  starts: `cognee.modules.improve.register_auto_improve_admission(check)`\n  registers one async check that `remember()` awaits on both paths. Returning\n  a reason string skips the improve and sets `result.improve_skipped`\n  (`result.improve` stays `None`); the data is stored either way. A check that\n  raises allows the improve. Explicit `improve()` calls are never gated.\n\n### Settings (`IMPROVE_*`, `cognee/modules/improve/config.py`)\n\n| Env var | Default | Meaning |\n|---|---|---|\n| `IMPROVE_AUTO_ENABLED` | `true` | Automatic improve after `remember()` |\n| `IMPROVE_DEBOUNCE_ENTRIES` | `1` | Session auto-improve fires after this many new entries |\n| `IMPROVE_DEBOUNCE_SECONDS` | `0` | ...or this many seconds since the last one. Seconds alone (entries left at 1) means time-only |\n| `IMPROVE_STAGES_DISABLED` | empty | CSV of stage names to skip |\n| `IMPROVE_FEEDBACK_ALPHA` | `0.1` | Feedback learning rate, in (0, 1] |\n| `IMPROVE_REVIEW_CONFLICTS` | `false` | Review fact conflicts, including automatic improve |\n| `IMPROVE_EFFECTIVE_DATE_KEY` | `effective_date` | Document metadata key holding the source date |\n\nThere is no debounce timer: held-back entries wait for the next\n`remember()` with that session, or an explicit `improve()`.\n\n## Pitfalls\n\n- **A plain `improve(dataset)` often does nothing.** Without `session_ids`,\n  only stages 8–9 can run, and both are off by default. Result: every\n  stage `skipped`. That is expected, not an error.\n- **A session's node set is pinned once.** The first write carrying\n  `node_set` fixes it for the session; a different set is a 409, start a\n  new session instead. Bridged Q&A, traces and lessons carry the set, user\n  preferences never do. The guarantee holds within one worker process (an\n  in-process lock); with several workers, send a session's writes to one.\n  Example: `examples/guides/session_node_sets.py`.\n- **Typed entries do not auto-improve.** `remember(QAEntry/TraceEntry/\n  FeedbackEntry, session_id=...)` stores the entry but never starts an\n  improve. Call `improve(session_ids=[...])` yourself.\n- **`lock_held` does not wait.** Improves for the same dataset or session\n  run one at a time: a second call returns at once with every stage\n  `skipped: lock_held`. If it shares a session with the running one, it sets\n  `rerun_requested=True` and the holder runs up to 2 extra passes (3 passes\n  in total; see `rerun_passes`). The bound is `IMPROVE_MAX_RERUN_PASSES`, a\n  constant in `cognee/api/v1/improve/improve.py`, not an env var. The lock is per process only; multiple API workers do not\n  share it.\n- **Sessions bridge once.** Q&A and trace persistence are tracked per user\n  and session, not per dataset, so bridging a session into dataset A and\n  then into dataset B persists no new Q&A/traces into B. Distillation is\n  tracked per (session, dataset) and still runs into B.\n- **`IMPROVE_STAGES_DISABLED` is validated.** An unknown stage name, or\n  `persist_session_qa` (fatal, cannot be disabled), raises `ValueError`, and\n  the API server refuses to start.\n- **Session writes with the cache off.** `remember(text, session_id=...)`\n  with `CACHING=false` only logs a warning and stores nothing; typed entries\n  raise `RuntimeError`. An explicit `improve(session_ids=...)` then fails in\n  the fatal stage.\n- **Fatal stage failure.** If stage 2 errors, `improve()` raises (HTTP 409)\n  and the error carries `.improve_result`. In background mode it is recorded\n  on `result.error` instead. Other stages failing only mark themselves\n  `errored`; HTTP still returns 200, so check `status`.\n- **Remote mode.** After `cognee.serve(url)`, a background improve is\n  fire-and-forget: `status` stays `running` and there is no polling.\n- `cognee/modules/session_bridge/` is gone (only stale `__pycache__` may be\n  left). The bridging now lives in the improve stages; some test names still\n  say \"session_bridge\".\n\n## How it works\n\n`improve()` resolves the dataset once (creating it if the name is new),\nclaims the improve lock for `dataset:<id>` plus every\n`session:<user>:<session_id>`, probes the graph adapter's capabilities, and\nruns the stages with one frozen `ImproveRunInputs`. Each stage is a gate\nplus a call into existing pipelines plus a result mapping. Stages never own\nretries or ordering.\n\nWatermarks keep repeat runs cheap:\n\n- Session stages track how many entries were already persisted, per user\n  and session.\n- Conflict review uses its last succeeded stamp to select touched entities,\n  and retries conflicts with missing citations or pending writes. Source dates\n  come from document metadata; session windows use their last entry time.\n  Fixed attributes remain disputed even when one document is newer.\n\nThe improve operation row is written when the run finishes: `failed` if any\nstage errored (a retry is never gated off), `noop` if nothing ran.\n\n- Orchestrator: `cognee/api/v1/improve/improve.py` (HTTP:\n  `routers/get_improve_router.py`; CLI: `cognee/cli/commands/improve_command.py`)\n- Stages, registry, results: `cognee/modules/improve/` (`stages.py`,\n  `registry.py`, `stage.py`, `result.py`, `inputs.py`, `capabilities.py`,\n  `config.py`, `graph_changes.py`, `constants.py`)\n- Lock: `cognee/infrastructure/locks/session_lock.py`\n- Session store and watermarks: `cognee/infrastructure/session/`\n  (`session_manager.py`, `session_persist_watermark.py`,\n  `feedback_detection.py`); cache backends in\n  `cognee/infrastructure/databases/cache/`\n- Auto-improve from remember: `cognee/api/v1/remember/remember.py`,\n  `cognee/api/v1/remember/auto_improve_debounce.py`\n- Entry types: `cognee/memory/entries.py`\n- Background tasks: `cognee/infrastructure/background_tasks.py`\n\nExamples: `examples/guides/improve_quickstart.py`, `sessions.py`,\n`session_distillation.py`, `review_conflicts.py`, `global_context_index.py`,\n`agent_memory_quickstart.py`, and\n`examples/advanced_guides/remember_recall_improve_example.py`.\n\n## Extending it\n\nAdding a stage:\n\n1. Subclass `BaseStage` in `cognee/modules/improve/stages.py`. Set `name`,\n   `needs_sessions`, and `fatal` (leave it `False`; exactly one fatal stage\n   is enforced at import). Implement `gate()` (return a skip reason\n   constant, or `None`, before any LLM/embedding cost) and `run()` (call\n   existing pipeline code, return a `StageResult`).\n2. Insert it into `DEFAULT_STAGES` in `registry.py` at the right position.\n   The order is pinned by `cognee/tests/unit/modules/improve/test_registry_order.py`;\n   update it deliberately.\n3. If it can re-run cheaply, give it a watermark so a repeat run reports\n   `already_completed` (graph-wide stages can stamp the improve row with the\n   helpers in `graph_changes.py`, as conflict review does).\n4. Tests: `cognee/tests/unit/modules/improve/` (gates, results, config) and\n   `cognee/tests/unit/api/v1/improve/` (orchestration, rerun, router).\n",".agents/skills/cognee-performance/SKILL.md":"# cognee-performance\n\nPath: `.agents/skills/cognee-performance/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-performance/SKILL.md)",".agents/skills/cognee-permissions/SKILL.md":"# cognee-permissions\n\nPath: `.agents/skills/cognee-permissions/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-permissions/SKILL.md)",".agents/skills/cognee-recall/SKILL.md":"# cognee-recall\n\nPath: `.agents/skills/cognee-recall/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-recall/SKILL.md)",".agents/skills/cognee-server/SKILL.md":"# cognee-server\n\nPath: `.agents/skills/cognee-server/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-server/SKILL.md)",".agents/skills/company-brain-company-qa/SKILL.md":"# company-brain-company-qa\n\nPath: `.agents/skills/company-brain-company-qa/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/company-brain-company-qa/SKILL.md)",".agents/skills/company-brain-follow-up-agent/SKILL.md":"# company-brain-follow-up-agent\n\nPath: `.agents/skills/company-brain-follow-up-agent/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/company-brain-follow-up-agent/SKILL.md)",".agents/skills/personalized-email/SKILL.md":"# personalized-email\n\nPath: `.agents/skills/personalized-email/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/personalized-email/SKILL.md)",".agents/skills/self-hosted-companion/SKILL.md":"# self-hosted-companion\n\nPath: `.agents/skills/self-hosted-companion/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/self-hosted-companion/SKILL.md)","examples/demos/feedback/skill_feedback_loop/skills/diff-risk-explainer/SKILL.md":"# diff-risk-explainer\n\nPath: `examples/demos/feedback/skill_feedback_loop/skills/diff-risk-explainer/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/examples/demos/feedback/skill_feedback_loop/skills/diff-risk-explainer/SKILL.md)","examples/demos/feedback/skill_feedback_loop/skills/pr-comment-evaluator/SKILL.md":"# pr-comment-evaluator\n\nPath: `examples/demos/feedback/skill_feedback_loop/skills/pr-comment-evaluator/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/examples/demos/feedback/skill_feedback_loop/skills/pr-comment-evaluator/SKILL.md)","examples/demos/feedback/skill_feedback_loop/skills/skill-feedback-writer/SKILL.md":"# skill-feedback-writer\n\nPath: `examples/demos/feedback/skill_feedback_loop/skills/skill-feedback-writer/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/examples/demos/feedback/skill_feedback_loop/skills/skill-feedback-writer/SKILL.md)","AGENTS.md":"# AI Agent Protocol & Instructions\n\nPath: `AGENTS.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/AGENTS.md)","CLAUDE.md":"# Claude Agent Guidelines & System Prompt\n\nPath: `CLAUDE.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/CLAUDE.md)","evals/README.md":"# Evals Skill\n\nPath: `evals/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/README.md)","tools/spec_extras.json":"# Tools Skill\n\nPath: `tools/spec_extras.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/tools/spec_extras.json)","cognee_db_workers/ladybug_extensions/README.md":"# ladybug_extensions Documentation\n\nPath: `cognee_db_workers/ladybug_extensions/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/cognee_db_workers/ladybug_extensions/README.md)","evals/old/hotpot_50_corpus.json":"# Old Skill\n\nPath: `evals/old/hotpot_50_corpus.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_50_corpus.json)","evals/old/hotpot_50_qa_pairs.json":"# Old Skill\n\nPath: `evals/old/hotpot_50_qa_pairs.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_50_qa_pairs.json)","catalog/entries/packages/qdrant.yaml":"# Packages Skill\n\nPath: `catalog/entries/packages/qdrant.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/catalog/entries/packages/qdrant.yaml)","catalog/entries/packages/weaviate.yaml":"# Packages Skill\n\nPath: `catalog/entries/packages/weaviate.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/catalog/entries/packages/weaviate.yaml)","evals/old/cognee_01042025/aggregate_metrics_v_deepeval.json":"# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/aggregate_metrics_v_deepeval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/aggregate_metrics_v_deepeval.json)","evals/old/cognee_01042025/aggregate_metrics_v_direct_llm.json":"# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/aggregate_metrics_v_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/aggregate_metrics_v_direct_llm.json)","evals/old/cognee_01042025/metrics_output_cognee.json":"# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/metrics_output_cognee.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/metrics_output_cognee.json)","evals/old/cognee_01042025/metrics_output_cognee_direct_llm.json":"# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/metrics_output_cognee_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/metrics_output_cognee_direct_llm.json)","evals/old/cognee_01042025/metrics_output_cognee_human_eval.json":"# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/metrics_output_cognee_human_eval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/metrics_output_cognee_human_eval.json)","evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10.json":"# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10.json)","evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short.json":"# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short.json)","evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short_deepeval.json":"# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short_deepeval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short_deepeval.json)","evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10.json":"# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10.json)","evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10_short.json":"# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10_short.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10_short.json)","evals/old/comparative_eval/README.md":"# Comparative_eval Skill\n\nPath: `evals/old/comparative_eval/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/comparative_eval/README.md)","evals/old/comparative_eval/hotpot_50_corpus.json":"# Comparative_eval Skill\n\nPath: `evals/old/comparative_eval/hotpot_50_corpus.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/comparative_eval/hotpot_50_corpus.json)","evals/old/comparative_eval/hotpot_50_qa_pairs.json":"# Comparative_eval Skill\n\nPath: `evals/old/comparative_eval/hotpot_50_qa_pairs.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/comparative_eval/hotpot_50_qa_pairs.json)","evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk.json":"# Falkor_01042025 Skill\n\nPath: `evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk.json)","evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk_direct_llm.json":"# Falkor_01042025 Skill\n\nPath: `evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk_direct_llm.json)","evals/old/falkor_01042025/metrics_output_falkor_graph_sdk_human_eval.json":"# Falkor_01042025 Skill\n\nPath: `evals/old/falkor_01042025/metrics_output_falkor_graph_sdk_human_eval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/metrics_output_falkor_graph_sdk_human_eval.json)","evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk.json":"# Falkor_01042025 Skill\n\nPath: `evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk.json)","evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk_direct_llm.json":"# Falkor_01042025 Skill\n\nPath: `evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk_direct_llm.json)","evals/old/graphiti_01042025/aggregate_metrics_graphiti.json":"# Graphiti_01042025 Skill\n\nPath: `evals/old/graphiti_01042025/aggregate_metrics_graphiti.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/aggregate_metrics_graphiti.json)","evals/old/graphiti_01042025/aggregate_metrics_graphiti_direct_llm.json":"# Graphiti_01042025 Skill\n\nPath: `evals/old/graphiti_01042025/aggregate_metrics_graphiti_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/aggregate_metrics_graphiti_direct_llm.json)","evals/old/graphiti_01042025/metrics_output_graphiti.json":"# Graphiti_01042025 Skill\n\nPath: `evals/old/graphiti_01042025/metrics_output_graphiti.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/metrics_output_graphiti.json)","evals/old/graphiti_01042025/metrics_output_graphiti_direct_llm.json":"# Graphiti_01042025 Skill\n\nPath: `evals/old/graphiti_01042025/metrics_output_graphiti_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/metrics_output_graphiti_direct_llm.json)","evals/old/graphiti_01042025/metrics_output_graphiti_huma_eval.json":"# Graphiti_01042025 Skill\n\nPath: `evals/old/graphiti_01042025/metrics_output_graphiti_huma_eval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/metrics_output_graphiti_huma_eval.json)","evals/old/graphiti_updated/hotpot_qa_graphiti_results_old.json":"# Graphiti_updated Skill\n\nPath: `evals/old/graphiti_updated/hotpot_qa_graphiti_results_old.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old.json)","evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics.json":"# Graphiti_updated Skill\n\nPath: `evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics.json)","evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics_direct_llm.json":"# Graphiti_updated Skill\n\nPath: `evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics_direct_llm.json)","evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics.json":"# Graphiti_updated Skill\n\nPath: `evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics.json)","evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics_direct_llm.json":"# Graphiti_updated Skill\n\nPath: `evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics_direct_llm.json)","evals/old/hotpot_qa_24_2025/README.md":"# Hotpot_qa_24_2025 Skill\n\nPath: `evals/old/hotpot_qa_24_2025/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/README.md)","evals/old/hotpot_qa_24_2025/benchmark_summary_cognee.json":"# Hotpot_qa_24_2025 Skill\n\nPath: `evals/old/hotpot_qa_24_2025/benchmark_summary_cognee.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/benchmark_summary_cognee.json)","evals/old/hotpot_qa_24_2025/benchmark_summary_competition.json":"# Hotpot_qa_24_2025 Skill\n\nPath: `evals/old/hotpot_qa_24_2025/benchmark_summary_competition.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/benchmark_summary_competition.json)","evals/old/mem0_01042025/aggregate_metrics_mem0.json":"# Mem0_01042025 Skill\n\nPath: `evals/old/mem0_01042025/aggregate_metrics_mem0.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/aggregate_metrics_mem0.json)","evals/old/mem0_01042025/aggregate_metrics_mem0_direct_llm.json":"# Mem0_01042025 Skill\n\nPath: `evals/old/mem0_01042025/aggregate_metrics_mem0_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/aggregate_metrics_mem0_direct_llm.json)","evals/old/mem0_01042025/metrics_output_mem0.json":"# Mem0_01042025 Skill\n\nPath: `evals/old/mem0_01042025/metrics_output_mem0.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/metrics_output_mem0.json)","evals/old/mem0_01042025/metrics_output_mem0_direct_llm.json":"# Mem0_01042025 Skill\n\nPath: `evals/old/mem0_01042025/metrics_output_mem0_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/metrics_output_mem0_direct_llm.json)","evals/old/mem0_01042025/metrics_output_mem0_human_eval.json":"# Mem0_01042025 Skill\n\nPath: `evals/old/mem0_01042025/metrics_output_mem0_human_eval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/metrics_output_mem0_human_eval.json)","evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_corpus.json":"# Src Skill\n\nPath: `evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_corpus.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_corpus.json)","evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_instance_filter.json":"# Src Skill\n\nPath: `evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_instance_filter.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_instance_filter.json)","evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_qa_pairs.json":"# Src Skill\n\nPath: `evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_qa_pairs.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_qa_pairs.json)"},"files":{".agents/skills/cognee-docker/SKILL.md":"---\nname: cognee-docker\ndescription: Use when the user wants to run cognee with Docker or docker compose — trying it out from the prebuilt image, starting the API server in a container, or bringing up the full stack (UI, MCP, Postgres, Neo4j) with compose profiles.\n---\n\n# Start cognee from the Docker image\n\n## Fastest path: prebuilt image, one file\n\nFor a local try-out, do NOT clone or build anything. Follow\n`docs/minimal-docker-compose.md`: save this as `docker-compose.yml` in an\nempty directory:\n\n```yaml\nservices:\n  cognee:\n    image: cognee/cognee:main\n    ports:\n      - \"8000:8000\"\n    environment:\n      LLM_API_KEY: ${LLM_API_KEY:?set LLM_API_KEY to your OpenAI API key}\n      # Single-user try-out: no auth, shared local databases.\n      ENABLE_BACKEND_ACCESS_CONTROL: \"false\"\n```\n\nThen:\n\n```bash\nexport LLM_API_KEY=\"sk-...\"   # OpenAI key (default LLM + embedding provider)\ndocker compose up\ncurl http://localhost:8000/health\n```\n\nInteractive API reference: http://localhost:8000/docs. First requests:\n\n```bash\necho \"Cognee turns documents into AI memory.\" > note.txt\n# remember = ingest + build the graph in one call (multipart form)\ncurl -X POST http://localhost:8000/api/v1/remember -F \"data=@note.txt\" -F \"datasetName=main_dataset\"\n# recall = query it (JSON)\ncurl -X POST http://localhost:8000/api/v1/recall -H \"Content-Type: application/json\" \\\n  -d '{\"query\": \"What does Cognee do?\", \"datasets\": [\"main_dataset\"]}'\n```\n\n`/api/v1/recall` takes the question as `query`. Omit `search_type` (or pass\n`null`) and the query is auto-routed by the same rule-based router the SDK\n`recall()` uses, with `HYBRID_COMPLETION` as the fallback; pass a value such as\n`\"search_type\": \"GRAPH_COMPLETION\"` to pin a strategy. The rule table is in\n`docs/recall-vs-search.md`.\n\nRequest DTOs accept both `snake_case` and `camelCase` for every field\n(`alias_generator=to_camel` + `populate_by_name` in `cognee/api/DTO.py`), so\n`search_type` and `searchType` are equally valid.\n\nThe legacy `/api/v1/add` + `/api/v1/cognify` + `/api/v1/search` endpoints still\nexist and are what `remember`/`recall` call underneath; use them only when you\nneed a single stage on its own. `/api/v1/improve` and `/api/v1/forget` complete\nthe memory API.\n\nData lives inside the container by default. To persist it, set\n`DATA_ROOT_DIRECTORY=/cognee-data/data` and\n`SYSTEM_ROOT_DIRECTORY=/cognee-data/system` and mount a named volume at\n`/cognee-data` (full example in `docs/minimal-docker-compose.md`).\n\n## Full stack from the repo\n\nThe repository's `docker-compose.yml` builds from source and adds opt-in\nprofiles. From the repo root (needs a `.env` with at least `LLM_API_KEY`;\ncopy `.env.template`):\n\n```bash\ndocker compose up                                  # API server only, port 8000\ndocker compose --profile ui up                     # + frontend on port 3000\ndocker compose --profile mcp up                    # + MCP server on port 8001\ndocker compose --profile postgres --profile neo4j up   # + databases\n```\n\nPostgres profile: pgvector/pg17, user/password/db `cognee`/`cognee`/`cognee_db`\non 5432. Neo4j profile: `neo4j`/`pleaseletmein` on 7474/7687. When cognee runs\nin a container and the database on the host, use `DB_HOST=host.docker.internal`.\n\n## Gotchas\n\n- With `ENABLE_BACKEND_ACCESS_CONTROL` unset (defaults to true), every API\n  call requires authentication — the single-user try-out sets it to `false`.\n- The image defaults to OpenAI for both LLM and embeddings; configuring only\n  one of them leaves the other on OpenAI, so keep a valid OpenAI key or\n  configure both (see the cognee-integrations skill).\n",".agents/skills/cognee-forget/SKILL.md":"---\nname: cognee-forget\ndescription: Use when removing data from cognee memory with forget() in the SDK, HTTP API, or CLI — finding which dataset and document hold the content to delete (listing datasets and data items, reading raw content), choosing between deleting one document, a whole dataset, or only the graph/vector memory, and doing it safely.\n---\n\n# Remove data with forget()\n\n`forget()` is cognee's one deletion API. It removes one document, a whole\ndataset, or only the derived memory (graph + vectors) while keeping the raw\nfiles. Deletion cannot be undone, so the workflow is always **find, read,\nconfirm, then delete**.\n\n> **Hard limits for agents**\n> - Delete only what the user asked to forget. Identify it by reading the\n>   content first; never guess from a file name alone.\n> - Confirm the exact items with the user before deleting, unless they\n>   already named exact ids.\n> - The widest deletion you may run is `forget(everything=True)`, and only\n>   when the user explicitly asks to wipe all of their memory. Never use any\n>   other reset or wipe mechanism to delete data.\n\n## Use it\n\n### 1. Find the dataset\n\n```python\nimport cognee\n\ndatasets = await cognee.datasets.list_datasets()  # datasets the user can read\nfor ds in datasets:\n    print(ds.id, ds.name)\n```\n\nHTTP: `GET /api/v1/datasets`. CLI: `cognee-cli datasets list`.\n\n### 2. List its documents\n\n```python\nitems = await cognee.datasets.list_data(dataset_id)  # all Data rows, oldest first\nfor item in items:\n    print(item.id, item.name, item.extension, item.created_at)\n```\n\nHTTP: `GET /api/v1/datasets/{dataset_id}/data?limit=100&offset=0` (limit up\nto 1000; `GET .../data/count` for the total; example:\n`examples/python/dataset_data_pagination.py`). CLI:\n`cognee-cli datasets data <dataset_uuid>`.\n\nEach item has `id`, `name`, `created_at`, `extension`, `mime_type`,\n`raw_data_location`, `dataset_id`, `label`, `external_metadata` (including\nany `node_set`), and `data_size`.\n\n### 3. Read the content before deciding\n\nNames are often `text_<hash>.txt`, so read the content to find what the user\nmeans.\n\n- HTTP: `GET /api/v1/datasets/{dataset_id}/data/{data_id}/raw` returns the\n  stored file (404 if it is gone).\n- SDK: there is no \"get raw\" helper; open the stored location:\n\n```python\nfrom cognee.infrastructure.files.utils.open_data_file import open_data_file\n\nasync with open_data_file(item.raw_data_location, mode=\"rb\") as f:\n    preview = f.read(2000).decode(\"utf-8\", errors=\"replace\")\n```\n\nJudge matches by meaning, not only by keywords, and show the user the\ncandidates (name + a short preview) before deleting.\n\n### 4. Delete\n\n| Goal | Call | What remains |\n|---|---|---|\n| One document | `forget(data_id=..., dataset_id=...)` (or `dataset=\"name\"`) | Nothing of that document; shared entities stay while another document still references them |\n| A whole dataset | `forget(dataset=\"name\")` or `forget(dataset_id=...)` | The dataset is deleted outright: the record, its data rows, graph and vector stores, and attributed sessions |\n| Rebuild a dataset's graph later | `forget(dataset=\"name\", memory_only=True)` | Raw files and data rows; graph, vectors, sessions and pipeline status are reset, so the data can be re-processed |\n| One document's memory only | `forget(dataset=\"name\", data_id=..., memory_only=True)` | That document's raw file and row |\n| Every dataset the user can delete | `forget(everything=True)` | Nothing, in any dataset the user has `delete` on in the current tenant (shared ones included). Only on explicit request (see the hard limits) |\n\nReturn values: `{\"data_id\", \"dataset_id\", \"status\"}` for a document,\n`{\"dataset_id\", \"status\"}` for a dataset (plus `data_records_reset` with\n`memory_only`), `{\"datasets_removed\", \"status\"}` for everything\n(`datasets_removed` counts the datasets the user can *read*, not the delete\nset).\n\n**HTTP:** `POST /api/v1/forget` with a JSON body; camelCase and snake_case\nkeys both work: `{\"datasetId\": \"...\", \"dataId\": \"...\"}`,\n`{\"dataset\": \"name\", \"memoryOnly\": true}`, `{\"everything\": true}`. Invalid\ncombinations return 422.\n\n**CLI:** `cognee-cli forget --dataset NAME | --dataset-id UUID\n[--data-id UUID] [--memory-only]`, or `--everything` / `--all`. The CLI\n**does not ask for confirmation**; confirm with the user first.\n\n## Pitfalls\n\n- **A `data_id` that is not in the dataset returns success and deletes\n  nothing.** The delete path treats an unknown id as a custom-graph-model\n  delete. Always take the id from `list_data` for that same dataset, and\n  check it is still listed afterwards if it matters.\n- **Pass either `dataset` or `dataset_id`, not both** (`ValueError`).\n  `data_id` and `memory_only` both need a dataset.\n- **`memory_only` is ignored when `everything=True`** in the SDK (the CLI\n  rejects the combination). `everything=True` always deletes everything.\n- **Not found and not allowed look the same.** An unknown dataset name and\n  one the user cannot delete both raise `DatasetNotFoundError`. Deleting\n  needs the `delete` permission on the dataset (see the `cognee-permissions`\n  skill). `everything=True` deletes every dataset the user has `delete`\n  permission on in the current tenant, including datasets shared to them\n  with delete rights, not only the ones they own.\n- **Sessions that cited deleted data are invalidated** so recall stops\n  returning answers built on it. Agent-trace entries are not invalidated.\n- **Changing a document is not a delete.** To replace a document's content,\n  use `cognee.update(data_id=..., data=..., dataset_id=...)`, which keeps its\n  id and re-extracts only the changed parts.\n- `cognee.delete()` is deprecated; use `forget()`.\n\n## How it works\n\n`forget()` resolves the dataset with the `delete` permission, then:\n\n- **One document** → `datasets.delete_data()`: takes the dataset lock,\n  deletes the graph nodes and edges the document owns, the matching vectors\n  and edge evidence, invalidates sessions that cited them, then deletes the\n  `Data` row. Ownership is tracked per document (source-refs on graph\n  elements), so an entity shared by two documents survives until both are\n  deleted. Raw files are reference-counted by storage location.\n- **A dataset** → `datasets.empty_dataset()`.\n- **`memory_only`** → drops the dataset's graph/vector memory and resets its\n  pipeline status, leaving raw data for a rebuild.\n- **`everything`** → `datasets.delete_all()` over every dataset the user has\n  `delete` on in the current tenant, plus a full prune of the session cache\n  (when caching or usage logging is on). This wipes **every user's**\n  sessions (Redis FLUSHDB / the whole fs cache / all SQL cache tables), not\n  just this user's.\n\nKey files:\n\n- `cognee/api/v1/forget/forget.py` (SDK), `routers/get_forget_router.py`\n  (HTTP), `cognee/cli/commands/forget_command.py` (CLI)\n- `cognee/api/v1/datasets/datasets.py` (`list_datasets`, `list_data`,\n  `delete_data`, `empty_dataset`, `delete_all`)\n- `cognee/api/v1/datasets/routers/get_datasets_router.py` (list, count, raw)\n- `cognee/infrastructure/databases/provenance/source_refs.py` (per-document\n  ownership of graph elements)\n- `cognee/infrastructure/files/utils/open_data_file.py`\n\n## Extending it\n\n- Anything new that writes graph nodes or edges for a document must record\n  its source-refs, or `forget(data_id=...)` cannot find and remove it.\n- Anything new that stores per-document data outside the graph (like edge\n  evidence) needs a cleanup step in the delete path and in `memory_only`.\n- Unit tests for `forget()` are in `cognee/tests/unit/api/v1/forget/`\n  (argument validation, the HTTP endpoint, `memory_only`); cover both the\n  document and the `memory_only` paths for new deletion behaviour.\n",".agents/skills/cognee-community/SKILL.md":"---\nname: cognee-community\ndescription: Use when the user needs something that ships outside cognee core — community database adapters (Qdrant, Milvus, Weaviate, Redis, Pinecone, FalkorDB, Memgraph, DuckDB, NetworkX, …), data-source connectors (Slack, Gmail, Notion, Confluence, Google Drive), custom tasks/pipelines/retrievers (Exa, ScrapeGraph, codify), Keywords AI observability — or wants to contribute a package to the cognee-community repo.\n---\n\n# Use and contribute cognee-community packages\n\nCommunity-maintained plugins live in a separate monorepo:\nhttps://github.com/topoteretes/cognee-community. Everything installable is\nunder `packages/`; `experimental/` holds demos (n8n nodes, dlt demos,\nbauplan, tower) that are not published packages. Each package publishes to\nPyPI as `cognee-community-<family>-<kind>-<name>` and imports as the same\nname with underscores.\n\n## Package families\n\n| Family | Packages |\n|---|---|\n| Vector adapters | azureaisearch, milvus, moss, opengauss, opensearch, pinecone, qdrant, redis, singlestore, turbopuffer, valkey, weaviate |\n| Graph adapters | arcadedb, memgraph, networkx, pggraph, spanner, turbopuffer, turingdb |\n| Hybrid (graph+vector in one DB) | arcadedb, duckdb, falkordb, helixdb |\n| Connectors (data sources) | confluence, gmail, google-drive, notion, slack |\n| Tasks / pipelines / retrievers | codify_tasks, codify_pipeline, code_retriever, exa_tasks, scrapegraph_tasks |\n| Observability | keywordsai (`MONITORING_TOOL=keywordsai` + `KEYWORDSAI_API_KEY`) |\n\n## Using a database adapter\n\nInstall, then **import the package's `register` module before cognee touches\nany engine** — registration is what makes the provider name valid:\n\n```python\nuv pip install cognee-community-vector-adapter-qdrant\n```\n\n```python\nimport cognee\nfrom cognee import config\nfrom cognee_community_vector_adapter_qdrant import register  # noqa: F401\n\nconfig.set_vector_db_config(\n    {\n        \"vector_db_provider\": \"qdrant\",\n        \"vector_db_url\": \"http://localhost:6333\",\n        \"vector_db_key\": \"...\",\n        \"vector_dataset_database_handler\": \"qdrant\",  # only if the adapter ships one\n    }\n)\n```\n\nThe `register.py` calls `use_vector_adapter(name, AdapterClass)` /\n`use_graph_adapter(...)`. Setting `VECTOR_DB_PROVIDER`/`GRAPH_DATABASE_PROVIDER`\nto a community name **without** the register import raises \"Unsupported\nvector database provider\". Hybrid adapters (e.g. falkordb) register as both\ngraph and vector — set both configs to the same provider name.\n\n**Multi-tenancy caveat**: with `ENABLE_BACKEND_ACCESS_CONTROL=true` (the\ndefault), both backends must have a dataset-database handler or cognee raises\n`EnvironmentError`. Community adapters that ship one (registered via\n`use_dataset_database_handler` in their `register.py`): qdrant, moss,\nsinglestore, turbopuffer (vector + graph), falkordb, arcadedb, helixdb. All\nother community adapters need `ENABLE_BACKEND_ACCESS_CONTROL=false`.\n\n## Using a connector\n\nConnectors expose a `dlt` source you hand straight to `remember()`; they\nreuse core's DLT ingestion path, so snapshot sync and forget-on-delete work\nwith no core changes:\n\n```python\nfrom cognee_community_connector_slack import slack_export_source\n\nawait cognee.remember(\n    slack_export_source(\"/path/to/slack-export\"),\n    dataset_name=\"team-slack-export\",  # use a dedicated dataset\n    max_rows_per_table=0,\n)\n```\n\nSame shape for gmail (\"ask my inbox\"), notion, confluence, and google-drive\n(incremental, forget-on-delete). Each package README documents its\ncredentials; always give a connector its own dataset.\n\n## Verifying an install\n\nEvery package has `examples/example.py` (run `uv run python examples/example.py`\nfrom the package dir) and a `tests/` directory. An LLM API key is still\nrequired (`LLM_API_KEY`, OpenAI by default).\n\n## Contributing a package\n\n- **Branch from `main`** — unlike the core repo, cognee-community does not\n  use a `dev` branch.\n- Follow the existing structure: package dir under `packages/<family>/<name>/`\n  with `pyproject.toml`, a `README.md` (install + usage), `examples/example.py`,\n  and `tests/` that go beyond the example.\n- New DB adapters implement `VectorDBInterface` / `GraphDBInterface` from\n  core, expose a `register.py`, and should run the shared conformance tests\n  in `packages/shared/contract_suite/` (vector_contract.py / graph_contract.py).\n- Add a handler via `use_dataset_database_handler(...)` if the backend can\n  isolate per user+dataset — that's what makes it work with access control on.\n- Name it `cognee-community-<family>-<kind>-<name>` and add it to the tables\n  in the repo README. Lint config is the repo-root `ruff.toml`.\n",".agents/skills/cognee-cli/SKILL.md":"---\nname: cognee-cli\ndescription: Use when the user wants to drive cognee from the terminal with cognee-cli — remember/recall/forget/improve memory commands, managing datasets and config, or database migrations.\n---\n\n# Use the cognee CLI\n\n`cognee-cli` ships with the package (entry point in `cognee/cli/_cognee.py`;\neach command lives in `cognee/cli/commands/`). Every command has\n`--help` for its flags, but only a few (`demo`, `eval`, `serve`,\n`push`, `upgrade`, `downgrade`, `stamp`, and `search` with one CODE example)\ninclude usage examples — for the memory commands use the examples\nin this file. Needs `LLM_API_KEY` configured, same as the SDK.\n\n## Core flow\n\nThe memory commands are the primary surface as of cognee 1.x:\n\n```bash\ncognee-cli remember \"Your text here\"         # also accepts file paths / URLs\ncognee-cli remember ./docs --dataset-name my_project\ncognee-cli recall \"Your question\"            # query the graph\ncognee-cli recall \"keyword\" --query-type CHUNKS\ncognee-cli forget --all                      # wipe local state\n```\n\n`remember` is ingest + graph build in one step (`add` + `cognify` under the\nhood); `--background`/`-b` runs the cognify stage in the background, and\n`--dry-run` estimates LLM tokens/cost without ingesting. `recall` takes\n`--datasets`/`-d`, `--top-k`/`-k` (default 10), and `--session-id`/`-s`.\n\n`forget` targets `--dataset`, `--dataset-id`, `--data-id` (needs a dataset), or\n`--everything`/`--all` — one unified command replacing the older `delete` and\nempty-dataset paths. `--memory-only` (with a dataset) drops the graph and\nvectors but keeps the raw files, so the data can be rebuilt.\n\n> **`forget --all` does not ask for confirmation.** It deletes every dataset\n> immediately, even on a non-interactive stdin. The legacy `delete --all`\n> prompts `Delete ALL data from cognee? [y/N]` first, so switching to `forget`\n> silently drops that safety net — script it with care.\n\n`--query-type` accepts 10 of the SDK's 20 `SearchType` values — the list in\n`cognee/cli/config.py:SEARCH_TYPE_CHOICES`: HYBRID_COMPLETION, GRAPH_COMPLETION,\nRAG_COMPLETION, CHUNKS, CHUNKS_LEXICAL, SUMMARIES, CODE, CYPHER, GRAPH_REPORT,\nSKILLS. The rest (TEMPORAL, GRAPH_COMPLETION_COT,\nAGENTIC_COMPLETION, NATURAL_LANGUAGE, …) are SDK-only, e.g.\n`cognee.recall(q, query_type=SearchType.TEMPORAL)`.\n\nWhen `--query-type` is omitted the CLI uses `HYBRID_COMPLETION`\n(`DEFAULT_SEARCH_TYPE`), whereas the SDK's `cognee.recall()` auto-routes\nbetween search types. `--top-k` defaults to 10 on the CLI and 15 in the SDK.\n\n## Session memory and enrichment\n\nSession entries are currently written from the SDK — `cognee.remember(...,\nsession_id=\"chat_1\")` — not the CLI (`cognee-cli remember` has no session\nflag). The CLI side of session memory is reading and bridging:\n\n```bash\ncognee-cli recall \"question\" -s chat_1       # session cache first: without -d/-t\n                                             # this searches the session directly\ncognee-cli sessions get                      # retrieve session Q&A history\ncognee-cli improve -d my_project -s chat_1   # bridge session content into the graph\ncognee-cli improve -d my_project             # enrich/index the graph (no session)\ncognee-cli feedback ...                      # attach feedback to results\n```\n\n`improve` also takes `--feedback-alpha` (learning rate in\n(0, 1]; default `IMPROVE_FEEDBACK_ALPHA`, 0.1), `--build-global-context-index`,\n`--build-truth-subspace` (both opt-in stages; the truth subspace needs\n`-s`), and `--background`/`-b` (`--node-name` is deprecated: it warns and is\nignored). It prints one line per stage — name, status\n(`completed` / `already_completed` / `skipped` / `errored`) and the skip\nreason (e.g. `no_session_ids`, `lock_held`, `opt_in_disabled`).\n`remember`/`improve` build their graphs through `cognify()`, so cognify-level\nsettings (e.g. `PROVENANCE_TRACKING=true`) apply to them too.\n\n## Legacy / lower-level commands\n\n`add`, `cognify`, `search`, and `delete` still ship and are what the\nmemory commands call underneath. Use them only to drive a single stage in\nisolation; prefer `remember`/`recall`/`forget`/`improve` otherwise.\n\n```bash\ncognee-cli add \"text\" && cognee-cli cognify  # what `remember` does in one step\ncognee-cli search \"question\"                 # `recall` minus routing/scope/session sources\ncognee-cli delete --all                      # superseded by `forget --all`\n```\n\n## Management\n\n```bash\ncognee-cli datasets list                     # dataset operations\ncognee-cli config get [key] [--show-secrets] # view one/all settings (API keys masked by default)\ncognee-cli config set <key> <value>          # set + persist to ./.env in the cwd\ncognee-cli config unset <key>                # reset a key to its default (also persisted)\ncognee-cli -ui                               # launch API server + UI (see cognee-server skill)\ncognee-cli serve --url http://localhost:8000 # connect CLI/SDK to a running instance\n```\n\n## Database migrations\n\ncognee has two migration chains: the relational schema (Alembic, in\n`cognee/alembic/`) and the graph/vector data chain (slugs registered in\n`cognee/modules/migrations/registry.py`). Both run automatically — at API\nserver startup and on the first write (`remember`, `add`, `cognify`,\n`improve`, …) in an SDK/CLI process — unless `ENABLE_AUTO_MIGRATIONS=false`.\nSo you rarely need these commands; they are for inspecting state, disabled\nauto-migration, and rollbacks. There is no `migrate` command.\n\n```bash\ncognee-cli current                    # stamped revision per database (per dataset\n                                      # with access control on)\ncognee-cli history                    # the data-migration chain, newest first\ncognee-cli upgrade                    # relational to head, then data chain to head\ncognee-cli upgrade <slug>             # data chain up to and including <slug>\ncognee-cli upgrade --alembic <rev>    # pin the relational (Alembic) target\ncognee-cli downgrade <slug|base>      # REWRITES DATA; revision is required,\n                                      # prompts unless --force; --dataset <uuid>\n                                      # (repeatable) limits it\ncognee-cli stamp <head|base|slug>     # set the stored revision WITHOUT running\n                                      # anything; prompts unless --force;\n                                      # --dataset <uuid> (repeatable) limits it\n```\n\nThe positional revision is always a **data-chain slug**; the relational\ntarget goes through `--alembic`. `downgrade` leaves the relational schema\nalone unless you pass `--alembic`. `upgrade` runs even when\n`ENABLE_AUTO_MIGRATIONS=false`. `--alembic-path` (or `COGNEE_ALEMBIC_PATH`)\npoints at a custom Alembic scripts directory.\n\n## Gotchas\n\n- The CLI initializes cognee lazily; the first command in a fresh environment\n  is slow (DB + model setup), later ones are fast.\n- `remember` (and `add`) without `--dataset-name` targets the default dataset\n  `main_dataset`; `recall`/`search` operate across your accessible datasets\n  unless a dataset is given.\n- `forget` refuses to run bare — pass `--dataset`, `--dataset-id`, `--data-id`\n  (with a dataset), or `--everything`/`--all`.\n- Session commands (`recall -s`, `sessions get`, `improve -s`) require\n  `CACHING=true` (the default) — with it off, session reads return nothing and\n  SDK session writes raise. To cut read latency and token cost while keeping\n  session memory, `cognee-cli config set AUTO_FEEDBACK false` — by default\n  cognee makes one structured-output LLM call per answered query to self-tune\n  its memory.\n- `config set`/`config unset` write to the `.env` file in whatever directory\n  you run the command from (creating it if missing). `config reset` (reset\n  *all* keys) is still not implemented.\n- **Which `.env` actually wins is not always the cwd one.** At import, cognee\n  calls `dotenv.load_dotenv(override=True)`, which resolves relative to the\n  *cognee package location*, not your working directory. In a source/editable\n  checkout (`uv pip install -e .`) a `.env` at the repo root therefore shadows\n  the `.env` in the directory you ran from — and because `override=True`, it\n  also beats variables you `export`ed. Symptom: `config set` appears to do\n  nothing, or the CLI connects to a backend you thought you had overridden.\n  To test against different settings, move the repo `.env` aside, or set\n  values programmatically after import (`cognee.config.set_*`). (Under\n  `python -c` the cwd `.env` does win, because dotenv falls back to the cwd\n  when `__main__` has no `__file__` — which is why the same command can\n  behave differently as a script vs. `-c`.)\n",".agents/skills/cognee-custom-pipelines/SKILL.md":"---\nname: cognee-custom-pipelines\ndescription: Use when building your own cognee processing — writing custom tasks, chaining them into a pipeline with run_custom_pipeline or the lightweight run_pipeline (from cognee.pipelines import run_pipeline), storing custom DataPoints with add_data_points, running custom enrichment over the existing graph, checking pipeline run status, or debugging how data flows between tasks (batch_size, data_per_batch, ctx, Drop, enriches).\n---\n\n# Custom tasks and pipelines\n\nEverything cognee does runs as a **pipeline**: an ordered list of **tasks**,\neach a plain Python function whose output feeds the next one. `remember()`\nis the right tool for ordinary ingestion. Build a pipeline when you need\nprocessing cognee does not ship: your own extraction, your own node types,\nor a post-processing step over the graph.\n\n```python\nimport cognee\nfrom cognee.modules.pipelines import Task\nfrom cognee.tasks.storage import add_data_points\nfrom cognee.low_level import DataPoint\n\n\nclass Person(DataPoint):\n    name: str\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nasync def extract_people(data_items: list) -> list[Person]:\n    people = []\n    for item in data_items:  # always a list, see below\n        text = item if isinstance(item, str) else \"\"\n        people += [Person(name=n.strip()) for n in text.split(\",\") if n.strip()]\n    return people\n\n\nresult = await cognee.run_custom_pipeline(\n    tasks=[\n        Task(extract_people, needs_llm=False),\n        Task(add_data_points, needs_llm=False),  # store in graph + vector DBs\n    ],\n    data=[\"Ada Lovelace, Alan Turing\"],\n    dataset=\"people\",\n)\n```\n\n## Use it\n\n### Pick the runner\n\nThere are three, and two share the name `run_pipeline`:\n\n| Runner | Import | Use it for |\n|---|---|---|\n| `cognee.run_custom_pipeline(...)` | `cognee` | The normal choice: runs your tasks against a dataset with permissions, a per-dataset lock, run records, and status |\n| Full orchestrator `run_pipeline(tasks=..., data=..., datasets=...)` | `cognee.modules.pipelines` | What `run_custom_pipeline` and `cognify` call; yields `PipelineRunInfo` |\n| Lightweight `run_pipeline([...], data=...)` | `from cognee.pipelines import run_pipeline` (after `import cognee`, the attribute `cognee.pipelines.run_pipeline` is the orchestrator) | Quick chains of `task()` specs with no permissions, locks, run rows, or migrations; returns the last step's outputs |\n\n`cognee.run_custom_pipeline(tasks, data=None, dataset=\"main_dataset\",\nuser=None, incremental_loading=False, data_per_batch=20,\nrun_in_background=False, pipeline_name=\"custom_pipeline\", data_cache=False,\n...)` returns `{dataset_id: PipelineRunInfo}` (the started run when\n`run_in_background=True`). With `data=None` it runs over the dataset's\nexisting documents (`Data` rows).\n\n### Write a task\n\n```python\nfrom cognee.modules.pipelines import Task\nfrom cognee.modules.pipelines.models import PipelineContext\nfrom cognee.modules.pipelines.tasks.task import task_summary\nfrom cognee.pipelines import Drop\n\n\n@task_summary(\"Tagged {n} chunk(s)\")\nasync def tag_chunks(chunks: list, ctx: PipelineContext = None, label: str = \"x\"):\n    for chunk in chunks:\n        chunk.metadata[\"label\"] = label\n    return chunks  # or yield per item; return/yield Drop to discard\n\n\ntag = Task(tag_chunks, label=\"reviewed\", batch_size=10, needs_llm=False)\n```\n\n- A task is an `async def`, a generator, an async generator, or a plain\n  `def`. Extra `Task(fn, *args, **kwargs)` arguments are passed after the\n  pipeline data.\n- `needs_llm=False` on tasks that never call an LLM lets an LLM-free\n  pipeline skip the LLM connection check.\n- `ctx` (injected by the parameter **name** `ctx`) carries `user`,\n  `data_item`, `dataset`, `pipeline_run_id`, `pipeline_name`, and `extras`.\n- `task.with_config(batch_size=..., **kwargs)` returns a modified copy.\n\n### How data flows\n\n- **Each document runs the whole chain on its own** with `run_custom_pipeline`\n  or the orchestrator, and the first task receives it as a **one-element\n  list** (`[data_item]`), not the bare item. The lightweight `run_pipeline`\n  passes `data` to the first task unchanged.\n- **`data_per_batch`** (default 20) is how many documents run at the same\n  time. It is a concurrency limit, not a batch size.\n- **`batch_size` belongs to the consumer.** A task's `batch_size` decides how\n  the *previous* task's generator output is grouped before it is passed in.\n  Generator tasks always hand over lists; a coroutine or function hands over\n  its single return value.\n- **Streaming:** each upstream result goes down the chain immediately, so a\n  downstream task can run many times per document.\n- **`enriches=True`:** if the task returns `None`, its input is passed on\n  unchanged (coroutines and functions only, not generators).\n- **`Drop`:** returning or yielding it removes that item from the stream.\n- Every `DataPoint` passing through is stamped automatically with where it\n  came from (`source_pipeline`, `source_task`, `source_user`, …).\n\n### Store results\n\n`add_data_points(data_points, custom_edges=None, graph_only=False)` writes a list of `DataPoint`s to the graph and indexes\ntheir `index_fields` in the vector DB. It returns the same list, so it can\nsit mid-chain. Give every node type `identity_fields` so repeated runs merge\ninstead of duplicating (see the `cognee-custom-graph-models` skill).\n\n### Work on the existing graph\n\n`cognee.memify`, `cognee-cli memify`, `POST /api/v1/memify` and `improve()`'s\n`extraction_tasks` / `enrichment_tasks` are deprecated and removed in the next\nrelease. Run a post-processing step over the\ngraph with `run_custom_pipeline`: the task reads the graph itself, and one\nplaceholder item as `data` makes the chain run once instead of once per\ndocument.\n\n```python\nfrom cognee.infrastructure.databases.graph import get_graph_engine\n\n\nasync def enrich_graph(_items: list):\n    graph = await get_graph_engine()  # the dataset's graph inside the pipeline\n    nodes, edges = await graph.get_graph_data()\n    return [...]  # new DataPoints for add_data_points\n\n\nawait cognee.run_custom_pipeline(\n    tasks=[Task(enrich_graph, needs_llm=False), Task(add_data_points, needs_llm=False)],\n    data=[{}],\n    dataset=\"people\",\n)\n```\n\nFor cognee's own enrichment (session bridging, feedback weights, conflict\nreview, global context index) call `improve()`.\n\n### Check status\n\n```python\nstatus = await cognee.datasets.get_status([dataset_id], pipeline_names=[\"custom_pipeline\"])\n```\n\nWithout `pipeline_names` it reports only `cognify_pipeline`. It returns\n`{str(dataset_id): PipelineRunStatus}` (`{str(dataset_id): {pipeline_name:\nstatus}}` for several `pipeline_names`): `DATASET_PROCESSING_STARTED`,\n`_COMPLETED`, or `_ERRORED` (`_INITIATED` exists only on legacy rows). The value `run_custom_pipeline`\nreturns per dataset is a `PipelineRunInfo` instead, whose class names the\noutcome: `PipelineRunCompleted`, `PipelineRunAlreadyCompleted`,\n`PipelineRunErrored`, and so on.\n\n## Pitfalls\n\n- **Wrong `run_pipeline`.** The one imported via\n  `from cognee.pipelines import run_pipeline` wants `task()`\n  specs *called* (`extract()`, not `extract`) and raises `TypeError`\n  otherwise; the orchestrator in `cognee.modules.pipelines` wants `Task`\n  objects and raises `WrongTaskTypeError` otherwise.\n- **`run_custom_pipeline` accepts only `Task` objects** despite its type hint;\n  string task names are not resolved.\n- **Some callables are rejected** by `Task` (`ValueError: Unsupported task\n  type`): bound methods and `functools.partial`s of a plain (non-generator)\n  sync function, and callable objects (instances with `__call__`). Generator\n  and async variants, plain functions, and lambdas work. When in doubt, wrap it\n  in a plain `def` / `async def`.\n- **`run_custom_pipeline` does not run database migrations.** On an existing\n  database, run `await cognee.run_migrations()` (or any `remember()` first).\n- **Nodes duplicate on every run** when a DataPoint has no\n  `identity_fields` (or `Dedup()` fields). `examples/guides/custom_data_models.py`\n  and `examples/guides/custom_tasks_and_pipelines.py` have this bug; don't\n  copy it.\n\n## How it works\n\n`run_custom_pipeline` → orchestrator `run_pipeline` (checks write\npermission, takes the per-dataset lock, records a `PipelineRun`) →\n`run_tasks` (a semaphore of `data_per_batch`, one chain per document) →\n`run_tasks_base` (streams each task's output into the next, batching by the\nconsumer's `batch_size`, injecting `ctx`, stamping provenance).\n\n- Package overview and the runner semantics: `cognee/modules/pipelines/__init__.py`\n- `Task`, `task()`, `TaskSpec`, `BoundTask`, `@task_summary`: `cognee/modules/pipelines/tasks/task.py`\n- Orchestrator: `cognee/modules/pipelines/operations/pipeline.py`; execution:\n  `run_tasks.py`, `run_tasks_base.py`, `run_tasks_data_item.py`\n- Lightweight runner: `cognee/modules/pipelines/operations/run_pipeline.py`,\n  exported from `cognee/pipelines/`\n- Context: `cognee/modules/pipelines/models/PipelineContext.py`\n- `run_custom_pipeline`: `cognee/modules/run_custom_pipeline/run_custom_pipeline.py`\n- Storage: `cognee/tasks/storage/add_data_points.py`\n- Index of all shipped tasks: `cognee/tasks/README.md`\n\nExamples:\n\n- `examples/demos/custom_pipelines/custom_pipeline_single_object_example.py`:\n  the best reference. It runs over added documents, does LLM extraction into\n  typed DataPoints, then recalls. Its models declare identity with `Dedup()`\n  (the `Annotated` alternative to `metadata[\"identity_fields\"]`).\n- `examples/demos/custom_pipelines/organizational_hierarchy/`: low-level\n  `run_tasks`, no LLM, dedup via `identity_fields`, status polling.\n- `examples/demos/custom_pipelines/custom_cognify_pipeline_example.py`:\n  rebuilds add + cognify from the default task list.\n\n## Extending it\n\n- **A new shipped task:** put it in the `cognee/tasks/` subpackage for its\n  stage, export it from that package's `__init__.py`, follow the template in\n  `cognee/tasks/README.md`, and add a unit test under `cognee/tests/unit/tasks/`.\n- Pipeline tests: `cognee/tests/unit/modules/pipelines/` (runner semantics,\n  context, provenance, rollback) and `cognee/tests/unit/pipelines/` (the\n  lightweight API).\n",".agents/skills/cognee-custom-graph-models/SKILL.md":"---\nname: cognee-custom-graph-models\ndescription: Use when defining the shape of cognee's knowledge graph with graph_model= — writing DataPoint node classes, choosing identity and index fields so nodes merge and are searchable, declaring typed Edge fields and FromIdentity references, building a model from a JSON schema, or debugging duplicated nodes, missing edges, or InvalidReferenceTypeError.\n---\n\n# Custom graph models\n\nBy default cognee extracts a generic `KnowledgeGraph` of entities and\nrelationships. Pass your own model with `graph_model=` and the LLM fills\nyour node and edge types instead.\n\n```python\nfrom typing import Annotated, Literal\nimport cognee\nfrom cognee.low_level import DataPoint, Edge, FromIdentity\n\n\nclass Role(DataPoint):\n    name: str\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nclass Person(DataPoint):\n    name: str\n    is_a: Annotated[Role, FromIdentity()] | None = None  # reference by name\n    reports_to: list[Edge[\"Person\", \"Person\"]] = []  # edge owned by Person\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nclass PeopleGraph(DataPoint):  # the root the LLM fills\n    people: list[Person]\n    friends_with: list[Edge[Person, Person]] = []\n    family: list[Edge[Person, Person, Literal[\"married_to\", \"sibling_of\"]]] = []\n    metadata: dict = {\"index_fields\": [], \"transparent\": True}\n\n\nawait cognee.remember(text, graph_model=PeopleGraph, custom_prompt=\"Extract every person...\")\n```\n\nFull example: `examples/guides/custom_graph_model.py`.\n\n## Use it\n\n### Nodes: DataPoint classes\n\nEvery node type subclasses `DataPoint` (`from cognee.low_level import\nDataPoint`). Its fields become:\n\n- **Node properties:** scalars, strings, dicts, and anything that is not a\n  DataPoint.\n- **Edges named after the field:** a field holding a DataPoint or a list of\n  DataPoints. `members: list[Person]` becomes `members` edges.\n\n`dict[str, Person]`, sets and plain tuples are stored as properties, not\nedges.\n\n### Identity and search: `metadata`\n\n| Key | What it does |\n|---|---|\n| `identity_fields` | The node id is derived from these field values (normalized: lowercased, spaces to `_`, apostrophes removed). The same entity from two chunks or two runs becomes **one node**. |\n| `index_fields` | Each field gets a vector collection named `<ClassName>_<field>`, so recall can find the node. |\n| `transparent` | The node is not stored; its children take its place. Use it for a root container like `PeopleGraph`. |\n\n**Without `identity_fields` every node gets a random id, so the same person\nis duplicated in every chunk and every run.** Set it on every node type that\nrepresents a real-world entity.\n\n**Write `metadata` explicitly**, as in the examples above. There is also an\nannotation shortcut (`from cognee.infrastructure.engine import Dedup,\nEmbeddable`; `name: Annotated[str, Embeddable(), Dedup()]`), but today only\nhalf of it works:\n\n- `Dedup()` works: ids are derived from the marked fields.\n- `Embeddable()` does not index. The markers update the class-level\n  default, but each instance still carries `{\"index_fields\": []}`, and\n  indexing reads the instance, so no vector collection is created and\n  recall cannot find the node.\n\nMarkers are also ignored entirely when the class declares `metadata`\nitself.\n\n### Typed edges: `list[Edge[Source, Target, Name]]`\n\nThe LLM answers edges as flat rows of identity strings (`source`, `target`),\nand cognee resolves them to the extracted nodes. The third parameter\ncontrols the relationship name:\n\n| Declaration | Relationship name |\n|---|---|\n| `list[Edge[Person, Person]]` | The field name (`friends_with`) |\n| `list[Edge[Person, Person, Literal[\"a\", \"b\"]]]` | The LLM picks one value |\n| `list[Edge[Person, Person, str]]` | Free-form from the LLM, normalized |\n\n- **Where to declare:** on the root model for relationships with no obvious\n  owner, or on the owning node. On the owner, endpoints of the owner's own\n  type must be strings (`Edge[\"Person\", \"Person\"]`), because the class is\n  not defined yet inside its own body.\n- **Always a list:** `Edge[...]` or `Edge[...] | None` on its own raises.\n- **Both endpoint types need exactly one `identity_fields` entry.**\n\n### References: `Annotated[Target, FromIdentity()]`\n\nInstead of a nested object, the LLM answers the identity string of a node\n(`is_a: \"engineer\"`), and cognee links to that node. Supported spellings:\n`Target`, `Target | None`, `list[Target]`, `list[Target] | None`.\nAnything else raises `InvalidReferenceTypeError`. The target needs exactly\none identity field, and its other required fields need defaults.\n\n### Edge values you build by hand\n\n`Edge(source=..., target=..., relationship_type=..., weight=...,\nproperties={...})`. An omitted `source` falls back to the node declaring the\nfield; on a parametrized field that node must be the declared `Source`\ntype, or it raises. On a root container, always pass `source=`. The tuple\nform `(Edge(weight=0.8), target_node)` attaches edge properties to a plain\nDataPoint field (`examples/guides/custom_data_models.py`).\n\n### From JSON instead of Python\n\n- `cognee.low_level.graph_model_from_spec(spec)`: a small entity/relation\n  spec (names, fields, `one`/`many` relations) compiled to DataPoint\n  classes, with identity and index on `name` by default. Example:\n  `examples/guides/graph_model_from_json.py`.\n- `cognee.low_level.graph_schema_to_graph_model(json_schema)`: a JSON\n  Schema (needs a top-level `title`; only internal `#` refs).\n- HTTP: `POST /api/v1/remember` takes a `graph_model` form field (JSON\n  schema string); `POST /api/v1/cognify` takes a `graphModel` JSON object.\n  `POST /api/v1/llm/infer-schema` proposes a schema from sample text.\n\nNeither JSON path can express typed `Edge` fields or `FromIdentity`; use\nPython classes for those.\n\n## Pitfalls\n\n- **Duplicated nodes** → missing `identity_fields`.\n- **Node never shows up in recall** → no `index_fields`, or the recalling\n  process never imported the model class (graph completion searches the\n  collections of DataPoint classes loaded in that process).\n- **Edge rows silently missing** → an unresolved row is dropped with a\n  warning. Endpoints resolve by **exact type** against nodes extracted from\n  the same chunk: a subclass instance does not match where its base is\n  declared, and a node from another chunk or an earlier run is not a\n  candidate.\n- **`InvalidReferenceTypeError`, \"declares Edge in a shape the LLM\n  extraction cannot fill\"** → an unsupported `FromIdentity` or `Edge`\n  spelling. These are raised when the model is converted during\n  extraction, not at class definition, so they appear mid-pipeline.\n- **String endpoints resolve only to the owning model itself or a\n  module-level class.** A string naming another class defined inside a\n  function raises `InvalidReferenceTypeError`, so define models at module\n  level.\n- **Field names that collide with DataPoint's own fields** (`id`, `type`,\n  `version`, `metadata`, `created_at`, `belongs_to_set`, …) are stripped\n  from what the LLM sees. Rename them.\n- **A subclass that overrides `metadata`** replaces the parent's entirely.\n  Dropping `identity_fields` only logs a warning. A subclass also hashes ids\n  under its own class name.\n- **Write a `custom_prompt`.** Without one the generic knowledge-graph\n  prompt is used; your schema reaches the LLM only as structured output.\n- **Not with GLiNER.** `extractor=\"gliner_demo\"` (alias `\"gliner\"`) raises\n  with a custom `graph_model`, and so does the default `GRAPH_EXTRACTOR=auto`\n  when no LLM key is configured (it resolves to `gliner_demo`).\n- **Remote mode drops it.** After `cognee.serve(url)`, `remember()` and\n  `cognify()` do not forward `graph_model`; the server builds a generic\n  graph.\n- A custom model skips the generic path's ontology resolution, per-graph\n  node dedup. Summaries still run.\n\n## How it works\n\n`extract_content_graph` converts a DataPoint model into a plain Pydantic\nmodel for the LLM: infrastructure fields and `metadata` are stripped, typed\nedge fields become row lists (`FriendsWithEdge` with `source`/`target`\nstrings), and `FromIdentity` fields become strings. The answer is converted\nback into DataPoint instances with ids from `identity_fields`, edge rows are\nresolved against the nodes in that answer, and the result is attached to the\nchunk (`chunk.contains`) and stored by `add_data_points`. Ownership is\nrecorded per document, so `forget(data_id=...)` removes a custom-model\ndocument's nodes while shared nodes survive.\n\n- LLM boundary, both directions: `cognee/shared/llm_graph_model.py`\n- DataPoint, metadata, ids: `cognee/infrastructure/engine/models/DataPoint.py`\n- Markers: `cognee/infrastructure/engine/models/FieldAnnotations.py`\n- Edge: `cognee/infrastructure/engine/models/Edge.py`\n- Property vs edge decision: `cognee/modules/graph/utils/field_edges.py`\n- Custom-model branch of extraction: `cognee/tasks/graph/extract_graph_from_data.py`\n- JSON schema / spec paths: `cognee/shared/graph_model_utils.py`,\n  `cognee/modules/graph_models/`\n- Vector collections: `cognee/tasks/storage/index_data_points.py`\n\n## Extending it\n\n- Tests for the LLM round trip: `cognee/tests/unit/modules/graph/test_content_graph_to_data_point.py`.\n  Edge typing: `cognee/tests/unit/interfaces/graph/test_typed_edge_model.py`,\n  `test_typed_edges_graph.py`. Identity: `cognee/tests/unit/infrastructure/engine/test_identity_fields.py`.\n  Property vs edge: `cognee/tests/unit/modules/graph/test_field_edges.py`.\n- Deletion of custom-model nodes: `cognee/tests/test_delete_custom_graph.py`.\n- A new `Edge` or `FromIdentity` spelling must be handled in both directions\n  in `llm_graph_model.py`, and rejected with `InvalidReferenceTypeError`\n  when unsupported, never silently accepted.\n","cognee/skill.md":"---\nname: cognee\ndescription: >\n  Use this skill whenever the user asks about Cognee, AI memory, persistent agent memory,\n  self-improving agents, agents learning from feedback, knowledge graphs, graph-based RAG,\n  long-term memory for agents, short-term memory for agents, personalization, personas,\n  temporal search, temporal knowledge graphs, ontology-based extraction, ontology grounding,\n  feedback, Cypher search, natural-language graph search, chunk search, RAG search, cross-session memory,\n  session feedback, feedback loops, session based memory, redis based memory, knowledge promotion.\n  Also use when the user describes the workflow such as:\n  \"turn documents into a knowledge graph\", \"build memory from files\", \"search my graph\",\n  \"extract entities and relations\", \"sync data into a graph\", \"update graph memory\",\n  \"store memories for an agent\", \"help my agent learn over time\", \"visualize a knowledge\n  graph built from documents\", \"let the agent learn\", \"adaptive agents\", \"personalized agents\",\n  \"session based personalization\", \"find important ontologies\", \"find custom pydantic models\",\n  \"isolate agentic behaviour\", \"add permission control to retrieval\", \"reduce context bloating\".\n---\n\n# Cognee\n\nUse this skill for **Cognee-specific Python API help** and for mapping user goals to the right\nCognee workflow.\n\n## When to apply this skill\n\nApply this skill whenever the user wants to do any of the following with Cognee:\n\n- ingest text, files, URLs, repos, or datasets\n- build or rebuild a knowledge graph\n- search documents, chunks, summaries, triplets, or graph context\n- choose a `SearchType`\n- enrich an existing graph with `improve`\n- define custom graph extraction models or `DataPoint` types\n- run custom task pipelines\n- configure LLM, graph DB, vector DB, or storage settings\n- tag and scope memory with `node_set` / NodeSets\n- build persistent memory for agents across sessions\n- create feedback loops or self-improving agent workflows\n- work with temporal extraction, ontologies, Cypher, or natural-language graph queries\n- manage datasets, sessions, feedback, deletion, updates, or visualization\n\nIf the user's intent is \"store information in memory and query it later\", prefer Cognee's\nmemory API: **remember -> recall** (plus **improve** to enrich and **forget** to delete).\n\n## Core workflow\n\n```python\nimport cognee\n\n# Store: ingest + build the graph (+ improve, because self_improvement=True by default)\nawait cognee.remember(\n    \"Your text, file path, URL, or list of inputs\",\n    dataset_name=\"main\",\n)\n\n# Query: recall picks a search strategy automatically (rule-based, no LLM call)\nresults = await cognee.recall(\"What are the key insights?\", datasets=[\"main\"])\nfor r in results:\n    print(r.source, r)  # each result is tagged \"graph\" / \"session\" / ...\n```\n\n`remember()` runs `add()` + `cognify()` and then `improve()` underneath. `recall()` wraps\n`search()` and adds routing, session memory as a source, and `source`-tagged results.\n\n## Default guidance\n\nWhen helping with Cognee:\n\n1. Start with the **simplest working path** unless the user explicitly asks for advanced\n   configuration.\n2. Prefer the memory API:\n   - `remember(...)` to store (ingest + graph build)\n   - `recall(...)` to query\n   - `improve(...)` to enrich or index an existing graph, and to bridge sessions into it\n   - `forget(...)` to delete\n3. Treat Cognee APIs as **async**.\n4. Use `dataset_name` / `datasets` to keep work organized when the user has multiple sources.\n5. Use `node_set` when the user wants lightweight tagging, project scoping, per-user memory\n   buckets, or subgraph filtering.\n6. Pass `query_type=SearchType.X` to `recall()` only when the user needs a specific strategy;\n   otherwise let it route.\n7. Recommend advanced features only when they match the task:\n   - `session_id` for fast short-term memory and conversation continuity\n   - `graph_model=` for schema-shaped extraction, `DataPoint` types for direct insertion\n   - `extractor=\"gliner_demo\"` for LLM-free graph extraction\n   - custom pipelines for non-default task orchestration\n   - feedback loops for retrieval improvement\n   - visualization tools for graph inspection\n\n## When to drop to the low-level operations\n\n`add()`, `cognify()` and `search()` still ship; the memory API calls them. Reach for\nthem only when `remember`/`recall` cannot express the job:\n\n- `cognify(datasets=[\"a\", \"b\"])` or `datasets=None` processes several datasets at once;\n  `remember()` always targets exactly one dataset.\n- Rebuilding a graph over data already in the DB (after `forget(memory_only=True)`, or with a\n  new `graph_model` / ontology) is `cognify()` only; `remember()` always runs `add()` first.\n- `search()` takes the agentic extras as first-class parameters (`skills`, `tools`, `max_iter`,\n  `code_query`, `node_type`) and returns raw `SearchResult` objects instead of tagged dicts.\n- `add()` is a staging area: use it to ingest now and `cognify()` later.\n- `prune.prune_system(metadata=True)` also drops the relational DB (users, ACLs, dataset\n  registry); `forget()` never touches those. Use prune only for full test teardown.\n\n`cognee.delete()` is deprecated in favour of `forget()`. Full comparison of the two query\nfunctions: `docs/recall-vs-search.md`.\n\n## Common tasks\n\n### Store data\n\n`remember()` accepts text, file paths, URLs, directories, git repository URLs, binary streams,\nor lists of these.\n\n```python\nawait cognee.remember(\"notes.md\", dataset_name=\"research\")\nawait cognee.remember(\"https://example.com\", dataset_name=\"research\")\nawait cognee.remember([\"paper.pdf\", \"summary.txt\"], dataset_name=\"research\")\n```\n\nUse `node_set` when the user wants data grouped into logical memory buckets.\n\n```python\nawait cognee.remember(\n    \"Customer prefers concise weekly summaries and Slack delivery.\",\n    dataset_name=\"customer_success\",\n    node_set=[\"preferences\", \"customer_123\", \"weekly_reports\"],\n)\n```\n\nUseful options:\n\n```python\nawait cognee.remember(\n    \"...\",\n    dataset_name=\"research\",\n    self_improvement=False,  # skip the improve() stage (faster)\n    run_in_background=True,  # return immediately; poll the pipeline status\n    chunk_size=1024,\n    custom_prompt=\"Extract companies, products, and partnerships.\",\n    extractor=\"gliner_demo\",  # LLM-free extraction; needs cognee[gliner]\n    dry_run=True,  # estimate LLM tokens/cost without ingesting\n)\nawait cognee.remember(\"./my_repo\", dataset_name=\"code\")  # code graph, no LLM\nawait cognee.remember(\"./skills\", dataset_name=\"ops\", content_type=\"skills\")  # SKILL.md playbooks\n```\n\n### Query memory\n\n```python\nfrom cognee import SearchType\n\nresults = await cognee.recall(\"What changed in Q1 2024?\", datasets=[\"research\"], top_k=10)\n\n# Pin a strategy when the user needs one\nresults = await cognee.recall(\n    \"What changed in Q1 2024?\",\n    query_type=SearchType.TEMPORAL,\n    datasets=[\"research\"],\n)\n\n# Answers with evidence, or validated into a Pydantic model\nresults = await cognee.recall(\"...\", include_references=True)\nresults = await cognee.recall(\"...\", response_model=MyAnswerModel)\n\n# Retrieval context only, no LLM completion (pin query_type here)\ncontext = await cognee.recall(\"...\", query_type=SearchType.GRAPH_COMPLETION, only_context=True)\n```\n\n### Scope retrieval with NodeSets\n\nUse NodeSets when the user wants to search only a subset of memory such as one project, one\ncustomer, one user, or one workflow.\n\n```python\nresults = await cognee.recall(\n    \"What are this customer's reporting preferences?\",\n    datasets=[\"customer_success\"],\n    node_name=[\"preferences\", \"customer_123\"],\n)\n```\n\n### Enrich an existing graph\n\nUse `improve()` when the user wants to improve or extend an already-built graph without\nre-ingesting. Without `session_ids` it runs only the graph-wide stages (opt-in conflict review\nand global context indexing); with them it also applies feedback weights, persists session Q&A,\nand distills session lessons into the graph.\n\n```python\nawait cognee.improve(dataset=\"research\")\nawait cognee.improve(dataset=\"research\", session_ids=[\"chat_1\"])\nawait cognee.improve(dataset=\"research\", build_global_context_index=True)\n```\n\n### Delete data\n\n`forget()` is the single deletion entry point.\n\n```python\nawait cognee.forget(data_id=data_id, dataset_id=dataset_id)  # one document\nawait cognee.forget(dataset=\"research\")  # a dataset: raw data + graph + vectors\nawait cognee.forget(dataset=\"research\", memory_only=True)  # graph + vectors only, keep raw files\nawait cognee.forget(everything=True)  # everything the current user owns\n```\n\n### Update a document in place\n\n```python\nawait cognee.update(data_id=data_id, data=\"Updated content\", dataset_id=dataset_id)\n```\n\nThe document keeps its `data_id`; only the chunks the edit touched are re-extracted.\n\n### Create domain-specific structures\n\nPass a `DataPoint`-derived Pydantic model as `graph_model` and the LLM fills it instead of the\ngeneric knowledge graph:\n\n```python\nfrom cognee.infrastructure.engine import DataPoint\n\n\nclass Person(DataPoint):\n    name: str\n    role: str\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nclass Company(DataPoint):\n    name: str\n    employs: list[Person] = []  # a DataPoint field becomes an edge named after the field\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nawait cognee.remember(\"...\", dataset_name=\"org\", graph_model=Company)\n```\n\nInsert structured Python objects directly, bypassing text extraction:\n\n```python\nfrom cognee.tasks.storage import add_data_points\n\nawait add_data_points([Person(name=\"Ada\", role=\"Engineer\")])\n```\n\nSee `examples/guides/custom_graph_model.py` and `examples/guides/custom_data_models.py`.\n\n### Run custom pipelines\n\nUse `run_custom_pipeline(...)` when the user needs explicit sequential task control.\n\n```python\nfrom cognee.modules.pipelines.tasks.task import Task\n\n\nasync def my_task(data):\n    return data\n\n\nawait cognee.run_custom_pipeline(\n    tasks=[Task(my_task)],\n    data=\"input\",\n    dataset=\"research\",\n)\n```\n\n## DataPoints\n\nA `DataPoint` is the **atomic unit of knowledge** in Cognee.\n\nUse this concept whenever the user asks how Cognee represents structured data internally or how\nto insert graph objects directly.\n\nKey ideas:\n\n- A `DataPoint` is a Pydantic model that represents one meaningful unit of information.\n- When inserted, DataPoints become graph nodes; fields holding other DataPoints become edges.\n- `metadata = {\"index_fields\": [...]}` controls which fields are embedded for semantic search.\n- `metadata = {\"identity_fields\": [...]}` makes the node id deterministic so repeated inserts\n  merge instead of duplicating.\n\nUse `DataPoint` when the user wants:\n\n- schema-shaped memory\n- exact control over graph structure\n- programmatic relationship creation\n- custom domain entities such as papers, customers, incidents, policies, products, or workflows\n\nPrefer plain `remember(...)` for unstructured documents. Prefer `graph_model=` when the text\nshould be extracted into a schema. Prefer `DataPoint` models plus `add_data_points(...)` when the\nuser already has structured Python objects.\n\n## NodeSets\n\nUse NodeSets when the user wants a lightweight way to **tag, group, and scope memory**.\n\nA NodeSet starts as a list of tags passed through `node_set=[...]` to `remember(...)`; after the\ngraph is built those tags are first-class graph nodes, and `recall(node_name=[...])` restricts\nretrieval to them.\n\n### Good NodeSet patterns\n\n- per customer: `[\"customer_123\"]`\n- per workflow: `[\"support_bot\", \"refund_flow\"]`\n- per topic: `[\"contracts\", \"vendor_risk\"]`\n- per environment: `[\"prod\", \"staging\"]`\n- per user memory: `[\"user_42\", \"preferences\"]`\n\n### Example\n\n```python\nawait cognee.remember(\n    [\n        \"Alice prefers terse answers and email follow-ups.\",\n        \"Alice escalates billing issues to finance first.\",\n        \"Bob prefers detailed technical explanations.\",\n    ],\n    dataset_name=\"agent_memory\",\n    node_set=[\"crm\", \"user_profiles\"],\n)\n\nresults = await cognee.recall(\n    \"How should I respond to Alice?\",\n    datasets=[\"agent_memory\"],\n    node_name=[\"crm\", \"user_profiles\"],\n)\n```\n\nUse NodeSets by default whenever the user says things like:\n\n- \"scope memory by customer\"\n- \"separate projects without making separate databases\"\n- \"let the agent search only its own memories\"\n- \"group facts by workflow or team\"\n\n## SearchType selection guide\n\n`recall()` routes automatically when `query_type` is omitted. When the user needs a specific\nstrategy, pick from `cognee.SearchType` (all 20 values):\n\nCompletion types (an LLM writes the answer):\n\n- `HYBRID_COMPLETION`: document passages plus entity neighbourhoods; the default when routing is off\n- `GRAPH_COMPLETION`: graph traversal + completion; the best general graph-aware Q&A\n- `GRAPH_COMPLETION_COT`: deeper chain-of-thought reasoning over graph context\n- `GRAPH_COMPLETION_CONTEXT_EXTENSION`: broader graph context retrieval\n- `GRAPH_COMPLETION_DECOMPOSITION`: splits the question into sub-queries first\n- `GRAPH_SUMMARY_COMPLETION`: graph context + pre-computed summaries\n- `RAG_COMPLETION`: traditional RAG over document chunks\n- `TEMPORAL`: time-aware graph search\n- `AGENTIC_COMPLETION`: multi-step loop that can load `skills` and call `tools`\n\nRetrieval-only types (no LLM call):\n\n- `CHUNKS`: semantic retrieval over chunks\n- `CHUNKS_LEXICAL`: exact-term / keyword (BM25) matching\n- `SUMMARIES`: pre-computed document summaries\n- `SKILLS`: discover SKILL.md playbooks (metadata only; exactly one dataset)\n- `CODE`: deterministic code-graph operations via `code_query` (callers, paths, impact analysis)\n\nOther:\n\n- `CYPHER`: raw Cypher, off by default (`ALLOW_CYPHER_QUERY=true` enables it; not on the Postgres demo graph)\n- `NATURAL_LANGUAGE`: natural language to graph query, off by default (same `ALLOW_CYPHER_QUERY=true` flag)\n- `CODING_RULES`: retrieve stored coding rules\n- `GRAPH_REPORT`: graph insight report (hubs, cross-source links, suggested questions)\n- `FEELING_LUCKY`: let Cognee choose\n\nThe CLI exposes 10 of these (`cognee-cli recall --query-type`); the rest are SDK-only.\n\n## Sessions, feedback, and self-improvement\n\nCognee has two memory tiers:\n\n- **Permanent memory**: `remember(...)` without `session_id` — the knowledge graph.\n- **Session memory**: `remember(..., session_id=...)` — a fast session cache written without an\n  LLM call. `recall(..., session_id=...)` searches it first and falls through to the graph.\n  Requires `CACHING=true` (the default).\n\n```python\n# Short-term: store a turn in the session cache, recall it instantly\nawait cognee.remember(\"User wants weekly summaries on Fridays.\", session_id=\"chat_1\")\nresults = await cognee.recall(\"when does the user want summaries?\", session_id=\"chat_1\")\n\n# Long-term: bridge the session into the permanent graph\nawait cognee.improve(dataset=\"main_dataset\", session_ids=[\"chat_1\"])\n```\n\n`remember(..., session_id=...)` with `self_improvement=True` (default) bridges into the graph\nin the background, so the explicit `improve()` call is only needed for control over timing.\n\n### Feedback\n\nFeedback is attached to a session Q&A entry and later folded into retrieval weights by\n`improve()`:\n\n```python\nfrom cognee import FeedbackEntry\n\n# Rate an earlier answer (qa_id is the entry_id returned by the remember() that stored it)\nawait cognee.remember(\n    FeedbackEntry(qa_id=qa_id, feedback_score=5, feedback_text=\"Captured the key themes.\"),\n    session_id=\"chat_1\",\n)\n# Equivalent helper API\nawait cognee.session.add_feedback(session_id=\"chat_1\", qa_id=qa_id, feedback_score=5)\nhistory = await cognee.session.get_session(session_id=\"chat_1\")\n```\n\nWith `AUTO_FEEDBACK=true` (default) every answered turn is also analysed for implicit feedback\nby one structured-output LLM call. Set `AUTO_FEEDBACK=false` for low-latency reads.\n\n### Wrap an agent\n\n`@cognee.agent_memory` records an agent function's calls as session traces and recalls context\nbefore each call. See `examples/guides/agent_memory_quickstart.py`.\n\n## Agentic workflows and feedback-driven improvement\n\nUse Cognee as the **memory layer for agent systems** that need to improve over time through\nbetter recall, better reuse of prior work, and better retrieval of successful past behavior.\n\nThe key idea is simple:\n\n- keep the **agent workflow itself constant**\n- keep the **prompt and tools constant**\n- change only what the agent can remember and retrieve\n\n\"Improvement\" comes from **memory reuse and retrieval quality**, not from changing the model.\n\n### General agent loop\n\n1. **Observe** — capture inputs, events, preferences, outcomes, errors, decisions.\n2. **Store** — `remember(...)` them, with `session_id` for the active run and without it for\n   durable facts.\n3. **Organize** — use datasets and NodeSets to separate memory by customer, workflow, team,\n   agent, or topic.\n4. **Recall before acting** — `recall(...)` before planning, tool use, synthesis, or response\n   generation.\n5. **Capture feedback** — `FeedbackEntry` / `session.add_feedback` for what worked and what\n   did not.\n6. **Consolidate** — `improve(dataset, session_ids=[...])` so session history and lessons become\n   long-term graph memory.\n7. **Reuse** — future runs benefit from richer context and more informed retrieval.\n\n### Minimal example pattern\n\n```python\nimport cognee\n\n# 1) Store a durable observation\nawait cognee.remember(\n    \"Customer 123 prefers concise status updates and Slack notifications.\",\n    dataset_name=\"agent_memory\",\n    node_set=[\"customer_123\", \"preferences\", \"support_agent\"],\n)\n\n# 2) Recall before acting, inside a session\ncontext = await cognee.recall(\n    \"What should I know before replying to customer 123?\",\n    datasets=[\"agent_memory\"],\n    session_id=\"support-session-123\",\n)\n\n# 3) Continue work in the same session\nanswer = await cognee.recall(\n    \"Draft the best reply for customer 123.\",\n    datasets=[\"agent_memory\"],\n    session_id=\"support-session-123\",\n)\n\n# 4) Consolidate the session into long-term memory later\nawait cognee.improve(dataset=\"agent_memory\", session_ids=[\"support-session-123\"])\n```\n\n### Best default explanation\n\nIf the user asks how Cognee helps agents improve over time:\n\n**Cognee lets agents improve by remembering more useful things, organizing them into searchable\ngraph memory, and reusing successful past work in future runs.**\n\n## Configuration help\n\nUse Cognee config helpers or environment variables when the user needs provider or backend setup.\n\n```python\ncognee.config.set_llm_provider(\"openai\")\ncognee.config.set_llm_model(\"gpt-5-mini\")\ncognee.config.set_llm_api_key(\"sk-...\")\n```\n\nEnvironment variables (`.env`): `LLM_API_KEY`, `LLM_MODEL`, `LLM_PROVIDER`, `EMBEDDING_*`,\n`GRAPH_DATABASE_PROVIDER` (ladybug default, neo4j, neptune, postgres_demo), `VECTOR_DB_PROVIDER`\n(lancedb default, pgvector, turso), `DB_PROVIDER` (sqlite default, postgres), `CACHE_BACKEND`.\nIf only the LLM or only embeddings are configured, the other defaults to OpenAI.\n\n## Dataset and lifecycle operations\n\n```python\ndatasets = await cognee.datasets.list_datasets()\ndata = await cognee.datasets.list_data(dataset_id)\nawait cognee.forget(dataset=\"research\")  # preferred over datasets.empty_dataset / delete_all\n```\n\n## Visualization\n\n`visualize_graph` renders a **bounded subgraph** by default (seed nodes + a k-hop neighborhood,\ncapped at `max_nodes`) instead of the whole graph.\n\n```python\n# Default: bounded subgraph. Seed by a query, explicit ids, or a recall result;\n# with none of those, the highest-degree nodes seed a representative view.\nawait cognee.visualize_graph(\"/path/to/output.html\")\nawait cognee.visualize_graph(\"/path/to/output.html\", query=\"What relates to Python?\")\nawait cognee.visualize_graph(\"/path/to/output.html\", seed_node_ids=[\"node-id-1\"])\nawait cognee.visualize_graph(\"/path/to/output.html\", recall_result=recall_output)\n\n# Legacy whole-graph render.\nawait cognee.visualize_graph(\"/path/to/output.html\", full=True)\n\nawait cognee.start_visualization_server(port=8080)\nawait cognee.start_ui()\n```\n\nCaps: `neighborhood_depth=2`, `neighborhood_seed_top_k=10`, `max_nodes=500`.\nSee `examples/guides/graph_visualization.py`.\n\n## Full reset (tests only)\n\n`forget(everything=True)` removes the user's data and memory. To also drop users, ACLs and the\ndataset registry — full test teardown — use prune:\n\n```python\nawait cognee.prune.prune_data()\nawait cognee.prune.prune_system(graph=True, vector=True, metadata=True, cache=True)\n```\n\n## Important behavior notes\n\n- Cognee APIs are **async**.\n- Prefer **remember -> recall** (+ `improve`, `forget`) unless the user needs one low-level stage.\n- Use `node_set` early when the user may later need scoped retrieval.\n- Use `session_id` for short-term memory and conversation continuity; `improve(session_ids=...)`\n  to make it permanent.\n- Use `graph_model=` or `DataPoint` types only when the user needs schema-shaped extraction.\n- Use `CYPHER` only when Cypher querying is enabled in config.\n- Keep examples minimal and runnable.\n\n## Do not overcomplicate\n\nDo not jump straight to advanced backends, ontology configuration, or custom pipelines unless the\nuser asks for them or the problem clearly requires them. Prefer the smallest correct Cognee\nsolution first, then extend it.\n",".agents/skills/cognee-install/SKILL.md":"---\nname: cognee-install\ndescription: Use when the user wants to install cognee and run their first remember → recall flow with the Python SDK — fresh setup, virtual env, extras selection, or a minimal working example.\n---\n\n# Install and run cognee\n\n## Install\n\nRequires Python 3.10–3.14. Prefer uv:\n\n```bash\nuv venv && source .venv/bin/activate\nuv pip install cognee            # from PyPI\n# or, working inside this repo:\nuv pip install -e .\n```\n\nAdd extras only when needed — examples: `cognee[postgres]`, `cognee[neo4j]`,\n`cognee[docling]` (office/HTML document parsing, slim), `cognee[docs]`\n(unstructured), `cognee[anthropic]`, `cognee[ollama]`, `cognee[aws]`. The full\nlist is in `pyproject.toml` under `[project.optional-dependencies]`.\n\n## Configure\n\nThe only required setting is an LLM API key. Create `.env` in the working\ndirectory (or export the variable):\n\n```bash\nLLM_API_KEY=\"your_openai_api_key\"\n```\n\nDefaults need no services: SQLite (relational), LanceDB (vector), and Ladybug\n(graph), all stored locally. OpenAI is the default LLM and embedding provider —\nif you configure a different LLM but not embeddings (or vice versa), the other\nsilently stays on OpenAI. For other providers and databases use the\ncognee-integrations skill.\n\n## First run\n\nAs of cognee 1.x the memory API — `remember`, `recall`, `forget`, `improve` —\nis the primary surface. All SDK functions are async. Minimal end-to-end script:\n\n```python\nimport asyncio\nimport cognee\n\n\nasync def main():\n    await cognee.remember(\"Cognee turns documents into AI memory.\")\n    results = await cognee.recall(\"What does cognee do?\")\n    print(results)\n\n\nasyncio.run(main())\n```\n\n`remember()` is the whole ingestion path in one call — it runs `add()` +\n`cognify()`, then `improve()` to index the graph (`self_improvement=True` by\ndefault). It accepts text, file paths, URLs, and binary streams, with an\noptional `dataset_name=\"my_project\"`; pass `datasets=[\"my_project\"]` to\n`recall()` to stay inside one dataset.\n\n`recall()` auto-routes the query to a search strategy by default. Pass\n`query_type=SearchType.CHUNKS` (etc.) to pin one, or `auto_route=False` to\nfall back to `GRAPH_COMPLETION`.\n\nSession memory is the other half of the API — `remember(..., session_id=\"chat_1\")`\nwrites to a fast session cache rather than running add+cognify inline, and\n`recall(..., session_id=\"chat_1\")` reads it back (session hits short-circuit the\ngraph search). With the default `self_improvement=True` it still bridges that\ndata into the permanent graph in the background; `improve(dataset=...,\nsession_ids=[...])` does the same explicitly. Session memory runs on the\nsession cache, which is on by default (`CACHING=true`); setting\n`CACHING=false` disables it entirely and makes `remember(session_id=...)`\nraise.\n\nStart with `examples/advanced_guides/remember_recall_improve_example.py`, which walks\nthrough permanent memory, session memory, and the sync between them.\n\nThe `add()` / `cognify()` / `search()` primitives still exist and\nare what `remember`/`recall`/`improve` call underneath — reach for them when you\nneed to drive a stage in isolation (e.g. custom pipeline tasks), not for\nordinary ingestion. `cognee.delete` is formally deprecated (since 0.3.9);\n`forget()` is the v1 replacement, unifying the old delete/empty_dataset\npaths behind one call. When to use `recall()` versus the low-level `search()`\nis covered in `docs/recall-vs-search.md`.\n\n## Verify / troubleshoot\n\n- `cognee-cli remember \"hello\" && cognee-cli recall \"hello\"` exercises the same\n  flow from the shell.\n- To wipe local state during experiments: `cognee-cli forget --all` (or\n  `await cognee.forget(everything=True)`).\n- Reads slow or spending tokens on every query → set `AUTO_FEEDBACK=false`\n  (keep `CACHING=true`); by default cognee makes one structured-output LLM\n  call per answered query to self-tune its memory.\n- Structured LLM output errors usually mean the model/provider needs an\n  explicit instructor mode: `LLM_INSTRUCTOR_MODE=\"json_schema_mode\"`.\n",".agents/skills/cognee-integrations/SKILL.md":"---\nname: cognee-integrations\ndescription: Use when the user wants to connect cognee to external services — switching LLM or embedding providers (OpenAI, Azure, Gemini, Anthropic, Ollama, OpenRouter), changing databases (Postgres, PGVector, Neo4j, Neptune, Turso), S3 storage, or the MCP server for IDE integration.\n---\n\n# Set up cognee integrations\n\nAll integration config is environment variables (`.env`). The authoritative,\nalways-current list with commented examples is `.env.template` at the repo\nroot — check it before inventing variable names. Install the matching extra\nbefore switching a backend (e.g. `pip install cognee[postgres]`).\n\n## LLM providers\n\nDefault is OpenAI (`LLM_API_KEY` is all you need). To switch, set\n`LLM_PROVIDER`, `LLM_MODEL`, `LLM_API_KEY`, and (where relevant)\n`LLM_ENDPOINT` / `LLM_API_VERSION`:\n\n- **Azure OpenAI**: `LLM_PROVIDER=azure`, `LLM_MODEL=azure/gpt-4o-mini`, endpoint + api version required.\n- **Gemini** (no extra needed): `LLM_PROVIDER=gemini`, `LLM_MODEL=gemini/gemini-2.0-flash-exp`.\n- **Anthropic** (`cognee[anthropic]`): `LLM_PROVIDER=anthropic`, model e.g. `claude-3-5-sonnet-20241022`.\n- **Ollama, local** (`cognee[ollama]`): `LLM_PROVIDER=ollama`, `LLM_ENDPOINT=http://localhost:11434/v1`, and set the embedding block + `HUGGINGFACE_TOKENIZER` too.\n- **Custom / OpenRouter / vLLM**: `LLM_PROVIDER=custom` with the provider's OpenAI-compatible endpoint.\n- **AWS Bedrock** (`cognee[aws]`): `LLM_PROVIDER=bedrock` + AWS credentials/region.\n\n**The classic trap**: LLM and embeddings are configured independently\n(`EMBEDDING_PROVIDER`, `EMBEDDING_MODEL`, `EMBEDDING_ENDPOINT`,\n`EMBEDDING_API_KEY`). Configuring only one leaves the other on OpenAI —\neither keep a valid OpenAI key or configure both.\n\n## Databases\n\n- **Relational** (`DB_PROVIDER`): sqlite (default) or postgres\n  (`cognee[postgres]`; host/port/user/password/name via `DB_*` vars).\n- **Vector** (`VECTOR_DB_PROVIDER`): lancedb (default), pgvector\n  (`cognee[postgres]`, needs `VECTOR_DB_URL`), neptune_analytics\n  (`cognee[neptune]`), turso (`cognee[turso]`). Anything else (ChromaDB,\n  Qdrant, Weaviate, Milvus, …) lives in community adapters — install from\n  https://github.com/topoteretes/cognee-community and register with\n  `use_vector_adapter` before use; setting `VECTOR_DB_PROVIDER` alone raises\n  \"Unsupported vector database provider\".\n- **Graph** (`GRAPH_DATABASE_PROVIDER`): ladybug (default), neo4j\n  (`cognee[neo4j]`, bolt URL + credentials), neptune (`cognee[neptune]`),\n  ladybug-remote, postgres (no raw Cypher / natural-language search).\n\nThe repo `docker-compose.yml` ships ready-to-use `postgres` (pgvector) and\n`neo4j` profiles with matching default credentials. From a container, reach\nhost services with `DB_HOST=host.docker.internal`.\n\n## Storage, cache, and the rest\n\n- **S3 storage** (`cognee[aws]`): `STORAGE_BACKEND=s3` + bucket/credentials,\n  and point `DATA_ROOT_DIRECTORY`/`SYSTEM_ROOT_DIRECTORY` at `s3://` paths.\n- **Session cache**: `CACHE_BACKEND` = sqlite (default) | postgres | redis | fs | tapes.\n- **Ontologies**: `ONTOLOGY_FILE_PATH` to an OWL file, resolver/matching via\n  `ONTOLOGY_RESOLVER` / `MATCHING_STRATEGY`.\n\n## MCP server (IDE integration)\n\n`docker compose --profile mcp up` starts the MCP server on port 8001\n(Streamable HTTP at `http://localhost:8001/mcp`), built from `cognee-mcp/`. Point Cursor / Claude Desktop /\nClaude Code at it to use cognee memory from the IDE. Configure its `DB_*` env\nto match the main service so both see the same data.\n\n## After changing providers mid-project\n\nEmbeddings from different models are not comparable — after switching the\nembedding provider or model, reset local state (`cognee-cli forget --all` or\n`await cognee.forget(everything=True)`) and re-ingest with `remember()`.\n\nTo drop just the graph and vectors while keeping the ingested files, use\n`await cognee.forget(dataset=\"my_project\", memory_only=True)` — the dataset can\nthen be rebuilt under the new embedding model without re-uploading anything.\n",".agents/skills/cognee-ingestion/SKILL.md":"---\nname: cognee-ingestion\ndescription: Use when putting data into cognee memory with remember() — choosing inputs (text, files, folders, URLs, repos, databases), datasets and node_sets, loaders, ontologies, the graph extractor (LLM or GLiNER), chunking, dry-run cost estimates, or when remember() raises on a keyword argument.\n---\n\n# Ingest data with remember()\n\n`remember()` is cognee's ingestion API. One call stores the data, builds the\nknowledge graph, and enriches it. Use it for all ingestion; every option in\nthis skill is a `remember()` argument unless it says otherwise.\n\n```python\nimport cognee\n\nresult = await cognee.remember(\"Einstein was born in Ulm.\")  # text\nresult = await cognee.remember(\n    [\"./notes.md\", \"./report.pdf\"],  # files\n    dataset_name=\"research\",\n)\nprint(result.status, result.dataset_id)  # \"completed\", UUID\n```\n\nAll cognee functions are async. Without `dataset_name` data goes to\n`main_dataset`. Needs `LLM_API_KEY` unless you use the GLiNER extractor\n(below).\n\n## Use it\n\n### Inputs\n\n`data` accepts a string, a list of strings, file paths (absolute, `file://`,\n`s3://`), http(s) URLs, binary streams, or a list mixing them.\n\n- **URLs** are fetched and scraped (needs `ALLOW_HTTP_REQUESTS=true`, the\n  default).\n- **Folders** are ingested file by file. A folder that looks like a code\n  project, or a GitHub/GitLab URL, becomes one code repository (needs `git`\n  on PATH).\n- **Code files** (`.py`, `.ts`, `.go`, …) go down the code-graph route: a\n  deterministic graph, no LLM calls, searchable only with\n  `SearchType.CODE`. To index a whole repository explicitly, pass\n  `content_type=\"code\"`.\n- **Databases and dlt sources**: a SQL connection string, a dlt\n  `DltResource` / `DltSource`, or a CSV. dlt is a core dependency, so no\n  extra is needed (`cognee[dlt]` is an empty compatibility extra). Options: `primary_key` (default `\"id\"`),\n  `write_disposition` (`\"replace\"` default, or `\"append\"`), `query`,\n  `max_rows_per_table`.\n- **Skill playbooks** (`SKILL.md` files): `content_type=\"skills\"`; ingests\n  into the target dataset (default `main_dataset`), so pass `dataset_name`\n  to keep skills in their own dataset.\n\n### Where the data goes\n\n| Argument | What it does |\n|---|---|\n| `dataset_name` / `dataset_id` | Target dataset. `dataset_id` wins. A dataset is the unit of permissions and isolation. |\n| `node_set=[\"AI\", \"FinTech\"]` | Tags the data so recall can filter to it later with `recall(..., node_name=[\"AI\"])`. With `session_id` it pins the session's node set instead (first write wins, a different set later is a 409); `improve()` carries it into the graph. See the `cognee-improve-sessions` skill. |\n| `session_id=\"chat_1\"` | Writes to the fast session cache instead of the graph; `improve()` bridges it into the graph in the background. See the `cognee-improve-sessions` skill. Requires `CACHING=true`. |\n\n### How the graph is built\n\n| Argument | What it does |\n|---|---|\n| `extractor` | `\"llm\"` or `\"gliner_demo\"` (alias `\"gliner\"`). Default is `GRAPH_EXTRACTOR=auto`: the LLM when an API key is configured, otherwise GLiNER. |\n| `graph_model=MyModel` | Extract into your own DataPoint model instead of the generic `KnowledgeGraph`. See the `cognee-custom-graph-models` skill. |\n| `custom_prompt` | Replaces the entity-extraction prompt (ignored by GLiNER). |\n| `config={\"ontology_config\": {...}}` | Ground entities in an OWL ontology (below). |\n| `chunk_size`, `chunker` | Max tokens per chunk (default: derived from the embedding and LLM limits) and the chunker class (default `TextChunker`). |\n| `preferred_loaders` | Choose a loader per file type (below). |\n| `self_improvement` | Default `True`: runs `improve()` after the graph is built. Its outcome is on `result.improve` / `result.improve_error`; a failed improve never fails the remember. |\n| `run_in_background=True` | Returns immediately with `status=\"running\"`; `await result` to wait. |\n\n### Ontologies\n\n```python\nfrom cognee.modules.ontology.rdf_xml.RDFLibOntologyResolver import RDFLibOntologyResolver\n\nconfig = {\n    \"ontology_config\": {\n        \"ontology_resolver\": RDFLibOntologyResolver(ontology_file=\"./my.owl\"),\n        # \"ontology_mode\": \"strict\",   # drop entities with no ontology match\n    }\n}\nawait cognee.remember(texts, config=config)\n```\n\nOr set `ONTOLOGY_FILE_PATH` (plus `ONTOLOGY_MODE`, `MATCHING_STRATEGY`) in\n`.env`. `annotate` (default) only enriches; `strict` drops entities that\nmatch no ontology class or individual. It prunes only the graph, chunk text\nis still stored. Strict mode with an empty or missing ontology file is a hard\nerror. Over HTTP, upload the ontology to `/api/v1/ontologies` and pass its\n`ontology_key` to `POST /api/v1/remember`. Example:\n`examples/guides/ontology_quickstart.py`.\n\n### Loaders\n\nEach file is claimed by the first loader that accepts it. Default order:\ncode, text, pypdf, image, audio, video, dlt_csv, csv, unstructured,\nadvanced_pdf, docling. Names: `text_loader`, `code_loader`, `csv_loader`,\n`dlt_csv_loader`, `pypdf_loader`, `image_loader`, `audio_loader`,\n`video_loader`, `unstructured_loader`, `advanced_pdf_loader`,\n`docling_loader`, `beautiful_soup_loader`.\n\n```python\n# Treat a code file as a plain document (chunking + LLM extraction):\nawait cognee.remember(\"./script.py\", preferred_loaders={\"text_loader\": {}})\n```\n\nOffice formats (DOCX, PPTX, …) need the `docs` (unstructured) or `docling`\nextra. A preferred loader that is not installed is skipped with only an info\nlog, so check the extra is installed when a file comes out wrong.\n\n### Check the cost first\n\n`dry_run=True` returns a token and cost estimate without ingesting anything\nor calling the LLM. It excludes the calls `improve()` makes. Not supported\nwith GLiNER, sessions, or a remote instance.\n\n`dry_run=\"presort\"` on a folder returns a `PresortReport` (junk, duplicates,\nversion candidates, possible personal data, proposed dataset groups). Apply\nit with `await cognee.remember(report)`, or pass `auto_apply=True`.\n\n### Without an LLM: GLiNER\n\n`extractor=\"gliner\"` builds the graph and summaries with a local GLiNER2\nmodel, with no LLM call (embeddings still run). Install\n`pip install \"cognee[gliner]\"`; the model (about 750 MB) downloads on first use.\nIt cannot be combined with a custom `graph_model`, `dry_run`, `session_id`,\nor a remote instance.\n\n> **For production:** the open-source GLiNER extractor is a demo. cognee's\n> enterprise GLiNER extraction is more accurate and covers more labels. The\n> same goes for the Postgres graph adapter (`postgres_demo`). Contact\n> social@cognee.ai.\n\n## Pitfalls\n\n- **Unknown keyword arguments raise.** `remember()` forwards kwargs through\n  a fixed allow-list and raises `TypeError: Unexpected keyword arguments`\n  for anything else. These real options are not on it yet:\n\n  | Option | Workaround through remember() |\n  |---|---|\n  | `ontology_file_path` | `config={\"ontology_config\": ...}` or `ONTOLOGY_FILE_PATH` (above) |\n  | `chunk_attachment` | None yet. Only `cognee.cognify()` accepts it. |\n  | `extraction_rules` | Pass it through the loader: `preferred_loaders={\"beautiful_soup_loader\": {\"extraction_rules\": {...}}}` (works in `remember()` and `add()`). Needs the `scraping` extra: without it the loader is not registered and the rules are silently ignored |\n  | `tavily_config`, `soup_crawler_config` | Not honoured by `add()` or `remember()`; only the `cognee/tasks/web_scraper` tasks use them |\n  | `column_value_columns` (dlt) | None yet. Only `cognee.add()` accepts it. |\n\n  If a user needs one with no workaround, say so plainly: the option exists\n  on the lower-level `add()` / `cognify()` but not on `remember()` yet.\n- **Changed files raise `DocumentUpdateRequiredError`.** Re-remembering the\n  same path (or the same filename for an upload) with different content is\n  an update, not a new document. Use\n  `cognee.update(data_id=..., data=..., dataset_id=...)`, which re-extracts\n  only the changed chunks and keeps the document's id. Identical content is\n  a no-op.\n- **`content_type` is strict.** Only `None`, `\"skills\"`, or `\"code\"`.\n  `\"code\"` rejects `session_id` and needs repository paths or git URLs;\n  `\"skills\"` ingests into the target dataset like any other call (default\n  `main_dataset`); pass `dataset_name` to keep skills in their own dataset.\n- **Session mode needs `CACHING=true`**, and `extractor` cannot be combined\n  with `session_id`.\n- **Remote mode.** After `cognee.serve(url)`, calls go to the server:\n  `extractor` and `session_ids` raise, and other options the client does not\n  forward (including `graph_model`, `node_set`, and ontology `config`) are\n  dropped without an error.\n- **Every remember runs `improve()`** unless `self_improvement=False` or\n  `IMPROVE_AUTO_ENABLED=false`. In scripts, call\n  `await cognee.wait_for_background_tasks()` before exiting.\n\n## How it works\n\n`remember(data)` runs `add()` (store raw data and create `Data` rows), then\n`cognify()` (classify documents, chunk, extract the graph and summaries,\nstore in graph and vector DBs), then `improve()`. `remember(data,\nsession_id=...)` writes to the session cache instead.\n\n- Entry point and kwarg routing: `cognee/api/v1/remember/remember.py`\n  (`RememberKwargs`, `_ADD_ONLY` / `_COGNIFY_ONLY` / `_SHARED`)\n- Storage: `cognee/api/v1/add/add.py`, `cognee/tasks/ingestion/ingest_data.py`\n- Graph build: `cognee/api/v1/cognify/cognify.py`,\n  `cognee/tasks/graph/extract_graph_from_data.py`,\n  `cognee/tasks/storage/add_data_points.py`\n- Extractor choice: `cognee/modules/cognify/config.py:resolve_extractor`;\n  GLiNER package: `cognee/tasks/graph/gliner_demo/`\n- Ontologies: `cognee/modules/ontology/`\n- Loaders: `cognee/infrastructure/loaders/` (`supported_loaders.py`,\n  `LoaderEngine.py`)\n- dlt: `cognee/tasks/ingestion/resolve_dlt_sources.py`\n\nExamples in `examples/guides/`: `simple_cognee_example.py`,\n`nodeset_grouping_example.py`, `ontology_quickstart.py`,\n`gliner_demo_llm_free_cognify.py`, `no_llm_remember_recall.py`,\n`temporal_recall.py`, `presort_downloads.py`,\n`web_url_content_ingestion_example.py`, `code_graph_example.py`.\n\n## Extending it\n\n- **New remember() option:** add it to `RememberKwargs` and to the matching\n  routing set in `remember.py`. An option on `add()`/`cognify()` that is not\n  in a routing set raises `TypeError` from `remember()`.\n- **New loader:** implement `LoaderInterface`\n  (`cognee/infrastructure/loaders/LoaderInterface.py`), register it in\n  `supported_loaders.py` (extras-gated loaders go under `external/`), and\n  add it to the priority list in `LoaderEngine.py` if it should run by\n  default.\n- **New cognify task:** see the `cognee-custom-pipelines` skill and\n  `cognee/tasks/README.md`.\n",".agents/skills/cognee-migrations/SKILL.md":"---\nname: cognee-migrations\ndescription: Use when dealing with cognee database migrations — understanding when they run automatically, checking or repairing migration state with cognee-cli upgrade/downgrade/stamp/current, a write blocked by a failed migration, authoring a new Alembic (relational schema) revision or a graph/vector data migration, or moving data between systems (relational DB import, memory export/import).\n---\n\n# Database migrations\n\ncognee has **two migration chains**, run together:\n\n| Chain | Changes | Lives in | Revision stored in |\n|---|---|---|---|\n| **Relational schema** (Alembic) | Tables and columns of the relational DB (users, datasets, ACLs, pipeline runs, …) | `cognee/alembic/` (`alembic.ini` is in `cognee/`) | `alembic_version` table |\n| **Graph/vector data** | Cross-store data rewrites (re-keying node ids, adding graph columns) across graph DB, vector DB and relational ledger | `cognee/modules/migrations/` (`registry.py`, `versions/`) | Per dataset: `dataset_database.migration_revision` (access control on). Globally: `global_database_version.global_migration_revision` (access control off) |\n\n## Use it\n\n### They run by themselves\n\n`run_migrations()` applies the relational chain first, then the data chain.\nIt runs:\n\n- at API server startup (and in the Docker `entrypoint.sh` before gunicorn);\n- on the first write in an SDK or CLI process (`remember`, `add`, `cognify`,\n  `improve`, memory imports), once per process;\n- when you call `await cognee.run_migrations()`.\n\nA fresh database is built by running the whole chain (no stamping). At\nhead, the first run in each process still does a no-op Alembic upgrade plus\na scan of the per-database revision rows; later calls in the same process\nare skipped by an in-memory flag. `ENABLE_AUTO_MIGRATIONS=false`\nturns off all automatic runs; then run `cognee-cli upgrade` yourself.\n\nConcurrent processes are serialized by a migration lock: a Postgres advisory\nlock (works across hosts) or a file lock next to the SQLite DB (one host\nonly).\n\n### Check and repair\n\n```bash\ncognee-cli current                   # stamped revision per database, and the last failure\ncognee-cli history                   # the data chain, newest first\ncognee-cli upgrade                   # relational to head, then data chain to head\ncognee-cli upgrade <slug>            # data chain up to and including <slug>\ncognee-cli upgrade --alembic <rev>   # pin the relational target\ncognee-cli downgrade <slug|base> [--dataset UUID ...] [--alembic REV] [--force]\ncognee-cli stamp <head|base|slug> [--dataset UUID ...] [--force]\n```\n\n- The positional revision is always a **data-chain slug**; relational\n  targets go through `--alembic`.\n- `downgrade` rewrites data and asks for confirmation. It only reverts\n  spans where every migration defines a `down()`, and leaves the relational\n  schema alone unless you pass `--alembic`.\n- `stamp` changes only the stored data-chain revision, without running\n  anything. Use `stamp base --dataset <id>` and then `upgrade` when a\n  database's data drifted from its stamp (for example after restoring a\n  backup); the chain is idempotent and converges it.\n- `upgrade` runs even with `ENABLE_AUTO_MIGRATIONS=false`.\n\n### A write is blocked\n\nIf a dataset's data migration failed, writes to that dataset are refused\nuntil it succeeds (with access control off, any failure blocks all writes).\nThe server still starts. Run `cognee-cli current` to see the error, fix the\ncause, then `cognee-cli upgrade`. A failed run is retried on the next start\nor write.\n\n### Moving data between systems (not schema migrations)\n\n| Goal | Use |\n|---|---|\n| Turn an existing relational database into a graph | `migrate_relational_database(graph_db, schema)` (`cognee/tasks/ingestion/migrate_relational_database.py`), with the source DB set by `MIGRATION_DB_PROVIDER` / `_PATH` / `_NAME` / `_HOST` / `_PORT` / `_USERNAME` / `_PASSWORD`. Examples: `examples/demos/ingestion_and_migration/` |\n| Back up a dataset, or move it to another cognee instance | A COGX archive, see below |\n| Export a dataset's graph for other tools | `await cognee.export(dataset, format=...)`: `\"json\"`, `\"graphml\"` or `\"cypher\"` write a file (one way: cognee can't import them back); `\"pydantic\"` (default) returns typed DataPoint objects in memory |\n| Import from another memory system (Mem0, Zep/Graphiti, Letta, LangMem) | Build a `MemorySource` (`cognee/modules/migration/sources/`) and pass it to `await cognee.remember(source, dataset_name=...)` |\n\nThere is no tool that moves a whole deployment from one database backend to\nanother.\n\n#### COGX archives\n\nCOGX (Cognee eXchange, `cognee/modules/migration/cogx.py`) is cognee's\nportable memory format and the only export format cognee can import back.\nAn archive is a directory with a `manifest.json` (COGX version, source\nsystem, the dataset's data-migration revision) and one JSONL file per record\nkind (`documents`, `episodes`, `entities`, `facts`, `memories`,\n`memory_blocks`), plus `nodes.jsonl` with the raw graph nodes. The Mem0,\nZep, Letta and LangMem importers also translate into COGX records first.\n\nUse it to back up and restore a dataset, or to copy one to another cognee\ninstance:\n\n```python\nfrom cognee.migration import COGXArchiveSource\n\nawait cognee.export(\"my_dataset\", format=\"cogx\", destination=\"backup_cogx\")\nawait cognee.remember(COGXArchiveSource(\"backup_cogx\"), dataset_name=\"my_dataset\")\n```\n\n- A restore defaults to `mode=\"preserve\"`: the archived graph is written\n  back as-is, with no LLM calls. `mode=\"hybrid\"` also re-cognifies the raw\n  content; `mode=\"re-derive\"` ignores the archived graph and extracts again\n  (costs LLM tokens).\n- `cognee.push()` / `cognee-cli push` does the same to Cognee Cloud: it\n  exports to COGX, packs it as a `.cogx.tar.gz` and uploads it, and the\n  receiving instance restores it (preserve mode unless you pass `mode=`).\n- `export(..., include_permissions=True)` also writes `permissions.json`\n  with the dataset owner and ACL grants, **including password hashes**, so\n  the restore recreates working accounts. Treat that archive as a secret.\n- An archive written by a newer major COGX version is rejected with a\n  `ValueError`; upgrade cognee on the importing side.\n\n## Pitfalls\n\n- **Never regenerate `cognee/alembic/frozen_schema.py`.** It is the\n  certified base schema the initial revision builds from, pinned by\n  `cognee/tests/unit/test_frozen_schema_seal.py`. Schema changes ship as\n  new revisions at head.\n- **Never hand-type an Alembic revision id.** Hand-typed patterns\n  (`a1b2c3d4e5f6`, …) already collided with a downstream chain that vendors\n  this one (`b2c3d4e5f6a7`). Generate ids with `alembic revision`.\n- **Never rename, remove, or reorder a data-chain entry.** The slug is what\n  deployed databases store; an unknown stored slug disables the chain for\n  that database.\n- **A model change and its migration land together.** CI's \"Migration/Model\n  Lockstep Guard\" fails otherwise.\n- **The relational schema cannot be downgraded below the data-bookkeeping\n  revisions** unless the data chain goes to `base` in the same call.\n- `alembic.ini` is always the packaged one; `COGNEE_ALEMBIC_PATH` or\n  `--alembic-path` only changes the scripts directory (for vendored chains).\n\n## How it works\n\n`run_migrations()` (`cognee/modules/migrations/startup.py`) takes the\nmigration lock, decides fresh vs existing (a `users` or `alembic_version`\ntable exists), runs Alembic in-process on a worker thread, then walks the\ndata chain per database with `runner.run_database_migrations`, stamping\nafter every step. After the chain, it syncs vector-adapter storage when the\nrecorded `cognee_version` differs from the library's\n(`versions/adapter_storage_migration.py`, not a chain entry).\n\n- Relational: `cognee/alembic.ini`, `cognee/alembic/env.py`,\n  `cognee/alembic/versions/`, `cognee/alembic/frozen_schema.py`\n- Data chain: `cognee/modules/migrations/` (`README.md` is the authoring\n  contract; `registry.py`, `migration.py`, `runner.py`, `startup.py`,\n  `versions/`)\n- CLI: `cognee/cli/commands/migrate_command.py`\n\n## Extending it\n\n### A new Alembic revision\n\n```bash\ncd cognee                              # the directory with alembic.ini\nuv run alembic revision -m \"add foo to data\"\n```\n\nThe DB URL comes from the live relational engine, so your normal `.env`\nsettings apply. Follow the recent revisions (for example\n`versions/e7f9a1c3d5b8_add_data_dataset_created_index.py`):\n\n- **Idempotent and guarded:** inspect first (`sa.inspect(op.get_bind())`)\n  and skip when the table is missing or the column/index already exists.\n- **Branch on dialect** (`conn.dialect.name == \"postgresql\"`) for\n  Postgres-only SQL. For Postgres enums use `postgresql.ENUM(...,\n  create_type=False)` and create the type up front with `checkfirst`.\n- **SQLite cannot drop or alter columns in place:** use\n  `op.batch_alter_table(...)`.\n- **Indexes:** plain `CREATE INDEX IF NOT EXISTS` inside the migration\n  transaction, not `CONCURRENTLY` (which releases the version-row lock and\n  lets concurrent workers into the same build). Repair invalid Postgres\n  indexes via `pg_index.indisvalid`.\n- A new model module outside the usual import path must be imported in\n  `cognee/alembic/env.py`, or autogenerate will not see it.\n\n### A new data migration\n\nRead `cognee/modules/migrations/README.md` first. In short:\n\n1. Write a module in `cognee/modules/migrations/versions/` with\n   `async def migrate(context)` (and optionally `async def downgrade(context)`);\n   step 2 registers them as `up=` / `down=`.\n2. Append `Migration(slug=..., cognee_version=..., up=..., down_revision=<previous slug>, down=...)`\n   to `MIGRATIONS` in `registry.py`. The chain is validated at import\n   (linear, unique slugs).\n3. Make it idempotent and cheap on empty stores, and crash-safe: re-key\n   derived stores (vectors, ledger) first and rename in the graph last.\n4. Freeze private copies of any logic you depend on; never import live\n   models that may change later.\n\n### Tests\n\n- `cognee/tests/e2e/migrations/test_migration_model_lockstep.py` (+\n  `schema_baseline.json`): the lockstep CI job.\n- `cognee/tests/unit/test_run_migrations.py`: single Alembic head, startup\n  behaviour.\n- `cognee/tests/unit/test_frozen_schema_seal.py`: frozen schema fingerprint.\n- `cognee/tests/unit/modules/migrations/`: data-chain unit tests.\n- `cognee/tests/migrations/test_migration_lockstep.py`: data chain against\n  real stores (seed, down, up, verify).\n",".agents/skills/cognee-improve-sessions/SKILL.md":"---\nname: cognee-improve-sessions\ndescription: Use when working with cognee's session memory or improve() — storing conversation turns, agent traces and feedback with session_id, bridging sessions into the permanent graph, reading an ImproveResult, understanding why an improve stage was skipped, already_completed or lock_held, or tuning the IMPROVE_* settings.\n---\n\n# Session memory and improve()\n\ncognee has two kinds of memory:\n\n- **Session memory**: a fast cache of conversation turns, agent traces, and\n  feedback, keyed by `session_id`. Writing is instant, with no LLM\n  extraction.\n- **The permanent graph**: what `remember()` builds without a session.\n\n`improve()` connects them. It bridges session content into the graph and\nenriches the graph itself. `remember()` calls it automatically, so most\nusers never call it directly.\n\n```python\nimport cognee\n\n# Session write: returns immediately; improve() bridges it in the background\nawait cognee.remember(\"User prefers dark mode.\", session_id=\"chat_1\")\n\n# Session-aware query: session cache first, then the graph\nresults = await cognee.recall(\"What does the user prefer?\", session_id=\"chat_1\")\n\n# Bridge sessions into a dataset's graph explicitly\nresult = await cognee.improve(dataset=\"main_dataset\", session_ids=[\"chat_1\"])\nprint(result.status, result.stage_summary())\n\nawait cognee.wait_for_background_tasks()  # before a script exits\n```\n\n## Use it\n\n### Writing session memory\n\n| What | How |\n|---|---|\n| A fact or note | `remember(text, session_id=...)` (stored as a Q&A entry with the text as the answer) |\n| A Q&A turn | `recall(query, session_id=...)` with a completion search type saves the turn itself; or `remember(cognee.QAEntry(question=..., answer=...), session_id=...)` |\n| An agent step | `remember(cognee.TraceEntry(origin_function=..., status=\"success\", ...), session_id=...)`, or the `@cognee.agent_memory(save_session_traces=True)` decorator |\n| Pin a session to a project / node set | `node_set=[...]` on the first `QAEntry`/`TraceEntry` (or as a kwarg on any session `remember`) pins it; later writes repeat or omit it, a different set raises `cognee.SessionNodeSetConflictError` (HTTP 409). `improve()` keeps the set on everything it bridges, so `recall(node_name=[...])` scopes to the project |\n| Feedback on an answer | `remember(cognee.FeedbackEntry(qa_id=..., feedback_score=...), session_id=...)` or `cognee.session.add_feedback(session_id, qa_id, feedback_text=..., feedback_score=...)` |\n| Read a session | `cognee.session.get_session(session_id, last_n=...)` |\n\nRequirements: `CACHING=true` (default). The cache backend is\n`CACHE_BACKEND`, one of `sqlite` (default), `postgres`, `redis`, `fs`,\n`tapes`. Sessions expire after `SESSION_TTL_SECONDS` (default 7 days).\n\n### What improve() does: nine stages, in order\n\nEvery run goes through the same ordered stages\n(`cognee/modules/improve/registry.py`). Each stage checks a gate before it\nspends any LLM or embedding cost, and reports one `StageResult`.\n\n| # | Stage | What it does | Runs when |\n|---|---|---|---|\n| 1 | `feedback_weights` | Adjusts the weight of graph elements that rated answers used | `session_ids` given; adapter supports feedback weights |\n| 2 | `persist_session_qa` | Turns session Q&A into graph content (node set `user_sessions_from_cache`) | `session_ids` given. **The only fatal stage** |\n| 3 | `persist_agent_traces` | Turns agent-trace feedback into graph content | `session_ids` given |\n| 4 | `extract_agent_context` | Drafts agent-profile lessons from traces | `session_ids`, `CACHING` + `AUTO_FEEDBACK`, an LLM |\n| 5 | `distill_sessions` | Distills session learnings into the graph | `session_ids`, an LLM |\n| 6 | `update_user_preferences` | Folds rated turns into per-user preferences | `session_ids`, `PERSONALIZATION_ENABLED=true` (default false) |\n| 7 | `build_truth_subspace` | Builds the truth subspace from distilled learnings | `session_ids`, `build_truth_subspace=True`, a Ladybug graph |\n| 8 | `review_conflicts` | Reviews dated source facts, stores conflicts and rewrites Entity descriptions | `review_conflicts=True` or `IMPROVE_REVIEW_CONFLICTS=true`, an LLM, edge evidence |\n| 9 | `global_context_index` | Bucket and root summaries for global questions | `build_global_context_index=True`, an LLM |\n\nStages 1–7 need `session_ids`; 8–9 work on the graph alone. The order\nmatters: 4 feeds 5, 5 feeds 7, and 7 runs before 8.\n\n`extraction_tasks` / `enrichment_tasks` are deprecated and removed in the next\nrelease: they still run, as a `custom_tasks` stage after the others, scoped by\n`node_name`, `data`, `node_type`, `vector_db_config` and `graph_db_config`.\nWithout custom tasks those options are ignored. Both cases warn with a\n`FutureWarning`; use `run_custom_pipeline()` instead.\n\n### Reading the result\n\n`improve()` returns an `ImproveResult`, and so do `POST /api/v1/improve`, the\nCLI, and `RememberResult.improve`.\n\n- `result.status`: `completed`, `errored` (any stage errored), `skipped`\n  (every stage skipped), or `running` (background, not finished).\n- `result.stages`: one `StageResult` per stage, with `stage`, `status`\n  (`completed` / `already_completed` / `skipped` / `errored`), `reason`,\n  `error`, `counts`, `duration_ms`.\n- `result.stage(\"distill_sessions\")`, `result.stage_summary()`,\n  `result.lock_held`, `result.rerun_requested`, `result.rerun_passes`.\n- `await result.wait()` finishes a background run (no-op otherwise).\n\n**Skip and no-op reasons:**\n\n| Reason | Meaning / fix |\n|---|---|\n| `no_session_ids` | Session stage, no `session_ids` passed |\n| `disabled_by_config` | Listed in `IMPROVE_STAGES_DISABLED` |\n| `opt_in_disabled` | Pass `build_truth_subspace=True` / `review_conflicts=True` / `build_global_context_index=True` |\n| `personalization_disabled` | Set `PERSONALIZATION_ENABLED=true` |\n| `auto_feedback_disabled` | Stage 4 needs `CACHING=true` and `AUTO_FEEDBACK=true` |\n| `no_llm_configured` | Stages 4, 5, 8, 9 draft text with an LLM; none configured |\n| `edge_evidence_disabled` | Conflict review needs `EDGE_EVIDENCE_ENABLED=true` |\n| `backend_unsupported` | The graph adapter lacks the feature (feedback weights, truth subspace) |\n| `session_manager_unavailable` | The session cache is not reachable |\n| `lock_held` | Another improve for the same dataset or session is running (below) |\n| `aborted_by_fatal_stage` | Stage 2 failed, so the rest did not run |\n| `budget_exhausted` | An earlier stage failed because the LLM budget is exhausted (a 402); the rest would fail the same way. Top up, then run improve again |\n| `no_new_entries`, `no_new_trace_steps`, `no_new_facts`, `no_writes_since_last_improve` | With status `already_completed`: nothing new since the last run |\n\n### How remember() triggers improve\n\n- **Without a session:** `add`, then `cognify`, then a foreground `improve()`.\n  Its outcome is on `result.improve` / `result.improve_error`. A failed\n  improve never marks the remember as errored.\n- **With `session_id`:** the text is cached, then a background\n  `improve(dataset, session_ids=[session_id])` starts if the debounce allows\n  it. `result.improve` fills in only after `await result` or\n  `wait_for_background_tasks()`.\n- `self_improvement=False` turns it off per call; `IMPROVE_AUTO_ENABLED=false`\n  turns it off everywhere and overrides `self_improvement=True`.\n- An application embedding cognee can decline one automatic improve before it\n  starts: `cognee.modules.improve.register_auto_improve_admission(check)`\n  registers one async check that `remember()` awaits on both paths. Returning\n  a reason string skips the improve and sets `result.improve_skipped`\n  (`result.improve` stays `None`); the data is stored either way. A check that\n  raises allows the improve. Explicit `improve()` calls are never gated.\n\n### Settings (`IMPROVE_*`, `cognee/modules/improve/config.py`)\n\n| Env var | Default | Meaning |\n|---|---|---|\n| `IMPROVE_AUTO_ENABLED` | `true` | Automatic improve after `remember()` |\n| `IMPROVE_DEBOUNCE_ENTRIES` | `1` | Session auto-improve fires after this many new entries |\n| `IMPROVE_DEBOUNCE_SECONDS` | `0` | ...or this many seconds since the last one. Seconds alone (entries left at 1) means time-only |\n| `IMPROVE_STAGES_DISABLED` | empty | CSV of stage names to skip |\n| `IMPROVE_FEEDBACK_ALPHA` | `0.1` | Feedback learning rate, in (0, 1] |\n| `IMPROVE_REVIEW_CONFLICTS` | `false` | Review fact conflicts, including automatic improve |\n| `IMPROVE_EFFECTIVE_DATE_KEY` | `effective_date` | Document metadata key holding the source date |\n\nThere is no debounce timer: held-back entries wait for the next\n`remember()` with that session, or an explicit `improve()`.\n\n## Pitfalls\n\n- **A plain `improve(dataset)` often does nothing.** Without `session_ids`,\n  only stages 8–9 can run, and both are off by default. Result: every\n  stage `skipped`. That is expected, not an error.\n- **A session's node set is pinned once.** The first write carrying\n  `node_set` fixes it for the session; a different set is a 409, start a\n  new session instead. Bridged Q&A, traces and lessons carry the set, user\n  preferences never do. The guarantee holds within one worker process (an\n  in-process lock); with several workers, send a session's writes to one.\n  Example: `examples/guides/session_node_sets.py`.\n- **Typed entries do not auto-improve.** `remember(QAEntry/TraceEntry/\n  FeedbackEntry, session_id=...)` stores the entry but never starts an\n  improve. Call `improve(session_ids=[...])` yourself.\n- **`lock_held` does not wait.** Improves for the same dataset or session\n  run one at a time: a second call returns at once with every stage\n  `skipped: lock_held`. If it shares a session with the running one, it sets\n  `rerun_requested=True` and the holder runs up to 2 extra passes (3 passes\n  in total; see `rerun_passes`). The bound is `IMPROVE_MAX_RERUN_PASSES`, a\n  constant in `cognee/api/v1/improve/improve.py`, not an env var. The lock is per process only; multiple API workers do not\n  share it.\n- **Sessions bridge once.** Q&A and trace persistence are tracked per user\n  and session, not per dataset, so bridging a session into dataset A and\n  then into dataset B persists no new Q&A/traces into B. Distillation is\n  tracked per (session, dataset) and still runs into B.\n- **`IMPROVE_STAGES_DISABLED` is validated.** An unknown stage name, or\n  `persist_session_qa` (fatal, cannot be disabled), raises `ValueError`, and\n  the API server refuses to start.\n- **Session writes with the cache off.** `remember(text, session_id=...)`\n  with `CACHING=false` only logs a warning and stores nothing; typed entries\n  raise `RuntimeError`. An explicit `improve(session_ids=...)` then fails in\n  the fatal stage.\n- **Fatal stage failure.** If stage 2 errors, `improve()` raises (HTTP 409)\n  and the error carries `.improve_result`. In background mode it is recorded\n  on `result.error` instead. Other stages failing only mark themselves\n  `errored`; HTTP still returns 200, so check `status`.\n- **Remote mode.** After `cognee.serve(url)`, a background improve is\n  fire-and-forget: `status` stays `running` and there is no polling.\n- `cognee/modules/session_bridge/` is gone (only stale `__pycache__` may be\n  left). The bridging now lives in the improve stages; some test names still\n  say \"session_bridge\".\n\n## How it works\n\n`improve()` resolves the dataset once (creating it if the name is new),\nclaims the improve lock for `dataset:<id>` plus every\n`session:<user>:<session_id>`, probes the graph adapter's capabilities, and\nruns the stages with one frozen `ImproveRunInputs`. Each stage is a gate\nplus a call into existing pipelines plus a result mapping. Stages never own\nretries or ordering.\n\nWatermarks keep repeat runs cheap:\n\n- Session stages track how many entries were already persisted, per user\n  and session.\n- Conflict review uses its last succeeded stamp to select touched entities,\n  and retries conflicts with missing citations or pending writes. Source dates\n  come from document metadata; session windows use their last entry time.\n  Fixed attributes remain disputed even when one document is newer.\n\nThe improve operation row is written when the run finishes: `failed` if any\nstage errored (a retry is never gated off), `noop` if nothing ran.\n\n- Orchestrator: `cognee/api/v1/improve/improve.py` (HTTP:\n  `routers/get_improve_router.py`; CLI: `cognee/cli/commands/improve_command.py`)\n- Stages, registry, results: `cognee/modules/improve/` (`stages.py`,\n  `registry.py`, `stage.py`, `result.py`, `inputs.py`, `capabilities.py`,\n  `config.py`, `graph_changes.py`, `constants.py`)\n- Lock: `cognee/infrastructure/locks/session_lock.py`\n- Session store and watermarks: `cognee/infrastructure/session/`\n  (`session_manager.py`, `session_persist_watermark.py`,\n  `feedback_detection.py`); cache backends in\n  `cognee/infrastructure/databases/cache/`\n- Auto-improve from remember: `cognee/api/v1/remember/remember.py`,\n  `cognee/api/v1/remember/auto_improve_debounce.py`\n- Entry types: `cognee/memory/entries.py`\n- Background tasks: `cognee/infrastructure/background_tasks.py`\n\nExamples: `examples/guides/improve_quickstart.py`, `sessions.py`,\n`session_distillation.py`, `review_conflicts.py`, `global_context_index.py`,\n`agent_memory_quickstart.py`, and\n`examples/advanced_guides/remember_recall_improve_example.py`.\n\n## Extending it\n\nAdding a stage:\n\n1. Subclass `BaseStage` in `cognee/modules/improve/stages.py`. Set `name`,\n   `needs_sessions`, and `fatal` (leave it `False`; exactly one fatal stage\n   is enforced at import). Implement `gate()` (return a skip reason\n   constant, or `None`, before any LLM/embedding cost) and `run()` (call\n   existing pipeline code, return a `StageResult`).\n2. Insert it into `DEFAULT_STAGES` in `registry.py` at the right position.\n   The order is pinned by `cognee/tests/unit/modules/improve/test_registry_order.py`;\n   update it deliberately.\n3. If it can re-run cheaply, give it a watermark so a repeat run reports\n   `already_completed` (graph-wide stages can stamp the improve row with the\n   helpers in `graph_changes.py`, as conflict review does).\n4. Tests: `cognee/tests/unit/modules/improve/` (gates, results, config) and\n   `cognee/tests/unit/api/v1/improve/` (orchestration, rerun, router).\n",".agents/skills/cognee-performance/SKILL.md":"# cognee-performance\n\nPath: `.agents/skills/cognee-performance/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-performance/SKILL.md)",".agents/skills/cognee-permissions/SKILL.md":"# cognee-permissions\n\nPath: `.agents/skills/cognee-permissions/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-permissions/SKILL.md)",".agents/skills/cognee-recall/SKILL.md":"# cognee-recall\n\nPath: `.agents/skills/cognee-recall/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-recall/SKILL.md)",".agents/skills/cognee-server/SKILL.md":"# cognee-server\n\nPath: `.agents/skills/cognee-server/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-server/SKILL.md)",".agents/skills/company-brain-company-qa/SKILL.md":"# company-brain-company-qa\n\nPath: `.agents/skills/company-brain-company-qa/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/company-brain-company-qa/SKILL.md)",".agents/skills/company-brain-follow-up-agent/SKILL.md":"# company-brain-follow-up-agent\n\nPath: `.agents/skills/company-brain-follow-up-agent/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/company-brain-follow-up-agent/SKILL.md)",".agents/skills/personalized-email/SKILL.md":"# personalized-email\n\nPath: `.agents/skills/personalized-email/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/personalized-email/SKILL.md)",".agents/skills/self-hosted-companion/SKILL.md":"# self-hosted-companion\n\nPath: `.agents/skills/self-hosted-companion/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/self-hosted-companion/SKILL.md)","examples/demos/feedback/skill_feedback_loop/skills/diff-risk-explainer/SKILL.md":"# diff-risk-explainer\n\nPath: `examples/demos/feedback/skill_feedback_loop/skills/diff-risk-explainer/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/examples/demos/feedback/skill_feedback_loop/skills/diff-risk-explainer/SKILL.md)","examples/demos/feedback/skill_feedback_loop/skills/pr-comment-evaluator/SKILL.md":"# pr-comment-evaluator\n\nPath: `examples/demos/feedback/skill_feedback_loop/skills/pr-comment-evaluator/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/examples/demos/feedback/skill_feedback_loop/skills/pr-comment-evaluator/SKILL.md)","examples/demos/feedback/skill_feedback_loop/skills/skill-feedback-writer/SKILL.md":"# skill-feedback-writer\n\nPath: `examples/demos/feedback/skill_feedback_loop/skills/skill-feedback-writer/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/examples/demos/feedback/skill_feedback_loop/skills/skill-feedback-writer/SKILL.md)","AGENTS.md":"# AI Agent Protocol & Instructions\n\nPath: `AGENTS.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/AGENTS.md)","CLAUDE.md":"# Claude Agent Guidelines & System Prompt\n\nPath: `CLAUDE.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/CLAUDE.md)","evals/README.md":"# Evals Skill\n\nPath: `evals/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/README.md)","tools/spec_extras.json":"# Tools Skill\n\nPath: `tools/spec_extras.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/tools/spec_extras.json)","cognee_db_workers/ladybug_extensions/README.md":"# ladybug_extensions Documentation\n\nPath: `cognee_db_workers/ladybug_extensions/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/cognee_db_workers/ladybug_extensions/README.md)","evals/old/hotpot_50_corpus.json":"# Old Skill\n\nPath: `evals/old/hotpot_50_corpus.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_50_corpus.json)","evals/old/hotpot_50_qa_pairs.json":"# Old Skill\n\nPath: `evals/old/hotpot_50_qa_pairs.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_50_qa_pairs.json)","catalog/entries/packages/qdrant.yaml":"# Packages Skill\n\nPath: `catalog/entries/packages/qdrant.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/catalog/entries/packages/qdrant.yaml)","catalog/entries/packages/weaviate.yaml":"# Packages Skill\n\nPath: `catalog/entries/packages/weaviate.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/catalog/entries/packages/weaviate.yaml)","evals/old/cognee_01042025/aggregate_metrics_v_deepeval.json":"# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/aggregate_metrics_v_deepeval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/aggregate_metrics_v_deepeval.json)","evals/old/cognee_01042025/aggregate_metrics_v_direct_llm.json":"# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/aggregate_metrics_v_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/aggregate_metrics_v_direct_llm.json)","evals/old/cognee_01042025/metrics_output_cognee.json":"# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/metrics_output_cognee.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/metrics_output_cognee.json)","evals/old/cognee_01042025/metrics_output_cognee_direct_llm.json":"# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/metrics_output_cognee_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/metrics_output_cognee_direct_llm.json)","evals/old/cognee_01042025/metrics_output_cognee_human_eval.json":"# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/metrics_output_cognee_human_eval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/metrics_output_cognee_human_eval.json)","evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10.json":"# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10.json)","evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short.json":"# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short.json)","evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short_deepeval.json":"# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short_deepeval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short_deepeval.json)","evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10.json":"# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10.json)","evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10_short.json":"# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10_short.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10_short.json)","evals/old/comparative_eval/README.md":"# Comparative_eval Skill\n\nPath: `evals/old/comparative_eval/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/comparative_eval/README.md)","evals/old/comparative_eval/hotpot_50_corpus.json":"# Comparative_eval Skill\n\nPath: `evals/old/comparative_eval/hotpot_50_corpus.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/comparative_eval/hotpot_50_corpus.json)","evals/old/comparative_eval/hotpot_50_qa_pairs.json":"# Comparative_eval Skill\n\nPath: `evals/old/comparative_eval/hotpot_50_qa_pairs.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/comparative_eval/hotpot_50_qa_pairs.json)","evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk.json":"# Falkor_01042025 Skill\n\nPath: `evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk.json)","evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk_direct_llm.json":"# Falkor_01042025 Skill\n\nPath: `evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk_direct_llm.json)","evals/old/falkor_01042025/metrics_output_falkor_graph_sdk_human_eval.json":"# Falkor_01042025 Skill\n\nPath: `evals/old/falkor_01042025/metrics_output_falkor_graph_sdk_human_eval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/metrics_output_falkor_graph_sdk_human_eval.json)","evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk.json":"# Falkor_01042025 Skill\n\nPath: `evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk.json)","evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk_direct_llm.json":"# Falkor_01042025 Skill\n\nPath: `evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk_direct_llm.json)","evals/old/graphiti_01042025/aggregate_metrics_graphiti.json":"# Graphiti_01042025 Skill\n\nPath: `evals/old/graphiti_01042025/aggregate_metrics_graphiti.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/aggregate_metrics_graphiti.json)","evals/old/graphiti_01042025/aggregate_metrics_graphiti_direct_llm.json":"# Graphiti_01042025 Skill\n\nPath: `evals/old/graphiti_01042025/aggregate_metrics_graphiti_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/aggregate_metrics_graphiti_direct_llm.json)","evals/old/graphiti_01042025/metrics_output_graphiti.json":"# Graphiti_01042025 Skill\n\nPath: `evals/old/graphiti_01042025/metrics_output_graphiti.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/metrics_output_graphiti.json)","evals/old/graphiti_01042025/metrics_output_graphiti_direct_llm.json":"# Graphiti_01042025 Skill\n\nPath: `evals/old/graphiti_01042025/metrics_output_graphiti_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/metrics_output_graphiti_direct_llm.json)","evals/old/graphiti_01042025/metrics_output_graphiti_huma_eval.json":"# Graphiti_01042025 Skill\n\nPath: `evals/old/graphiti_01042025/metrics_output_graphiti_huma_eval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/metrics_output_graphiti_huma_eval.json)","evals/old/graphiti_updated/hotpot_qa_graphiti_results_old.json":"# Graphiti_updated Skill\n\nPath: `evals/old/graphiti_updated/hotpot_qa_graphiti_results_old.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old.json)","evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics.json":"# Graphiti_updated Skill\n\nPath: `evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics.json)","evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics_direct_llm.json":"# Graphiti_updated Skill\n\nPath: `evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics_direct_llm.json)","evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics.json":"# Graphiti_updated Skill\n\nPath: `evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics.json)","evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics_direct_llm.json":"# Graphiti_updated Skill\n\nPath: `evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics_direct_llm.json)","evals/old/hotpot_qa_24_2025/README.md":"# Hotpot_qa_24_2025 Skill\n\nPath: `evals/old/hotpot_qa_24_2025/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/README.md)","evals/old/hotpot_qa_24_2025/benchmark_summary_cognee.json":"# Hotpot_qa_24_2025 Skill\n\nPath: `evals/old/hotpot_qa_24_2025/benchmark_summary_cognee.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/benchmark_summary_cognee.json)","evals/old/hotpot_qa_24_2025/benchmark_summary_competition.json":"# Hotpot_qa_24_2025 Skill\n\nPath: `evals/old/hotpot_qa_24_2025/benchmark_summary_competition.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/benchmark_summary_competition.json)","evals/old/mem0_01042025/aggregate_metrics_mem0.json":"# Mem0_01042025 Skill\n\nPath: `evals/old/mem0_01042025/aggregate_metrics_mem0.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/aggregate_metrics_mem0.json)","evals/old/mem0_01042025/aggregate_metrics_mem0_direct_llm.json":"# Mem0_01042025 Skill\n\nPath: `evals/old/mem0_01042025/aggregate_metrics_mem0_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/aggregate_metrics_mem0_direct_llm.json)","evals/old/mem0_01042025/metrics_output_mem0.json":"# Mem0_01042025 Skill\n\nPath: `evals/old/mem0_01042025/metrics_output_mem0.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/metrics_output_mem0.json)","evals/old/mem0_01042025/metrics_output_mem0_direct_llm.json":"# Mem0_01042025 Skill\n\nPath: `evals/old/mem0_01042025/metrics_output_mem0_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/metrics_output_mem0_direct_llm.json)","evals/old/mem0_01042025/metrics_output_mem0_human_eval.json":"# Mem0_01042025 Skill\n\nPath: `evals/old/mem0_01042025/metrics_output_mem0_human_eval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/metrics_output_mem0_human_eval.json)","evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_corpus.json":"# Src Skill\n\nPath: `evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_corpus.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_corpus.json)","evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_instance_filter.json":"# Src Skill\n\nPath: `evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_instance_filter.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_instance_filter.json)","evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_qa_pairs.json":"# Src Skill\n\nPath: `evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_qa_pairs.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_qa_pairs.json)"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# AI Agent Protocol & Instructions\n\nPath: `AGENTS.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/AGENTS.md)","tokens":300,"sizeBytes":152},{"name":"SKILL.md","path":".agents/skills/cognee-cli/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-cli/SKILL.md","title":"cognee-cli","category":"anthropic-skill","format":"markdown","content":"---\nname: cognee-cli\ndescription: Use when the user wants to drive cognee from the terminal with cognee-cli — remember/recall/forget/improve memory commands, managing datasets and config, or database migrations.\n---\n\n# Use the cognee CLI\n\n`cognee-cli` ships with the package (entry point in `cognee/cli/_cognee.py`;\neach command lives in `cognee/cli/commands/`). Every command has\n`--help` for its flags, but only a few (`demo`, `eval`, `serve`,\n`push`, `upgrade`, `downgrade`, `stamp`, and `search` with one CODE example)\ninclude usage examples — for the memory commands use the examples\nin this file. Needs `LLM_API_KEY` configured, same as the SDK.\n\n## Core flow\n\nThe memory commands are the primary surface as of cognee 1.x:\n\n```bash\ncognee-cli remember \"Your text here\"         # also accepts file paths / URLs\ncognee-cli remember ./docs --dataset-name my_project\ncognee-cli recall \"Your question\"            # query the graph\ncognee-cli recall \"keyword\" --query-type CHUNKS\ncognee-cli forget --all                      # wipe local state\n```\n\n`remember` is ingest + graph build in one step (`add` + `cognify` under the\nhood); `--background`/`-b` runs the cognify stage in the background, and\n`--dry-run` estimates LLM tokens/cost without ingesting. `recall` takes\n`--datasets`/`-d`, `--top-k`/`-k` (default 10), and `--session-id`/`-s`.\n\n`forget` targets `--dataset`, `--dataset-id`, `--data-id` (needs a dataset), or\n`--everything`/`--all` — one unified command replacing the older `delete` and\nempty-dataset paths. `--memory-only` (with a dataset) drops the graph and\nvectors but keeps the raw files, so the data can be rebuilt.\n\n> **`forget --all` does not ask for confirmation.** It deletes every dataset\n> immediately, even on a non-interactive stdin. The legacy `delete --all`\n> prompts `Delete ALL data from cognee? [y/N]` first, so switching to `forget`\n> silently drops that safety net — script it with care.\n\n`--query-type` accepts 10 of the SDK's 20 `SearchType` values — the list in\n`cognee/cli/config.py:SEARCH_TYPE_CHOICES`: HYBRID_COMPLETION, GRAPH_COMPLETION,\nRAG_COMPLETION, CHUNKS, CHUNKS_LEXICAL, SUMMARIES, CODE, CYPHER, GRAPH_REPORT,\nSKILLS. The rest (TEMPORAL, GRAPH_COMPLETION_COT,\nAGENTIC_COMPLETION, NATURAL_LANGUAGE, …) are SDK-only, e.g.\n`cognee.recall(q, query_type=SearchType.TEMPORAL)`.\n\nWhen `--query-type` is omitted the CLI uses `HYBRID_COMPLETION`\n(`DEFAULT_SEARCH_TYPE`), whereas the SDK's `cognee.recall()` auto-routes\nbetween search types. `--top-k` defaults to 10 on the CLI and 15 in the SDK.\n\n## Session memory and enrichment\n\nSession entries are currently written from the SDK — `cognee.remember(...,\nsession_id=\"chat_1\")` — not the CLI (`cognee-cli remember` has no session\nflag). The CLI side of session memory is reading and bridging:\n\n```bash\ncognee-cli recall \"question\" -s chat_1       # session cache first: without -d/-t\n                                             # this searches the session directly\ncognee-cli sessions get                      # retrieve session Q&A history\ncognee-cli improve -d my_project -s chat_1   # bridge session content into the graph\ncognee-cli improve -d my_project             # enrich/index the graph (no session)\ncognee-cli feedback ...                      # attach feedback to results\n```\n\n`improve` also takes `--feedback-alpha` (learning rate in\n(0, 1]; default `IMPROVE_FEEDBACK_ALPHA`, 0.1), `--build-global-context-index`,\n`--build-truth-subspace` (both opt-in stages; the truth subspace needs\n`-s`), and `--background`/`-b` (`--node-name` is deprecated: it warns and is\nignored). It prints one line per stage — name, status\n(`completed` / `already_completed` / `skipped` / `errored`) and the skip\nreason (e.g. `no_session_ids`, `lock_held`, `opt_in_disabled`).\n`remember`/`improve` build their graphs through `cognify()`, so cognify-level\nsettings (e.g. `PROVENANCE_TRACKING=true`) apply to them too.\n\n## Legacy / lower-level commands\n\n`add`, `cognify`, `search`, and `delete` still ship and are what the\nmemory commands call underneath. Use them only to drive a single stage in\nisolation; prefer `remember`/`recall`/`forget`/`improve` otherwise.\n\n```bash\ncognee-cli add \"text\" && cognee-cli cognify  # what `remember` does in one step\ncognee-cli search \"question\"                 # `recall` minus routing/scope/session sources\ncognee-cli delete --all                      # superseded by `forget --all`\n```\n\n## Management\n\n```bash\ncognee-cli datasets list                     # dataset operations\ncognee-cli config get [key] [--show-secrets] # view one/all settings (API keys masked by default)\ncognee-cli config set <key> <value>          # set + persist to ./.env in the cwd\ncognee-cli config unset <key>                # reset a key to its default (also persisted)\ncognee-cli -ui                               # launch API server + UI (see cognee-server skill)\ncognee-cli serve --url http://localhost:8000 # connect CLI/SDK to a running instance\n```\n\n## Database migrations\n\ncognee has two migration chains: the relational schema (Alembic, in\n`cognee/alembic/`) and the graph/vector data chain (slugs registered in\n`cognee/modules/migrations/registry.py`). Both run automatically — at API\nserver startup and on the first write (`remember`, `add`, `cognify`,\n`improve`, …) in an SDK/CLI process — unless `ENABLE_AUTO_MIGRATIONS=false`.\nSo you rarely need these commands; they are for inspecting state, disabled\nauto-migration, and rollbacks. There is no `migrate` command.\n\n```bash\ncognee-cli current                    # stamped revision per database (per dataset\n                                      # with access control on)\ncognee-cli history                    # the data-migration chain, newest first\ncognee-cli upgrade                    # relational to head, then data chain to head\ncognee-cli upgrade <slug>             # data chain up to and including <slug>\ncognee-cli upgrade --alembic <rev>    # pin the relational (Alembic) target\ncognee-cli downgrade <slug|base>      # REWRITES DATA; revision is required,\n                                      # prompts unless --force; --dataset <uuid>\n                                      # (repeatable) limits it\ncognee-cli stamp <head|base|slug>     # set the stored revision WITHOUT running\n                                      # anything; prompts unless --force;\n                                      # --dataset <uuid> (repeatable) limits it\n```\n\nThe positional revision is always a **data-chain slug**; the relational\ntarget goes through `--alembic`. `downgrade` leaves the relational schema\nalone unless you pass `--alembic`. `upgrade` runs even when\n`ENABLE_AUTO_MIGRATIONS=false`. `--alembic-path` (or `COGNEE_ALEMBIC_PATH`)\npoints at a custom Alembic scripts directory.\n\n## Gotchas\n\n- The CLI initializes cognee lazily; the first command in a fresh environment\n  is slow (DB + model setup), later ones are fast.\n- `remember` (and `add`) without `--dataset-name` targets the default dataset\n  `main_dataset`; `recall`/`search` operate across your accessible datasets\n  unless a dataset is given.\n- `forget` refuses to run bare — pass `--dataset`, `--dataset-id`, `--data-id`\n  (with a dataset), or `--everything`/`--all`.\n- Session commands (`recall -s`, `sessions get`, `improve -s`) require\n  `CACHING=true` (the default) — with it off, session reads return nothing and\n  SDK session writes raise. To cut read latency and token cost while keeping\n  session memory, `cognee-cli config set AUTO_FEEDBACK false` — by default\n  cognee makes one structured-output LLM call per answered query to self-tune\n  its memory.\n- `config set`/`config unset` write to the `.env` file in whatever directory\n  you run the command from (creating it if missing). `config reset` (reset\n  *all* keys) is still not implemented.\n- **Which `.env` actually wins is not always the cwd one.** At import, cognee\n  calls `dotenv.load_dotenv(override=True)`, which resolves relative to the\n  *cognee package location*, not your working directory. In a source/editable\n  checkout (`uv pip install -e .`) a `.env` at the repo root therefore shadows\n  the `.env` in the directory you ran from — and because `override=True`, it\n  also beats variables you `export`ed. Symptom: `config set` appears to do\n  nothing, or the CLI connects to a backend you thought you had overridden.\n  To test against different settings, move the repo `.env` aside, or set\n  values programmatically after import (`cognee.config.set_*`). (Under\n  `python -c` the cwd `.env` does win, because dotenv falls back to the cwd\n  when `__main__` has no `__file__` — which is why the same command can\n  behave differently as a script vs. `-c`.)\n","frontmatter":{"name":"cognee-cli","description":"Use when the user wants to drive cognee from the terminal with cognee-cli — remember/recall/forget/improve memory commands, managing datasets and config, or database migrations."},"isInternal":false,"tokens":2249,"sizeBytes":8680},{"name":"SKILL.md","path":".agents/skills/cognee-community/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-community/SKILL.md","title":"cognee-community","category":"anthropic-skill","format":"markdown","content":"---\nname: cognee-community\ndescription: Use when the user needs something that ships outside cognee core — community database adapters (Qdrant, Milvus, Weaviate, Redis, Pinecone, FalkorDB, Memgraph, DuckDB, NetworkX, …), data-source connectors (Slack, Gmail, Notion, Confluence, Google Drive), custom tasks/pipelines/retrievers (Exa, ScrapeGraph, codify), Keywords AI observability — or wants to contribute a package to the cognee-community repo.\n---\n\n# Use and contribute cognee-community packages\n\nCommunity-maintained plugins live in a separate monorepo:\nhttps://github.com/topoteretes/cognee-community. Everything installable is\nunder `packages/`; `experimental/` holds demos (n8n nodes, dlt demos,\nbauplan, tower) that are not published packages. Each package publishes to\nPyPI as `cognee-community-<family>-<kind>-<name>` and imports as the same\nname with underscores.\n\n## Package families\n\n| Family | Packages |\n|---|---|\n| Vector adapters | azureaisearch, milvus, moss, opengauss, opensearch, pinecone, qdrant, redis, singlestore, turbopuffer, valkey, weaviate |\n| Graph adapters | arcadedb, memgraph, networkx, pggraph, spanner, turbopuffer, turingdb |\n| Hybrid (graph+vector in one DB) | arcadedb, duckdb, falkordb, helixdb |\n| Connectors (data sources) | confluence, gmail, google-drive, notion, slack |\n| Tasks / pipelines / retrievers | codify_tasks, codify_pipeline, code_retriever, exa_tasks, scrapegraph_tasks |\n| Observability | keywordsai (`MONITORING_TOOL=keywordsai` + `KEYWORDSAI_API_KEY`) |\n\n## Using a database adapter\n\nInstall, then **import the package's `register` module before cognee touches\nany engine** — registration is what makes the provider name valid:\n\n```python\nuv pip install cognee-community-vector-adapter-qdrant\n```\n\n```python\nimport cognee\nfrom cognee import config\nfrom cognee_community_vector_adapter_qdrant import register  # noqa: F401\n\nconfig.set_vector_db_config(\n    {\n        \"vector_db_provider\": \"qdrant\",\n        \"vector_db_url\": \"http://localhost:6333\",\n        \"vector_db_key\": \"...\",\n        \"vector_dataset_database_handler\": \"qdrant\",  # only if the adapter ships one\n    }\n)\n```\n\nThe `register.py` calls `use_vector_adapter(name, AdapterClass)` /\n`use_graph_adapter(...)`. Setting `VECTOR_DB_PROVIDER`/`GRAPH_DATABASE_PROVIDER`\nto a community name **without** the register import raises \"Unsupported\nvector database provider\". Hybrid adapters (e.g. falkordb) register as both\ngraph and vector — set both configs to the same provider name.\n\n**Multi-tenancy caveat**: with `ENABLE_BACKEND_ACCESS_CONTROL=true` (the\ndefault), both backends must have a dataset-database handler or cognee raises\n`EnvironmentError`. Community adapters that ship one (registered via\n`use_dataset_database_handler` in their `register.py`): qdrant, moss,\nsinglestore, turbopuffer (vector + graph), falkordb, arcadedb, helixdb. All\nother community adapters need `ENABLE_BACKEND_ACCESS_CONTROL=false`.\n\n## Using a connector\n\nConnectors expose a `dlt` source you hand straight to `remember()`; they\nreuse core's DLT ingestion path, so snapshot sync and forget-on-delete work\nwith no core changes:\n\n```python\nfrom cognee_community_connector_slack import slack_export_source\n\nawait cognee.remember(\n    slack_export_source(\"/path/to/slack-export\"),\n    dataset_name=\"team-slack-export\",  # use a dedicated dataset\n    max_rows_per_table=0,\n)\n```\n\nSame shape for gmail (\"ask my inbox\"), notion, confluence, and google-drive\n(incremental, forget-on-delete). Each package README documents its\ncredentials; always give a connector its own dataset.\n\n## Verifying an install\n\nEvery package has `examples/example.py` (run `uv run python examples/example.py`\nfrom the package dir) and a `tests/` directory. An LLM API key is still\nrequired (`LLM_API_KEY`, OpenAI by default).\n\n## Contributing a package\n\n- **Branch from `main`** — unlike the core repo, cognee-community does not\n  use a `dev` branch.\n- Follow the existing structure: package dir under `packages/<family>/<name>/`\n  with `pyproject.toml`, a `README.md` (install + usage), `examples/example.py`,\n  and `tests/` that go beyond the example.\n- New DB adapters implement `VectorDBInterface` / `GraphDBInterface` from\n  core, expose a `register.py`, and should run the shared conformance tests\n  in `packages/shared/contract_suite/` (vector_contract.py / graph_contract.py).\n- Add a handler via `use_dataset_database_handler(...)` if the backend can\n  isolate per user+dataset — that's what makes it work with access control on.\n- Name it `cognee-community-<family>-<kind>-<name>` and add it to the tables\n  in the repo README. Lint config is the repo-root `ruff.toml`.\n","frontmatter":{"name":"cognee-community","description":"Use when the user needs something that ships outside cognee core — community database adapters (Qdrant, Milvus, Weaviate, Redis, Pinecone, FalkorDB, Memgraph, DuckDB, NetworkX, …), data-source connectors (Slack, Gmail, Notion, Confluence, Google Drive), custom tasks/pipelines/retrievers (Exa, ScrapeGraph, codify), Keywords AI observability — or wants to contribute a package to the cognee-community repo."},"isInternal":false,"tokens":1166,"sizeBytes":4664},{"name":"SKILL.md","path":".agents/skills/cognee-custom-graph-models/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-custom-graph-models/SKILL.md","title":"cognee-custom-graph-models","category":"anthropic-skill","format":"markdown","content":"---\nname: cognee-custom-graph-models\ndescription: Use when defining the shape of cognee's knowledge graph with graph_model= — writing DataPoint node classes, choosing identity and index fields so nodes merge and are searchable, declaring typed Edge fields and FromIdentity references, building a model from a JSON schema, or debugging duplicated nodes, missing edges, or InvalidReferenceTypeError.\n---\n\n# Custom graph models\n\nBy default cognee extracts a generic `KnowledgeGraph` of entities and\nrelationships. Pass your own model with `graph_model=` and the LLM fills\nyour node and edge types instead.\n\n```python\nfrom typing import Annotated, Literal\nimport cognee\nfrom cognee.low_level import DataPoint, Edge, FromIdentity\n\n\nclass Role(DataPoint):\n    name: str\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nclass Person(DataPoint):\n    name: str\n    is_a: Annotated[Role, FromIdentity()] | None = None  # reference by name\n    reports_to: list[Edge[\"Person\", \"Person\"]] = []  # edge owned by Person\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nclass PeopleGraph(DataPoint):  # the root the LLM fills\n    people: list[Person]\n    friends_with: list[Edge[Person, Person]] = []\n    family: list[Edge[Person, Person, Literal[\"married_to\", \"sibling_of\"]]] = []\n    metadata: dict = {\"index_fields\": [], \"transparent\": True}\n\n\nawait cognee.remember(text, graph_model=PeopleGraph, custom_prompt=\"Extract every person...\")\n```\n\nFull example: `examples/guides/custom_graph_model.py`.\n\n## Use it\n\n### Nodes: DataPoint classes\n\nEvery node type subclasses `DataPoint` (`from cognee.low_level import\nDataPoint`). Its fields become:\n\n- **Node properties:** scalars, strings, dicts, and anything that is not a\n  DataPoint.\n- **Edges named after the field:** a field holding a DataPoint or a list of\n  DataPoints. `members: list[Person]` becomes `members` edges.\n\n`dict[str, Person]`, sets and plain tuples are stored as properties, not\nedges.\n\n### Identity and search: `metadata`\n\n| Key | What it does |\n|---|---|\n| `identity_fields` | The node id is derived from these field values (normalized: lowercased, spaces to `_`, apostrophes removed). The same entity from two chunks or two runs becomes **one node**. |\n| `index_fields` | Each field gets a vector collection named `<ClassName>_<field>`, so recall can find the node. |\n| `transparent` | The node is not stored; its children take its place. Use it for a root container like `PeopleGraph`. |\n\n**Without `identity_fields` every node gets a random id, so the same person\nis duplicated in every chunk and every run.** Set it on every node type that\nrepresents a real-world entity.\n\n**Write `metadata` explicitly**, as in the examples above. There is also an\nannotation shortcut (`from cognee.infrastructure.engine import Dedup,\nEmbeddable`; `name: Annotated[str, Embeddable(), Dedup()]`), but today only\nhalf of it works:\n\n- `Dedup()` works: ids are derived from the marked fields.\n- `Embeddable()` does not index. The markers update the class-level\n  default, but each instance still carries `{\"index_fields\": []}`, and\n  indexing reads the instance, so no vector collection is created and\n  recall cannot find the node.\n\nMarkers are also ignored entirely when the class declares `metadata`\nitself.\n\n### Typed edges: `list[Edge[Source, Target, Name]]`\n\nThe LLM answers edges as flat rows of identity strings (`source`, `target`),\nand cognee resolves them to the extracted nodes. The third parameter\ncontrols the relationship name:\n\n| Declaration | Relationship name |\n|---|---|\n| `list[Edge[Person, Person]]` | The field name (`friends_with`) |\n| `list[Edge[Person, Person, Literal[\"a\", \"b\"]]]` | The LLM picks one value |\n| `list[Edge[Person, Person, str]]` | Free-form from the LLM, normalized |\n\n- **Where to declare:** on the root model for relationships with no obvious\n  owner, or on the owning node. On the owner, endpoints of the owner's own\n  type must be strings (`Edge[\"Person\", \"Person\"]`), because the class is\n  not defined yet inside its own body.\n- **Always a list:** `Edge[...]` or `Edge[...] | None` on its own raises.\n- **Both endpoint types need exactly one `identity_fields` entry.**\n\n### References: `Annotated[Target, FromIdentity()]`\n\nInstead of a nested object, the LLM answers the identity string of a node\n(`is_a: \"engineer\"`), and cognee links to that node. Supported spellings:\n`Target`, `Target | None`, `list[Target]`, `list[Target] | None`.\nAnything else raises `InvalidReferenceTypeError`. The target needs exactly\none identity field, and its other required fields need defaults.\n\n### Edge values you build by hand\n\n`Edge(source=..., target=..., relationship_type=..., weight=...,\nproperties={...})`. An omitted `source` falls back to the node declaring the\nfield; on a parametrized field that node must be the declared `Source`\ntype, or it raises. On a root container, always pass `source=`. The tuple\nform `(Edge(weight=0.8), target_node)` attaches edge properties to a plain\nDataPoint field (`examples/guides/custom_data_models.py`).\n\n### From JSON instead of Python\n\n- `cognee.low_level.graph_model_from_spec(spec)`: a small entity/relation\n  spec (names, fields, `one`/`many` relations) compiled to DataPoint\n  classes, with identity and index on `name` by default. Example:\n  `examples/guides/graph_model_from_json.py`.\n- `cognee.low_level.graph_schema_to_graph_model(json_schema)`: a JSON\n  Schema (needs a top-level `title`; only internal `#` refs).\n- HTTP: `POST /api/v1/remember` takes a `graph_model` form field (JSON\n  schema string); `POST /api/v1/cognify` takes a `graphModel` JSON object.\n  `POST /api/v1/llm/infer-schema` proposes a schema from sample text.\n\nNeither JSON path can express typed `Edge` fields or `FromIdentity`; use\nPython classes for those.\n\n## Pitfalls\n\n- **Duplicated nodes** → missing `identity_fields`.\n- **Node never shows up in recall** → no `index_fields`, or the recalling\n  process never imported the model class (graph completion searches the\n  collections of DataPoint classes loaded in that process).\n- **Edge rows silently missing** → an unresolved row is dropped with a\n  warning. Endpoints resolve by **exact type** against nodes extracted from\n  the same chunk: a subclass instance does not match where its base is\n  declared, and a node from another chunk or an earlier run is not a\n  candidate.\n- **`InvalidReferenceTypeError`, \"declares Edge in a shape the LLM\n  extraction cannot fill\"** → an unsupported `FromIdentity` or `Edge`\n  spelling. These are raised when the model is converted during\n  extraction, not at class definition, so they appear mid-pipeline.\n- **String endpoints resolve only to the owning model itself or a\n  module-level class.** A string naming another class defined inside a\n  function raises `InvalidReferenceTypeError`, so define models at module\n  level.\n- **Field names that collide with DataPoint's own fields** (`id`, `type`,\n  `version`, `metadata`, `created_at`, `belongs_to_set`, …) are stripped\n  from what the LLM sees. Rename them.\n- **A subclass that overrides `metadata`** replaces the parent's entirely.\n  Dropping `identity_fields` only logs a warning. A subclass also hashes ids\n  under its own class name.\n- **Write a `custom_prompt`.** Without one the generic knowledge-graph\n  prompt is used; your schema reaches the LLM only as structured output.\n- **Not with GLiNER.** `extractor=\"gliner_demo\"` (alias `\"gliner\"`) raises\n  with a custom `graph_model`, and so does the default `GRAPH_EXTRACTOR=auto`\n  when no LLM key is configured (it resolves to `gliner_demo`).\n- **Remote mode drops it.** After `cognee.serve(url)`, `remember()` and\n  `cognify()` do not forward `graph_model`; the server builds a generic\n  graph.\n- A custom model skips the generic path's ontology resolution, per-graph\n  node dedup. Summaries still run.\n\n## How it works\n\n`extract_content_graph` converts a DataPoint model into a plain Pydantic\nmodel for the LLM: infrastructure fields and `metadata` are stripped, typed\nedge fields become row lists (`FriendsWithEdge` with `source`/`target`\nstrings), and `FromIdentity` fields become strings. The answer is converted\nback into DataPoint instances with ids from `identity_fields`, edge rows are\nresolved against the nodes in that answer, and the result is attached to the\nchunk (`chunk.contains`) and stored by `add_data_points`. Ownership is\nrecorded per document, so `forget(data_id=...)` removes a custom-model\ndocument's nodes while shared nodes survive.\n\n- LLM boundary, both directions: `cognee/shared/llm_graph_model.py`\n- DataPoint, metadata, ids: `cognee/infrastructure/engine/models/DataPoint.py`\n- Markers: `cognee/infrastructure/engine/models/FieldAnnotations.py`\n- Edge: `cognee/infrastructure/engine/models/Edge.py`\n- Property vs edge decision: `cognee/modules/graph/utils/field_edges.py`\n- Custom-model branch of extraction: `cognee/tasks/graph/extract_graph_from_data.py`\n- JSON schema / spec paths: `cognee/shared/graph_model_utils.py`,\n  `cognee/modules/graph_models/`\n- Vector collections: `cognee/tasks/storage/index_data_points.py`\n\n## Extending it\n\n- Tests for the LLM round trip: `cognee/tests/unit/modules/graph/test_content_graph_to_data_point.py`.\n  Edge typing: `cognee/tests/unit/interfaces/graph/test_typed_edge_model.py`,\n  `test_typed_edges_graph.py`. Identity: `cognee/tests/unit/infrastructure/engine/test_identity_fields.py`.\n  Property vs edge: `cognee/tests/unit/modules/graph/test_field_edges.py`.\n- Deletion of custom-model nodes: `cognee/tests/test_delete_custom_graph.py`.\n- A new `Edge` or `FromIdentity` spelling must be handled in both directions\n  in `llm_graph_model.py`, and rejected with `InvalidReferenceTypeError`\n  when unsupported, never silently accepted.\n","frontmatter":{"name":"cognee-custom-graph-models","description":"Use when defining the shape of cognee's knowledge graph with graph_model= — writing DataPoint node classes, choosing identity and index fields so nodes merge and are searchable, declaring typed Edge fields and FromIdentity references, building a model from a JSON schema, or debugging duplicated nodes, missing edges, or InvalidReferenceTypeError."},"isInternal":false,"tokens":2391,"sizeBytes":9782},{"name":"SKILL.md","path":".agents/skills/cognee-custom-pipelines/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-custom-pipelines/SKILL.md","title":"cognee-custom-pipelines","category":"anthropic-skill","format":"markdown","content":"---\nname: cognee-custom-pipelines\ndescription: Use when building your own cognee processing — writing custom tasks, chaining them into a pipeline with run_custom_pipeline or the lightweight run_pipeline (from cognee.pipelines import run_pipeline), storing custom DataPoints with add_data_points, running custom enrichment over the existing graph, checking pipeline run status, or debugging how data flows between tasks (batch_size, data_per_batch, ctx, Drop, enriches).\n---\n\n# Custom tasks and pipelines\n\nEverything cognee does runs as a **pipeline**: an ordered list of **tasks**,\neach a plain Python function whose output feeds the next one. `remember()`\nis the right tool for ordinary ingestion. Build a pipeline when you need\nprocessing cognee does not ship: your own extraction, your own node types,\nor a post-processing step over the graph.\n\n```python\nimport cognee\nfrom cognee.modules.pipelines import Task\nfrom cognee.tasks.storage import add_data_points\nfrom cognee.low_level import DataPoint\n\n\nclass Person(DataPoint):\n    name: str\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nasync def extract_people(data_items: list) -> list[Person]:\n    people = []\n    for item in data_items:  # always a list, see below\n        text = item if isinstance(item, str) else \"\"\n        people += [Person(name=n.strip()) for n in text.split(\",\") if n.strip()]\n    return people\n\n\nresult = await cognee.run_custom_pipeline(\n    tasks=[\n        Task(extract_people, needs_llm=False),\n        Task(add_data_points, needs_llm=False),  # store in graph + vector DBs\n    ],\n    data=[\"Ada Lovelace, Alan Turing\"],\n    dataset=\"people\",\n)\n```\n\n## Use it\n\n### Pick the runner\n\nThere are three, and two share the name `run_pipeline`:\n\n| Runner | Import | Use it for |\n|---|---|---|\n| `cognee.run_custom_pipeline(...)` | `cognee` | The normal choice: runs your tasks against a dataset with permissions, a per-dataset lock, run records, and status |\n| Full orchestrator `run_pipeline(tasks=..., data=..., datasets=...)` | `cognee.modules.pipelines` | What `run_custom_pipeline` and `cognify` call; yields `PipelineRunInfo` |\n| Lightweight `run_pipeline([...], data=...)` | `from cognee.pipelines import run_pipeline` (after `import cognee`, the attribute `cognee.pipelines.run_pipeline` is the orchestrator) | Quick chains of `task()` specs with no permissions, locks, run rows, or migrations; returns the last step's outputs |\n\n`cognee.run_custom_pipeline(tasks, data=None, dataset=\"main_dataset\",\nuser=None, incremental_loading=False, data_per_batch=20,\nrun_in_background=False, pipeline_name=\"custom_pipeline\", data_cache=False,\n...)` returns `{dataset_id: PipelineRunInfo}` (the started run when\n`run_in_background=True`). With `data=None` it runs over the dataset's\nexisting documents (`Data` rows).\n\n### Write a task\n\n```python\nfrom cognee.modules.pipelines import Task\nfrom cognee.modules.pipelines.models import PipelineContext\nfrom cognee.modules.pipelines.tasks.task import task_summary\nfrom cognee.pipelines import Drop\n\n\n@task_summary(\"Tagged {n} chunk(s)\")\nasync def tag_chunks(chunks: list, ctx: PipelineContext = None, label: str = \"x\"):\n    for chunk in chunks:\n        chunk.metadata[\"label\"] = label\n    return chunks  # or yield per item; return/yield Drop to discard\n\n\ntag = Task(tag_chunks, label=\"reviewed\", batch_size=10, needs_llm=False)\n```\n\n- A task is an `async def`, a generator, an async generator, or a plain\n  `def`. Extra `Task(fn, *args, **kwargs)` arguments are passed after the\n  pipeline data.\n- `needs_llm=False` on tasks that never call an LLM lets an LLM-free\n  pipeline skip the LLM connection check.\n- `ctx` (injected by the parameter **name** `ctx`) carries `user`,\n  `data_item`, `dataset`, `pipeline_run_id`, `pipeline_name`, and `extras`.\n- `task.with_config(batch_size=..., **kwargs)` returns a modified copy.\n\n### How data flows\n\n- **Each document runs the whole chain on its own** with `run_custom_pipeline`\n  or the orchestrator, and the first task receives it as a **one-element\n  list** (`[data_item]`), not the bare item. The lightweight `run_pipeline`\n  passes `data` to the first task unchanged.\n- **`data_per_batch`** (default 20) is how many documents run at the same\n  time. It is a concurrency limit, not a batch size.\n- **`batch_size` belongs to the consumer.** A task's `batch_size` decides how\n  the *previous* task's generator output is grouped before it is passed in.\n  Generator tasks always hand over lists; a coroutine or function hands over\n  its single return value.\n- **Streaming:** each upstream result goes down the chain immediately, so a\n  downstream task can run many times per document.\n- **`enriches=True`:** if the task returns `None`, its input is passed on\n  unchanged (coroutines and functions only, not generators).\n- **`Drop`:** returning or yielding it removes that item from the stream.\n- Every `DataPoint` passing through is stamped automatically with where it\n  came from (`source_pipeline`, `source_task`, `source_user`, …).\n\n### Store results\n\n`add_data_points(data_points, custom_edges=None, graph_only=False)` writes a list of `DataPoint`s to the graph and indexes\ntheir `index_fields` in the vector DB. It returns the same list, so it can\nsit mid-chain. Give every node type `identity_fields` so repeated runs merge\ninstead of duplicating (see the `cognee-custom-graph-models` skill).\n\n### Work on the existing graph\n\n`cognee.memify`, `cognee-cli memify`, `POST /api/v1/memify` and `improve()`'s\n`extraction_tasks` / `enrichment_tasks` are deprecated and removed in the next\nrelease. Run a post-processing step over the\ngraph with `run_custom_pipeline`: the task reads the graph itself, and one\nplaceholder item as `data` makes the chain run once instead of once per\ndocument.\n\n```python\nfrom cognee.infrastructure.databases.graph import get_graph_engine\n\n\nasync def enrich_graph(_items: list):\n    graph = await get_graph_engine()  # the dataset's graph inside the pipeline\n    nodes, edges = await graph.get_graph_data()\n    return [...]  # new DataPoints for add_data_points\n\n\nawait cognee.run_custom_pipeline(\n    tasks=[Task(enrich_graph, needs_llm=False), Task(add_data_points, needs_llm=False)],\n    data=[{}],\n    dataset=\"people\",\n)\n```\n\nFor cognee's own enrichment (session bridging, feedback weights, conflict\nreview, global context index) call `improve()`.\n\n### Check status\n\n```python\nstatus = await cognee.datasets.get_status([dataset_id], pipeline_names=[\"custom_pipeline\"])\n```\n\nWithout `pipeline_names` it reports only `cognify_pipeline`. It returns\n`{str(dataset_id): PipelineRunStatus}` (`{str(dataset_id): {pipeline_name:\nstatus}}` for several `pipeline_names`): `DATASET_PROCESSING_STARTED`,\n`_COMPLETED`, or `_ERRORED` (`_INITIATED` exists only on legacy rows). The value `run_custom_pipeline`\nreturns per dataset is a `PipelineRunInfo` instead, whose class names the\noutcome: `PipelineRunCompleted`, `PipelineRunAlreadyCompleted`,\n`PipelineRunErrored`, and so on.\n\n## Pitfalls\n\n- **Wrong `run_pipeline`.** The one imported via\n  `from cognee.pipelines import run_pipeline` wants `task()`\n  specs *called* (`extract()`, not `extract`) and raises `TypeError`\n  otherwise; the orchestrator in `cognee.modules.pipelines` wants `Task`\n  objects and raises `WrongTaskTypeError` otherwise.\n- **`run_custom_pipeline` accepts only `Task` objects** despite its type hint;\n  string task names are not resolved.\n- **Some callables are rejected** by `Task` (`ValueError: Unsupported task\n  type`): bound methods and `functools.partial`s of a plain (non-generator)\n  sync function, and callable objects (instances with `__call__`). Generator\n  and async variants, plain functions, and lambdas work. When in doubt, wrap it\n  in a plain `def` / `async def`.\n- **`run_custom_pipeline` does not run database migrations.** On an existing\n  database, run `await cognee.run_migrations()` (or any `remember()` first).\n- **Nodes duplicate on every run** when a DataPoint has no\n  `identity_fields` (or `Dedup()` fields). `examples/guides/custom_data_models.py`\n  and `examples/guides/custom_tasks_and_pipelines.py` have this bug; don't\n  copy it.\n\n## How it works\n\n`run_custom_pipeline` → orchestrator `run_pipeline` (checks write\npermission, takes the per-dataset lock, records a `PipelineRun`) →\n`run_tasks` (a semaphore of `data_per_batch`, one chain per document) →\n`run_tasks_base` (streams each task's output into the next, batching by the\nconsumer's `batch_size`, injecting `ctx`, stamping provenance).\n\n- Package overview and the runner semantics: `cognee/modules/pipelines/__init__.py`\n- `Task`, `task()`, `TaskSpec`, `BoundTask`, `@task_summary`: `cognee/modules/pipelines/tasks/task.py`\n- Orchestrator: `cognee/modules/pipelines/operations/pipeline.py`; execution:\n  `run_tasks.py`, `run_tasks_base.py`, `run_tasks_data_item.py`\n- Lightweight runner: `cognee/modules/pipelines/operations/run_pipeline.py`,\n  exported from `cognee/pipelines/`\n- Context: `cognee/modules/pipelines/models/PipelineContext.py`\n- `run_custom_pipeline`: `cognee/modules/run_custom_pipeline/run_custom_pipeline.py`\n- Storage: `cognee/tasks/storage/add_data_points.py`\n- Index of all shipped tasks: `cognee/tasks/README.md`\n\nExamples:\n\n- `examples/demos/custom_pipelines/custom_pipeline_single_object_example.py`:\n  the best reference. It runs over added documents, does LLM extraction into\n  typed DataPoints, then recalls. Its models declare identity with `Dedup()`\n  (the `Annotated` alternative to `metadata[\"identity_fields\"]`).\n- `examples/demos/custom_pipelines/organizational_hierarchy/`: low-level\n  `run_tasks`, no LLM, dedup via `identity_fields`, status polling.\n- `examples/demos/custom_pipelines/custom_cognify_pipeline_example.py`:\n  rebuilds add + cognify from the default task list.\n\n## Extending it\n\n- **A new shipped task:** put it in the `cognee/tasks/` subpackage for its\n  stage, export it from that package's `__init__.py`, follow the template in\n  `cognee/tasks/README.md`, and add a unit test under `cognee/tests/unit/tasks/`.\n- Pipeline tests: `cognee/tests/unit/modules/pipelines/` (runner semantics,\n  context, provenance, rollback) and `cognee/tests/unit/pipelines/` (the\n  lightweight API).\n","frontmatter":{"name":"cognee-custom-pipelines","description":"Use when building your own cognee processing — writing custom tasks, chaining them into a pipeline with run_custom_pipeline or the lightweight run_pipeline (from cognee.pipelines import run_pipeline), storing custom DataPoints with add_data_points, running custom enrichment over the existing graph, checking pipeline run status, or debugging how data flows between tasks (batch_size, data_per_batch, ctx, Drop, enriches)."},"isInternal":false,"tokens":2521,"sizeBytes":10225},{"name":"SKILL.md","path":".agents/skills/cognee-docker/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-docker/SKILL.md","title":"cognee-docker","category":"anthropic-skill","format":"markdown","content":"---\nname: cognee-docker\ndescription: Use when the user wants to run cognee with Docker or docker compose — trying it out from the prebuilt image, starting the API server in a container, or bringing up the full stack (UI, MCP, Postgres, Neo4j) with compose profiles.\n---\n\n# Start cognee from the Docker image\n\n## Fastest path: prebuilt image, one file\n\nFor a local try-out, do NOT clone or build anything. Follow\n`docs/minimal-docker-compose.md`: save this as `docker-compose.yml` in an\nempty directory:\n\n```yaml\nservices:\n  cognee:\n    image: cognee/cognee:main\n    ports:\n      - \"8000:8000\"\n    environment:\n      LLM_API_KEY: ${LLM_API_KEY:?set LLM_API_KEY to your OpenAI API key}\n      # Single-user try-out: no auth, shared local databases.\n      ENABLE_BACKEND_ACCESS_CONTROL: \"false\"\n```\n\nThen:\n\n```bash\nexport LLM_API_KEY=\"sk-...\"   # OpenAI key (default LLM + embedding provider)\ndocker compose up\ncurl http://localhost:8000/health\n```\n\nInteractive API reference: http://localhost:8000/docs. First requests:\n\n```bash\necho \"Cognee turns documents into AI memory.\" > note.txt\n# remember = ingest + build the graph in one call (multipart form)\ncurl -X POST http://localhost:8000/api/v1/remember -F \"data=@note.txt\" -F \"datasetName=main_dataset\"\n# recall = query it (JSON)\ncurl -X POST http://localhost:8000/api/v1/recall -H \"Content-Type: application/json\" \\\n  -d '{\"query\": \"What does Cognee do?\", \"datasets\": [\"main_dataset\"]}'\n```\n\n`/api/v1/recall` takes the question as `query`. Omit `search_type` (or pass\n`null`) and the query is auto-routed by the same rule-based router the SDK\n`recall()` uses, with `HYBRID_COMPLETION` as the fallback; pass a value such as\n`\"search_type\": \"GRAPH_COMPLETION\"` to pin a strategy. The rule table is in\n`docs/recall-vs-search.md`.\n\nRequest DTOs accept both `snake_case` and `camelCase` for every field\n(`alias_generator=to_camel` + `populate_by_name` in `cognee/api/DTO.py`), so\n`search_type` and `searchType` are equally valid.\n\nThe legacy `/api/v1/add` + `/api/v1/cognify` + `/api/v1/search` endpoints still\nexist and are what `remember`/`recall` call underneath; use them only when you\nneed a single stage on its own. `/api/v1/improve` and `/api/v1/forget` complete\nthe memory API.\n\nData lives inside the container by default. To persist it, set\n`DATA_ROOT_DIRECTORY=/cognee-data/data` and\n`SYSTEM_ROOT_DIRECTORY=/cognee-data/system` and mount a named volume at\n`/cognee-data` (full example in `docs/minimal-docker-compose.md`).\n\n## Full stack from the repo\n\nThe repository's `docker-compose.yml` builds from source and adds opt-in\nprofiles. From the repo root (needs a `.env` with at least `LLM_API_KEY`;\ncopy `.env.template`):\n\n```bash\ndocker compose up                                  # API server only, port 8000\ndocker compose --profile ui up                     # + frontend on port 3000\ndocker compose --profile mcp up                    # + MCP server on port 8001\ndocker compose --profile postgres --profile neo4j up   # + databases\n```\n\nPostgres profile: pgvector/pg17, user/password/db `cognee`/`cognee`/`cognee_db`\non 5432. Neo4j profile: `neo4j`/`pleaseletmein` on 7474/7687. When cognee runs\nin a container and the database on the host, use `DB_HOST=host.docker.internal`.\n\n## Gotchas\n\n- With `ENABLE_BACKEND_ACCESS_CONTROL` unset (defaults to true), every API\n  call requires authentication — the single-user try-out sets it to `false`.\n- The image defaults to OpenAI for both LLM and embeddings; configuring only\n  one of them leaves the other on OpenAI, so keep a valid OpenAI key or\n  configure both (see the cognee-integrations skill).\n","frontmatter":{"name":"cognee-docker","description":"Use when the user wants to run cognee with Docker or docker compose — trying it out from the prebuilt image, starting the API server in a container, or bringing up the full stack (UI, MCP, Postgres, Neo4j) with compose profiles."},"isInternal":false,"tokens":975,"sizeBytes":3608},{"name":"SKILL.md","path":".agents/skills/cognee-forget/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-forget/SKILL.md","title":"cognee-forget","category":"anthropic-skill","format":"markdown","content":"---\nname: cognee-forget\ndescription: Use when removing data from cognee memory with forget() in the SDK, HTTP API, or CLI — finding which dataset and document hold the content to delete (listing datasets and data items, reading raw content), choosing between deleting one document, a whole dataset, or only the graph/vector memory, and doing it safely.\n---\n\n# Remove data with forget()\n\n`forget()` is cognee's one deletion API. It removes one document, a whole\ndataset, or only the derived memory (graph + vectors) while keeping the raw\nfiles. Deletion cannot be undone, so the workflow is always **find, read,\nconfirm, then delete**.\n\n> **Hard limits for agents**\n> - Delete only what the user asked to forget. Identify it by reading the\n>   content first; never guess from a file name alone.\n> - Confirm the exact items with the user before deleting, unless they\n>   already named exact ids.\n> - The widest deletion you may run is `forget(everything=True)`, and only\n>   when the user explicitly asks to wipe all of their memory. Never use any\n>   other reset or wipe mechanism to delete data.\n\n## Use it\n\n### 1. Find the dataset\n\n```python\nimport cognee\n\ndatasets = await cognee.datasets.list_datasets()  # datasets the user can read\nfor ds in datasets:\n    print(ds.id, ds.name)\n```\n\nHTTP: `GET /api/v1/datasets`. CLI: `cognee-cli datasets list`.\n\n### 2. List its documents\n\n```python\nitems = await cognee.datasets.list_data(dataset_id)  # all Data rows, oldest first\nfor item in items:\n    print(item.id, item.name, item.extension, item.created_at)\n```\n\nHTTP: `GET /api/v1/datasets/{dataset_id}/data?limit=100&offset=0` (limit up\nto 1000; `GET .../data/count` for the total; example:\n`examples/python/dataset_data_pagination.py`). CLI:\n`cognee-cli datasets data <dataset_uuid>`.\n\nEach item has `id`, `name`, `created_at`, `extension`, `mime_type`,\n`raw_data_location`, `dataset_id`, `label`, `external_metadata` (including\nany `node_set`), and `data_size`.\n\n### 3. Read the content before deciding\n\nNames are often `text_<hash>.txt`, so read the content to find what the user\nmeans.\n\n- HTTP: `GET /api/v1/datasets/{dataset_id}/data/{data_id}/raw` returns the\n  stored file (404 if it is gone).\n- SDK: there is no \"get raw\" helper; open the stored location:\n\n```python\nfrom cognee.infrastructure.files.utils.open_data_file import open_data_file\n\nasync with open_data_file(item.raw_data_location, mode=\"rb\") as f:\n    preview = f.read(2000).decode(\"utf-8\", errors=\"replace\")\n```\n\nJudge matches by meaning, not only by keywords, and show the user the\ncandidates (name + a short preview) before deleting.\n\n### 4. Delete\n\n| Goal | Call | What remains |\n|---|---|---|\n| One document | `forget(data_id=..., dataset_id=...)` (or `dataset=\"name\"`) | Nothing of that document; shared entities stay while another document still references them |\n| A whole dataset | `forget(dataset=\"name\")` or `forget(dataset_id=...)` | The dataset is deleted outright: the record, its data rows, graph and vector stores, and attributed sessions |\n| Rebuild a dataset's graph later | `forget(dataset=\"name\", memory_only=True)` | Raw files and data rows; graph, vectors, sessions and pipeline status are reset, so the data can be re-processed |\n| One document's memory only | `forget(dataset=\"name\", data_id=..., memory_only=True)` | That document's raw file and row |\n| Every dataset the user can delete | `forget(everything=True)` | Nothing, in any dataset the user has `delete` on in the current tenant (shared ones included). Only on explicit request (see the hard limits) |\n\nReturn values: `{\"data_id\", \"dataset_id\", \"status\"}` for a document,\n`{\"dataset_id\", \"status\"}` for a dataset (plus `data_records_reset` with\n`memory_only`), `{\"datasets_removed\", \"status\"}` for everything\n(`datasets_removed` counts the datasets the user can *read*, not the delete\nset).\n\n**HTTP:** `POST /api/v1/forget` with a JSON body; camelCase and snake_case\nkeys both work: `{\"datasetId\": \"...\", \"dataId\": \"...\"}`,\n`{\"dataset\": \"name\", \"memoryOnly\": true}`, `{\"everything\": true}`. Invalid\ncombinations return 422.\n\n**CLI:** `cognee-cli forget --dataset NAME | --dataset-id UUID\n[--data-id UUID] [--memory-only]`, or `--everything` / `--all`. The CLI\n**does not ask for confirmation**; confirm with the user first.\n\n## Pitfalls\n\n- **A `data_id` that is not in the dataset returns success and deletes\n  nothing.** The delete path treats an unknown id as a custom-graph-model\n  delete. Always take the id from `list_data` for that same dataset, and\n  check it is still listed afterwards if it matters.\n- **Pass either `dataset` or `dataset_id`, not both** (`ValueError`).\n  `data_id` and `memory_only` both need a dataset.\n- **`memory_only` is ignored when `everything=True`** in the SDK (the CLI\n  rejects the combination). `everything=True` always deletes everything.\n- **Not found and not allowed look the same.** An unknown dataset name and\n  one the user cannot delete both raise `DatasetNotFoundError`. Deleting\n  needs the `delete` permission on the dataset (see the `cognee-permissions`\n  skill). `everything=True` deletes every dataset the user has `delete`\n  permission on in the current tenant, including datasets shared to them\n  with delete rights, not only the ones they own.\n- **Sessions that cited deleted data are invalidated** so recall stops\n  returning answers built on it. Agent-trace entries are not invalidated.\n- **Changing a document is not a delete.** To replace a document's content,\n  use `cognee.update(data_id=..., data=..., dataset_id=...)`, which keeps its\n  id and re-extracts only the changed parts.\n- `cognee.delete()` is deprecated; use `forget()`.\n\n## How it works\n\n`forget()` resolves the dataset with the `delete` permission, then:\n\n- **One document** → `datasets.delete_data()`: takes the dataset lock,\n  deletes the graph nodes and edges the document owns, the matching vectors\n  and edge evidence, invalidates sessions that cited them, then deletes the\n  `Data` row. Ownership is tracked per document (source-refs on graph\n  elements), so an entity shared by two documents survives until both are\n  deleted. Raw files are reference-counted by storage location.\n- **A dataset** → `datasets.empty_dataset()`.\n- **`memory_only`** → drops the dataset's graph/vector memory and resets its\n  pipeline status, leaving raw data for a rebuild.\n- **`everything`** → `datasets.delete_all()` over every dataset the user has\n  `delete` on in the current tenant, plus a full prune of the session cache\n  (when caching or usage logging is on). This wipes **every user's**\n  sessions (Redis FLUSHDB / the whole fs cache / all SQL cache tables), not\n  just this user's.\n\nKey files:\n\n- `cognee/api/v1/forget/forget.py` (SDK), `routers/get_forget_router.py`\n  (HTTP), `cognee/cli/commands/forget_command.py` (CLI)\n- `cognee/api/v1/datasets/datasets.py` (`list_datasets`, `list_data`,\n  `delete_data`, `empty_dataset`, `delete_all`)\n- `cognee/api/v1/datasets/routers/get_datasets_router.py` (list, count, raw)\n- `cognee/infrastructure/databases/provenance/source_refs.py` (per-document\n  ownership of graph elements)\n- `cognee/infrastructure/files/utils/open_data_file.py`\n\n## Extending it\n\n- Anything new that writes graph nodes or edges for a document must record\n  its source-refs, or `forget(data_id=...)` cannot find and remove it.\n- Anything new that stores per-document data outside the graph (like edge\n  evidence) needs a cleanup step in the delete path and in `memory_only`.\n- Unit tests for `forget()` are in `cognee/tests/unit/api/v1/forget/`\n  (argument validation, the HTTP endpoint, `memory_only`); cover both the\n  document and the `memory_only` paths for new deletion behaviour.\n","frontmatter":{"name":"cognee-forget","description":"Use when removing data from cognee memory with forget() in the SDK, HTTP API, or CLI — finding which dataset and document hold the content to delete (listing datasets and data items, reading raw content), choosing between deleting one document, a whole dataset, or only the graph/vector memory, and doing it safely."},"isInternal":false,"tokens":1928,"sizeBytes":7689},{"name":"SKILL.md","path":".agents/skills/cognee-improve-sessions/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-improve-sessions/SKILL.md","title":"cognee-improve-sessions","category":"anthropic-skill","format":"markdown","content":"---\nname: cognee-improve-sessions\ndescription: Use when working with cognee's session memory or improve() — storing conversation turns, agent traces and feedback with session_id, bridging sessions into the permanent graph, reading an ImproveResult, understanding why an improve stage was skipped, already_completed or lock_held, or tuning the IMPROVE_* settings.\n---\n\n# Session memory and improve()\n\ncognee has two kinds of memory:\n\n- **Session memory**: a fast cache of conversation turns, agent traces, and\n  feedback, keyed by `session_id`. Writing is instant, with no LLM\n  extraction.\n- **The permanent graph**: what `remember()` builds without a session.\n\n`improve()` connects them. It bridges session content into the graph and\nenriches the graph itself. `remember()` calls it automatically, so most\nusers never call it directly.\n\n```python\nimport cognee\n\n# Session write: returns immediately; improve() bridges it in the background\nawait cognee.remember(\"User prefers dark mode.\", session_id=\"chat_1\")\n\n# Session-aware query: session cache first, then the graph\nresults = await cognee.recall(\"What does the user prefer?\", session_id=\"chat_1\")\n\n# Bridge sessions into a dataset's graph explicitly\nresult = await cognee.improve(dataset=\"main_dataset\", session_ids=[\"chat_1\"])\nprint(result.status, result.stage_summary())\n\nawait cognee.wait_for_background_tasks()  # before a script exits\n```\n\n## Use it\n\n### Writing session memory\n\n| What | How |\n|---|---|\n| A fact or note | `remember(text, session_id=...)` (stored as a Q&A entry with the text as the answer) |\n| A Q&A turn | `recall(query, session_id=...)` with a completion search type saves the turn itself; or `remember(cognee.QAEntry(question=..., answer=...), session_id=...)` |\n| An agent step | `remember(cognee.TraceEntry(origin_function=..., status=\"success\", ...), session_id=...)`, or the `@cognee.agent_memory(save_session_traces=True)` decorator |\n| Pin a session to a project / node set | `node_set=[...]` on the first `QAEntry`/`TraceEntry` (or as a kwarg on any session `remember`) pins it; later writes repeat or omit it, a different set raises `cognee.SessionNodeSetConflictError` (HTTP 409). `improve()` keeps the set on everything it bridges, so `recall(node_name=[...])` scopes to the project |\n| Feedback on an answer | `remember(cognee.FeedbackEntry(qa_id=..., feedback_score=...), session_id=...)` or `cognee.session.add_feedback(session_id, qa_id, feedback_text=..., feedback_score=...)` |\n| Read a session | `cognee.session.get_session(session_id, last_n=...)` |\n\nRequirements: `CACHING=true` (default). The cache backend is\n`CACHE_BACKEND`, one of `sqlite` (default), `postgres`, `redis`, `fs`,\n`tapes`. Sessions expire after `SESSION_TTL_SECONDS` (default 7 days).\n\n### What improve() does: nine stages, in order\n\nEvery run goes through the same ordered stages\n(`cognee/modules/improve/registry.py`). Each stage checks a gate before it\nspends any LLM or embedding cost, and reports one `StageResult`.\n\n| # | Stage | What it does | Runs when |\n|---|---|---|---|\n| 1 | `feedback_weights` | Adjusts the weight of graph elements that rated answers used | `session_ids` given; adapter supports feedback weights |\n| 2 | `persist_session_qa` | Turns session Q&A into graph content (node set `user_sessions_from_cache`) | `session_ids` given. **The only fatal stage** |\n| 3 | `persist_agent_traces` | Turns agent-trace feedback into graph content | `session_ids` given |\n| 4 | `extract_agent_context` | Drafts agent-profile lessons from traces | `session_ids`, `CACHING` + `AUTO_FEEDBACK`, an LLM |\n| 5 | `distill_sessions` | Distills session learnings into the graph | `session_ids`, an LLM |\n| 6 | `update_user_preferences` | Folds rated turns into per-user preferences | `session_ids`, `PERSONALIZATION_ENABLED=true` (default false) |\n| 7 | `build_truth_subspace` | Builds the truth subspace from distilled learnings | `session_ids`, `build_truth_subspace=True`, a Ladybug graph |\n| 8 | `review_conflicts` | Reviews dated source facts, stores conflicts and rewrites Entity descriptions | `review_conflicts=True` or `IMPROVE_REVIEW_CONFLICTS=true`, an LLM, edge evidence |\n| 9 | `global_context_index` | Bucket and root summaries for global questions | `build_global_context_index=True`, an LLM |\n\nStages 1–7 need `session_ids`; 8–9 work on the graph alone. The order\nmatters: 4 feeds 5, 5 feeds 7, and 7 runs before 8.\n\n`extraction_tasks` / `enrichment_tasks` are deprecated and removed in the next\nrelease: they still run, as a `custom_tasks` stage after the others, scoped by\n`node_name`, `data`, `node_type`, `vector_db_config` and `graph_db_config`.\nWithout custom tasks those options are ignored. Both cases warn with a\n`FutureWarning`; use `run_custom_pipeline()` instead.\n\n### Reading the result\n\n`improve()` returns an `ImproveResult`, and so do `POST /api/v1/improve`, the\nCLI, and `RememberResult.improve`.\n\n- `result.status`: `completed`, `errored` (any stage errored), `skipped`\n  (every stage skipped), or `running` (background, not finished).\n- `result.stages`: one `StageResult` per stage, with `stage`, `status`\n  (`completed` / `already_completed` / `skipped` / `errored`), `reason`,\n  `error`, `counts`, `duration_ms`.\n- `result.stage(\"distill_sessions\")`, `result.stage_summary()`,\n  `result.lock_held`, `result.rerun_requested`, `result.rerun_passes`.\n- `await result.wait()` finishes a background run (no-op otherwise).\n\n**Skip and no-op reasons:**\n\n| Reason | Meaning / fix |\n|---|---|\n| `no_session_ids` | Session stage, no `session_ids` passed |\n| `disabled_by_config` | Listed in `IMPROVE_STAGES_DISABLED` |\n| `opt_in_disabled` | Pass `build_truth_subspace=True` / `review_conflicts=True` / `build_global_context_index=True` |\n| `personalization_disabled` | Set `PERSONALIZATION_ENABLED=true` |\n| `auto_feedback_disabled` | Stage 4 needs `CACHING=true` and `AUTO_FEEDBACK=true` |\n| `no_llm_configured` | Stages 4, 5, 8, 9 draft text with an LLM; none configured |\n| `edge_evidence_disabled` | Conflict review needs `EDGE_EVIDENCE_ENABLED=true` |\n| `backend_unsupported` | The graph adapter lacks the feature (feedback weights, truth subspace) |\n| `session_manager_unavailable` | The session cache is not reachable |\n| `lock_held` | Another improve for the same dataset or session is running (below) |\n| `aborted_by_fatal_stage` | Stage 2 failed, so the rest did not run |\n| `budget_exhausted` | An earlier stage failed because the LLM budget is exhausted (a 402); the rest would fail the same way. Top up, then run improve again |\n| `no_new_entries`, `no_new_trace_steps`, `no_new_facts`, `no_writes_since_last_improve` | With status `already_completed`: nothing new since the last run |\n\n### How remember() triggers improve\n\n- **Without a session:** `add`, then `cognify`, then a foreground `improve()`.\n  Its outcome is on `result.improve` / `result.improve_error`. A failed\n  improve never marks the remember as errored.\n- **With `session_id`:** the text is cached, then a background\n  `improve(dataset, session_ids=[session_id])` starts if the debounce allows\n  it. `result.improve` fills in only after `await result` or\n  `wait_for_background_tasks()`.\n- `self_improvement=False` turns it off per call; `IMPROVE_AUTO_ENABLED=false`\n  turns it off everywhere and overrides `self_improvement=True`.\n- An application embedding cognee can decline one automatic improve before it\n  starts: `cognee.modules.improve.register_auto_improve_admission(check)`\n  registers one async check that `remember()` awaits on both paths. Returning\n  a reason string skips the improve and sets `result.improve_skipped`\n  (`result.improve` stays `None`); the data is stored either way. A check that\n  raises allows the improve. Explicit `improve()` calls are never gated.\n\n### Settings (`IMPROVE_*`, `cognee/modules/improve/config.py`)\n\n| Env var | Default | Meaning |\n|---|---|---|\n| `IMPROVE_AUTO_ENABLED` | `true` | Automatic improve after `remember()` |\n| `IMPROVE_DEBOUNCE_ENTRIES` | `1` | Session auto-improve fires after this many new entries |\n| `IMPROVE_DEBOUNCE_SECONDS` | `0` | ...or this many seconds since the last one. Seconds alone (entries left at 1) means time-only |\n| `IMPROVE_STAGES_DISABLED` | empty | CSV of stage names to skip |\n| `IMPROVE_FEEDBACK_ALPHA` | `0.1` | Feedback learning rate, in (0, 1] |\n| `IMPROVE_REVIEW_CONFLICTS` | `false` | Review fact conflicts, including automatic improve |\n| `IMPROVE_EFFECTIVE_DATE_KEY` | `effective_date` | Document metadata key holding the source date |\n\nThere is no debounce timer: held-back entries wait for the next\n`remember()` with that session, or an explicit `improve()`.\n\n## Pitfalls\n\n- **A plain `improve(dataset)` often does nothing.** Without `session_ids`,\n  only stages 8–9 can run, and both are off by default. Result: every\n  stage `skipped`. That is expected, not an error.\n- **A session's node set is pinned once.** The first write carrying\n  `node_set` fixes it for the session; a different set is a 409, start a\n  new session instead. Bridged Q&A, traces and lessons carry the set, user\n  preferences never do. The guarantee holds within one worker process (an\n  in-process lock); with several workers, send a session's writes to one.\n  Example: `examples/guides/session_node_sets.py`.\n- **Typed entries do not auto-improve.** `remember(QAEntry/TraceEntry/\n  FeedbackEntry, session_id=...)` stores the entry but never starts an\n  improve. Call `improve(session_ids=[...])` yourself.\n- **`lock_held` does not wait.** Improves for the same dataset or session\n  run one at a time: a second call returns at once with every stage\n  `skipped: lock_held`. If it shares a session with the running one, it sets\n  `rerun_requested=True` and the holder runs up to 2 extra passes (3 passes\n  in total; see `rerun_passes`). The bound is `IMPROVE_MAX_RERUN_PASSES`, a\n  constant in `cognee/api/v1/improve/improve.py`, not an env var. The lock is per process only; multiple API workers do not\n  share it.\n- **Sessions bridge once.** Q&A and trace persistence are tracked per user\n  and session, not per dataset, so bridging a session into dataset A and\n  then into dataset B persists no new Q&A/traces into B. Distillation is\n  tracked per (session, dataset) and still runs into B.\n- **`IMPROVE_STAGES_DISABLED` is validated.** An unknown stage name, or\n  `persist_session_qa` (fatal, cannot be disabled), raises `ValueError`, and\n  the API server refuses to start.\n- **Session writes with the cache off.** `remember(text, session_id=...)`\n  with `CACHING=false` only logs a warning and stores nothing; typed entries\n  raise `RuntimeError`. An explicit `improve(session_ids=...)` then fails in\n  the fatal stage.\n- **Fatal stage failure.** If stage 2 errors, `improve()` raises (HTTP 409)\n  and the error carries `.improve_result`. In background mode it is recorded\n  on `result.error` instead. Other stages failing only mark themselves\n  `errored`; HTTP still returns 200, so check `status`.\n- **Remote mode.** After `cognee.serve(url)`, a background improve is\n  fire-and-forget: `status` stays `running` and there is no polling.\n- `cognee/modules/session_bridge/` is gone (only stale `__pycache__` may be\n  left). The bridging now lives in the improve stages; some test names still\n  say \"session_bridge\".\n\n## How it works\n\n`improve()` resolves the dataset once (creating it if the name is new),\nclaims the improve lock for `dataset:<id>` plus every\n`session:<user>:<session_id>`, probes the graph adapter's capabilities, and\nruns the stages with one frozen `ImproveRunInputs`. Each stage is a gate\nplus a call into existing pipelines plus a result mapping. Stages never own\nretries or ordering.\n\nWatermarks keep repeat runs cheap:\n\n- Session stages track how many entries were already persisted, per user\n  and session.\n- Conflict review uses its last succeeded stamp to select touched entities,\n  and retries conflicts with missing citations or pending writes. Source dates\n  come from document metadata; session windows use their last entry time.\n  Fixed attributes remain disputed even when one document is newer.\n\nThe improve operation row is written when the run finishes: `failed` if any\nstage errored (a retry is never gated off), `noop` if nothing ran.\n\n- Orchestrator: `cognee/api/v1/improve/improve.py` (HTTP:\n  `routers/get_improve_router.py`; CLI: `cognee/cli/commands/improve_command.py`)\n- Stages, registry, results: `cognee/modules/improve/` (`stages.py`,\n  `registry.py`, `stage.py`, `result.py`, `inputs.py`, `capabilities.py`,\n  `config.py`, `graph_changes.py`, `constants.py`)\n- Lock: `cognee/infrastructure/locks/session_lock.py`\n- Session store and watermarks: `cognee/infrastructure/session/`\n  (`session_manager.py`, `session_persist_watermark.py`,\n  `feedback_detection.py`); cache backends in\n  `cognee/infrastructure/databases/cache/`\n- Auto-improve from remember: `cognee/api/v1/remember/remember.py`,\n  `cognee/api/v1/remember/auto_improve_debounce.py`\n- Entry types: `cognee/memory/entries.py`\n- Background tasks: `cognee/infrastructure/background_tasks.py`\n\nExamples: `examples/guides/improve_quickstart.py`, `sessions.py`,\n`session_distillation.py`, `review_conflicts.py`, `global_context_index.py`,\n`agent_memory_quickstart.py`, and\n`examples/advanced_guides/remember_recall_improve_example.py`.\n\n## Extending it\n\nAdding a stage:\n\n1. Subclass `BaseStage` in `cognee/modules/improve/stages.py`. Set `name`,\n   `needs_sessions`, and `fatal` (leave it `False`; exactly one fatal stage\n   is enforced at import). Implement `gate()` (return a skip reason\n   constant, or `None`, before any LLM/embedding cost) and `run()` (call\n   existing pipeline code, return a `StageResult`).\n2. Insert it into `DEFAULT_STAGES` in `registry.py` at the right position.\n   The order is pinned by `cognee/tests/unit/modules/improve/test_registry_order.py`;\n   update it deliberately.\n3. If it can re-run cheaply, give it a watermark so a repeat run reports\n   `already_completed` (graph-wide stages can stamp the improve row with the\n   helpers in `graph_changes.py`, as conflict review does).\n4. Tests: `cognee/tests/unit/modules/improve/` (gates, results, config) and\n   `cognee/tests/unit/api/v1/improve/` (orchestration, rerun, router).\n","frontmatter":{"name":"cognee-improve-sessions","description":"Use when working with cognee's session memory or improve() — storing conversation turns, agent traces and feedback with session_id, bridging sessions into the permanent graph, reading an ImproveResult, understanding why an improve stage was skipped, already_completed or lock_held, or tuning the IMPROVE_* settings."},"isInternal":false,"tokens":3676,"sizeBytes":14222},{"name":"SKILL.md","path":".agents/skills/cognee-ingestion/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-ingestion/SKILL.md","title":"cognee-ingestion","category":"anthropic-skill","format":"markdown","content":"---\nname: cognee-ingestion\ndescription: Use when putting data into cognee memory with remember() — choosing inputs (text, files, folders, URLs, repos, databases), datasets and node_sets, loaders, ontologies, the graph extractor (LLM or GLiNER), chunking, dry-run cost estimates, or when remember() raises on a keyword argument.\n---\n\n# Ingest data with remember()\n\n`remember()` is cognee's ingestion API. One call stores the data, builds the\nknowledge graph, and enriches it. Use it for all ingestion; every option in\nthis skill is a `remember()` argument unless it says otherwise.\n\n```python\nimport cognee\n\nresult = await cognee.remember(\"Einstein was born in Ulm.\")  # text\nresult = await cognee.remember(\n    [\"./notes.md\", \"./report.pdf\"],  # files\n    dataset_name=\"research\",\n)\nprint(result.status, result.dataset_id)  # \"completed\", UUID\n```\n\nAll cognee functions are async. Without `dataset_name` data goes to\n`main_dataset`. Needs `LLM_API_KEY` unless you use the GLiNER extractor\n(below).\n\n## Use it\n\n### Inputs\n\n`data` accepts a string, a list of strings, file paths (absolute, `file://`,\n`s3://`), http(s) URLs, binary streams, or a list mixing them.\n\n- **URLs** are fetched and scraped (needs `ALLOW_HTTP_REQUESTS=true`, the\n  default).\n- **Folders** are ingested file by file. A folder that looks like a code\n  project, or a GitHub/GitLab URL, becomes one code repository (needs `git`\n  on PATH).\n- **Code files** (`.py`, `.ts`, `.go`, …) go down the code-graph route: a\n  deterministic graph, no LLM calls, searchable only with\n  `SearchType.CODE`. To index a whole repository explicitly, pass\n  `content_type=\"code\"`.\n- **Databases and dlt sources**: a SQL connection string, a dlt\n  `DltResource` / `DltSource`, or a CSV. dlt is a core dependency, so no\n  extra is needed (`cognee[dlt]` is an empty compatibility extra). Options: `primary_key` (default `\"id\"`),\n  `write_disposition` (`\"replace\"` default, or `\"append\"`), `query`,\n  `max_rows_per_table`.\n- **Skill playbooks** (`SKILL.md` files): `content_type=\"skills\"`; ingests\n  into the target dataset (default `main_dataset`), so pass `dataset_name`\n  to keep skills in their own dataset.\n\n### Where the data goes\n\n| Argument | What it does |\n|---|---|\n| `dataset_name` / `dataset_id` | Target dataset. `dataset_id` wins. A dataset is the unit of permissions and isolation. |\n| `node_set=[\"AI\", \"FinTech\"]` | Tags the data so recall can filter to it later with `recall(..., node_name=[\"AI\"])`. With `session_id` it pins the session's node set instead (first write wins, a different set later is a 409); `improve()` carries it into the graph. See the `cognee-improve-sessions` skill. |\n| `session_id=\"chat_1\"` | Writes to the fast session cache instead of the graph; `improve()` bridges it into the graph in the background. See the `cognee-improve-sessions` skill. Requires `CACHING=true`. |\n\n### How the graph is built\n\n| Argument | What it does |\n|---|---|\n| `extractor` | `\"llm\"` or `\"gliner_demo\"` (alias `\"gliner\"`). Default is `GRAPH_EXTRACTOR=auto`: the LLM when an API key is configured, otherwise GLiNER. |\n| `graph_model=MyModel` | Extract into your own DataPoint model instead of the generic `KnowledgeGraph`. See the `cognee-custom-graph-models` skill. |\n| `custom_prompt` | Replaces the entity-extraction prompt (ignored by GLiNER). |\n| `config={\"ontology_config\": {...}}` | Ground entities in an OWL ontology (below). |\n| `chunk_size`, `chunker` | Max tokens per chunk (default: derived from the embedding and LLM limits) and the chunker class (default `TextChunker`). |\n| `preferred_loaders` | Choose a loader per file type (below). |\n| `self_improvement` | Default `True`: runs `improve()` after the graph is built. Its outcome is on `result.improve` / `result.improve_error`; a failed improve never fails the remember. |\n| `run_in_background=True` | Returns immediately with `status=\"running\"`; `await result` to wait. |\n\n### Ontologies\n\n```python\nfrom cognee.modules.ontology.rdf_xml.RDFLibOntologyResolver import RDFLibOntologyResolver\n\nconfig = {\n    \"ontology_config\": {\n        \"ontology_resolver\": RDFLibOntologyResolver(ontology_file=\"./my.owl\"),\n        # \"ontology_mode\": \"strict\",   # drop entities with no ontology match\n    }\n}\nawait cognee.remember(texts, config=config)\n```\n\nOr set `ONTOLOGY_FILE_PATH` (plus `ONTOLOGY_MODE`, `MATCHING_STRATEGY`) in\n`.env`. `annotate` (default) only enriches; `strict` drops entities that\nmatch no ontology class or individual. It prunes only the graph, chunk text\nis still stored. Strict mode with an empty or missing ontology file is a hard\nerror. Over HTTP, upload the ontology to `/api/v1/ontologies` and pass its\n`ontology_key` to `POST /api/v1/remember`. Example:\n`examples/guides/ontology_quickstart.py`.\n\n### Loaders\n\nEach file is claimed by the first loader that accepts it. Default order:\ncode, text, pypdf, image, audio, video, dlt_csv, csv, unstructured,\nadvanced_pdf, docling. Names: `text_loader`, `code_loader`, `csv_loader`,\n`dlt_csv_loader`, `pypdf_loader`, `image_loader`, `audio_loader`,\n`video_loader`, `unstructured_loader`, `advanced_pdf_loader`,\n`docling_loader`, `beautiful_soup_loader`.\n\n```python\n# Treat a code file as a plain document (chunking + LLM extraction):\nawait cognee.remember(\"./script.py\", preferred_loaders={\"text_loader\": {}})\n```\n\nOffice formats (DOCX, PPTX, …) need the `docs` (unstructured) or `docling`\nextra. A preferred loader that is not installed is skipped with only an info\nlog, so check the extra is installed when a file comes out wrong.\n\n### Check the cost first\n\n`dry_run=True` returns a token and cost estimate without ingesting anything\nor calling the LLM. It excludes the calls `improve()` makes. Not supported\nwith GLiNER, sessions, or a remote instance.\n\n`dry_run=\"presort\"` on a folder returns a `PresortReport` (junk, duplicates,\nversion candidates, possible personal data, proposed dataset groups). Apply\nit with `await cognee.remember(report)`, or pass `auto_apply=True`.\n\n### Without an LLM: GLiNER\n\n`extractor=\"gliner\"` builds the graph and summaries with a local GLiNER2\nmodel, with no LLM call (embeddings still run). Install\n`pip install \"cognee[gliner]\"`; the model (about 750 MB) downloads on first use.\nIt cannot be combined with a custom `graph_model`, `dry_run`, `session_id`,\nor a remote instance.\n\n> **For production:** the open-source GLiNER extractor is a demo. cognee's\n> enterprise GLiNER extraction is more accurate and covers more labels. The\n> same goes for the Postgres graph adapter (`postgres_demo`). Contact\n> social@cognee.ai.\n\n## Pitfalls\n\n- **Unknown keyword arguments raise.** `remember()` forwards kwargs through\n  a fixed allow-list and raises `TypeError: Unexpected keyword arguments`\n  for anything else. These real options are not on it yet:\n\n  | Option | Workaround through remember() |\n  |---|---|\n  | `ontology_file_path` | `config={\"ontology_config\": ...}` or `ONTOLOGY_FILE_PATH` (above) |\n  | `chunk_attachment` | None yet. Only `cognee.cognify()` accepts it. |\n  | `extraction_rules` | Pass it through the loader: `preferred_loaders={\"beautiful_soup_loader\": {\"extraction_rules\": {...}}}` (works in `remember()` and `add()`). Needs the `scraping` extra: without it the loader is not registered and the rules are silently ignored |\n  | `tavily_config`, `soup_crawler_config` | Not honoured by `add()` or `remember()`; only the `cognee/tasks/web_scraper` tasks use them |\n  | `column_value_columns` (dlt) | None yet. Only `cognee.add()` accepts it. |\n\n  If a user needs one with no workaround, say so plainly: the option exists\n  on the lower-level `add()` / `cognify()` but not on `remember()` yet.\n- **Changed files raise `DocumentUpdateRequiredError`.** Re-remembering the\n  same path (or the same filename for an upload) with different content is\n  an update, not a new document. Use\n  `cognee.update(data_id=..., data=..., dataset_id=...)`, which re-extracts\n  only the changed chunks and keeps the document's id. Identical content is\n  a no-op.\n- **`content_type` is strict.** Only `None`, `\"skills\"`, or `\"code\"`.\n  `\"code\"` rejects `session_id` and needs repository paths or git URLs;\n  `\"skills\"` ingests into the target dataset like any other call (default\n  `main_dataset`); pass `dataset_name` to keep skills in their own dataset.\n- **Session mode needs `CACHING=true`**, and `extractor` cannot be combined\n  with `session_id`.\n- **Remote mode.** After `cognee.serve(url)`, calls go to the server:\n  `extractor` and `session_ids` raise, and other options the client does not\n  forward (including `graph_model`, `node_set`, and ontology `config`) are\n  dropped without an error.\n- **Every remember runs `improve()`** unless `self_improvement=False` or\n  `IMPROVE_AUTO_ENABLED=false`. In scripts, call\n  `await cognee.wait_for_background_tasks()` before exiting.\n\n## How it works\n\n`remember(data)` runs `add()` (store raw data and create `Data` rows), then\n`cognify()` (classify documents, chunk, extract the graph and summaries,\nstore in graph and vector DBs), then `improve()`. `remember(data,\nsession_id=...)` writes to the session cache instead.\n\n- Entry point and kwarg routing: `cognee/api/v1/remember/remember.py`\n  (`RememberKwargs`, `_ADD_ONLY` / `_COGNIFY_ONLY` / `_SHARED`)\n- Storage: `cognee/api/v1/add/add.py`, `cognee/tasks/ingestion/ingest_data.py`\n- Graph build: `cognee/api/v1/cognify/cognify.py`,\n  `cognee/tasks/graph/extract_graph_from_data.py`,\n  `cognee/tasks/storage/add_data_points.py`\n- Extractor choice: `cognee/modules/cognify/config.py:resolve_extractor`;\n  GLiNER package: `cognee/tasks/graph/gliner_demo/`\n- Ontologies: `cognee/modules/ontology/`\n- Loaders: `cognee/infrastructure/loaders/` (`supported_loaders.py`,\n  `LoaderEngine.py`)\n- dlt: `cognee/tasks/ingestion/resolve_dlt_sources.py`\n\nExamples in `examples/guides/`: `simple_cognee_example.py`,\n`nodeset_grouping_example.py`, `ontology_quickstart.py`,\n`gliner_demo_llm_free_cognify.py`, `no_llm_remember_recall.py`,\n`temporal_recall.py`, `presort_downloads.py`,\n`web_url_content_ingestion_example.py`, `code_graph_example.py`.\n\n## Extending it\n\n- **New remember() option:** add it to `RememberKwargs` and to the matching\n  routing set in `remember.py`. An option on `add()`/`cognify()` that is not\n  in a routing set raises `TypeError` from `remember()`.\n- **New loader:** implement `LoaderInterface`\n  (`cognee/infrastructure/loaders/LoaderInterface.py`), register it in\n  `supported_loaders.py` (extras-gated loaders go under `external/`), and\n  add it to the priority list in `LoaderEngine.py` if it should run by\n  default.\n- **New cognify task:** see the `cognee-custom-pipelines` skill and\n  `cognee/tasks/README.md`.\n","frontmatter":{"name":"cognee-ingestion","description":"Use when putting data into cognee memory with remember() — choosing inputs (text, files, folders, URLs, repos, databases), datasets and node_sets, loaders, ontologies, the graph extractor (LLM or GLiNER), chunking, dry-run cost estimates, or when remember() raises on a keyword argument."},"isInternal":false,"tokens":2839,"sizeBytes":10664},{"name":"SKILL.md","path":".agents/skills/cognee-install/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-install/SKILL.md","title":"cognee-install","category":"anthropic-skill","format":"markdown","content":"---\nname: cognee-install\ndescription: Use when the user wants to install cognee and run their first remember → recall flow with the Python SDK — fresh setup, virtual env, extras selection, or a minimal working example.\n---\n\n# Install and run cognee\n\n## Install\n\nRequires Python 3.10–3.14. Prefer uv:\n\n```bash\nuv venv && source .venv/bin/activate\nuv pip install cognee            # from PyPI\n# or, working inside this repo:\nuv pip install -e .\n```\n\nAdd extras only when needed — examples: `cognee[postgres]`, `cognee[neo4j]`,\n`cognee[docling]` (office/HTML document parsing, slim), `cognee[docs]`\n(unstructured), `cognee[anthropic]`, `cognee[ollama]`, `cognee[aws]`. The full\nlist is in `pyproject.toml` under `[project.optional-dependencies]`.\n\n## Configure\n\nThe only required setting is an LLM API key. Create `.env` in the working\ndirectory (or export the variable):\n\n```bash\nLLM_API_KEY=\"your_openai_api_key\"\n```\n\nDefaults need no services: SQLite (relational), LanceDB (vector), and Ladybug\n(graph), all stored locally. OpenAI is the default LLM and embedding provider —\nif you configure a different LLM but not embeddings (or vice versa), the other\nsilently stays on OpenAI. For other providers and databases use the\ncognee-integrations skill.\n\n## First run\n\nAs of cognee 1.x the memory API — `remember`, `recall`, `forget`, `improve` —\nis the primary surface. All SDK functions are async. Minimal end-to-end script:\n\n```python\nimport asyncio\nimport cognee\n\n\nasync def main():\n    await cognee.remember(\"Cognee turns documents into AI memory.\")\n    results = await cognee.recall(\"What does cognee do?\")\n    print(results)\n\n\nasyncio.run(main())\n```\n\n`remember()` is the whole ingestion path in one call — it runs `add()` +\n`cognify()`, then `improve()` to index the graph (`self_improvement=True` by\ndefault). It accepts text, file paths, URLs, and binary streams, with an\noptional `dataset_name=\"my_project\"`; pass `datasets=[\"my_project\"]` to\n`recall()` to stay inside one dataset.\n\n`recall()` auto-routes the query to a search strategy by default. Pass\n`query_type=SearchType.CHUNKS` (etc.) to pin one, or `auto_route=False` to\nfall back to `GRAPH_COMPLETION`.\n\nSession memory is the other half of the API — `remember(..., session_id=\"chat_1\")`\nwrites to a fast session cache rather than running add+cognify inline, and\n`recall(..., session_id=\"chat_1\")` reads it back (session hits short-circuit the\ngraph search). With the default `self_improvement=True` it still bridges that\ndata into the permanent graph in the background; `improve(dataset=...,\nsession_ids=[...])` does the same explicitly. Session memory runs on the\nsession cache, which is on by default (`CACHING=true`); setting\n`CACHING=false` disables it entirely and makes `remember(session_id=...)`\nraise.\n\nStart with `examples/advanced_guides/remember_recall_improve_example.py`, which walks\nthrough permanent memory, session memory, and the sync between them.\n\nThe `add()` / `cognify()` / `search()` primitives still exist and\nare what `remember`/`recall`/`improve` call underneath — reach for them when you\nneed to drive a stage in isolation (e.g. custom pipeline tasks), not for\nordinary ingestion. `cognee.delete` is formally deprecated (since 0.3.9);\n`forget()` is the v1 replacement, unifying the old delete/empty_dataset\npaths behind one call. When to use `recall()` versus the low-level `search()`\nis covered in `docs/recall-vs-search.md`.\n\n## Verify / troubleshoot\n\n- `cognee-cli remember \"hello\" && cognee-cli recall \"hello\"` exercises the same\n  flow from the shell.\n- To wipe local state during experiments: `cognee-cli forget --all` (or\n  `await cognee.forget(everything=True)`).\n- Reads slow or spending tokens on every query → set `AUTO_FEEDBACK=false`\n  (keep `CACHING=true`); by default cognee makes one structured-output LLM\n  call per answered query to self-tune its memory.\n- Structured LLM output errors usually mean the model/provider needs an\n  explicit instructor mode: `LLM_INSTRUCTOR_MODE=\"json_schema_mode\"`.\n","frontmatter":{"name":"cognee-install","description":"Use when the user wants to install cognee and run their first remember → recall flow with the Python SDK — fresh setup, virtual env, extras selection, or a minimal working example."},"isInternal":false,"tokens":1038,"sizeBytes":4028},{"name":"SKILL.md","path":".agents/skills/cognee-integrations/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-integrations/SKILL.md","title":"cognee-integrations","category":"anthropic-skill","format":"markdown","content":"---\nname: cognee-integrations\ndescription: Use when the user wants to connect cognee to external services — switching LLM or embedding providers (OpenAI, Azure, Gemini, Anthropic, Ollama, OpenRouter), changing databases (Postgres, PGVector, Neo4j, Neptune, Turso), S3 storage, or the MCP server for IDE integration.\n---\n\n# Set up cognee integrations\n\nAll integration config is environment variables (`.env`). The authoritative,\nalways-current list with commented examples is `.env.template` at the repo\nroot — check it before inventing variable names. Install the matching extra\nbefore switching a backend (e.g. `pip install cognee[postgres]`).\n\n## LLM providers\n\nDefault is OpenAI (`LLM_API_KEY` is all you need). To switch, set\n`LLM_PROVIDER`, `LLM_MODEL`, `LLM_API_KEY`, and (where relevant)\n`LLM_ENDPOINT` / `LLM_API_VERSION`:\n\n- **Azure OpenAI**: `LLM_PROVIDER=azure`, `LLM_MODEL=azure/gpt-4o-mini`, endpoint + api version required.\n- **Gemini** (no extra needed): `LLM_PROVIDER=gemini`, `LLM_MODEL=gemini/gemini-2.0-flash-exp`.\n- **Anthropic** (`cognee[anthropic]`): `LLM_PROVIDER=anthropic`, model e.g. `claude-3-5-sonnet-20241022`.\n- **Ollama, local** (`cognee[ollama]`): `LLM_PROVIDER=ollama`, `LLM_ENDPOINT=http://localhost:11434/v1`, and set the embedding block + `HUGGINGFACE_TOKENIZER` too.\n- **Custom / OpenRouter / vLLM**: `LLM_PROVIDER=custom` with the provider's OpenAI-compatible endpoint.\n- **AWS Bedrock** (`cognee[aws]`): `LLM_PROVIDER=bedrock` + AWS credentials/region.\n\n**The classic trap**: LLM and embeddings are configured independently\n(`EMBEDDING_PROVIDER`, `EMBEDDING_MODEL`, `EMBEDDING_ENDPOINT`,\n`EMBEDDING_API_KEY`). Configuring only one leaves the other on OpenAI —\neither keep a valid OpenAI key or configure both.\n\n## Databases\n\n- **Relational** (`DB_PROVIDER`): sqlite (default) or postgres\n  (`cognee[postgres]`; host/port/user/password/name via `DB_*` vars).\n- **Vector** (`VECTOR_DB_PROVIDER`): lancedb (default), pgvector\n  (`cognee[postgres]`, needs `VECTOR_DB_URL`), neptune_analytics\n  (`cognee[neptune]`), turso (`cognee[turso]`). Anything else (ChromaDB,\n  Qdrant, Weaviate, Milvus, …) lives in community adapters — install from\n  https://github.com/topoteretes/cognee-community and register with\n  `use_vector_adapter` before use; setting `VECTOR_DB_PROVIDER` alone raises\n  \"Unsupported vector database provider\".\n- **Graph** (`GRAPH_DATABASE_PROVIDER`): ladybug (default), neo4j\n  (`cognee[neo4j]`, bolt URL + credentials), neptune (`cognee[neptune]`),\n  ladybug-remote, postgres (no raw Cypher / natural-language search).\n\nThe repo `docker-compose.yml` ships ready-to-use `postgres` (pgvector) and\n`neo4j` profiles with matching default credentials. From a container, reach\nhost services with `DB_HOST=host.docker.internal`.\n\n## Storage, cache, and the rest\n\n- **S3 storage** (`cognee[aws]`): `STORAGE_BACKEND=s3` + bucket/credentials,\n  and point `DATA_ROOT_DIRECTORY`/`SYSTEM_ROOT_DIRECTORY` at `s3://` paths.\n- **Session cache**: `CACHE_BACKEND` = sqlite (default) | postgres | redis | fs | tapes.\n- **Ontologies**: `ONTOLOGY_FILE_PATH` to an OWL file, resolver/matching via\n  `ONTOLOGY_RESOLVER` / `MATCHING_STRATEGY`.\n\n## MCP server (IDE integration)\n\n`docker compose --profile mcp up` starts the MCP server on port 8001\n(Streamable HTTP at `http://localhost:8001/mcp`), built from `cognee-mcp/`. Point Cursor / Claude Desktop /\nClaude Code at it to use cognee memory from the IDE. Configure its `DB_*` env\nto match the main service so both see the same data.\n\n## After changing providers mid-project\n\nEmbeddings from different models are not comparable — after switching the\nembedding provider or model, reset local state (`cognee-cli forget --all` or\n`await cognee.forget(everything=True)`) and re-ingest with `remember()`.\n\nTo drop just the graph and vectors while keeping the ingested files, use\n`await cognee.forget(dataset=\"my_project\", memory_only=True)` — the dataset can\nthen be rebuilt under the new embedding model without re-uploading anything.\n","frontmatter":{"name":"cognee-integrations","description":"Use when the user wants to connect cognee to external services — switching LLM or embedding providers (OpenAI, Azure, Gemini, Anthropic, Ollama, OpenRouter), changing databases (Postgres, PGVector, Neo4j, Neptune, Turso), S3 storage, or the MCP server for IDE integration."},"isInternal":false,"tokens":1099,"sizeBytes":4025},{"name":"SKILL.md","path":".agents/skills/cognee-migrations/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-migrations/SKILL.md","title":"cognee-migrations","category":"anthropic-skill","format":"markdown","content":"---\nname: cognee-migrations\ndescription: Use when dealing with cognee database migrations — understanding when they run automatically, checking or repairing migration state with cognee-cli upgrade/downgrade/stamp/current, a write blocked by a failed migration, authoring a new Alembic (relational schema) revision or a graph/vector data migration, or moving data between systems (relational DB import, memory export/import).\n---\n\n# Database migrations\n\ncognee has **two migration chains**, run together:\n\n| Chain | Changes | Lives in | Revision stored in |\n|---|---|---|---|\n| **Relational schema** (Alembic) | Tables and columns of the relational DB (users, datasets, ACLs, pipeline runs, …) | `cognee/alembic/` (`alembic.ini` is in `cognee/`) | `alembic_version` table |\n| **Graph/vector data** | Cross-store data rewrites (re-keying node ids, adding graph columns) across graph DB, vector DB and relational ledger | `cognee/modules/migrations/` (`registry.py`, `versions/`) | Per dataset: `dataset_database.migration_revision` (access control on). Globally: `global_database_version.global_migration_revision` (access control off) |\n\n## Use it\n\n### They run by themselves\n\n`run_migrations()` applies the relational chain first, then the data chain.\nIt runs:\n\n- at API server startup (and in the Docker `entrypoint.sh` before gunicorn);\n- on the first write in an SDK or CLI process (`remember`, `add`, `cognify`,\n  `improve`, memory imports), once per process;\n- when you call `await cognee.run_migrations()`.\n\nA fresh database is built by running the whole chain (no stamping). At\nhead, the first run in each process still does a no-op Alembic upgrade plus\na scan of the per-database revision rows; later calls in the same process\nare skipped by an in-memory flag. `ENABLE_AUTO_MIGRATIONS=false`\nturns off all automatic runs; then run `cognee-cli upgrade` yourself.\n\nConcurrent processes are serialized by a migration lock: a Postgres advisory\nlock (works across hosts) or a file lock next to the SQLite DB (one host\nonly).\n\n### Check and repair\n\n```bash\ncognee-cli current                   # stamped revision per database, and the last failure\ncognee-cli history                   # the data chain, newest first\ncognee-cli upgrade                   # relational to head, then data chain to head\ncognee-cli upgrade <slug>            # data chain up to and including <slug>\ncognee-cli upgrade --alembic <rev>   # pin the relational target\ncognee-cli downgrade <slug|base> [--dataset UUID ...] [--alembic REV] [--force]\ncognee-cli stamp <head|base|slug> [--dataset UUID ...] [--force]\n```\n\n- The positional revision is always a **data-chain slug**; relational\n  targets go through `--alembic`.\n- `downgrade` rewrites data and asks for confirmation. It only reverts\n  spans where every migration defines a `down()`, and leaves the relational\n  schema alone unless you pass `--alembic`.\n- `stamp` changes only the stored data-chain revision, without running\n  anything. Use `stamp base --dataset <id>` and then `upgrade` when a\n  database's data drifted from its stamp (for example after restoring a\n  backup); the chain is idempotent and converges it.\n- `upgrade` runs even with `ENABLE_AUTO_MIGRATIONS=false`.\n\n### A write is blocked\n\nIf a dataset's data migration failed, writes to that dataset are refused\nuntil it succeeds (with access control off, any failure blocks all writes).\nThe server still starts. Run `cognee-cli current` to see the error, fix the\ncause, then `cognee-cli upgrade`. A failed run is retried on the next start\nor write.\n\n### Moving data between systems (not schema migrations)\n\n| Goal | Use |\n|---|---|\n| Turn an existing relational database into a graph | `migrate_relational_database(graph_db, schema)` (`cognee/tasks/ingestion/migrate_relational_database.py`), with the source DB set by `MIGRATION_DB_PROVIDER` / `_PATH` / `_NAME` / `_HOST` / `_PORT` / `_USERNAME` / `_PASSWORD`. Examples: `examples/demos/ingestion_and_migration/` |\n| Back up a dataset, or move it to another cognee instance | A COGX archive, see below |\n| Export a dataset's graph for other tools | `await cognee.export(dataset, format=...)`: `\"json\"`, `\"graphml\"` or `\"cypher\"` write a file (one way: cognee can't import them back); `\"pydantic\"` (default) returns typed DataPoint objects in memory |\n| Import from another memory system (Mem0, Zep/Graphiti, Letta, LangMem) | Build a `MemorySource` (`cognee/modules/migration/sources/`) and pass it to `await cognee.remember(source, dataset_name=...)` |\n\nThere is no tool that moves a whole deployment from one database backend to\nanother.\n\n#### COGX archives\n\nCOGX (Cognee eXchange, `cognee/modules/migration/cogx.py`) is cognee's\nportable memory format and the only export format cognee can import back.\nAn archive is a directory with a `manifest.json` (COGX version, source\nsystem, the dataset's data-migration revision) and one JSONL file per record\nkind (`documents`, `episodes`, `entities`, `facts`, `memories`,\n`memory_blocks`), plus `nodes.jsonl` with the raw graph nodes. The Mem0,\nZep, Letta and LangMem importers also translate into COGX records first.\n\nUse it to back up and restore a dataset, or to copy one to another cognee\ninstance:\n\n```python\nfrom cognee.migration import COGXArchiveSource\n\nawait cognee.export(\"my_dataset\", format=\"cogx\", destination=\"backup_cogx\")\nawait cognee.remember(COGXArchiveSource(\"backup_cogx\"), dataset_name=\"my_dataset\")\n```\n\n- A restore defaults to `mode=\"preserve\"`: the archived graph is written\n  back as-is, with no LLM calls. `mode=\"hybrid\"` also re-cognifies the raw\n  content; `mode=\"re-derive\"` ignores the archived graph and extracts again\n  (costs LLM tokens).\n- `cognee.push()` / `cognee-cli push` does the same to Cognee Cloud: it\n  exports to COGX, packs it as a `.cogx.tar.gz` and uploads it, and the\n  receiving instance restores it (preserve mode unless you pass `mode=`).\n- `export(..., include_permissions=True)` also writes `permissions.json`\n  with the dataset owner and ACL grants, **including password hashes**, so\n  the restore recreates working accounts. Treat that archive as a secret.\n- An archive written by a newer major COGX version is rejected with a\n  `ValueError`; upgrade cognee on the importing side.\n\n## Pitfalls\n\n- **Never regenerate `cognee/alembic/frozen_schema.py`.** It is the\n  certified base schema the initial revision builds from, pinned by\n  `cognee/tests/unit/test_frozen_schema_seal.py`. Schema changes ship as\n  new revisions at head.\n- **Never hand-type an Alembic revision id.** Hand-typed patterns\n  (`a1b2c3d4e5f6`, …) already collided with a downstream chain that vendors\n  this one (`b2c3d4e5f6a7`). Generate ids with `alembic revision`.\n- **Never rename, remove, or reorder a data-chain entry.** The slug is what\n  deployed databases store; an unknown stored slug disables the chain for\n  that database.\n- **A model change and its migration land together.** CI's \"Migration/Model\n  Lockstep Guard\" fails otherwise.\n- **The relational schema cannot be downgraded below the data-bookkeeping\n  revisions** unless the data chain goes to `base` in the same call.\n- `alembic.ini` is always the packaged one; `COGNEE_ALEMBIC_PATH` or\n  `--alembic-path` only changes the scripts directory (for vendored chains).\n\n## How it works\n\n`run_migrations()` (`cognee/modules/migrations/startup.py`) takes the\nmigration lock, decides fresh vs existing (a `users` or `alembic_version`\ntable exists), runs Alembic in-process on a worker thread, then walks the\ndata chain per database with `runner.run_database_migrations`, stamping\nafter every step. After the chain, it syncs vector-adapter storage when the\nrecorded `cognee_version` differs from the library's\n(`versions/adapter_storage_migration.py`, not a chain entry).\n\n- Relational: `cognee/alembic.ini`, `cognee/alembic/env.py`,\n  `cognee/alembic/versions/`, `cognee/alembic/frozen_schema.py`\n- Data chain: `cognee/modules/migrations/` (`README.md` is the authoring\n  contract; `registry.py`, `migration.py`, `runner.py`, `startup.py`,\n  `versions/`)\n- CLI: `cognee/cli/commands/migrate_command.py`\n\n## Extending it\n\n### A new Alembic revision\n\n```bash\ncd cognee                              # the directory with alembic.ini\nuv run alembic revision -m \"add foo to data\"\n```\n\nThe DB URL comes from the live relational engine, so your normal `.env`\nsettings apply. Follow the recent revisions (for example\n`versions/e7f9a1c3d5b8_add_data_dataset_created_index.py`):\n\n- **Idempotent and guarded:** inspect first (`sa.inspect(op.get_bind())`)\n  and skip when the table is missing or the column/index already exists.\n- **Branch on dialect** (`conn.dialect.name == \"postgresql\"`) for\n  Postgres-only SQL. For Postgres enums use `postgresql.ENUM(...,\n  create_type=False)` and create the type up front with `checkfirst`.\n- **SQLite cannot drop or alter columns in place:** use\n  `op.batch_alter_table(...)`.\n- **Indexes:** plain `CREATE INDEX IF NOT EXISTS` inside the migration\n  transaction, not `CONCURRENTLY` (which releases the version-row lock and\n  lets concurrent workers into the same build). Repair invalid Postgres\n  indexes via `pg_index.indisvalid`.\n- A new model module outside the usual import path must be imported in\n  `cognee/alembic/env.py`, or autogenerate will not see it.\n\n### A new data migration\n\nRead `cognee/modules/migrations/README.md` first. In short:\n\n1. Write a module in `cognee/modules/migrations/versions/` with\n   `async def migrate(context)` (and optionally `async def downgrade(context)`);\n   step 2 registers them as `up=` / `down=`.\n2. Append `Migration(slug=..., cognee_version=..., up=..., down_revision=<previous slug>, down=...)`\n   to `MIGRATIONS` in `registry.py`. The chain is validated at import\n   (linear, unique slugs).\n3. Make it idempotent and cheap on empty stores, and crash-safe: re-key\n   derived stores (vectors, ledger) first and rename in the graph last.\n4. Freeze private copies of any logic you depend on; never import live\n   models that may change later.\n\n### Tests\n\n- `cognee/tests/e2e/migrations/test_migration_model_lockstep.py` (+\n  `schema_baseline.json`): the lockstep CI job.\n- `cognee/tests/unit/test_run_migrations.py`: single Alembic head, startup\n  behaviour.\n- `cognee/tests/unit/test_frozen_schema_seal.py`: frozen schema fingerprint.\n- `cognee/tests/unit/modules/migrations/`: data-chain unit tests.\n- `cognee/tests/migrations/test_migration_lockstep.py`: data chain against\n  real stores (seed, down, up, verify).\n","frontmatter":{"name":"cognee-migrations","description":"Use when dealing with cognee database migrations — understanding when they run automatically, checking or repairing migration state with cognee-cli upgrade/downgrade/stamp/current, a write blocked by a failed migration, authoring a new Alembic (relational schema) revision or a graph/vector data migration, or moving data between systems (relational DB import, memory export/import)."},"isInternal":false,"tokens":2677,"sizeBytes":10480},{"name":"SKILL.md","path":".agents/skills/cognee-performance/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-performance/SKILL.md","title":"cognee-performance","category":"anthropic-skill","format":"markdown","content":"# cognee-performance\n\nPath: `.agents/skills/cognee-performance/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-performance/SKILL.md)","tokens":300,"sizeBytes":204},{"name":"SKILL.md","path":".agents/skills/cognee-permissions/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-permissions/SKILL.md","title":"cognee-permissions","category":"anthropic-skill","format":"markdown","content":"# cognee-permissions\n\nPath: `.agents/skills/cognee-permissions/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-permissions/SKILL.md)","tokens":300,"sizeBytes":204},{"name":"SKILL.md","path":".agents/skills/cognee-recall/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-recall/SKILL.md","title":"cognee-recall","category":"anthropic-skill","format":"markdown","content":"# cognee-recall\n\nPath: `.agents/skills/cognee-recall/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-recall/SKILL.md)","tokens":300,"sizeBytes":189},{"name":"SKILL.md","path":".agents/skills/cognee-server/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-server/SKILL.md","title":"cognee-server","category":"anthropic-skill","format":"markdown","content":"# cognee-server\n\nPath: `.agents/skills/cognee-server/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-server/SKILL.md)","tokens":300,"sizeBytes":189},{"name":"SKILL.md","path":".agents/skills/company-brain-company-qa/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/company-brain-company-qa/SKILL.md","title":"company-brain-company-qa","category":"anthropic-skill","format":"markdown","content":"# company-brain-company-qa\n\nPath: `.agents/skills/company-brain-company-qa/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/company-brain-company-qa/SKILL.md)","tokens":300,"sizeBytes":222},{"name":"SKILL.md","path":".agents/skills/company-brain-follow-up-agent/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/company-brain-follow-up-agent/SKILL.md","title":"company-brain-follow-up-agent","category":"anthropic-skill","format":"markdown","content":"# company-brain-follow-up-agent\n\nPath: `.agents/skills/company-brain-follow-up-agent/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/company-brain-follow-up-agent/SKILL.md)","tokens":300,"sizeBytes":237},{"name":"SKILL.md","path":".agents/skills/personalized-email/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/personalized-email/SKILL.md","title":"personalized-email","category":"anthropic-skill","format":"markdown","content":"# personalized-email\n\nPath: `.agents/skills/personalized-email/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/personalized-email/SKILL.md)","tokens":300,"sizeBytes":204},{"name":"SKILL.md","path":".agents/skills/self-hosted-companion/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/self-hosted-companion/SKILL.md","title":"self-hosted-companion","category":"anthropic-skill","format":"markdown","content":"# self-hosted-companion\n\nPath: `.agents/skills/self-hosted-companion/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/self-hosted-companion/SKILL.md)","tokens":300,"sizeBytes":213},{"name":"qdrant.yaml","path":"catalog/entries/packages/qdrant.yaml","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/catalog/entries/packages/qdrant.yaml","title":"Packages Skill","category":"anthropic-skill","format":"yaml","content":"# Packages Skill\n\nPath: `catalog/entries/packages/qdrant.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/catalog/entries/packages/qdrant.yaml)","tokens":300,"sizeBytes":188},{"name":"weaviate.yaml","path":"catalog/entries/packages/weaviate.yaml","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/catalog/entries/packages/weaviate.yaml","title":"Packages Skill","category":"anthropic-skill","format":"yaml","content":"# Packages Skill\n\nPath: `catalog/entries/packages/weaviate.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/catalog/entries/packages/weaviate.yaml)","tokens":300,"sizeBytes":192},{"name":"skill.md","path":"cognee/skill.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/cognee/skill.md","title":"cognee","category":"anthropic-skill","format":"markdown","content":"---\nname: cognee\ndescription: >\n  Use this skill whenever the user asks about Cognee, AI memory, persistent agent memory,\n  self-improving agents, agents learning from feedback, knowledge graphs, graph-based RAG,\n  long-term memory for agents, short-term memory for agents, personalization, personas,\n  temporal search, temporal knowledge graphs, ontology-based extraction, ontology grounding,\n  feedback, Cypher search, natural-language graph search, chunk search, RAG search, cross-session memory,\n  session feedback, feedback loops, session based memory, redis based memory, knowledge promotion.\n  Also use when the user describes the workflow such as:\n  \"turn documents into a knowledge graph\", \"build memory from files\", \"search my graph\",\n  \"extract entities and relations\", \"sync data into a graph\", \"update graph memory\",\n  \"store memories for an agent\", \"help my agent learn over time\", \"visualize a knowledge\n  graph built from documents\", \"let the agent learn\", \"adaptive agents\", \"personalized agents\",\n  \"session based personalization\", \"find important ontologies\", \"find custom pydantic models\",\n  \"isolate agentic behaviour\", \"add permission control to retrieval\", \"reduce context bloating\".\n---\n\n# Cognee\n\nUse this skill for **Cognee-specific Python API help** and for mapping user goals to the right\nCognee workflow.\n\n## When to apply this skill\n\nApply this skill whenever the user wants to do any of the following with Cognee:\n\n- ingest text, files, URLs, repos, or datasets\n- build or rebuild a knowledge graph\n- search documents, chunks, summaries, triplets, or graph context\n- choose a `SearchType`\n- enrich an existing graph with `improve`\n- define custom graph extraction models or `DataPoint` types\n- run custom task pipelines\n- configure LLM, graph DB, vector DB, or storage settings\n- tag and scope memory with `node_set` / NodeSets\n- build persistent memory for agents across sessions\n- create feedback loops or self-improving agent workflows\n- work with temporal extraction, ontologies, Cypher, or natural-language graph queries\n- manage datasets, sessions, feedback, deletion, updates, or visualization\n\nIf the user's intent is \"store information in memory and query it later\", prefer Cognee's\nmemory API: **remember -> recall** (plus **improve** to enrich and **forget** to delete).\n\n## Core workflow\n\n```python\nimport cognee\n\n# Store: ingest + build the graph (+ improve, because self_improvement=True by default)\nawait cognee.remember(\n    \"Your text, file path, URL, or list of inputs\",\n    dataset_name=\"main\",\n)\n\n# Query: recall picks a search strategy automatically (rule-based, no LLM call)\nresults = await cognee.recall(\"What are the key insights?\", datasets=[\"main\"])\nfor r in results:\n    print(r.source, r)  # each result is tagged \"graph\" / \"session\" / ...\n```\n\n`remember()` runs `add()` + `cognify()` and then `improve()` underneath. `recall()` wraps\n`search()` and adds routing, session memory as a source, and `source`-tagged results.\n\n## Default guidance\n\nWhen helping with Cognee:\n\n1. Start with the **simplest working path** unless the user explicitly asks for advanced\n   configuration.\n2. Prefer the memory API:\n   - `remember(...)` to store (ingest + graph build)\n   - `recall(...)` to query\n   - `improve(...)` to enrich or index an existing graph, and to bridge sessions into it\n   - `forget(...)` to delete\n3. Treat Cognee APIs as **async**.\n4. Use `dataset_name` / `datasets` to keep work organized when the user has multiple sources.\n5. Use `node_set` when the user wants lightweight tagging, project scoping, per-user memory\n   buckets, or subgraph filtering.\n6. Pass `query_type=SearchType.X` to `recall()` only when the user needs a specific strategy;\n   otherwise let it route.\n7. Recommend advanced features only when they match the task:\n   - `session_id` for fast short-term memory and conversation continuity\n   - `graph_model=` for schema-shaped extraction, `DataPoint` types for direct insertion\n   - `extractor=\"gliner_demo\"` for LLM-free graph extraction\n   - custom pipelines for non-default task orchestration\n   - feedback loops for retrieval improvement\n   - visualization tools for graph inspection\n\n## When to drop to the low-level operations\n\n`add()`, `cognify()` and `search()` still ship; the memory API calls them. Reach for\nthem only when `remember`/`recall` cannot express the job:\n\n- `cognify(datasets=[\"a\", \"b\"])` or `datasets=None` processes several datasets at once;\n  `remember()` always targets exactly one dataset.\n- Rebuilding a graph over data already in the DB (after `forget(memory_only=True)`, or with a\n  new `graph_model` / ontology) is `cognify()` only; `remember()` always runs `add()` first.\n- `search()` takes the agentic extras as first-class parameters (`skills`, `tools`, `max_iter`,\n  `code_query`, `node_type`) and returns raw `SearchResult` objects instead of tagged dicts.\n- `add()` is a staging area: use it to ingest now and `cognify()` later.\n- `prune.prune_system(metadata=True)` also drops the relational DB (users, ACLs, dataset\n  registry); `forget()` never touches those. Use prune only for full test teardown.\n\n`cognee.delete()` is deprecated in favour of `forget()`. Full comparison of the two query\nfunctions: `docs/recall-vs-search.md`.\n\n## Common tasks\n\n### Store data\n\n`remember()` accepts text, file paths, URLs, directories, git repository URLs, binary streams,\nor lists of these.\n\n```python\nawait cognee.remember(\"notes.md\", dataset_name=\"research\")\nawait cognee.remember(\"https://example.com\", dataset_name=\"research\")\nawait cognee.remember([\"paper.pdf\", \"summary.txt\"], dataset_name=\"research\")\n```\n\nUse `node_set` when the user wants data grouped into logical memory buckets.\n\n```python\nawait cognee.remember(\n    \"Customer prefers concise weekly summaries and Slack delivery.\",\n    dataset_name=\"customer_success\",\n    node_set=[\"preferences\", \"customer_123\", \"weekly_reports\"],\n)\n```\n\nUseful options:\n\n```python\nawait cognee.remember(\n    \"...\",\n    dataset_name=\"research\",\n    self_improvement=False,  # skip the improve() stage (faster)\n    run_in_background=True,  # return immediately; poll the pipeline status\n    chunk_size=1024,\n    custom_prompt=\"Extract companies, products, and partnerships.\",\n    extractor=\"gliner_demo\",  # LLM-free extraction; needs cognee[gliner]\n    dry_run=True,  # estimate LLM tokens/cost without ingesting\n)\nawait cognee.remember(\"./my_repo\", dataset_name=\"code\")  # code graph, no LLM\nawait cognee.remember(\"./skills\", dataset_name=\"ops\", content_type=\"skills\")  # SKILL.md playbooks\n```\n\n### Query memory\n\n```python\nfrom cognee import SearchType\n\nresults = await cognee.recall(\"What changed in Q1 2024?\", datasets=[\"research\"], top_k=10)\n\n# Pin a strategy when the user needs one\nresults = await cognee.recall(\n    \"What changed in Q1 2024?\",\n    query_type=SearchType.TEMPORAL,\n    datasets=[\"research\"],\n)\n\n# Answers with evidence, or validated into a Pydantic model\nresults = await cognee.recall(\"...\", include_references=True)\nresults = await cognee.recall(\"...\", response_model=MyAnswerModel)\n\n# Retrieval context only, no LLM completion (pin query_type here)\ncontext = await cognee.recall(\"...\", query_type=SearchType.GRAPH_COMPLETION, only_context=True)\n```\n\n### Scope retrieval with NodeSets\n\nUse NodeSets when the user wants to search only a subset of memory such as one project, one\ncustomer, one user, or one workflow.\n\n```python\nresults = await cognee.recall(\n    \"What are this customer's reporting preferences?\",\n    datasets=[\"customer_success\"],\n    node_name=[\"preferences\", \"customer_123\"],\n)\n```\n\n### Enrich an existing graph\n\nUse `improve()` when the user wants to improve or extend an already-built graph without\nre-ingesting. Without `session_ids` it runs only the graph-wide stages (opt-in conflict review\nand global context indexing); with them it also applies feedback weights, persists session Q&A,\nand distills session lessons into the graph.\n\n```python\nawait cognee.improve(dataset=\"research\")\nawait cognee.improve(dataset=\"research\", session_ids=[\"chat_1\"])\nawait cognee.improve(dataset=\"research\", build_global_context_index=True)\n```\n\n### Delete data\n\n`forget()` is the single deletion entry point.\n\n```python\nawait cognee.forget(data_id=data_id, dataset_id=dataset_id)  # one document\nawait cognee.forget(dataset=\"research\")  # a dataset: raw data + graph + vectors\nawait cognee.forget(dataset=\"research\", memory_only=True)  # graph + vectors only, keep raw files\nawait cognee.forget(everything=True)  # everything the current user owns\n```\n\n### Update a document in place\n\n```python\nawait cognee.update(data_id=data_id, data=\"Updated content\", dataset_id=dataset_id)\n```\n\nThe document keeps its `data_id`; only the chunks the edit touched are re-extracted.\n\n### Create domain-specific structures\n\nPass a `DataPoint`-derived Pydantic model as `graph_model` and the LLM fills it instead of the\ngeneric knowledge graph:\n\n```python\nfrom cognee.infrastructure.engine import DataPoint\n\n\nclass Person(DataPoint):\n    name: str\n    role: str\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nclass Company(DataPoint):\n    name: str\n    employs: list[Person] = []  # a DataPoint field becomes an edge named after the field\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nawait cognee.remember(\"...\", dataset_name=\"org\", graph_model=Company)\n```\n\nInsert structured Python objects directly, bypassing text extraction:\n\n```python\nfrom cognee.tasks.storage import add_data_points\n\nawait add_data_points([Person(name=\"Ada\", role=\"Engineer\")])\n```\n\nSee `examples/guides/custom_graph_model.py` and `examples/guides/custom_data_models.py`.\n\n### Run custom pipelines\n\nUse `run_custom_pipeline(...)` when the user needs explicit sequential task control.\n\n```python\nfrom cognee.modules.pipelines.tasks.task import Task\n\n\nasync def my_task(data):\n    return data\n\n\nawait cognee.run_custom_pipeline(\n    tasks=[Task(my_task)],\n    data=\"input\",\n    dataset=\"research\",\n)\n```\n\n## DataPoints\n\nA `DataPoint` is the **atomic unit of knowledge** in Cognee.\n\nUse this concept whenever the user asks how Cognee represents structured data internally or how\nto insert graph objects directly.\n\nKey ideas:\n\n- A `DataPoint` is a Pydantic model that represents one meaningful unit of information.\n- When inserted, DataPoints become graph nodes; fields holding other DataPoints become edges.\n- `metadata = {\"index_fields\": [...]}` controls which fields are embedded for semantic search.\n- `metadata = {\"identity_fields\": [...]}` makes the node id deterministic so repeated inserts\n  merge instead of duplicating.\n\nUse `DataPoint` when the user wants:\n\n- schema-shaped memory\n- exact control over graph structure\n- programmatic relationship creation\n- custom domain entities such as papers, customers, incidents, policies, products, or workflows\n\nPrefer plain `remember(...)` for unstructured documents. Prefer `graph_model=` when the text\nshould be extracted into a schema. Prefer `DataPoint` models plus `add_data_points(...)` when the\nuser already has structured Python objects.\n\n## NodeSets\n\nUse NodeSets when the user wants a lightweight way to **tag, group, and scope memory**.\n\nA NodeSet starts as a list of tags passed through `node_set=[...]` to `remember(...)`; after the\ngraph is built those tags are first-class graph nodes, and `recall(node_name=[...])` restricts\nretrieval to them.\n\n### Good NodeSet patterns\n\n- per customer: `[\"customer_123\"]`\n- per workflow: `[\"support_bot\", \"refund_flow\"]`\n- per topic: `[\"contracts\", \"vendor_risk\"]`\n- per environment: `[\"prod\", \"staging\"]`\n- per user memory: `[\"user_42\", \"preferences\"]`\n\n### Example\n\n```python\nawait cognee.remember(\n    [\n        \"Alice prefers terse answers and email follow-ups.\",\n        \"Alice escalates billing issues to finance first.\",\n        \"Bob prefers detailed technical explanations.\",\n    ],\n    dataset_name=\"agent_memory\",\n    node_set=[\"crm\", \"user_profiles\"],\n)\n\nresults = await cognee.recall(\n    \"How should I respond to Alice?\",\n    datasets=[\"agent_memory\"],\n    node_name=[\"crm\", \"user_profiles\"],\n)\n```\n\nUse NodeSets by default whenever the user says things like:\n\n- \"scope memory by customer\"\n- \"separate projects without making separate databases\"\n- \"let the agent search only its own memories\"\n- \"group facts by workflow or team\"\n\n## SearchType selection guide\n\n`recall()` routes automatically when `query_type` is omitted. When the user needs a specific\nstrategy, pick from `cognee.SearchType` (all 20 values):\n\nCompletion types (an LLM writes the answer):\n\n- `HYBRID_COMPLETION`: document passages plus entity neighbourhoods; the default when routing is off\n- `GRAPH_COMPLETION`: graph traversal + completion; the best general graph-aware Q&A\n- `GRAPH_COMPLETION_COT`: deeper chain-of-thought reasoning over graph context\n- `GRAPH_COMPLETION_CONTEXT_EXTENSION`: broader graph context retrieval\n- `GRAPH_COMPLETION_DECOMPOSITION`: splits the question into sub-queries first\n- `GRAPH_SUMMARY_COMPLETION`: graph context + pre-computed summaries\n- `RAG_COMPLETION`: traditional RAG over document chunks\n- `TEMPORAL`: time-aware graph search\n- `AGENTIC_COMPLETION`: multi-step loop that can load `skills` and call `tools`\n\nRetrieval-only types (no LLM call):\n\n- `CHUNKS`: semantic retrieval over chunks\n- `CHUNKS_LEXICAL`: exact-term / keyword (BM25) matching\n- `SUMMARIES`: pre-computed document summaries\n- `SKILLS`: discover SKILL.md playbooks (metadata only; exactly one dataset)\n- `CODE`: deterministic code-graph operations via `code_query` (callers, paths, impact analysis)\n\nOther:\n\n- `CYPHER`: raw Cypher, off by default (`ALLOW_CYPHER_QUERY=true` enables it; not on the Postgres demo graph)\n- `NATURAL_LANGUAGE`: natural language to graph query, off by default (same `ALLOW_CYPHER_QUERY=true` flag)\n- `CODING_RULES`: retrieve stored coding rules\n- `GRAPH_REPORT`: graph insight report (hubs, cross-source links, suggested questions)\n- `FEELING_LUCKY`: let Cognee choose\n\nThe CLI exposes 10 of these (`cognee-cli recall --query-type`); the rest are SDK-only.\n\n## Sessions, feedback, and self-improvement\n\nCognee has two memory tiers:\n\n- **Permanent memory**: `remember(...)` without `session_id` — the knowledge graph.\n- **Session memory**: `remember(..., session_id=...)` — a fast session cache written without an\n  LLM call. `recall(..., session_id=...)` searches it first and falls through to the graph.\n  Requires `CACHING=true` (the default).\n\n```python\n# Short-term: store a turn in the session cache, recall it instantly\nawait cognee.remember(\"User wants weekly summaries on Fridays.\", session_id=\"chat_1\")\nresults = await cognee.recall(\"when does the user want summaries?\", session_id=\"chat_1\")\n\n# Long-term: bridge the session into the permanent graph\nawait cognee.improve(dataset=\"main_dataset\", session_ids=[\"chat_1\"])\n```\n\n`remember(..., session_id=...)` with `self_improvement=True` (default) bridges into the graph\nin the background, so the explicit `improve()` call is only needed for control over timing.\n\n### Feedback\n\nFeedback is attached to a session Q&A entry and later folded into retrieval weights by\n`improve()`:\n\n```python\nfrom cognee import FeedbackEntry\n\n# Rate an earlier answer (qa_id is the entry_id returned by the remember() that stored it)\nawait cognee.remember(\n    FeedbackEntry(qa_id=qa_id, feedback_score=5, feedback_text=\"Captured the key themes.\"),\n    session_id=\"chat_1\",\n)\n# Equivalent helper API\nawait cognee.session.add_feedback(session_id=\"chat_1\", qa_id=qa_id, feedback_score=5)\nhistory = await cognee.session.get_session(session_id=\"chat_1\")\n```\n\nWith `AUTO_FEEDBACK=true` (default) every answered turn is also analysed for implicit feedback\nby one structured-output LLM call. Set `AUTO_FEEDBACK=false` for low-latency reads.\n\n### Wrap an agent\n\n`@cognee.agent_memory` records an agent function's calls as session traces and recalls context\nbefore each call. See `examples/guides/agent_memory_quickstart.py`.\n\n## Agentic workflows and feedback-driven improvement\n\nUse Cognee as the **memory layer for agent systems** that need to improve over time through\nbetter recall, better reuse of prior work, and better retrieval of successful past behavior.\n\nThe key idea is simple:\n\n- keep the **agent workflow itself constant**\n- keep the **prompt and tools constant**\n- change only what the agent can remember and retrieve\n\n\"Improvement\" comes from **memory reuse and retrieval quality**, not from changing the model.\n\n### General agent loop\n\n1. **Observe** — capture inputs, events, preferences, outcomes, errors, decisions.\n2. **Store** — `remember(...)` them, with `session_id` for the active run and without it for\n   durable facts.\n3. **Organize** — use datasets and NodeSets to separate memory by customer, workflow, team,\n   agent, or topic.\n4. **Recall before acting** — `recall(...)` before planning, tool use, synthesis, or response\n   generation.\n5. **Capture feedback** — `FeedbackEntry` / `session.add_feedback` for what worked and what\n   did not.\n6. **Consolidate** — `improve(dataset, session_ids=[...])` so session history and lessons become\n   long-term graph memory.\n7. **Reuse** — future runs benefit from richer context and more informed retrieval.\n\n### Minimal example pattern\n\n```python\nimport cognee\n\n# 1) Store a durable observation\nawait cognee.remember(\n    \"Customer 123 prefers concise status updates and Slack notifications.\",\n    dataset_name=\"agent_memory\",\n    node_set=[\"customer_123\", \"preferences\", \"support_agent\"],\n)\n\n# 2) Recall before acting, inside a session\ncontext = await cognee.recall(\n    \"What should I know before replying to customer 123?\",\n    datasets=[\"agent_memory\"],\n    session_id=\"support-session-123\",\n)\n\n# 3) Continue work in the same session\nanswer = await cognee.recall(\n    \"Draft the best reply for customer 123.\",\n    datasets=[\"agent_memory\"],\n    session_id=\"support-session-123\",\n)\n\n# 4) Consolidate the session into long-term memory later\nawait cognee.improve(dataset=\"agent_memory\", session_ids=[\"support-session-123\"])\n```\n\n### Best default explanation\n\nIf the user asks how Cognee helps agents improve over time:\n\n**Cognee lets agents improve by remembering more useful things, organizing them into searchable\ngraph memory, and reusing successful past work in future runs.**\n\n## Configuration help\n\nUse Cognee config helpers or environment variables when the user needs provider or backend setup.\n\n```python\ncognee.config.set_llm_provider(\"openai\")\ncognee.config.set_llm_model(\"gpt-5-mini\")\ncognee.config.set_llm_api_key(\"sk-...\")\n```\n\nEnvironment variables (`.env`): `LLM_API_KEY`, `LLM_MODEL`, `LLM_PROVIDER`, `EMBEDDING_*`,\n`GRAPH_DATABASE_PROVIDER` (ladybug default, neo4j, neptune, postgres_demo), `VECTOR_DB_PROVIDER`\n(lancedb default, pgvector, turso), `DB_PROVIDER` (sqlite default, postgres), `CACHE_BACKEND`.\nIf only the LLM or only embeddings are configured, the other defaults to OpenAI.\n\n## Dataset and lifecycle operations\n\n```python\ndatasets = await cognee.datasets.list_datasets()\ndata = await cognee.datasets.list_data(dataset_id)\nawait cognee.forget(dataset=\"research\")  # preferred over datasets.empty_dataset / delete_all\n```\n\n## Visualization\n\n`visualize_graph` renders a **bounded subgraph** by default (seed nodes + a k-hop neighborhood,\ncapped at `max_nodes`) instead of the whole graph.\n\n```python\n# Default: bounded subgraph. Seed by a query, explicit ids, or a recall result;\n# with none of those, the highest-degree nodes seed a representative view.\nawait cognee.visualize_graph(\"/path/to/output.html\")\nawait cognee.visualize_graph(\"/path/to/output.html\", query=\"What relates to Python?\")\nawait cognee.visualize_graph(\"/path/to/output.html\", seed_node_ids=[\"node-id-1\"])\nawait cognee.visualize_graph(\"/path/to/output.html\", recall_result=recall_output)\n\n# Legacy whole-graph render.\nawait cognee.visualize_graph(\"/path/to/output.html\", full=True)\n\nawait cognee.start_visualization_server(port=8080)\nawait cognee.start_ui()\n```\n\nCaps: `neighborhood_depth=2`, `neighborhood_seed_top_k=10`, `max_nodes=500`.\nSee `examples/guides/graph_visualization.py`.\n\n## Full reset (tests only)\n\n`forget(everything=True)` removes the user's data and memory. To also drop users, ACLs and the\ndataset registry — full test teardown — use prune:\n\n```python\nawait cognee.prune.prune_data()\nawait cognee.prune.prune_system(graph=True, vector=True, metadata=True, cache=True)\n```\n\n## Important behavior notes\n\n- Cognee APIs are **async**.\n- Prefer **remember -> recall** (+ `improve`, `forget`) unless the user needs one low-level stage.\n- Use `node_set` early when the user may later need scoped retrieval.\n- Use `session_id` for short-term memory and conversation continuity; `improve(session_ids=...)`\n  to make it permanent.\n- Use `graph_model=` or `DataPoint` types only when the user needs schema-shaped extraction.\n- Use `CYPHER` only when Cypher querying is enabled in config.\n- Keep examples minimal and runnable.\n\n## Do not overcomplicate\n\nDo not jump straight to advanced backends, ontology configuration, or custom pipelines unless the\nuser asks for them or the problem clearly requires them. Prefer the smallest correct Cognee\nsolution first, then extend it.\n","frontmatter":{"name":"cognee","description":"Use this skill whenever the user asks about Cognee, AI memory, persistent agent memory, self-improving agents, agents learning from feedback, knowledge graphs, graph-based RAG, long-term memory for agents, short-term memory for agents, personalization, personas, temporal search, temporal knowledge graphs, ontology-based extraction, ontology grounding, feedback, Cypher search, natural-language graph search, chunk search, RAG search, cross-session memory, session feedback, feedback loops, session based memory, redis based memory, knowledge promotion. Also use when the user describes the workflow such as: \"turn documents into a knowledge graph\", \"build memory from files\", \"search my graph\", \"extract entities and relations\", \"sync data into a graph\", \"update graph memory\", \"store memories for an agent\", \"help my agent learn over time\", \"visualize a knowledge graph built from documents\", \"let the agent learn\", \"adaptive agents\", \"personalized agents\", \"session based personalization\", \"find important ontologies\", \"find custom pydantic models\", \"isolate agentic behaviour\", \"add permission control to retrieval\", \"reduce context bloating\".\n"},"isInternal":false,"tokens":5025,"sizeBytes":21235},{"name":"aggregate_metrics_v_deepeval.json","path":"evals/old/cognee_01042025/aggregate_metrics_v_deepeval.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/aggregate_metrics_v_deepeval.json","title":"Cognee_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/aggregate_metrics_v_deepeval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/aggregate_metrics_v_deepeval.json)","tokens":300,"sizeBytes":241},{"name":"aggregate_metrics_v_direct_llm.json","path":"evals/old/cognee_01042025/aggregate_metrics_v_direct_llm.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/aggregate_metrics_v_direct_llm.json","title":"Cognee_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/aggregate_metrics_v_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/aggregate_metrics_v_direct_llm.json)","tokens":300,"sizeBytes":245},{"name":"metrics_output_cognee_direct_llm.json","path":"evals/old/cognee_01042025/metrics_output_cognee_direct_llm.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/metrics_output_cognee_direct_llm.json","title":"Cognee_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/metrics_output_cognee_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/metrics_output_cognee_direct_llm.json)","tokens":300,"sizeBytes":249},{"name":"metrics_output_cognee_human_eval.json","path":"evals/old/cognee_01042025/metrics_output_cognee_human_eval.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/metrics_output_cognee_human_eval.json","title":"Cognee_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/metrics_output_cognee_human_eval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/metrics_output_cognee_human_eval.json)","tokens":300,"sizeBytes":249},{"name":"metrics_output_cognee.json","path":"evals/old/cognee_01042025/metrics_output_cognee.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/metrics_output_cognee.json","title":"Cognee_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/metrics_output_cognee.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/metrics_output_cognee.json)","tokens":300,"sizeBytes":227},{"name":"aggregate_metrics_4o_cognee_10_short_deepeval.json","path":"evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short_deepeval.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short_deepeval.json","title":"Cognee_optimized_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short_deepeval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short_deepeval.json)","tokens":300,"sizeBytes":305},{"name":"aggregate_metrics_4o_cognee_10_short.json","path":"evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short.json","title":"Cognee_optimized_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short.json)","tokens":300,"sizeBytes":287},{"name":"aggregate_metrics_4o_cognee_10.json","path":"evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10.json","title":"Cognee_optimized_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10.json)","tokens":300,"sizeBytes":275},{"name":"metrics_output_cognee_4o_10_short.json","path":"evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10_short.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10_short.json","title":"Cognee_optimized_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10_short.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10_short.json)","tokens":300,"sizeBytes":281},{"name":"metrics_output_cognee_4o_10.json","path":"evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10.json","title":"Cognee_optimized_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/metrics_output_cognee_4o_10.json)","tokens":300,"sizeBytes":269},{"name":"hotpot_50_corpus.json","path":"evals/old/comparative_eval/hotpot_50_corpus.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/comparative_eval/hotpot_50_corpus.json","title":"Comparative_eval Skill","category":"anthropic-skill","format":"json","content":"# Comparative_eval Skill\n\nPath: `evals/old/comparative_eval/hotpot_50_corpus.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/comparative_eval/hotpot_50_corpus.json)","tokens":300,"sizeBytes":220},{"name":"hotpot_50_qa_pairs.json","path":"evals/old/comparative_eval/hotpot_50_qa_pairs.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/comparative_eval/hotpot_50_qa_pairs.json","title":"Comparative_eval Skill","category":"anthropic-skill","format":"json","content":"# Comparative_eval Skill\n\nPath: `evals/old/comparative_eval/hotpot_50_qa_pairs.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/comparative_eval/hotpot_50_qa_pairs.json)","tokens":300,"sizeBytes":224},{"name":"README.md","path":"evals/old/comparative_eval/README.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/comparative_eval/README.md","title":"Comparative_eval Skill","category":"anthropic-skill","format":"markdown","content":"# Comparative_eval Skill\n\nPath: `evals/old/comparative_eval/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/comparative_eval/README.md)","tokens":300,"sizeBytes":196},{"name":"aggregate_metrics_falkor_graphrag_sdk_direct_llm.json","path":"evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk_direct_llm.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk_direct_llm.json","title":"Falkor_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Falkor_01042025 Skill\n\nPath: `evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk_direct_llm.json)","tokens":300,"sizeBytes":281},{"name":"aggregate_metrics_falkor_graphrag_sdk.json","path":"evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk.json","title":"Falkor_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Falkor_01042025 Skill\n\nPath: `evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/aggregate_metrics_falkor_graphrag_sdk.json)","tokens":300,"sizeBytes":259},{"name":"metrics_output_falkor_graph_sdk_human_eval.json","path":"evals/old/falkor_01042025/metrics_output_falkor_graph_sdk_human_eval.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/metrics_output_falkor_graph_sdk_human_eval.json","title":"Falkor_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Falkor_01042025 Skill\n\nPath: `evals/old/falkor_01042025/metrics_output_falkor_graph_sdk_human_eval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/metrics_output_falkor_graph_sdk_human_eval.json)","tokens":300,"sizeBytes":269},{"name":"metrics_output_falkor_graphrag_sdk_direct_llm.json","path":"evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk_direct_llm.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk_direct_llm.json","title":"Falkor_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Falkor_01042025 Skill\n\nPath: `evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk_direct_llm.json)","tokens":300,"sizeBytes":275},{"name":"metrics_output_falkor_graphrag_sdk.json","path":"evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk.json","title":"Falkor_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Falkor_01042025 Skill\n\nPath: `evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/falkor_01042025/metrics_output_falkor_graphrag_sdk.json)","tokens":300,"sizeBytes":253},{"name":"aggregate_metrics_graphiti_direct_llm.json","path":"evals/old/graphiti_01042025/aggregate_metrics_graphiti_direct_llm.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/aggregate_metrics_graphiti_direct_llm.json","title":"Graphiti_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Graphiti_01042025 Skill\n\nPath: `evals/old/graphiti_01042025/aggregate_metrics_graphiti_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/aggregate_metrics_graphiti_direct_llm.json)","tokens":300,"sizeBytes":265},{"name":"aggregate_metrics_graphiti.json","path":"evals/old/graphiti_01042025/aggregate_metrics_graphiti.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/aggregate_metrics_graphiti.json","title":"Graphiti_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Graphiti_01042025 Skill\n\nPath: `evals/old/graphiti_01042025/aggregate_metrics_graphiti.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/aggregate_metrics_graphiti.json)","tokens":300,"sizeBytes":243},{"name":"metrics_output_graphiti_direct_llm.json","path":"evals/old/graphiti_01042025/metrics_output_graphiti_direct_llm.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/metrics_output_graphiti_direct_llm.json","title":"Graphiti_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Graphiti_01042025 Skill\n\nPath: `evals/old/graphiti_01042025/metrics_output_graphiti_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/metrics_output_graphiti_direct_llm.json)","tokens":300,"sizeBytes":259},{"name":"metrics_output_graphiti_huma_eval.json","path":"evals/old/graphiti_01042025/metrics_output_graphiti_huma_eval.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/metrics_output_graphiti_huma_eval.json","title":"Graphiti_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Graphiti_01042025 Skill\n\nPath: `evals/old/graphiti_01042025/metrics_output_graphiti_huma_eval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/metrics_output_graphiti_huma_eval.json)","tokens":300,"sizeBytes":257},{"name":"metrics_output_graphiti.json","path":"evals/old/graphiti_01042025/metrics_output_graphiti.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/metrics_output_graphiti.json","title":"Graphiti_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Graphiti_01042025 Skill\n\nPath: `evals/old/graphiti_01042025/metrics_output_graphiti.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_01042025/metrics_output_graphiti.json)","tokens":300,"sizeBytes":237},{"name":"hotpot_qa_graphiti_results_old_aggregate_metrics_direct_llm.json","path":"evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics_direct_llm.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics_direct_llm.json","title":"Graphiti_updated Skill","category":"anthropic-skill","format":"json","content":"# Graphiti_updated Skill\n\nPath: `evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics_direct_llm.json)","tokens":300,"sizeBytes":306},{"name":"hotpot_qa_graphiti_results_old_aggregate_metrics.json","path":"evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics.json","title":"Graphiti_updated Skill","category":"anthropic-skill","format":"json","content":"# Graphiti_updated Skill\n\nPath: `evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_aggregate_metrics.json)","tokens":300,"sizeBytes":284},{"name":"hotpot_qa_graphiti_results_old_metrics_direct_llm.json","path":"evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics_direct_llm.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics_direct_llm.json","title":"Graphiti_updated Skill","category":"anthropic-skill","format":"json","content":"# Graphiti_updated Skill\n\nPath: `evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics_direct_llm.json)","tokens":300,"sizeBytes":286},{"name":"hotpot_qa_graphiti_results_old_metrics.json","path":"evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics.json","title":"Graphiti_updated Skill","category":"anthropic-skill","format":"json","content":"# Graphiti_updated Skill\n\nPath: `evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old_metrics.json)","tokens":300,"sizeBytes":264},{"name":"hotpot_qa_graphiti_results_old.json","path":"evals/old/graphiti_updated/hotpot_qa_graphiti_results_old.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old.json","title":"Graphiti_updated Skill","category":"anthropic-skill","format":"json","content":"# Graphiti_updated Skill\n\nPath: `evals/old/graphiti_updated/hotpot_qa_graphiti_results_old.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/graphiti_updated/hotpot_qa_graphiti_results_old.json)","tokens":300,"sizeBytes":248},{"name":"hotpot_50_corpus.json","path":"evals/old/hotpot_50_corpus.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_50_corpus.json","title":"Old Skill","category":"anthropic-skill","format":"json","content":"# Old Skill\n\nPath: `evals/old/hotpot_50_corpus.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_50_corpus.json)","tokens":300,"sizeBytes":173},{"name":"hotpot_50_qa_pairs.json","path":"evals/old/hotpot_50_qa_pairs.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_50_qa_pairs.json","title":"Old Skill","category":"anthropic-skill","format":"json","content":"# Old Skill\n\nPath: `evals/old/hotpot_50_qa_pairs.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_50_qa_pairs.json)","tokens":300,"sizeBytes":177},{"name":"benchmark_summary_cognee.json","path":"evals/old/hotpot_qa_24_2025/benchmark_summary_cognee.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/benchmark_summary_cognee.json","title":"Hotpot_qa_24_2025 Skill","category":"anthropic-skill","format":"json","content":"# Hotpot_qa_24_2025 Skill\n\nPath: `evals/old/hotpot_qa_24_2025/benchmark_summary_cognee.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/benchmark_summary_cognee.json)","tokens":300,"sizeBytes":239},{"name":"benchmark_summary_competition.json","path":"evals/old/hotpot_qa_24_2025/benchmark_summary_competition.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/benchmark_summary_competition.json","title":"Hotpot_qa_24_2025 Skill","category":"anthropic-skill","format":"json","content":"# Hotpot_qa_24_2025 Skill\n\nPath: `evals/old/hotpot_qa_24_2025/benchmark_summary_competition.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/benchmark_summary_competition.json)","tokens":300,"sizeBytes":249},{"name":"README.md","path":"evals/old/hotpot_qa_24_2025/README.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/README.md","title":"Hotpot_qa_24_2025 Skill","category":"anthropic-skill","format":"markdown","content":"# Hotpot_qa_24_2025 Skill\n\nPath: `evals/old/hotpot_qa_24_2025/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/README.md)","tokens":300,"sizeBytes":199},{"name":"hotpot_qa_24_corpus.json","path":"evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_corpus.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_corpus.json","title":"Src Skill","category":"anthropic-skill","format":"json","content":"# Src Skill\n\nPath: `evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_corpus.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_corpus.json)","tokens":300,"sizeBytes":223},{"name":"hotpot_qa_24_instance_filter.json","path":"evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_instance_filter.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_instance_filter.json","title":"Src Skill","category":"anthropic-skill","format":"json","content":"# Src Skill\n\nPath: `evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_instance_filter.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_instance_filter.json)","tokens":300,"sizeBytes":241},{"name":"hotpot_qa_24_qa_pairs.json","path":"evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_qa_pairs.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_qa_pairs.json","title":"Src Skill","category":"anthropic-skill","format":"json","content":"# Src Skill\n\nPath: `evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_qa_pairs.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/hotpot_qa_24_2025/src/hotpot_qa_24_qa_pairs.json)","tokens":300,"sizeBytes":227},{"name":"aggregate_metrics_mem0_direct_llm.json","path":"evals/old/mem0_01042025/aggregate_metrics_mem0_direct_llm.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/aggregate_metrics_mem0_direct_llm.json","title":"Mem0_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Mem0_01042025 Skill\n\nPath: `evals/old/mem0_01042025/aggregate_metrics_mem0_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/aggregate_metrics_mem0_direct_llm.json)","tokens":300,"sizeBytes":245},{"name":"aggregate_metrics_mem0.json","path":"evals/old/mem0_01042025/aggregate_metrics_mem0.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/aggregate_metrics_mem0.json","title":"Mem0_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Mem0_01042025 Skill\n\nPath: `evals/old/mem0_01042025/aggregate_metrics_mem0.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/aggregate_metrics_mem0.json)","tokens":300,"sizeBytes":223},{"name":"metrics_output_mem0_direct_llm.json","path":"evals/old/mem0_01042025/metrics_output_mem0_direct_llm.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/metrics_output_mem0_direct_llm.json","title":"Mem0_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Mem0_01042025 Skill\n\nPath: `evals/old/mem0_01042025/metrics_output_mem0_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/metrics_output_mem0_direct_llm.json)","tokens":300,"sizeBytes":239},{"name":"metrics_output_mem0_human_eval.json","path":"evals/old/mem0_01042025/metrics_output_mem0_human_eval.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/metrics_output_mem0_human_eval.json","title":"Mem0_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Mem0_01042025 Skill\n\nPath: `evals/old/mem0_01042025/metrics_output_mem0_human_eval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/metrics_output_mem0_human_eval.json)","tokens":300,"sizeBytes":239},{"name":"metrics_output_mem0.json","path":"evals/old/mem0_01042025/metrics_output_mem0.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/metrics_output_mem0.json","title":"Mem0_01042025 Skill","category":"anthropic-skill","format":"json","content":"# Mem0_01042025 Skill\n\nPath: `evals/old/mem0_01042025/metrics_output_mem0.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/mem0_01042025/metrics_output_mem0.json)","tokens":300,"sizeBytes":217},{"name":"README.md","path":"evals/README.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/README.md","title":"Evals Skill","category":"anthropic-skill","format":"markdown","content":"# Evals Skill\n\nPath: `evals/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/README.md)","tokens":300,"sizeBytes":143},{"name":"SKILL.md","path":"examples/demos/feedback/skill_feedback_loop/skills/diff-risk-explainer/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/examples/demos/feedback/skill_feedback_loop/skills/diff-risk-explainer/SKILL.md","title":"diff-risk-explainer","category":"anthropic-skill","format":"markdown","content":"# diff-risk-explainer\n\nPath: `examples/demos/feedback/skill_feedback_loop/skills/diff-risk-explainer/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/examples/demos/feedback/skill_feedback_loop/skills/diff-risk-explainer/SKILL.md)","tokens":300,"sizeBytes":279},{"name":"SKILL.md","path":"examples/demos/feedback/skill_feedback_loop/skills/pr-comment-evaluator/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/examples/demos/feedback/skill_feedback_loop/skills/pr-comment-evaluator/SKILL.md","title":"pr-comment-evaluator","category":"anthropic-skill","format":"markdown","content":"# pr-comment-evaluator\n\nPath: `examples/demos/feedback/skill_feedback_loop/skills/pr-comment-evaluator/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/examples/demos/feedback/skill_feedback_loop/skills/pr-comment-evaluator/SKILL.md)","tokens":300,"sizeBytes":282},{"name":"SKILL.md","path":"examples/demos/feedback/skill_feedback_loop/skills/skill-feedback-writer/SKILL.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/examples/demos/feedback/skill_feedback_loop/skills/skill-feedback-writer/SKILL.md","title":"skill-feedback-writer","category":"anthropic-skill","format":"markdown","content":"# skill-feedback-writer\n\nPath: `examples/demos/feedback/skill_feedback_loop/skills/skill-feedback-writer/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/examples/demos/feedback/skill_feedback_loop/skills/skill-feedback-writer/SKILL.md)","tokens":300,"sizeBytes":285},{"name":"spec_extras.json","path":"tools/spec_extras.json","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/tools/spec_extras.json","title":"Tools Skill","category":"anthropic-skill","format":"json","content":"# Tools Skill\n\nPath: `tools/spec_extras.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/tools/spec_extras.json)","tokens":300,"sizeBytes":157},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"# Claude Agent Guidelines & System Prompt\n\nPath: `CLAUDE.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/CLAUDE.md)","tokens":300,"sizeBytes":159},{"name":"README.md","path":"cognee_db_workers/ladybug_extensions/README.md","rawUrl":"https://raw.githubusercontent.com/topoteretes/cognee/HEAD/cognee_db_workers/ladybug_extensions/README.md","title":"ladybug_extensions Documentation","category":"plugin-manifest","format":"markdown","content":"# ladybug_extensions Documentation\n\nPath: `cognee_db_workers/ladybug_extensions/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/cognee_db_workers/ladybug_extensions/README.md)","tokens":300,"sizeBytes":226}],"systemPromptSnippet":"<yakaai_skills repo=\"topoteretes/cognee\">\n<!-- File: AGENTS.md (Tokens: ~300 | Category: root-instruction) -->\n# AI Agent Protocol & Instructions\n\nPath: `AGENTS.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/AGENTS.md)\n\n<!-- File: .agents/skills/cognee-cli/SKILL.md (Tokens: ~2249 | Category: anthropic-skill) -->\n---\nname: cognee-cli\ndescription: Use when the user wants to drive cognee from the terminal with cognee-cli — remember/recall/forget/improve memory commands, managing datasets and config, or database migrations.\n---\n\n# Use the cognee CLI\n\n`cognee-cli` ships with the package (entry point in `cognee/cli/_cognee.py`;\neach command lives in `cognee/cli/commands/`). Every command has\n`--help` for its flags, but only a few (`demo`, `eval`, `serve`,\n`push`, `upgrade`, `downgrade`, `stamp`, and `search` with one CODE example)\ninclude usage examples — for the memory commands use the examples\nin this file. Needs `LLM_API_KEY` configured, same as the SDK.\n\n## Core flow\n\nThe memory commands are the primary surface as of cognee 1.x:\n\n```bash\ncognee-cli remember \"Your text here\"         # also accepts file paths / URLs\ncognee-cli remember ./docs --dataset-name my_project\ncognee-cli recall \"Your question\"            # query the graph\ncognee-cli recall \"keyword\" --query-type CHUNKS\ncognee-cli forget --all                      # wipe local state\n```\n\n`remember` is ingest + graph build in one step (`add` + `cognify` under the\nhood); `--background`/`-b` runs the cognify stage in the background, and\n`--dry-run` estimates LLM tokens/cost without ingesting. `recall` takes\n`--datasets`/`-d`, `--top-k`/`-k` (default 10), and `--session-id`/`-s`.\n\n`forget` targets `--dataset`, `--dataset-id`, `--data-id` (needs a dataset), or\n`--everything`/`--all` — one unified command replacing the older `delete` and\nempty-dataset paths. `--memory-only` (with a dataset) drops the graph and\nvectors but keeps the raw files, so the data can be rebuilt.\n\n> **`forget --all` does not ask for confirmation.** It deletes every dataset\n> immediately, even on a non-interactive stdin. The legacy `delete --all`\n> prompts `Delete ALL data from cognee? [y/N]` first, so switching to `forget`\n> silently drops that safety net — script it with care.\n\n`--query-type` accepts 10 of the SDK's 20 `SearchType` values — the list in\n`cognee/cli/config.py:SEARCH_TYPE_CHOICES`: HYBRID_COMPLETION, GRAPH_COMPLETION,\nRAG_COMPLETION, CHUNKS, CHUNKS_LEXICAL, SUMMARIES, CODE, CYPHER, GRAPH_REPORT,\nSKILLS. The rest (TEMPORAL, GRAPH_COMPLETION_COT,\nAGENTIC_COMPLETION, NATURAL_LANGUAGE, …) are SDK-only, e.g.\n`cognee.recall(q, query_type=SearchType.TEMPORAL)`.\n\nWhen `--query-type` is omitted the CLI uses `HYBRID_COMPLETION`\n(`DEFAULT_SEARCH_TYPE`), whereas the SDK's `cognee.recall()` auto-routes\nbetween search types. `--top-k` defaults to 10 on the CLI and 15 in the SDK.\n\n## Session memory and enrichment\n\nSession entries are currently written from the SDK — `cognee.remember(...,\nsession_id=\"chat_1\")` — not the CLI (`cognee-cli remember` has no session\nflag). The CLI side of session memory is reading and bridging:\n\n```bash\ncognee-cli recall \"question\" -s chat_1       # session cache first: without -d/-t\n                                             # this searches the session directly\ncognee-cli sessions get                      # retrieve session Q&A history\ncognee-cli improve -d my_project -s chat_1   # bridge session content into the graph\ncognee-cli improve -d my_project             # enrich/index the graph (no session)\ncognee-cli feedback ...                      # attach feedback to results\n```\n\n`improve` also takes `--feedback-alpha` (learning rate in\n(0, 1]; default `IMPROVE_FEEDBACK_ALPHA`, 0.1), `--build-global-context-index`,\n`--build-truth-subspace` (both opt-in stages; the truth subspace needs\n`-s`), and `--background`/`-b` (`--node-name` is deprecated: it warns and is\nignored). It prints one line per stage — name, status\n(`completed` / `already_completed` / `skipped` / `errored`) and the skip\nreason (e.g. `no_session_ids`, `lock_held`, `opt_in_disabled`).\n`remember`/`improve` build their graphs through `cognify()`, so cognify-level\nsettings (e.g. `PROVENANCE_TRACKING=true`) apply to them too.\n\n## Legacy / lower-level commands\n\n`add`, `cognify`, `search`, and `delete` still ship and are what the\nmemory commands call underneath. Use them only to drive a single stage in\nisolation; prefer `remember`/`recall`/`forget`/`improve` otherwise.\n\n```bash\ncognee-cli add \"text\" && cognee-cli cognify  # what `remember` does in one step\ncognee-cli search \"question\"                 # `recall` minus routing/scope/session sources\ncognee-cli delete --all                      # superseded by `forget --all`\n```\n\n## Management\n\n```bash\ncognee-cli datasets list                     # dataset operations\ncognee-cli config get [key] [--show-secrets] # view one/all settings (API keys masked by default)\ncognee-cli config set <key> <value>          # set + persist to ./.env in the cwd\ncognee-cli config unset <key>                # reset a key to its default (also persisted)\ncognee-cli -ui                               # launch API server + UI (see cognee-server skill)\ncognee-cli serve --url http://localhost:8000 # connect CLI/SDK to a running instance\n```\n\n## Database migrations\n\ncognee has two migration chains: the relational schema (Alembic, in\n`cognee/alembic/`) and the graph/vector data chain (slugs registered in\n`cognee/modules/migrations/registry.py`). Both run automatically — at API\nserver startup and on the first write (`remember`, `add`, `cognify`,\n`improve`, …) in an SDK/CLI process — unless `ENABLE_AUTO_MIGRATIONS=false`.\nSo you rarely need these commands; they are for inspecting state, disabled\nauto-migration, and rollbacks. There is no `migrate` command.\n\n```bash\ncognee-cli current                    # stamped revision per database (per dataset\n                                      # with access control on)\ncognee-cli history                    # the data-migration chain, newest first\ncognee-cli upgrade                    # relational to head, then data chain to head\ncognee-cli upgrade <slug>             # data chain up to and including <slug>\ncognee-cli upgrade --alembic <rev>    # pin the relational (Alembic) target\ncognee-cli downgrade <slug|base>      # REWRITES DATA; revision is required,\n                                      # prompts unless --force; --dataset <uuid>\n                                      # (repeatable) limits it\ncognee-cli stamp <head|base|slug>     # set the stored revision WITHOUT running\n                                      # anything; prompts unless --force;\n                                      # --dataset <uuid> (repeatable) limits it\n```\n\nThe positional revision is always a **data-chain slug**; the relational\ntarget goes through `--alembic`. `downgrade` leaves the relational schema\nalone unless you pass `--alembic`. `upgrade` runs even when\n`ENABLE_AUTO_MIGRATIONS=false`. `--alembic-path` (or `COGNEE_ALEMBIC_PATH`)\npoints at a custom Alembic scripts directory.\n\n## Gotchas\n\n- The CLI initializes cognee lazily; the first command in a fresh environment\n  is slow (DB + model setup), later ones are fast.\n- `remember` (and `add`) without `--dataset-name` targets the default dataset\n  `main_dataset`; `recall`/`search` operate across your accessible datasets\n  unless a dataset is given.\n- `forget` refuses to run bare — pass `--dataset`, `--dataset-id`, `--data-id`\n  (with a dataset), or `--everything`/`--all`.\n- Session commands (`recall -s`, `sessions get`, `improve -s`) require\n  `CACHING=true` (the default) — with it off, session reads return nothing and\n  SDK session writes raise. To cut read latency and token cost while keeping\n  session memory, `cognee-cli config set AUTO_FEEDBACK false` — by default\n  cognee makes one structured-output LLM call per answered query to self-tune\n  its memory.\n- `config set`/`config unset` write to the `.env` file in whatever directory\n  you run the command from (creating it if missing). `config reset` (reset\n  *all* keys) is still not implemented.\n- **Which `.env` actually wins is not always the cwd one.** At import, cognee\n  calls `dotenv.load_dotenv(override=True)`, which resolves relative to the\n  *cognee package location*, not your working directory. In a source/editable\n  checkout (`uv pip install -e .`) a `.env` at the repo root therefore shadows\n  the `.env` in the directory you ran from — and because `override=True`, it\n  also beats variables you `export`ed. Symptom: `config set` appears to do\n  nothing, or the CLI connects to a backend you thought you had overridden.\n  To test against different settings, move the repo `.env` aside, or set\n  values programmatically after import (`cognee.config.set_*`). (Under\n  `python -c` the cwd `.env` does win, because dotenv falls back to the cwd\n  when `__main__` has no `__file__` — which is why the same command can\n  behave differently as a script vs. `-c`.)\n\n<!-- File: .agents/skills/cognee-community/SKILL.md (Tokens: ~1166 | Category: anthropic-skill) -->\n---\nname: cognee-community\ndescription: Use when the user needs something that ships outside cognee core — community database adapters (Qdrant, Milvus, Weaviate, Redis, Pinecone, FalkorDB, Memgraph, DuckDB, NetworkX, …), data-source connectors (Slack, Gmail, Notion, Confluence, Google Drive), custom tasks/pipelines/retrievers (Exa, ScrapeGraph, codify), Keywords AI observability — or wants to contribute a package to the cognee-community repo.\n---\n\n# Use and contribute cognee-community packages\n\nCommunity-maintained plugins live in a separate monorepo:\nhttps://github.com/topoteretes/cognee-community. Everything installable is\nunder `packages/`; `experimental/` holds demos (n8n nodes, dlt demos,\nbauplan, tower) that are not published packages. Each package publishes to\nPyPI as `cognee-community-<family>-<kind>-<name>` and imports as the same\nname with underscores.\n\n## Package families\n\n| Family | Packages |\n|---|---|\n| Vector adapters | azureaisearch, milvus, moss, opengauss, opensearch, pinecone, qdrant, redis, singlestore, turbopuffer, valkey, weaviate |\n| Graph adapters | arcadedb, memgraph, networkx, pggraph, spanner, turbopuffer, turingdb |\n| Hybrid (graph+vector in one DB) | arcadedb, duckdb, falkordb, helixdb |\n| Connectors (data sources) | confluence, gmail, google-drive, notion, slack |\n| Tasks / pipelines / retrievers | codify_tasks, codify_pipeline, code_retriever, exa_tasks, scrapegraph_tasks |\n| Observability | keywordsai (`MONITORING_TOOL=keywordsai` + `KEYWORDSAI_API_KEY`) |\n\n## Using a database adapter\n\nInstall, then **import the package's `register` module before cognee touches\nany engine** — registration is what makes the provider name valid:\n\n```python\nuv pip install cognee-community-vector-adapter-qdrant\n```\n\n```python\nimport cognee\nfrom cognee import config\nfrom cognee_community_vector_adapter_qdrant import register  # noqa: F401\n\nconfig.set_vector_db_config(\n    {\n        \"vector_db_provider\": \"qdrant\",\n        \"vector_db_url\": \"http://localhost:6333\",\n        \"vector_db_key\": \"...\",\n        \"vector_dataset_database_handler\": \"qdrant\",  # only if the adapter ships one\n    }\n)\n```\n\nThe `register.py` calls `use_vector_adapter(name, AdapterClass)` /\n`use_graph_adapter(...)`. Setting `VECTOR_DB_PROVIDER`/`GRAPH_DATABASE_PROVIDER`\nto a community name **without** the register import raises \"Unsupported\nvector database provider\". Hybrid adapters (e.g. falkordb) register as both\ngraph and vector — set both configs to the same provider name.\n\n**Multi-tenancy caveat**: with `ENABLE_BACKEND_ACCESS_CONTROL=true` (the\ndefault), both backends must have a dataset-database handler or cognee raises\n`EnvironmentError`. Community adapters that ship one (registered via\n`use_dataset_database_handler` in their `register.py`): qdrant, moss,\nsinglestore, turbopuffer (vector + graph), falkordb, arcadedb, helixdb. All\nother community adapters need `ENABLE_BACKEND_ACCESS_CONTROL=false`.\n\n## Using a connector\n\nConnectors expose a `dlt` source you hand straight to `remember()`; they\nreuse core's DLT ingestion path, so snapshot sync and forget-on-delete work\nwith no core changes:\n\n```python\nfrom cognee_community_connector_slack import slack_export_source\n\nawait cognee.remember(\n    slack_export_source(\"/path/to/slack-export\"),\n    dataset_name=\"team-slack-export\",  # use a dedicated dataset\n    max_rows_per_table=0,\n)\n```\n\nSame shape for gmail (\"ask my inbox\"), notion, confluence, and google-drive\n(incremental, forget-on-delete). Each package README documents its\ncredentials; always give a connector its own dataset.\n\n## Verifying an install\n\nEvery package has `examples/example.py` (run `uv run python examples/example.py`\nfrom the package dir) and a `tests/` directory. An LLM API key is still\nrequired (`LLM_API_KEY`, OpenAI by default).\n\n## Contributing a package\n\n- **Branch from `main`** — unlike the core repo, cognee-community does not\n  use a `dev` branch.\n- Follow the existing structure: package dir under `packages/<family>/<name>/`\n  with `pyproject.toml`, a `README.md` (install + usage), `examples/example.py`,\n  and `tests/` that go beyond the example.\n- New DB adapters implement `VectorDBInterface` / `GraphDBInterface` from\n  core, expose a `register.py`, and should run the shared conformance tests\n  in `packages/shared/contract_suite/` (vector_contract.py / graph_contract.py).\n- Add a handler via `use_dataset_database_handler(...)` if the backend can\n  isolate per user+dataset — that's what makes it work with access control on.\n- Name it `cognee-community-<family>-<kind>-<name>` and add it to the tables\n  in the repo README. Lint config is the repo-root `ruff.toml`.\n\n<!-- File: .agents/skills/cognee-custom-graph-models/SKILL.md (Tokens: ~2391 | Category: anthropic-skill) -->\n---\nname: cognee-custom-graph-models\ndescription: Use when defining the shape of cognee's knowledge graph with graph_model= — writing DataPoint node classes, choosing identity and index fields so nodes merge and are searchable, declaring typed Edge fields and FromIdentity references, building a model from a JSON schema, or debugging duplicated nodes, missing edges, or InvalidReferenceTypeError.\n---\n\n# Custom graph models\n\nBy default cognee extracts a generic `KnowledgeGraph` of entities and\nrelationships. Pass your own model with `graph_model=` and the LLM fills\nyour node and edge types instead.\n\n```python\nfrom typing import Annotated, Literal\nimport cognee\nfrom cognee.low_level import DataPoint, Edge, FromIdentity\n\n\nclass Role(DataPoint):\n    name: str\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nclass Person(DataPoint):\n    name: str\n    is_a: Annotated[Role, FromIdentity()] | None = None  # reference by name\n    reports_to: list[Edge[\"Person\", \"Person\"]] = []  # edge owned by Person\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nclass PeopleGraph(DataPoint):  # the root the LLM fills\n    people: list[Person]\n    friends_with: list[Edge[Person, Person]] = []\n    family: list[Edge[Person, Person, Literal[\"married_to\", \"sibling_of\"]]] = []\n    metadata: dict = {\"index_fields\": [], \"transparent\": True}\n\n\nawait cognee.remember(text, graph_model=PeopleGraph, custom_prompt=\"Extract every person...\")\n```\n\nFull example: `examples/guides/custom_graph_model.py`.\n\n## Use it\n\n### Nodes: DataPoint classes\n\nEvery node type subclasses `DataPoint` (`from cognee.low_level import\nDataPoint`). Its fields become:\n\n- **Node properties:** scalars, strings, dicts, and anything that is not a\n  DataPoint.\n- **Edges named after the field:** a field holding a DataPoint or a list of\n  DataPoints. `members: list[Person]` becomes `members` edges.\n\n`dict[str, Person]`, sets and plain tuples are stored as properties, not\nedges.\n\n### Identity and search: `metadata`\n\n| Key | What it does |\n|---|---|\n| `identity_fields` | The node id is derived from these field values (normalized: lowercased, spaces to `_`, apostrophes removed). The same entity from two chunks or two runs becomes **one node**. |\n| `index_fields` | Each field gets a vector collection named `<ClassName>_<field>`, so recall can find the node. |\n| `transparent` | The node is not stored; its children take its place. Use it for a root container like `PeopleGraph`. |\n\n**Without `identity_fields` every node gets a random id, so the same person\nis duplicated in every chunk and every run.** Set it on every node type that\nrepresents a real-world entity.\n\n**Write `metadata` explicitly**, as in the examples above. There is also an\nannotation shortcut (`from cognee.infrastructure.engine import Dedup,\nEmbeddable`; `name: Annotated[str, Embeddable(), Dedup()]`), but today only\nhalf of it works:\n\n- `Dedup()` works: ids are derived from the marked fields.\n- `Embeddable()` does not index. The markers update the class-level\n  default, but each instance still carries `{\"index_fields\": []}`, and\n  indexing reads the instance, so no vector collection is created and\n  recall cannot find the node.\n\nMarkers are also ignored entirely when the class declares `metadata`\nitself.\n\n### Typed edges: `list[Edge[Source, Target, Name]]`\n\nThe LLM answers edges as flat rows of identity strings (`source`, `target`),\nand cognee resolves them to the extracted nodes. The third parameter\ncontrols the relationship name:\n\n| Declaration | Relationship name |\n|---|---|\n| `list[Edge[Person, Person]]` | The field name (`friends_with`) |\n| `list[Edge[Person, Person, Literal[\"a\", \"b\"]]]` | The LLM picks one value |\n| `list[Edge[Person, Person, str]]` | Free-form from the LLM, normalized |\n\n- **Where to declare:** on the root model for relationships with no obvious\n  owner, or on the owning node. On the owner, endpoints of the owner's own\n  type must be strings (`Edge[\"Person\", \"Person\"]`), because the class is\n  not defined yet inside its own body.\n- **Always a list:** `Edge[...]` or `Edge[...] | None` on its own raises.\n- **Both endpoint types need exactly one `identity_fields` entry.**\n\n### References: `Annotated[Target, FromIdentity()]`\n\nInstead of a nested object, the LLM answers the identity string of a node\n(`is_a: \"engineer\"`), and cognee links to that node. Supported spellings:\n`Target`, `Target | None`, `list[Target]`, `list[Target] | None`.\nAnything else raises `InvalidReferenceTypeError`. The target needs exactly\none identity field, and its other required fields need defaults.\n\n### Edge values you build by hand\n\n`Edge(source=..., target=..., relationship_type=..., weight=...,\nproperties={...})`. An omitted `source` falls back to the node declaring the\nfield; on a parametrized field that node must be the declared `Source`\ntype, or it raises. On a root container, always pass `source=`. The tuple\nform `(Edge(weight=0.8), target_node)` attaches edge properties to a plain\nDataPoint field (`examples/guides/custom_data_models.py`).\n\n### From JSON instead of Python\n\n- `cognee.low_level.graph_model_from_spec(spec)`: a small entity/relation\n  spec (names, fields, `one`/`many` relations) compiled to DataPoint\n  classes, with identity and index on `name` by default. Example:\n  `examples/guides/graph_model_from_json.py`.\n- `cognee.low_level.graph_schema_to_graph_model(json_schema)`: a JSON\n  Schema (needs a top-level `title`; only internal `#` refs).\n- HTTP: `POST /api/v1/remember` takes a `graph_model` form field (JSON\n  schema string); `POST /api/v1/cognify` takes a `graphModel` JSON object.\n  `POST /api/v1/llm/infer-schema` proposes a schema from sample text.\n\nNeither JSON path can express typed `Edge` fields or `FromIdentity`; use\nPython classes for those.\n\n## Pitfalls\n\n- **Duplicated nodes** → missing `identity_fields`.\n- **Node never shows up in recall** → no `index_fields`, or the recalling\n  process never imported the model class (graph completion searches the\n  collections of DataPoint classes loaded in that process).\n- **Edge rows silently missing** → an unresolved row is dropped with a\n  warning. Endpoints resolve by **exact type** against nodes extracted from\n  the same chunk: a subclass instance does not match where its base is\n  declared, and a node from another chunk or an earlier run is not a\n  candidate.\n- **`InvalidReferenceTypeError`, \"declares Edge in a shape the LLM\n  extraction cannot fill\"** → an unsupported `FromIdentity` or `Edge`\n  spelling. These are raised when the model is converted during\n  extraction, not at class definition, so they appear mid-pipeline.\n- **String endpoints resolve only to the owning model itself or a\n  module-level class.** A string naming another class defined inside a\n  function raises `InvalidReferenceTypeError`, so define models at module\n  level.\n- **Field names that collide with DataPoint's own fields** (`id`, `type`,\n  `version`, `metadata`, `created_at`, `belongs_to_set`, …) are stripped\n  from what the LLM sees. Rename them.\n- **A subclass that overrides `metadata`** replaces the parent's entirely.\n  Dropping `identity_fields` only logs a warning. A subclass also hashes ids\n  under its own class name.\n- **Write a `custom_prompt`.** Without one the generic knowledge-graph\n  prompt is used; your schema reaches the LLM only as structured output.\n- **Not with GLiNER.** `extractor=\"gliner_demo\"` (alias `\"gliner\"`) raises\n  with a custom `graph_model`, and so does the default `GRAPH_EXTRACTOR=auto`\n  when no LLM key is configured (it resolves to `gliner_demo`).\n- **Remote mode drops it.** After `cognee.serve(url)`, `remember()` and\n  `cognify()` do not forward `graph_model`; the server builds a generic\n  graph.\n- A custom model skips the generic path's ontology resolution, per-graph\n  node dedup. Summaries still run.\n\n## How it works\n\n`extract_content_graph` converts a DataPoint model into a plain Pydantic\nmodel for the LLM: infrastructure fields and `metadata` are stripped, typed\nedge fields become row lists (`FriendsWithEdge` with `source`/`target`\nstrings), and `FromIdentity` fields become strings. The answer is converted\nback into DataPoint instances with ids from `identity_fields`, edge rows are\nresolved against the nodes in that answer, and the result is attached to the\nchunk (`chunk.contains`) and stored by `add_data_points`. Ownership is\nrecorded per document, so `forget(data_id=...)` removes a custom-model\ndocument's nodes while shared nodes survive.\n\n- LLM boundary, both directions: `cognee/shared/llm_graph_model.py`\n- DataPoint, metadata, ids: `cognee/infrastructure/engine/models/DataPoint.py`\n- Markers: `cognee/infrastructure/engine/models/FieldAnnotations.py`\n- Edge: `cognee/infrastructure/engine/models/Edge.py`\n- Property vs edge decision: `cognee/modules/graph/utils/field_edges.py`\n- Custom-model branch of extraction: `cognee/tasks/graph/extract_graph_from_data.py`\n- JSON schema / spec paths: `cognee/shared/graph_model_utils.py`,\n  `cognee/modules/graph_models/`\n- Vector collections: `cognee/tasks/storage/index_data_points.py`\n\n## Extending it\n\n- Tests for the LLM round trip: `cognee/tests/unit/modules/graph/test_content_graph_to_data_point.py`.\n  Edge typing: `cognee/tests/unit/interfaces/graph/test_typed_edge_model.py`,\n  `test_typed_edges_graph.py`. Identity: `cognee/tests/unit/infrastructure/engine/test_identity_fields.py`.\n  Property vs edge: `cognee/tests/unit/modules/graph/test_field_edges.py`.\n- Deletion of custom-model nodes: `cognee/tests/test_delete_custom_graph.py`.\n- A new `Edge` or `FromIdentity` spelling must be handled in both directions\n  in `llm_graph_model.py`, and rejected with `InvalidReferenceTypeError`\n  when unsupported, never silently accepted.\n\n<!-- File: .agents/skills/cognee-custom-pipelines/SKILL.md (Tokens: ~2521 | Category: anthropic-skill) -->\n---\nname: cognee-custom-pipelines\ndescription: Use when building your own cognee processing — writing custom tasks, chaining them into a pipeline with run_custom_pipeline or the lightweight run_pipeline (from cognee.pipelines import run_pipeline), storing custom DataPoints with add_data_points, running custom enrichment over the existing graph, checking pipeline run status, or debugging how data flows between tasks (batch_size, data_per_batch, ctx, Drop, enriches).\n---\n\n# Custom tasks and pipelines\n\nEverything cognee does runs as a **pipeline**: an ordered list of **tasks**,\neach a plain Python function whose output feeds the next one. `remember()`\nis the right tool for ordinary ingestion. Build a pipeline when you need\nprocessing cognee does not ship: your own extraction, your own node types,\nor a post-processing step over the graph.\n\n```python\nimport cognee\nfrom cognee.modules.pipelines import Task\nfrom cognee.tasks.storage import add_data_points\nfrom cognee.low_level import DataPoint\n\n\nclass Person(DataPoint):\n    name: str\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nasync def extract_people(data_items: list) -> list[Person]:\n    people = []\n    for item in data_items:  # always a list, see below\n        text = item if isinstance(item, str) else \"\"\n        people += [Person(name=n.strip()) for n in text.split(\",\") if n.strip()]\n    return people\n\n\nresult = await cognee.run_custom_pipeline(\n    tasks=[\n        Task(extract_people, needs_llm=False),\n        Task(add_data_points, needs_llm=False),  # store in graph + vector DBs\n    ],\n    data=[\"Ada Lovelace, Alan Turing\"],\n    dataset=\"people\",\n)\n```\n\n## Use it\n\n### Pick the runner\n\nThere are three, and two share the name `run_pipeline`:\n\n| Runner | Import | Use it for |\n|---|---|---|\n| `cognee.run_custom_pipeline(...)` | `cognee` | The normal choice: runs your tasks against a dataset with permissions, a per-dataset lock, run records, and status |\n| Full orchestrator `run_pipeline(tasks=..., data=..., datasets=...)` | `cognee.modules.pipelines` | What `run_custom_pipeline` and `cognify` call; yields `PipelineRunInfo` |\n| Lightweight `run_pipeline([...], data=...)` | `from cognee.pipelines import run_pipeline` (after `import cognee`, the attribute `cognee.pipelines.run_pipeline` is the orchestrator) | Quick chains of `task()` specs with no permissions, locks, run rows, or migrations; returns the last step's outputs |\n\n`cognee.run_custom_pipeline(tasks, data=None, dataset=\"main_dataset\",\nuser=None, incremental_loading=False, data_per_batch=20,\nrun_in_background=False, pipeline_name=\"custom_pipeline\", data_cache=False,\n...)` returns `{dataset_id: PipelineRunInfo}` (the started run when\n`run_in_background=True`). With `data=None` it runs over the dataset's\nexisting documents (`Data` rows).\n\n### Write a task\n\n```python\nfrom cognee.modules.pipelines import Task\nfrom cognee.modules.pipelines.models import PipelineContext\nfrom cognee.modules.pipelines.tasks.task import task_summary\nfrom cognee.pipelines import Drop\n\n\n@task_summary(\"Tagged {n} chunk(s)\")\nasync def tag_chunks(chunks: list, ctx: PipelineContext = None, label: str = \"x\"):\n    for chunk in chunks:\n        chunk.metadata[\"label\"] = label\n    return chunks  # or yield per item; return/yield Drop to discard\n\n\ntag = Task(tag_chunks, label=\"reviewed\", batch_size=10, needs_llm=False)\n```\n\n- A task is an `async def`, a generator, an async generator, or a plain\n  `def`. Extra `Task(fn, *args, **kwargs)` arguments are passed after the\n  pipeline data.\n- `needs_llm=False` on tasks that never call an LLM lets an LLM-free\n  pipeline skip the LLM connection check.\n- `ctx` (injected by the parameter **name** `ctx`) carries `user`,\n  `data_item`, `dataset`, `pipeline_run_id`, `pipeline_name`, and `extras`.\n- `task.with_config(batch_size=..., **kwargs)` returns a modified copy.\n\n### How data flows\n\n- **Each document runs the whole chain on its own** with `run_custom_pipeline`\n  or the orchestrator, and the first task receives it as a **one-element\n  list** (`[data_item]`), not the bare item. The lightweight `run_pipeline`\n  passes `data` to the first task unchanged.\n- **`data_per_batch`** (default 20) is how many documents run at the same\n  time. It is a concurrency limit, not a batch size.\n- **`batch_size` belongs to the consumer.** A task's `batch_size` decides how\n  the *previous* task's generator output is grouped before it is passed in.\n  Generator tasks always hand over lists; a coroutine or function hands over\n  its single return value.\n- **Streaming:** each upstream result goes down the chain immediately, so a\n  downstream task can run many times per document.\n- **`enriches=True`:** if the task returns `None`, its input is passed on\n  unchanged (coroutines and functions only, not generators).\n- **`Drop`:** returning or yielding it removes that item from the stream.\n- Every `DataPoint` passing through is stamped automatically with where it\n  came from (`source_pipeline`, `source_task`, `source_user`, …).\n\n### Store results\n\n`add_data_points(data_points, custom_edges=None, graph_only=False)` writes a list of `DataPoint`s to the graph and indexes\ntheir `index_fields` in the vector DB. It returns the same list, so it can\nsit mid-chain. Give every node type `identity_fields` so repeated runs merge\ninstead of duplicating (see the `cognee-custom-graph-models` skill).\n\n### Work on the existing graph\n\n`cognee.memify`, `cognee-cli memify`, `POST /api/v1/memify` and `improve()`'s\n`extraction_tasks` / `enrichment_tasks` are deprecated and removed in the next\nrelease. Run a post-processing step over the\ngraph with `run_custom_pipeline`: the task reads the graph itself, and one\nplaceholder item as `data` makes the chain run once instead of once per\ndocument.\n\n```python\nfrom cognee.infrastructure.databases.graph import get_graph_engine\n\n\nasync def enrich_graph(_items: list):\n    graph = await get_graph_engine()  # the dataset's graph inside the pipeline\n    nodes, edges = await graph.get_graph_data()\n    return [...]  # new DataPoints for add_data_points\n\n\nawait cognee.run_custom_pipeline(\n    tasks=[Task(enrich_graph, needs_llm=False), Task(add_data_points, needs_llm=False)],\n    data=[{}],\n    dataset=\"people\",\n)\n```\n\nFor cognee's own enrichment (session bridging, feedback weights, conflict\nreview, global context index) call `improve()`.\n\n### Check status\n\n```python\nstatus = await cognee.datasets.get_status([dataset_id], pipeline_names=[\"custom_pipeline\"])\n```\n\nWithout `pipeline_names` it reports only `cognify_pipeline`. It returns\n`{str(dataset_id): PipelineRunStatus}` (`{str(dataset_id): {pipeline_name:\nstatus}}` for several `pipeline_names`): `DATASET_PROCESSING_STARTED`,\n`_COMPLETED`, or `_ERRORED` (`_INITIATED` exists only on legacy rows). The value `run_custom_pipeline`\nreturns per dataset is a `PipelineRunInfo` instead, whose class names the\noutcome: `PipelineRunCompleted`, `PipelineRunAlreadyCompleted`,\n`PipelineRunErrored`, and so on.\n\n## Pitfalls\n\n- **Wrong `run_pipeline`.** The one imported via\n  `from cognee.pipelines import run_pipeline` wants `task()`\n  specs *called* (`extract()`, not `extract`) and raises `TypeError`\n  otherwise; the orchestrator in `cognee.modules.pipelines` wants `Task`\n  objects and raises `WrongTaskTypeError` otherwise.\n- **`run_custom_pipeline` accepts only `Task` objects** despite its type hint;\n  string task names are not resolved.\n- **Some callables are rejected** by `Task` (`ValueError: Unsupported task\n  type`): bound methods and `functools.partial`s of a plain (non-generator)\n  sync function, and callable objects (instances with `__call__`). Generator\n  and async variants, plain functions, and lambdas work. When in doubt, wrap it\n  in a plain `def` / `async def`.\n- **`run_custom_pipeline` does not run database migrations.** On an existing\n  database, run `await cognee.run_migrations()` (or any `remember()` first).\n- **Nodes duplicate on every run** when a DataPoint has no\n  `identity_fields` (or `Dedup()` fields). `examples/guides/custom_data_models.py`\n  and `examples/guides/custom_tasks_and_pipelines.py` have this bug; don't\n  copy it.\n\n## How it works\n\n`run_custom_pipeline` → orchestrator `run_pipeline` (checks write\npermission, takes the per-dataset lock, records a `PipelineRun`) →\n`run_tasks` (a semaphore of `data_per_batch`, one chain per document) →\n`run_tasks_base` (streams each task's output into the next, batching by the\nconsumer's `batch_size`, injecting `ctx`, stamping provenance).\n\n- Package overview and the runner semantics: `cognee/modules/pipelines/__init__.py`\n- `Task`, `task()`, `TaskSpec`, `BoundTask`, `@task_summary`: `cognee/modules/pipelines/tasks/task.py`\n- Orchestrator: `cognee/modules/pipelines/operations/pipeline.py`; execution:\n  `run_tasks.py`, `run_tasks_base.py`, `run_tasks_data_item.py`\n- Lightweight runner: `cognee/modules/pipelines/operations/run_pipeline.py`,\n  exported from `cognee/pipelines/`\n- Context: `cognee/modules/pipelines/models/PipelineContext.py`\n- `run_custom_pipeline`: `cognee/modules/run_custom_pipeline/run_custom_pipeline.py`\n- Storage: `cognee/tasks/storage/add_data_points.py`\n- Index of all shipped tasks: `cognee/tasks/README.md`\n\nExamples:\n\n- `examples/demos/custom_pipelines/custom_pipeline_single_object_example.py`:\n  the best reference. It runs over added documents, does LLM extraction into\n  typed DataPoints, then recalls. Its models declare identity with `Dedup()`\n  (the `Annotated` alternative to `metadata[\"identity_fields\"]`).\n- `examples/demos/custom_pipelines/organizational_hierarchy/`: low-level\n  `run_tasks`, no LLM, dedup via `identity_fields`, status polling.\n- `examples/demos/custom_pipelines/custom_cognify_pipeline_example.py`:\n  rebuilds add + cognify from the default task list.\n\n## Extending it\n\n- **A new shipped task:** put it in the `cognee/tasks/` subpackage for its\n  stage, export it from that package's `__init__.py`, follow the template in\n  `cognee/tasks/README.md`, and add a unit test under `cognee/tests/unit/tasks/`.\n- Pipeline tests: `cognee/tests/unit/modules/pipelines/` (runner semantics,\n  context, provenance, rollback) and `cognee/tests/unit/pipelines/` (the\n  lightweight API).\n\n<!-- File: .agents/skills/cognee-docker/SKILL.md (Tokens: ~975 | Category: anthropic-skill) -->\n---\nname: cognee-docker\ndescription: Use when the user wants to run cognee with Docker or docker compose — trying it out from the prebuilt image, starting the API server in a container, or bringing up the full stack (UI, MCP, Postgres, Neo4j) with compose profiles.\n---\n\n# Start cognee from the Docker image\n\n## Fastest path: prebuilt image, one file\n\nFor a local try-out, do NOT clone or build anything. Follow\n`docs/minimal-docker-compose.md`: save this as `docker-compose.yml` in an\nempty directory:\n\n```yaml\nservices:\n  cognee:\n    image: cognee/cognee:main\n    ports:\n      - \"8000:8000\"\n    environment:\n      LLM_API_KEY: ${LLM_API_KEY:?set LLM_API_KEY to your OpenAI API key}\n      # Single-user try-out: no auth, shared local databases.\n      ENABLE_BACKEND_ACCESS_CONTROL: \"false\"\n```\n\nThen:\n\n```bash\nexport LLM_API_KEY=\"sk-...\"   # OpenAI key (default LLM + embedding provider)\ndocker compose up\ncurl http://localhost:8000/health\n```\n\nInteractive API reference: http://localhost:8000/docs. First requests:\n\n```bash\necho \"Cognee turns documents into AI memory.\" > note.txt\n# remember = ingest + build the graph in one call (multipart form)\ncurl -X POST http://localhost:8000/api/v1/remember -F \"data=@note.txt\" -F \"datasetName=main_dataset\"\n# recall = query it (JSON)\ncurl -X POST http://localhost:8000/api/v1/recall -H \"Content-Type: application/json\" \\\n  -d '{\"query\": \"What does Cognee do?\", \"datasets\": [\"main_dataset\"]}'\n```\n\n`/api/v1/recall` takes the question as `query`. Omit `search_type` (or pass\n`null`) and the query is auto-routed by the same rule-based router the SDK\n`recall()` uses, with `HYBRID_COMPLETION` as the fallback; pass a value such as\n`\"search_type\": \"GRAPH_COMPLETION\"` to pin a strategy. The rule table is in\n`docs/recall-vs-search.md`.\n\nRequest DTOs accept both `snake_case` and `camelCase` for every field\n(`alias_generator=to_camel` + `populate_by_name` in `cognee/api/DTO.py`), so\n`search_type` and `searchType` are equally valid.\n\nThe legacy `/api/v1/add` + `/api/v1/cognify` + `/api/v1/search` endpoints still\nexist and are what `remember`/`recall` call underneath; use them only when you\nneed a single stage on its own. `/api/v1/improve` and `/api/v1/forget` complete\nthe memory API.\n\nData lives inside the container by default. To persist it, set\n`DATA_ROOT_DIRECTORY=/cognee-data/data` and\n`SYSTEM_ROOT_DIRECTORY=/cognee-data/system` and mount a named volume at\n`/cognee-data` (full example in `docs/minimal-docker-compose.md`).\n\n## Full stack from the repo\n\nThe repository's `docker-compose.yml` builds from source and adds opt-in\nprofiles. From the repo root (needs a `.env` with at least `LLM_API_KEY`;\ncopy `.env.template`):\n\n```bash\ndocker compose up                                  # API server only, port 8000\ndocker compose --profile ui up                     # + frontend on port 3000\ndocker compose --profile mcp up                    # + MCP server on port 8001\ndocker compose --profile postgres --profile neo4j up   # + databases\n```\n\nPostgres profile: pgvector/pg17, user/password/db `cognee`/`cognee`/`cognee_db`\non 5432. Neo4j profile: `neo4j`/`pleaseletmein` on 7474/7687. When cognee runs\nin a container and the database on the host, use `DB_HOST=host.docker.internal`.\n\n## Gotchas\n\n- With `ENABLE_BACKEND_ACCESS_CONTROL` unset (defaults to true), every API\n  call requires authentication — the single-user try-out sets it to `false`.\n- The image defaults to OpenAI for both LLM and embeddings; configuring only\n  one of them leaves the other on OpenAI, so keep a valid OpenAI key or\n  configure both (see the cognee-integrations skill).\n\n<!-- File: .agents/skills/cognee-forget/SKILL.md (Tokens: ~1928 | Category: anthropic-skill) -->\n---\nname: cognee-forget\ndescription: Use when removing data from cognee memory with forget() in the SDK, HTTP API, or CLI — finding which dataset and document hold the content to delete (listing datasets and data items, reading raw content), choosing between deleting one document, a whole dataset, or only the graph/vector memory, and doing it safely.\n---\n\n# Remove data with forget()\n\n`forget()` is cognee's one deletion API. It removes one document, a whole\ndataset, or only the derived memory (graph + vectors) while keeping the raw\nfiles. Deletion cannot be undone, so the workflow is always **find, read,\nconfirm, then delete**.\n\n> **Hard limits for agents**\n> - Delete only what the user asked to forget. Identify it by reading the\n>   content first; never guess from a file name alone.\n> - Confirm the exact items with the user before deleting, unless they\n>   already named exact ids.\n> - The widest deletion you may run is `forget(everything=True)`, and only\n>   when the user explicitly asks to wipe all of their memory. Never use any\n>   other reset or wipe mechanism to delete data.\n\n## Use it\n\n### 1. Find the dataset\n\n```python\nimport cognee\n\ndatasets = await cognee.datasets.list_datasets()  # datasets the user can read\nfor ds in datasets:\n    print(ds.id, ds.name)\n```\n\nHTTP: `GET /api/v1/datasets`. CLI: `cognee-cli datasets list`.\n\n### 2. List its documents\n\n```python\nitems = await cognee.datasets.list_data(dataset_id)  # all Data rows, oldest first\nfor item in items:\n    print(item.id, item.name, item.extension, item.created_at)\n```\n\nHTTP: `GET /api/v1/datasets/{dataset_id}/data?limit=100&offset=0` (limit up\nto 1000; `GET .../data/count` for the total; example:\n`examples/python/dataset_data_pagination.py`). CLI:\n`cognee-cli datasets data <dataset_uuid>`.\n\nEach item has `id`, `name`, `created_at`, `extension`, `mime_type`,\n`raw_data_location`, `dataset_id`, `label`, `external_metadata` (including\nany `node_set`), and `data_size`.\n\n### 3. Read the content before deciding\n\nNames are often `text_<hash>.txt`, so read the content to find what the user\nmeans.\n\n- HTTP: `GET /api/v1/datasets/{dataset_id}/data/{data_id}/raw` returns the\n  stored file (404 if it is gone).\n- SDK: there is no \"get raw\" helper; open the stored location:\n\n```python\nfrom cognee.infrastructure.files.utils.open_data_file import open_data_file\n\nasync with open_data_file(item.raw_data_location, mode=\"rb\") as f:\n    preview = f.read(2000).decode(\"utf-8\", errors=\"replace\")\n```\n\nJudge matches by meaning, not only by keywords, and show the user the\ncandidates (name + a short preview) before deleting.\n\n### 4. Delete\n\n| Goal | Call | What remains |\n|---|---|---|\n| One document | `forget(data_id=..., dataset_id=...)` (or `dataset=\"name\"`) | Nothing of that document; shared entities stay while another document still references them |\n| A whole dataset | `forget(dataset=\"name\")` or `forget(dataset_id=...)` | The dataset is deleted outright: the record, its data rows, graph and vector stores, and attributed sessions |\n| Rebuild a dataset's graph later | `forget(dataset=\"name\", memory_only=True)` | Raw files and data rows; graph, vectors, sessions and pipeline status are reset, so the data can be re-processed |\n| One document's memory only | `forget(dataset=\"name\", data_id=..., memory_only=True)` | That document's raw file and row |\n| Every dataset the user can delete | `forget(everything=True)` | Nothing, in any dataset the user has `delete` on in the current tenant (shared ones included). Only on explicit request (see the hard limits) |\n\nReturn values: `{\"data_id\", \"dataset_id\", \"status\"}` for a document,\n`{\"dataset_id\", \"status\"}` for a dataset (plus `data_records_reset` with\n`memory_only`), `{\"datasets_removed\", \"status\"}` for everything\n(`datasets_removed` counts the datasets the user can *read*, not the delete\nset).\n\n**HTTP:** `POST /api/v1/forget` with a JSON body; camelCase and snake_case\nkeys both work: `{\"datasetId\": \"...\", \"dataId\": \"...\"}`,\n`{\"dataset\": \"name\", \"memoryOnly\": true}`, `{\"everything\": true}`. Invalid\ncombinations return 422.\n\n**CLI:** `cognee-cli forget --dataset NAME | --dataset-id UUID\n[--data-id UUID] [--memory-only]`, or `--everything` / `--all`. The CLI\n**does not ask for confirmation**; confirm with the user first.\n\n## Pitfalls\n\n- **A `data_id` that is not in the dataset returns success and deletes\n  nothing.** The delete path treats an unknown id as a custom-graph-model\n  delete. Always take the id from `list_data` for that same dataset, and\n  check it is still listed afterwards if it matters.\n- **Pass either `dataset` or `dataset_id`, not both** (`ValueError`).\n  `data_id` and `memory_only` both need a dataset.\n- **`memory_only` is ignored when `everything=True`** in the SDK (the CLI\n  rejects the combination). `everything=True` always deletes everything.\n- **Not found and not allowed look the same.** An unknown dataset name and\n  one the user cannot delete both raise `DatasetNotFoundError`. Deleting\n  needs the `delete` permission on the dataset (see the `cognee-permissions`\n  skill). `everything=True` deletes every dataset the user has `delete`\n  permission on in the current tenant, including datasets shared to them\n  with delete rights, not only the ones they own.\n- **Sessions that cited deleted data are invalidated** so recall stops\n  returning answers built on it. Agent-trace entries are not invalidated.\n- **Changing a document is not a delete.** To replace a document's content,\n  use `cognee.update(data_id=..., data=..., dataset_id=...)`, which keeps its\n  id and re-extracts only the changed parts.\n- `cognee.delete()` is deprecated; use `forget()`.\n\n## How it works\n\n`forget()` resolves the dataset with the `delete` permission, then:\n\n- **One document** → `datasets.delete_data()`: takes the dataset lock,\n  deletes the graph nodes and edges the document owns, the matching vectors\n  and edge evidence, invalidates sessions that cited them, then deletes the\n  `Data` row. Ownership is tracked per document (source-refs on graph\n  elements), so an entity shared by two documents survives until both are\n  deleted. Raw files are reference-counted by storage location.\n- **A dataset** → `datasets.empty_dataset()`.\n- **`memory_only`** → drops the dataset's graph/vector memory and resets its\n  pipeline status, leaving raw data for a rebuild.\n- **`everything`** → `datasets.delete_all()` over every dataset the user has\n  `delete` on in the current tenant, plus a full prune of the session cache\n  (when caching or usage logging is on). This wipes **every user's**\n  sessions (Redis FLUSHDB / the whole fs cache / all SQL cache tables), not\n  just this user's.\n\nKey files:\n\n- `cognee/api/v1/forget/forget.py` (SDK), `routers/get_forget_router.py`\n  (HTTP), `cognee/cli/commands/forget_command.py` (CLI)\n- `cognee/api/v1/datasets/datasets.py` (`list_datasets`, `list_data`,\n  `delete_data`, `empty_dataset`, `delete_all`)\n- `cognee/api/v1/datasets/routers/get_datasets_router.py` (list, count, raw)\n- `cognee/infrastructure/databases/provenance/source_refs.py` (per-document\n  ownership of graph elements)\n- `cognee/infrastructure/files/utils/open_data_file.py`\n\n## Extending it\n\n- Anything new that writes graph nodes or edges for a document must record\n  its source-refs, or `forget(data_id=...)` cannot find and remove it.\n- Anything new that stores per-document data outside the graph (like edge\n  evidence) needs a cleanup step in the delete path and in `memory_only`.\n- Unit tests for `forget()` are in `cognee/tests/unit/api/v1/forget/`\n  (argument validation, the HTTP endpoint, `memory_only`); cover both the\n  document and the `memory_only` paths for new deletion behaviour.\n\n<!-- File: .agents/skills/cognee-improve-sessions/SKILL.md (Tokens: ~3676 | Category: anthropic-skill) -->\n---\nname: cognee-improve-sessions\ndescription: Use when working with cognee's session memory or improve() — storing conversation turns, agent traces and feedback with session_id, bridging sessions into the permanent graph, reading an ImproveResult, understanding why an improve stage was skipped, already_completed or lock_held, or tuning the IMPROVE_* settings.\n---\n\n# Session memory and improve()\n\ncognee has two kinds of memory:\n\n- **Session memory**: a fast cache of conversation turns, agent traces, and\n  feedback, keyed by `session_id`. Writing is instant, with no LLM\n  extraction.\n- **The permanent graph**: what `remember()` builds without a session.\n\n`improve()` connects them. It bridges session content into the graph and\nenriches the graph itself. `remember()` calls it automatically, so most\nusers never call it directly.\n\n```python\nimport cognee\n\n# Session write: returns immediately; improve() bridges it in the background\nawait cognee.remember(\"User prefers dark mode.\", session_id=\"chat_1\")\n\n# Session-aware query: session cache first, then the graph\nresults = await cognee.recall(\"What does the user prefer?\", session_id=\"chat_1\")\n\n# Bridge sessions into a dataset's graph explicitly\nresult = await cognee.improve(dataset=\"main_dataset\", session_ids=[\"chat_1\"])\nprint(result.status, result.stage_summary())\n\nawait cognee.wait_for_background_tasks()  # before a script exits\n```\n\n## Use it\n\n### Writing session memory\n\n| What | How |\n|---|---|\n| A fact or note | `remember(text, session_id=...)` (stored as a Q&A entry with the text as the answer) |\n| A Q&A turn | `recall(query, session_id=...)` with a completion search type saves the turn itself; or `remember(cognee.QAEntry(question=..., answer=...), session_id=...)` |\n| An agent step | `remember(cognee.TraceEntry(origin_function=..., status=\"success\", ...), session_id=...)`, or the `@cognee.agent_memory(save_session_traces=True)` decorator |\n| Pin a session to a project / node set | `node_set=[...]` on the first `QAEntry`/`TraceEntry` (or as a kwarg on any session `remember`) pins it; later writes repeat or omit it, a different set raises `cognee.SessionNodeSetConflictError` (HTTP 409). `improve()` keeps the set on everything it bridges, so `recall(node_name=[...])` scopes to the project |\n| Feedback on an answer | `remember(cognee.FeedbackEntry(qa_id=..., feedback_score=...), session_id=...)` or `cognee.session.add_feedback(session_id, qa_id, feedback_text=..., feedback_score=...)` |\n| Read a session | `cognee.session.get_session(session_id, last_n=...)` |\n\nRequirements: `CACHING=true` (default). The cache backend is\n`CACHE_BACKEND`, one of `sqlite` (default), `postgres`, `redis`, `fs`,\n`tapes`. Sessions expire after `SESSION_TTL_SECONDS` (default 7 days).\n\n### What improve() does: nine stages, in order\n\nEvery run goes through the same ordered stages\n(`cognee/modules/improve/registry.py`). Each stage checks a gate before it\nspends any LLM or embedding cost, and reports one `StageResult`.\n\n| # | Stage | What it does | Runs when |\n|---|---|---|---|\n| 1 | `feedback_weights` | Adjusts the weight of graph elements that rated answers used | `session_ids` given; adapter supports feedback weights |\n| 2 | `persist_session_qa` | Turns session Q&A into graph content (node set `user_sessions_from_cache`) | `session_ids` given. **The only fatal stage** |\n| 3 | `persist_agent_traces` | Turns agent-trace feedback into graph content | `session_ids` given |\n| 4 | `extract_agent_context` | Drafts agent-profile lessons from traces | `session_ids`, `CACHING` + `AUTO_FEEDBACK`, an LLM |\n| 5 | `distill_sessions` | Distills session learnings into the graph | `session_ids`, an LLM |\n| 6 | `update_user_preferences` | Folds rated turns into per-user preferences | `session_ids`, `PERSONALIZATION_ENABLED=true` (default false) |\n| 7 | `build_truth_subspace` | Builds the truth subspace from distilled learnings | `session_ids`, `build_truth_subspace=True`, a Ladybug graph |\n| 8 | `review_conflicts` | Reviews dated source facts, stores conflicts and rewrites Entity descriptions | `review_conflicts=True` or `IMPROVE_REVIEW_CONFLICTS=true`, an LLM, edge evidence |\n| 9 | `global_context_index` | Bucket and root summaries for global questions | `build_global_context_index=True`, an LLM |\n\nStages 1–7 need `session_ids`; 8–9 work on the graph alone. The order\nmatters: 4 feeds 5, 5 feeds 7, and 7 runs before 8.\n\n`extraction_tasks` / `enrichment_tasks` are deprecated and removed in the next\nrelease: they still run, as a `custom_tasks` stage after the others, scoped by\n`node_name`, `data`, `node_type`, `vector_db_config` and `graph_db_config`.\nWithout custom tasks those options are ignored. Both cases warn with a\n`FutureWarning`; use `run_custom_pipeline()` instead.\n\n### Reading the result\n\n`improve()` returns an `ImproveResult`, and so do `POST /api/v1/improve`, the\nCLI, and `RememberResult.improve`.\n\n- `result.status`: `completed`, `errored` (any stage errored), `skipped`\n  (every stage skipped), or `running` (background, not finished).\n- `result.stages`: one `StageResult` per stage, with `stage`, `status`\n  (`completed` / `already_completed` / `skipped` / `errored`), `reason`,\n  `error`, `counts`, `duration_ms`.\n- `result.stage(\"distill_sessions\")`, `result.stage_summary()`,\n  `result.lock_held`, `result.rerun_requested`, `result.rerun_passes`.\n- `await result.wait()` finishes a background run (no-op otherwise).\n\n**Skip and no-op reasons:**\n\n| Reason | Meaning / fix |\n|---|---|\n| `no_session_ids` | Session stage, no `session_ids` passed |\n| `disabled_by_config` | Listed in `IMPROVE_STAGES_DISABLED` |\n| `opt_in_disabled` | Pass `build_truth_subspace=True` / `review_conflicts=True` / `build_global_context_index=True` |\n| `personalization_disabled` | Set `PERSONALIZATION_ENABLED=true` |\n| `auto_feedback_disabled` | Stage 4 needs `CACHING=true` and `AUTO_FEEDBACK=true` |\n| `no_llm_configured` | Stages 4, 5, 8, 9 draft text with an LLM; none configured |\n| `edge_evidence_disabled` | Conflict review needs `EDGE_EVIDENCE_ENABLED=true` |\n| `backend_unsupported` | The graph adapter lacks the feature (feedback weights, truth subspace) |\n| `session_manager_unavailable` | The session cache is not reachable |\n| `lock_held` | Another improve for the same dataset or session is running (below) |\n| `aborted_by_fatal_stage` | Stage 2 failed, so the rest did not run |\n| `budget_exhausted` | An earlier stage failed because the LLM budget is exhausted (a 402); the rest would fail the same way. Top up, then run improve again |\n| `no_new_entries`, `no_new_trace_steps`, `no_new_facts`, `no_writes_since_last_improve` | With status `already_completed`: nothing new since the last run |\n\n### How remember() triggers improve\n\n- **Without a session:** `add`, then `cognify`, then a foreground `improve()`.\n  Its outcome is on `result.improve` / `result.improve_error`. A failed\n  improve never marks the remember as errored.\n- **With `session_id`:** the text is cached, then a background\n  `improve(dataset, session_ids=[session_id])` starts if the debounce allows\n  it. `result.improve` fills in only after `await result` or\n  `wait_for_background_tasks()`.\n- `self_improvement=False` turns it off per call; `IMPROVE_AUTO_ENABLED=false`\n  turns it off everywhere and overrides `self_improvement=True`.\n- An application embedding cognee can decline one automatic improve before it\n  starts: `cognee.modules.improve.register_auto_improve_admission(check)`\n  registers one async check that `remember()` awaits on both paths. Returning\n  a reason string skips the improve and sets `result.improve_skipped`\n  (`result.improve` stays `None`); the data is stored either way. A check that\n  raises allows the improve. Explicit `improve()` calls are never gated.\n\n### Settings (`IMPROVE_*`, `cognee/modules/improve/config.py`)\n\n| Env var | Default | Meaning |\n|---|---|---|\n| `IMPROVE_AUTO_ENABLED` | `true` | Automatic improve after `remember()` |\n| `IMPROVE_DEBOUNCE_ENTRIES` | `1` | Session auto-improve fires after this many new entries |\n| `IMPROVE_DEBOUNCE_SECONDS` | `0` | ...or this many seconds since the last one. Seconds alone (entries left at 1) means time-only |\n| `IMPROVE_STAGES_DISABLED` | empty | CSV of stage names to skip |\n| `IMPROVE_FEEDBACK_ALPHA` | `0.1` | Feedback learning rate, in (0, 1] |\n| `IMPROVE_REVIEW_CONFLICTS` | `false` | Review fact conflicts, including automatic improve |\n| `IMPROVE_EFFECTIVE_DATE_KEY` | `effective_date` | Document metadata key holding the source date |\n\nThere is no debounce timer: held-back entries wait for the next\n`remember()` with that session, or an explicit `improve()`.\n\n## Pitfalls\n\n- **A plain `improve(dataset)` often does nothing.** Without `session_ids`,\n  only stages 8–9 can run, and both are off by default. Result: every\n  stage `skipped`. That is expected, not an error.\n- **A session's node set is pinned once.** The first write carrying\n  `node_set` fixes it for the session; a different set is a 409, start a\n  new session instead. Bridged Q&A, traces and lessons carry the set, user\n  preferences never do. The guarantee holds within one worker process (an\n  in-process lock); with several workers, send a session's writes to one.\n  Example: `examples/guides/session_node_sets.py`.\n- **Typed entries do not auto-improve.** `remember(QAEntry/TraceEntry/\n  FeedbackEntry, session_id=...)` stores the entry but never starts an\n  improve. Call `improve(session_ids=[...])` yourself.\n- **`lock_held` does not wait.** Improves for the same dataset or session\n  run one at a time: a second call returns at once with every stage\n  `skipped: lock_held`. If it shares a session with the running one, it sets\n  `rerun_requested=True` and the holder runs up to 2 extra passes (3 passes\n  in total; see `rerun_passes`). The bound is `IMPROVE_MAX_RERUN_PASSES`, a\n  constant in `cognee/api/v1/improve/improve.py`, not an env var. The lock is per process only; multiple API workers do not\n  share it.\n- **Sessions bridge once.** Q&A and trace persistence are tracked per user\n  and session, not per dataset, so bridging a session into dataset A and\n  then into dataset B persists no new Q&A/traces into B. Distillation is\n  tracked per (session, dataset) and still runs into B.\n- **`IMPROVE_STAGES_DISABLED` is validated.** An unknown stage name, or\n  `persist_session_qa` (fatal, cannot be disabled), raises `ValueError`, and\n  the API server refuses to start.\n- **Session writes with the cache off.** `remember(text, session_id=...)`\n  with `CACHING=false` only logs a warning and stores nothing; typed entries\n  raise `RuntimeError`. An explicit `improve(session_ids=...)` then fails in\n  the fatal stage.\n- **Fatal stage failure.** If stage 2 errors, `improve()` raises (HTTP 409)\n  and the error carries `.improve_result`. In background mode it is recorded\n  on `result.error` instead. Other stages failing only mark themselves\n  `errored`; HTTP still returns 200, so check `status`.\n- **Remote mode.** After `cognee.serve(url)`, a background improve is\n  fire-and-forget: `status` stays `running` and there is no polling.\n- `cognee/modules/session_bridge/` is gone (only stale `__pycache__` may be\n  left). The bridging now lives in the improve stages; some test names still\n  say \"session_bridge\".\n\n## How it works\n\n`improve()` resolves the dataset once (creating it if the name is new),\nclaims the improve lock for `dataset:<id>` plus every\n`session:<user>:<session_id>`, probes the graph adapter's capabilities, and\nruns the stages with one frozen `ImproveRunInputs`. Each stage is a gate\nplus a call into existing pipelines plus a result mapping. Stages never own\nretries or ordering.\n\nWatermarks keep repeat runs cheap:\n\n- Session stages track how many entries were already persisted, per user\n  and session.\n- Conflict review uses its last succeeded stamp to select touched entities,\n  and retries conflicts with missing citations or pending writes. Source dates\n  come from document metadata; session windows use their last entry time.\n  Fixed attributes remain disputed even when one document is newer.\n\nThe improve operation row is written when the run finishes: `failed` if any\nstage errored (a retry is never gated off), `noop` if nothing ran.\n\n- Orchestrator: `cognee/api/v1/improve/improve.py` (HTTP:\n  `routers/get_improve_router.py`; CLI: `cognee/cli/commands/improve_command.py`)\n- Stages, registry, results: `cognee/modules/improve/` (`stages.py`,\n  `registry.py`, `stage.py`, `result.py`, `inputs.py`, `capabilities.py`,\n  `config.py`, `graph_changes.py`, `constants.py`)\n- Lock: `cognee/infrastructure/locks/session_lock.py`\n- Session store and watermarks: `cognee/infrastructure/session/`\n  (`session_manager.py`, `session_persist_watermark.py`,\n  `feedback_detection.py`); cache backends in\n  `cognee/infrastructure/databases/cache/`\n- Auto-improve from remember: `cognee/api/v1/remember/remember.py`,\n  `cognee/api/v1/remember/auto_improve_debounce.py`\n- Entry types: `cognee/memory/entries.py`\n- Background tasks: `cognee/infrastructure/background_tasks.py`\n\nExamples: `examples/guides/improve_quickstart.py`, `sessions.py`,\n`session_distillation.py`, `review_conflicts.py`, `global_context_index.py`,\n`agent_memory_quickstart.py`, and\n`examples/advanced_guides/remember_recall_improve_example.py`.\n\n## Extending it\n\nAdding a stage:\n\n1. Subclass `BaseStage` in `cognee/modules/improve/stages.py`. Set `name`,\n   `needs_sessions`, and `fatal` (leave it `False`; exactly one fatal stage\n   is enforced at import). Implement `gate()` (return a skip reason\n   constant, or `None`, before any LLM/embedding cost) and `run()` (call\n   existing pipeline code, return a `StageResult`).\n2. Insert it into `DEFAULT_STAGES` in `registry.py` at the right position.\n   The order is pinned by `cognee/tests/unit/modules/improve/test_registry_order.py`;\n   update it deliberately.\n3. If it can re-run cheaply, give it a watermark so a repeat run reports\n   `already_completed` (graph-wide stages can stamp the improve row with the\n   helpers in `graph_changes.py`, as conflict review does).\n4. Tests: `cognee/tests/unit/modules/improve/` (gates, results, config) and\n   `cognee/tests/unit/api/v1/improve/` (orchestration, rerun, router).\n\n<!-- File: .agents/skills/cognee-ingestion/SKILL.md (Tokens: ~2839 | Category: anthropic-skill) -->\n---\nname: cognee-ingestion\ndescription: Use when putting data into cognee memory with remember() — choosing inputs (text, files, folders, URLs, repos, databases), datasets and node_sets, loaders, ontologies, the graph extractor (LLM or GLiNER), chunking, dry-run cost estimates, or when remember() raises on a keyword argument.\n---\n\n# Ingest data with remember()\n\n`remember()` is cognee's ingestion API. One call stores the data, builds the\nknowledge graph, and enriches it. Use it for all ingestion; every option in\nthis skill is a `remember()` argument unless it says otherwise.\n\n```python\nimport cognee\n\nresult = await cognee.remember(\"Einstein was born in Ulm.\")  # text\nresult = await cognee.remember(\n    [\"./notes.md\", \"./report.pdf\"],  # files\n    dataset_name=\"research\",\n)\nprint(result.status, result.dataset_id)  # \"completed\", UUID\n```\n\nAll cognee functions are async. Without `dataset_name` data goes to\n`main_dataset`. Needs `LLM_API_KEY` unless you use the GLiNER extractor\n(below).\n\n## Use it\n\n### Inputs\n\n`data` accepts a string, a list of strings, file paths (absolute, `file://`,\n`s3://`), http(s) URLs, binary streams, or a list mixing them.\n\n- **URLs** are fetched and scraped (needs `ALLOW_HTTP_REQUESTS=true`, the\n  default).\n- **Folders** are ingested file by file. A folder that looks like a code\n  project, or a GitHub/GitLab URL, becomes one code repository (needs `git`\n  on PATH).\n- **Code files** (`.py`, `.ts`, `.go`, …) go down the code-graph route: a\n  deterministic graph, no LLM calls, searchable only with\n  `SearchType.CODE`. To index a whole repository explicitly, pass\n  `content_type=\"code\"`.\n- **Databases and dlt sources**: a SQL connection string, a dlt\n  `DltResource` / `DltSource`, or a CSV. dlt is a core dependency, so no\n  extra is needed (`cognee[dlt]` is an empty compatibility extra). Options: `primary_key` (default `\"id\"`),\n  `write_disposition` (`\"replace\"` default, or `\"append\"`), `query`,\n  `max_rows_per_table`.\n- **Skill playbooks** (`SKILL.md` files): `content_type=\"skills\"`; ingests\n  into the target dataset (default `main_dataset`), so pass `dataset_name`\n  to keep skills in their own dataset.\n\n### Where the data goes\n\n| Argument | What it does |\n|---|---|\n| `dataset_name` / `dataset_id` | Target dataset. `dataset_id` wins. A dataset is the unit of permissions and isolation. |\n| `node_set=[\"AI\", \"FinTech\"]` | Tags the data so recall can filter to it later with `recall(..., node_name=[\"AI\"])`. With `session_id` it pins the session's node set instead (first write wins, a different set later is a 409); `improve()` carries it into the graph. See the `cognee-improve-sessions` skill. |\n| `session_id=\"chat_1\"` | Writes to the fast session cache instead of the graph; `improve()` bridges it into the graph in the background. See the `cognee-improve-sessions` skill. Requires `CACHING=true`. |\n\n### How the graph is built\n\n| Argument | What it does |\n|---|---|\n| `extractor` | `\"llm\"` or `\"gliner_demo\"` (alias `\"gliner\"`). Default is `GRAPH_EXTRACTOR=auto`: the LLM when an API key is configured, otherwise GLiNER. |\n| `graph_model=MyModel` | Extract into your own DataPoint model instead of the generic `KnowledgeGraph`. See the `cognee-custom-graph-models` skill. |\n| `custom_prompt` | Replaces the entity-extraction prompt (ignored by GLiNER). |\n| `config={\"ontology_config\": {...}}` | Ground entities in an OWL ontology (below). |\n| `chunk_size`, `chunker` | Max tokens per chunk (default: derived from the embedding and LLM limits) and the chunker class (default `TextChunker`). |\n| `preferred_loaders` | Choose a loader per file type (below). |\n| `self_improvement` | Default `True`: runs `improve()` after the graph is built. Its outcome is on `result.improve` / `result.improve_error`; a failed improve never fails the remember. |\n| `run_in_background=True` | Returns immediately with `status=\"running\"`; `await result` to wait. |\n\n### Ontologies\n\n```python\nfrom cognee.modules.ontology.rdf_xml.RDFLibOntologyResolver import RDFLibOntologyResolver\n\nconfig = {\n    \"ontology_config\": {\n        \"ontology_resolver\": RDFLibOntologyResolver(ontology_file=\"./my.owl\"),\n        # \"ontology_mode\": \"strict\",   # drop entities with no ontology match\n    }\n}\nawait cognee.remember(texts, config=config)\n```\n\nOr set `ONTOLOGY_FILE_PATH` (plus `ONTOLOGY_MODE`, `MATCHING_STRATEGY`) in\n`.env`. `annotate` (default) only enriches; `strict` drops entities that\nmatch no ontology class or individual. It prunes only the graph, chunk text\nis still stored. Strict mode with an empty or missing ontology file is a hard\nerror. Over HTTP, upload the ontology to `/api/v1/ontologies` and pass its\n`ontology_key` to `POST /api/v1/remember`. Example:\n`examples/guides/ontology_quickstart.py`.\n\n### Loaders\n\nEach file is claimed by the first loader that accepts it. Default order:\ncode, text, pypdf, image, audio, video, dlt_csv, csv, unstructured,\nadvanced_pdf, docling. Names: `text_loader`, `code_loader`, `csv_loader`,\n`dlt_csv_loader`, `pypdf_loader`, `image_loader`, `audio_loader`,\n`video_loader`, `unstructured_loader`, `advanced_pdf_loader`,\n`docling_loader`, `beautiful_soup_loader`.\n\n```python\n# Treat a code file as a plain document (chunking + LLM extraction):\nawait cognee.remember(\"./script.py\", preferred_loaders={\"text_loader\": {}})\n```\n\nOffice formats (DOCX, PPTX, …) need the `docs` (unstructured) or `docling`\nextra. A preferred loader that is not installed is skipped with only an info\nlog, so check the extra is installed when a file comes out wrong.\n\n### Check the cost first\n\n`dry_run=True` returns a token and cost estimate without ingesting anything\nor calling the LLM. It excludes the calls `improve()` makes. Not supported\nwith GLiNER, sessions, or a remote instance.\n\n`dry_run=\"presort\"` on a folder returns a `PresortReport` (junk, duplicates,\nversion candidates, possible personal data, proposed dataset groups). Apply\nit with `await cognee.remember(report)`, or pass `auto_apply=True`.\n\n### Without an LLM: GLiNER\n\n`extractor=\"gliner\"` builds the graph and summaries with a local GLiNER2\nmodel, with no LLM call (embeddings still run). Install\n`pip install \"cognee[gliner]\"`; the model (about 750 MB) downloads on first use.\nIt cannot be combined with a custom `graph_model`, `dry_run`, `session_id`,\nor a remote instance.\n\n> **For production:** the open-source GLiNER extractor is a demo. cognee's\n> enterprise GLiNER extraction is more accurate and covers more labels. The\n> same goes for the Postgres graph adapter (`postgres_demo`). Contact\n> social@cognee.ai.\n\n## Pitfalls\n\n- **Unknown keyword arguments raise.** `remember()` forwards kwargs through\n  a fixed allow-list and raises `TypeError: Unexpected keyword arguments`\n  for anything else. These real options are not on it yet:\n\n  | Option | Workaround through remember() |\n  |---|---|\n  | `ontology_file_path` | `config={\"ontology_config\": ...}` or `ONTOLOGY_FILE_PATH` (above) |\n  | `chunk_attachment` | None yet. Only `cognee.cognify()` accepts it. |\n  | `extraction_rules` | Pass it through the loader: `preferred_loaders={\"beautiful_soup_loader\": {\"extraction_rules\": {...}}}` (works in `remember()` and `add()`). Needs the `scraping` extra: without it the loader is not registered and the rules are silently ignored |\n  | `tavily_config`, `soup_crawler_config` | Not honoured by `add()` or `remember()`; only the `cognee/tasks/web_scraper` tasks use them |\n  | `column_value_columns` (dlt) | None yet. Only `cognee.add()` accepts it. |\n\n  If a user needs one with no workaround, say so plainly: the option exists\n  on the lower-level `add()` / `cognify()` but not on `remember()` yet.\n- **Changed files raise `DocumentUpdateRequiredError`.** Re-remembering the\n  same path (or the same filename for an upload) with different content is\n  an update, not a new document. Use\n  `cognee.update(data_id=..., data=..., dataset_id=...)`, which re-extracts\n  only the changed chunks and keeps the document's id. Identical content is\n  a no-op.\n- **`content_type` is strict.** Only `None`, `\"skills\"`, or `\"code\"`.\n  `\"code\"` rejects `session_id` and needs repository paths or git URLs;\n  `\"skills\"` ingests into the target dataset like any other call (default\n  `main_dataset`); pass `dataset_name` to keep skills in their own dataset.\n- **Session mode needs `CACHING=true`**, and `extractor` cannot be combined\n  with `session_id`.\n- **Remote mode.** After `cognee.serve(url)`, calls go to the server:\n  `extractor` and `session_ids` raise, and other options the client does not\n  forward (including `graph_model`, `node_set`, and ontology `config`) are\n  dropped without an error.\n- **Every remember runs `improve()`** unless `self_improvement=False` or\n  `IMPROVE_AUTO_ENABLED=false`. In scripts, call\n  `await cognee.wait_for_background_tasks()` before exiting.\n\n## How it works\n\n`remember(data)` runs `add()` (store raw data and create `Data` rows), then\n`cognify()` (classify documents, chunk, extract the graph and summaries,\nstore in graph and vector DBs), then `improve()`. `remember(data,\nsession_id=...)` writes to the session cache instead.\n\n- Entry point and kwarg routing: `cognee/api/v1/remember/remember.py`\n  (`RememberKwargs`, `_ADD_ONLY` / `_COGNIFY_ONLY` / `_SHARED`)\n- Storage: `cognee/api/v1/add/add.py`, `cognee/tasks/ingestion/ingest_data.py`\n- Graph build: `cognee/api/v1/cognify/cognify.py`,\n  `cognee/tasks/graph/extract_graph_from_data.py`,\n  `cognee/tasks/storage/add_data_points.py`\n- Extractor choice: `cognee/modules/cognify/config.py:resolve_extractor`;\n  GLiNER package: `cognee/tasks/graph/gliner_demo/`\n- Ontologies: `cognee/modules/ontology/`\n- Loaders: `cognee/infrastructure/loaders/` (`supported_loaders.py`,\n  `LoaderEngine.py`)\n- dlt: `cognee/tasks/ingestion/resolve_dlt_sources.py`\n\nExamples in `examples/guides/`: `simple_cognee_example.py`,\n`nodeset_grouping_example.py`, `ontology_quickstart.py`,\n`gliner_demo_llm_free_cognify.py`, `no_llm_remember_recall.py`,\n`temporal_recall.py`, `presort_downloads.py`,\n`web_url_content_ingestion_example.py`, `code_graph_example.py`.\n\n## Extending it\n\n- **New remember() option:** add it to `RememberKwargs` and to the matching\n  routing set in `remember.py`. An option on `add()`/`cognify()` that is not\n  in a routing set raises `TypeError` from `remember()`.\n- **New loader:** implement `LoaderInterface`\n  (`cognee/infrastructure/loaders/LoaderInterface.py`), register it in\n  `supported_loaders.py` (extras-gated loaders go under `external/`), and\n  add it to the priority list in `LoaderEngine.py` if it should run by\n  default.\n- **New cognify task:** see the `cognee-custom-pipelines` skill and\n  `cognee/tasks/README.md`.\n\n<!-- File: .agents/skills/cognee-install/SKILL.md (Tokens: ~1038 | Category: anthropic-skill) -->\n---\nname: cognee-install\ndescription: Use when the user wants to install cognee and run their first remember → recall flow with the Python SDK — fresh setup, virtual env, extras selection, or a minimal working example.\n---\n\n# Install and run cognee\n\n## Install\n\nRequires Python 3.10–3.14. Prefer uv:\n\n```bash\nuv venv && source .venv/bin/activate\nuv pip install cognee            # from PyPI\n# or, working inside this repo:\nuv pip install -e .\n```\n\nAdd extras only when needed — examples: `cognee[postgres]`, `cognee[neo4j]`,\n`cognee[docling]` (office/HTML document parsing, slim), `cognee[docs]`\n(unstructured), `cognee[anthropic]`, `cognee[ollama]`, `cognee[aws]`. The full\nlist is in `pyproject.toml` under `[project.optional-dependencies]`.\n\n## Configure\n\nThe only required setting is an LLM API key. Create `.env` in the working\ndirectory (or export the variable):\n\n```bash\nLLM_API_KEY=\"your_openai_api_key\"\n```\n\nDefaults need no services: SQLite (relational), LanceDB (vector), and Ladybug\n(graph), all stored locally. OpenAI is the default LLM and embedding provider —\nif you configure a different LLM but not embeddings (or vice versa), the other\nsilently stays on OpenAI. For other providers and databases use the\ncognee-integrations skill.\n\n## First run\n\nAs of cognee 1.x the memory API — `remember`, `recall`, `forget`, `improve` —\nis the primary surface. All SDK functions are async. Minimal end-to-end script:\n\n```python\nimport asyncio\nimport cognee\n\n\nasync def main():\n    await cognee.remember(\"Cognee turns documents into AI memory.\")\n    results = await cognee.recall(\"What does cognee do?\")\n    print(results)\n\n\nasyncio.run(main())\n```\n\n`remember()` is the whole ingestion path in one call — it runs `add()` +\n`cognify()`, then `improve()` to index the graph (`self_improvement=True` by\ndefault). It accepts text, file paths, URLs, and binary streams, with an\noptional `dataset_name=\"my_project\"`; pass `datasets=[\"my_project\"]` to\n`recall()` to stay inside one dataset.\n\n`recall()` auto-routes the query to a search strategy by default. Pass\n`query_type=SearchType.CHUNKS` (etc.) to pin one, or `auto_route=False` to\nfall back to `GRAPH_COMPLETION`.\n\nSession memory is the other half of the API — `remember(..., session_id=\"chat_1\")`\nwrites to a fast session cache rather than running add+cognify inline, and\n`recall(..., session_id=\"chat_1\")` reads it back (session hits short-circuit the\ngraph search). With the default `self_improvement=True` it still bridges that\ndata into the permanent graph in the background; `improve(dataset=...,\nsession_ids=[...])` does the same explicitly. Session memory runs on the\nsession cache, which is on by default (`CACHING=true`); setting\n`CACHING=false` disables it entirely and makes `remember(session_id=...)`\nraise.\n\nStart with `examples/advanced_guides/remember_recall_improve_example.py`, which walks\nthrough permanent memory, session memory, and the sync between them.\n\nThe `add()` / `cognify()` / `search()` primitives still exist and\nare what `remember`/`recall`/`improve` call underneath — reach for them when you\nneed to drive a stage in isolation (e.g. custom pipeline tasks), not for\nordinary ingestion. `cognee.delete` is formally deprecated (since 0.3.9);\n`forget()` is the v1 replacement, unifying the old delete/empty_dataset\npaths behind one call. When to use `recall()` versus the low-level `search()`\nis covered in `docs/recall-vs-search.md`.\n\n## Verify / troubleshoot\n\n- `cognee-cli remember \"hello\" && cognee-cli recall \"hello\"` exercises the same\n  flow from the shell.\n- To wipe local state during experiments: `cognee-cli forget --all` (or\n  `await cognee.forget(everything=True)`).\n- Reads slow or spending tokens on every query → set `AUTO_FEEDBACK=false`\n  (keep `CACHING=true`); by default cognee makes one structured-output LLM\n  call per answered query to self-tune its memory.\n- Structured LLM output errors usually mean the model/provider needs an\n  explicit instructor mode: `LLM_INSTRUCTOR_MODE=\"json_schema_mode\"`.\n\n<!-- File: .agents/skills/cognee-integrations/SKILL.md (Tokens: ~1099 | Category: anthropic-skill) -->\n---\nname: cognee-integrations\ndescription: Use when the user wants to connect cognee to external services — switching LLM or embedding providers (OpenAI, Azure, Gemini, Anthropic, Ollama, OpenRouter), changing databases (Postgres, PGVector, Neo4j, Neptune, Turso), S3 storage, or the MCP server for IDE integration.\n---\n\n# Set up cognee integrations\n\nAll integration config is environment variables (`.env`). The authoritative,\nalways-current list with commented examples is `.env.template` at the repo\nroot — check it before inventing variable names. Install the matching extra\nbefore switching a backend (e.g. `pip install cognee[postgres]`).\n\n## LLM providers\n\nDefault is OpenAI (`LLM_API_KEY` is all you need). To switch, set\n`LLM_PROVIDER`, `LLM_MODEL`, `LLM_API_KEY`, and (where relevant)\n`LLM_ENDPOINT` / `LLM_API_VERSION`:\n\n- **Azure OpenAI**: `LLM_PROVIDER=azure`, `LLM_MODEL=azure/gpt-4o-mini`, endpoint + api version required.\n- **Gemini** (no extra needed): `LLM_PROVIDER=gemini`, `LLM_MODEL=gemini/gemini-2.0-flash-exp`.\n- **Anthropic** (`cognee[anthropic]`): `LLM_PROVIDER=anthropic`, model e.g. `claude-3-5-sonnet-20241022`.\n- **Ollama, local** (`cognee[ollama]`): `LLM_PROVIDER=ollama`, `LLM_ENDPOINT=http://localhost:11434/v1`, and set the embedding block + `HUGGINGFACE_TOKENIZER` too.\n- **Custom / OpenRouter / vLLM**: `LLM_PROVIDER=custom` with the provider's OpenAI-compatible endpoint.\n- **AWS Bedrock** (`cognee[aws]`): `LLM_PROVIDER=bedrock` + AWS credentials/region.\n\n**The classic trap**: LLM and embeddings are configured independently\n(`EMBEDDING_PROVIDER`, `EMBEDDING_MODEL`, `EMBEDDING_ENDPOINT`,\n`EMBEDDING_API_KEY`). Configuring only one leaves the other on OpenAI —\neither keep a valid OpenAI key or configure both.\n\n## Databases\n\n- **Relational** (`DB_PROVIDER`): sqlite (default) or postgres\n  (`cognee[postgres]`; host/port/user/password/name via `DB_*` vars).\n- **Vector** (`VECTOR_DB_PROVIDER`): lancedb (default), pgvector\n  (`cognee[postgres]`, needs `VECTOR_DB_URL`), neptune_analytics\n  (`cognee[neptune]`), turso (`cognee[turso]`). Anything else (ChromaDB,\n  Qdrant, Weaviate, Milvus, …) lives in community adapters — install from\n  https://github.com/topoteretes/cognee-community and register with\n  `use_vector_adapter` before use; setting `VECTOR_DB_PROVIDER` alone raises\n  \"Unsupported vector database provider\".\n- **Graph** (`GRAPH_DATABASE_PROVIDER`): ladybug (default), neo4j\n  (`cognee[neo4j]`, bolt URL + credentials), neptune (`cognee[neptune]`),\n  ladybug-remote, postgres (no raw Cypher / natural-language search).\n\nThe repo `docker-compose.yml` ships ready-to-use `postgres` (pgvector) and\n`neo4j` profiles with matching default credentials. From a container, reach\nhost services with `DB_HOST=host.docker.internal`.\n\n## Storage, cache, and the rest\n\n- **S3 storage** (`cognee[aws]`): `STORAGE_BACKEND=s3` + bucket/credentials,\n  and point `DATA_ROOT_DIRECTORY`/`SYSTEM_ROOT_DIRECTORY` at `s3://` paths.\n- **Session cache**: `CACHE_BACKEND` = sqlite (default) | postgres | redis | fs | tapes.\n- **Ontologies**: `ONTOLOGY_FILE_PATH` to an OWL file, resolver/matching via\n  `ONTOLOGY_RESOLVER` / `MATCHING_STRATEGY`.\n\n## MCP server (IDE integration)\n\n`docker compose --profile mcp up` starts the MCP server on port 8001\n(Streamable HTTP at `http://localhost:8001/mcp`), built from `cognee-mcp/`. Point Cursor / Claude Desktop /\nClaude Code at it to use cognee memory from the IDE. Configure its `DB_*` env\nto match the main service so both see the same data.\n\n## After changing providers mid-project\n\nEmbeddings from different models are not comparable — after switching the\nembedding provider or model, reset local state (`cognee-cli forget --all` or\n`await cognee.forget(everything=True)`) and re-ingest with `remember()`.\n\nTo drop just the graph and vectors while keeping the ingested files, use\n`await cognee.forget(dataset=\"my_project\", memory_only=True)` — the dataset can\nthen be rebuilt under the new embedding model without re-uploading anything.\n\n<!-- File: .agents/skills/cognee-migrations/SKILL.md (Tokens: ~2677 | Category: anthropic-skill) -->\n---\nname: cognee-migrations\ndescription: Use when dealing with cognee database migrations — understanding when they run automatically, checking or repairing migration state with cognee-cli upgrade/downgrade/stamp/current, a write blocked by a failed migration, authoring a new Alembic (relational schema) revision or a graph/vector data migration, or moving data between systems (relational DB import, memory export/import).\n---\n\n# Database migrations\n\ncognee has **two migration chains**, run together:\n\n| Chain | Changes | Lives in | Revision stored in |\n|---|---|---|---|\n| **Relational schema** (Alembic) | Tables and columns of the relational DB (users, datasets, ACLs, pipeline runs, …) | `cognee/alembic/` (`alembic.ini` is in `cognee/`) | `alembic_version` table |\n| **Graph/vector data** | Cross-store data rewrites (re-keying node ids, adding graph columns) across graph DB, vector DB and relational ledger | `cognee/modules/migrations/` (`registry.py`, `versions/`) | Per dataset: `dataset_database.migration_revision` (access control on). Globally: `global_database_version.global_migration_revision` (access control off) |\n\n## Use it\n\n### They run by themselves\n\n`run_migrations()` applies the relational chain first, then the data chain.\nIt runs:\n\n- at API server startup (and in the Docker `entrypoint.sh` before gunicorn);\n- on the first write in an SDK or CLI process (`remember`, `add`, `cognify`,\n  `improve`, memory imports), once per process;\n- when you call `await cognee.run_migrations()`.\n\nA fresh database is built by running the whole chain (no stamping). At\nhead, the first run in each process still does a no-op Alembic upgrade plus\na scan of the per-database revision rows; later calls in the same process\nare skipped by an in-memory flag. `ENABLE_AUTO_MIGRATIONS=false`\nturns off all automatic runs; then run `cognee-cli upgrade` yourself.\n\nConcurrent processes are serialized by a migration lock: a Postgres advisory\nlock (works across hosts) or a file lock next to the SQLite DB (one host\nonly).\n\n### Check and repair\n\n```bash\ncognee-cli current                   # stamped revision per database, and the last failure\ncognee-cli history                   # the data chain, newest first\ncognee-cli upgrade                   # relational to head, then data chain to head\ncognee-cli upgrade <slug>            # data chain up to and including <slug>\ncognee-cli upgrade --alembic <rev>   # pin the relational target\ncognee-cli downgrade <slug|base> [--dataset UUID ...] [--alembic REV] [--force]\ncognee-cli stamp <head|base|slug> [--dataset UUID ...] [--force]\n```\n\n- The positional revision is always a **data-chain slug**; relational\n  targets go through `--alembic`.\n- `downgrade` rewrites data and asks for confirmation. It only reverts\n  spans where every migration defines a `down()`, and leaves the relational\n  schema alone unless you pass `--alembic`.\n- `stamp` changes only the stored data-chain revision, without running\n  anything. Use `stamp base --dataset <id>` and then `upgrade` when a\n  database's data drifted from its stamp (for example after restoring a\n  backup); the chain is idempotent and converges it.\n- `upgrade` runs even with `ENABLE_AUTO_MIGRATIONS=false`.\n\n### A write is blocked\n\nIf a dataset's data migration failed, writes to that dataset are refused\nuntil it succeeds (with access control off, any failure blocks all writes).\nThe server still starts. Run `cognee-cli current` to see the error, fix the\ncause, then `cognee-cli upgrade`. A failed run is retried on the next start\nor write.\n\n### Moving data between systems (not schema migrations)\n\n| Goal | Use |\n|---|---|\n| Turn an existing relational database into a graph | `migrate_relational_database(graph_db, schema)` (`cognee/tasks/ingestion/migrate_relational_database.py`), with the source DB set by `MIGRATION_DB_PROVIDER` / `_PATH` / `_NAME` / `_HOST` / `_PORT` / `_USERNAME` / `_PASSWORD`. Examples: `examples/demos/ingestion_and_migration/` |\n| Back up a dataset, or move it to another cognee instance | A COGX archive, see below |\n| Export a dataset's graph for other tools | `await cognee.export(dataset, format=...)`: `\"json\"`, `\"graphml\"` or `\"cypher\"` write a file (one way: cognee can't import them back); `\"pydantic\"` (default) returns typed DataPoint objects in memory |\n| Import from another memory system (Mem0, Zep/Graphiti, Letta, LangMem) | Build a `MemorySource` (`cognee/modules/migration/sources/`) and pass it to `await cognee.remember(source, dataset_name=...)` |\n\nThere is no tool that moves a whole deployment from one database backend to\nanother.\n\n#### COGX archives\n\nCOGX (Cognee eXchange, `cognee/modules/migration/cogx.py`) is cognee's\nportable memory format and the only export format cognee can import back.\nAn archive is a directory with a `manifest.json` (COGX version, source\nsystem, the dataset's data-migration revision) and one JSONL file per record\nkind (`documents`, `episodes`, `entities`, `facts`, `memories`,\n`memory_blocks`), plus `nodes.jsonl` with the raw graph nodes. The Mem0,\nZep, Letta and LangMem importers also translate into COGX records first.\n\nUse it to back up and restore a dataset, or to copy one to another cognee\ninstance:\n\n```python\nfrom cognee.migration import COGXArchiveSource\n\nawait cognee.export(\"my_dataset\", format=\"cogx\", destination=\"backup_cogx\")\nawait cognee.remember(COGXArchiveSource(\"backup_cogx\"), dataset_name=\"my_dataset\")\n```\n\n- A restore defaults to `mode=\"preserve\"`: the archived graph is written\n  back as-is, with no LLM calls. `mode=\"hybrid\"` also re-cognifies the raw\n  content; `mode=\"re-derive\"` ignores the archived graph and extracts again\n  (costs LLM tokens).\n- `cognee.push()` / `cognee-cli push` does the same to Cognee Cloud: it\n  exports to COGX, packs it as a `.cogx.tar.gz` and uploads it, and the\n  receiving instance restores it (preserve mode unless you pass `mode=`).\n- `export(..., include_permissions=True)` also writes `permissions.json`\n  with the dataset owner and ACL grants, **including password hashes**, so\n  the restore recreates working accounts. Treat that archive as a secret.\n- An archive written by a newer major COGX version is rejected with a\n  `ValueError`; upgrade cognee on the importing side.\n\n## Pitfalls\n\n- **Never regenerate `cognee/alembic/frozen_schema.py`.** It is the\n  certified base schema the initial revision builds from, pinned by\n  `cognee/tests/unit/test_frozen_schema_seal.py`. Schema changes ship as\n  new revisions at head.\n- **Never hand-type an Alembic revision id.** Hand-typed patterns\n  (`a1b2c3d4e5f6`, …) already collided with a downstream chain that vendors\n  this one (`b2c3d4e5f6a7`). Generate ids with `alembic revision`.\n- **Never rename, remove, or reorder a data-chain entry.** The slug is what\n  deployed databases store; an unknown stored slug disables the chain for\n  that database.\n- **A model change and its migration land together.** CI's \"Migration/Model\n  Lockstep Guard\" fails otherwise.\n- **The relational schema cannot be downgraded below the data-bookkeeping\n  revisions** unless the data chain goes to `base` in the same call.\n- `alembic.ini` is always the packaged one; `COGNEE_ALEMBIC_PATH` or\n  `--alembic-path` only changes the scripts directory (for vendored chains).\n\n## How it works\n\n`run_migrations()` (`cognee/modules/migrations/startup.py`) takes the\nmigration lock, decides fresh vs existing (a `users` or `alembic_version`\ntable exists), runs Alembic in-process on a worker thread, then walks the\ndata chain per database with `runner.run_database_migrations`, stamping\nafter every step. After the chain, it syncs vector-adapter storage when the\nrecorded `cognee_version` differs from the library's\n(`versions/adapter_storage_migration.py`, not a chain entry).\n\n- Relational: `cognee/alembic.ini`, `cognee/alembic/env.py`,\n  `cognee/alembic/versions/`, `cognee/alembic/frozen_schema.py`\n- Data chain: `cognee/modules/migrations/` (`README.md` is the authoring\n  contract; `registry.py`, `migration.py`, `runner.py`, `startup.py`,\n  `versions/`)\n- CLI: `cognee/cli/commands/migrate_command.py`\n\n## Extending it\n\n### A new Alembic revision\n\n```bash\ncd cognee                              # the directory with alembic.ini\nuv run alembic revision -m \"add foo to data\"\n```\n\nThe DB URL comes from the live relational engine, so your normal `.env`\nsettings apply. Follow the recent revisions (for example\n`versions/e7f9a1c3d5b8_add_data_dataset_created_index.py`):\n\n- **Idempotent and guarded:** inspect first (`sa.inspect(op.get_bind())`)\n  and skip when the table is missing or the column/index already exists.\n- **Branch on dialect** (`conn.dialect.name == \"postgresql\"`) for\n  Postgres-only SQL. For Postgres enums use `postgresql.ENUM(...,\n  create_type=False)` and create the type up front with `checkfirst`.\n- **SQLite cannot drop or alter columns in place:** use\n  `op.batch_alter_table(...)`.\n- **Indexes:** plain `CREATE INDEX IF NOT EXISTS` inside the migration\n  transaction, not `CONCURRENTLY` (which releases the version-row lock and\n  lets concurrent workers into the same build). Repair invalid Postgres\n  indexes via `pg_index.indisvalid`.\n- A new model module outside the usual import path must be imported in\n  `cognee/alembic/env.py`, or autogenerate will not see it.\n\n### A new data migration\n\nRead `cognee/modules/migrations/README.md` first. In short:\n\n1. Write a module in `cognee/modules/migrations/versions/` with\n   `async def migrate(context)` (and optionally `async def downgrade(context)`);\n   step 2 registers them as `up=` / `down=`.\n2. Append `Migration(slug=..., cognee_version=..., up=..., down_revision=<previous slug>, down=...)`\n   to `MIGRATIONS` in `registry.py`. The chain is validated at import\n   (linear, unique slugs).\n3. Make it idempotent and cheap on empty stores, and crash-safe: re-key\n   derived stores (vectors, ledger) first and rename in the graph last.\n4. Freeze private copies of any logic you depend on; never import live\n   models that may change later.\n\n### Tests\n\n- `cognee/tests/e2e/migrations/test_migration_model_lockstep.py` (+\n  `schema_baseline.json`): the lockstep CI job.\n- `cognee/tests/unit/test_run_migrations.py`: single Alembic head, startup\n  behaviour.\n- `cognee/tests/unit/test_frozen_schema_seal.py`: frozen schema fingerprint.\n- `cognee/tests/unit/modules/migrations/`: data-chain unit tests.\n- `cognee/tests/migrations/test_migration_lockstep.py`: data chain against\n  real stores (seed, down, up, verify).\n\n<!-- File: .agents/skills/cognee-performance/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# cognee-performance\n\nPath: `.agents/skills/cognee-performance/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-performance/SKILL.md)\n\n<!-- File: .agents/skills/cognee-permissions/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# cognee-permissions\n\nPath: `.agents/skills/cognee-permissions/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-permissions/SKILL.md)\n\n<!-- File: .agents/skills/cognee-recall/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# cognee-recall\n\nPath: `.agents/skills/cognee-recall/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-recall/SKILL.md)\n\n<!-- File: .agents/skills/cognee-server/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# cognee-server\n\nPath: `.agents/skills/cognee-server/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/cognee-server/SKILL.md)\n\n<!-- File: .agents/skills/company-brain-company-qa/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# company-brain-company-qa\n\nPath: `.agents/skills/company-brain-company-qa/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/company-brain-company-qa/SKILL.md)\n\n<!-- File: .agents/skills/company-brain-follow-up-agent/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# company-brain-follow-up-agent\n\nPath: `.agents/skills/company-brain-follow-up-agent/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/company-brain-follow-up-agent/SKILL.md)\n\n<!-- File: .agents/skills/personalized-email/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# personalized-email\n\nPath: `.agents/skills/personalized-email/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/personalized-email/SKILL.md)\n\n<!-- File: .agents/skills/self-hosted-companion/SKILL.md (Tokens: ~300 | Category: anthropic-skill) -->\n# self-hosted-companion\n\nPath: `.agents/skills/self-hosted-companion/SKILL.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/.agents/skills/self-hosted-companion/SKILL.md)\n\n<!-- File: catalog/entries/packages/qdrant.yaml (Tokens: ~300 | Category: anthropic-skill) -->\n# Packages Skill\n\nPath: `catalog/entries/packages/qdrant.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/catalog/entries/packages/qdrant.yaml)\n\n<!-- File: catalog/entries/packages/weaviate.yaml (Tokens: ~300 | Category: anthropic-skill) -->\n# Packages Skill\n\nPath: `catalog/entries/packages/weaviate.yaml`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/catalog/entries/packages/weaviate.yaml)\n\n<!-- File: cognee/skill.md (Tokens: ~5025 | Category: anthropic-skill) -->\n---\nname: cognee\ndescription: >\n  Use this skill whenever the user asks about Cognee, AI memory, persistent agent memory,\n  self-improving agents, agents learning from feedback, knowledge graphs, graph-based RAG,\n  long-term memory for agents, short-term memory for agents, personalization, personas,\n  temporal search, temporal knowledge graphs, ontology-based extraction, ontology grounding,\n  feedback, Cypher search, natural-language graph search, chunk search, RAG search, cross-session memory,\n  session feedback, feedback loops, session based memory, redis based memory, knowledge promotion.\n  Also use when the user describes the workflow such as:\n  \"turn documents into a knowledge graph\", \"build memory from files\", \"search my graph\",\n  \"extract entities and relations\", \"sync data into a graph\", \"update graph memory\",\n  \"store memories for an agent\", \"help my agent learn over time\", \"visualize a knowledge\n  graph built from documents\", \"let the agent learn\", \"adaptive agents\", \"personalized agents\",\n  \"session based personalization\", \"find important ontologies\", \"find custom pydantic models\",\n  \"isolate agentic behaviour\", \"add permission control to retrieval\", \"reduce context bloating\".\n---\n\n# Cognee\n\nUse this skill for **Cognee-specific Python API help** and for mapping user goals to the right\nCognee workflow.\n\n## When to apply this skill\n\nApply this skill whenever the user wants to do any of the following with Cognee:\n\n- ingest text, files, URLs, repos, or datasets\n- build or rebuild a knowledge graph\n- search documents, chunks, summaries, triplets, or graph context\n- choose a `SearchType`\n- enrich an existing graph with `improve`\n- define custom graph extraction models or `DataPoint` types\n- run custom task pipelines\n- configure LLM, graph DB, vector DB, or storage settings\n- tag and scope memory with `node_set` / NodeSets\n- build persistent memory for agents across sessions\n- create feedback loops or self-improving agent workflows\n- work with temporal extraction, ontologies, Cypher, or natural-language graph queries\n- manage datasets, sessions, feedback, deletion, updates, or visualization\n\nIf the user's intent is \"store information in memory and query it later\", prefer Cognee's\nmemory API: **remember -> recall** (plus **improve** to enrich and **forget** to delete).\n\n## Core workflow\n\n```python\nimport cognee\n\n# Store: ingest + build the graph (+ improve, because self_improvement=True by default)\nawait cognee.remember(\n    \"Your text, file path, URL, or list of inputs\",\n    dataset_name=\"main\",\n)\n\n# Query: recall picks a search strategy automatically (rule-based, no LLM call)\nresults = await cognee.recall(\"What are the key insights?\", datasets=[\"main\"])\nfor r in results:\n    print(r.source, r)  # each result is tagged \"graph\" / \"session\" / ...\n```\n\n`remember()` runs `add()` + `cognify()` and then `improve()` underneath. `recall()` wraps\n`search()` and adds routing, session memory as a source, and `source`-tagged results.\n\n## Default guidance\n\nWhen helping with Cognee:\n\n1. Start with the **simplest working path** unless the user explicitly asks for advanced\n   configuration.\n2. Prefer the memory API:\n   - `remember(...)` to store (ingest + graph build)\n   - `recall(...)` to query\n   - `improve(...)` to enrich or index an existing graph, and to bridge sessions into it\n   - `forget(...)` to delete\n3. Treat Cognee APIs as **async**.\n4. Use `dataset_name` / `datasets` to keep work organized when the user has multiple sources.\n5. Use `node_set` when the user wants lightweight tagging, project scoping, per-user memory\n   buckets, or subgraph filtering.\n6. Pass `query_type=SearchType.X` to `recall()` only when the user needs a specific strategy;\n   otherwise let it route.\n7. Recommend advanced features only when they match the task:\n   - `session_id` for fast short-term memory and conversation continuity\n   - `graph_model=` for schema-shaped extraction, `DataPoint` types for direct insertion\n   - `extractor=\"gliner_demo\"` for LLM-free graph extraction\n   - custom pipelines for non-default task orchestration\n   - feedback loops for retrieval improvement\n   - visualization tools for graph inspection\n\n## When to drop to the low-level operations\n\n`add()`, `cognify()` and `search()` still ship; the memory API calls them. Reach for\nthem only when `remember`/`recall` cannot express the job:\n\n- `cognify(datasets=[\"a\", \"b\"])` or `datasets=None` processes several datasets at once;\n  `remember()` always targets exactly one dataset.\n- Rebuilding a graph over data already in the DB (after `forget(memory_only=True)`, or with a\n  new `graph_model` / ontology) is `cognify()` only; `remember()` always runs `add()` first.\n- `search()` takes the agentic extras as first-class parameters (`skills`, `tools`, `max_iter`,\n  `code_query`, `node_type`) and returns raw `SearchResult` objects instead of tagged dicts.\n- `add()` is a staging area: use it to ingest now and `cognify()` later.\n- `prune.prune_system(metadata=True)` also drops the relational DB (users, ACLs, dataset\n  registry); `forget()` never touches those. Use prune only for full test teardown.\n\n`cognee.delete()` is deprecated in favour of `forget()`. Full comparison of the two query\nfunctions: `docs/recall-vs-search.md`.\n\n## Common tasks\n\n### Store data\n\n`remember()` accepts text, file paths, URLs, directories, git repository URLs, binary streams,\nor lists of these.\n\n```python\nawait cognee.remember(\"notes.md\", dataset_name=\"research\")\nawait cognee.remember(\"https://example.com\", dataset_name=\"research\")\nawait cognee.remember([\"paper.pdf\", \"summary.txt\"], dataset_name=\"research\")\n```\n\nUse `node_set` when the user wants data grouped into logical memory buckets.\n\n```python\nawait cognee.remember(\n    \"Customer prefers concise weekly summaries and Slack delivery.\",\n    dataset_name=\"customer_success\",\n    node_set=[\"preferences\", \"customer_123\", \"weekly_reports\"],\n)\n```\n\nUseful options:\n\n```python\nawait cognee.remember(\n    \"...\",\n    dataset_name=\"research\",\n    self_improvement=False,  # skip the improve() stage (faster)\n    run_in_background=True,  # return immediately; poll the pipeline status\n    chunk_size=1024,\n    custom_prompt=\"Extract companies, products, and partnerships.\",\n    extractor=\"gliner_demo\",  # LLM-free extraction; needs cognee[gliner]\n    dry_run=True,  # estimate LLM tokens/cost without ingesting\n)\nawait cognee.remember(\"./my_repo\", dataset_name=\"code\")  # code graph, no LLM\nawait cognee.remember(\"./skills\", dataset_name=\"ops\", content_type=\"skills\")  # SKILL.md playbooks\n```\n\n### Query memory\n\n```python\nfrom cognee import SearchType\n\nresults = await cognee.recall(\"What changed in Q1 2024?\", datasets=[\"research\"], top_k=10)\n\n# Pin a strategy when the user needs one\nresults = await cognee.recall(\n    \"What changed in Q1 2024?\",\n    query_type=SearchType.TEMPORAL,\n    datasets=[\"research\"],\n)\n\n# Answers with evidence, or validated into a Pydantic model\nresults = await cognee.recall(\"...\", include_references=True)\nresults = await cognee.recall(\"...\", response_model=MyAnswerModel)\n\n# Retrieval context only, no LLM completion (pin query_type here)\ncontext = await cognee.recall(\"...\", query_type=SearchType.GRAPH_COMPLETION, only_context=True)\n```\n\n### Scope retrieval with NodeSets\n\nUse NodeSets when the user wants to search only a subset of memory such as one project, one\ncustomer, one user, or one workflow.\n\n```python\nresults = await cognee.recall(\n    \"What are this customer's reporting preferences?\",\n    datasets=[\"customer_success\"],\n    node_name=[\"preferences\", \"customer_123\"],\n)\n```\n\n### Enrich an existing graph\n\nUse `improve()` when the user wants to improve or extend an already-built graph without\nre-ingesting. Without `session_ids` it runs only the graph-wide stages (opt-in conflict review\nand global context indexing); with them it also applies feedback weights, persists session Q&A,\nand distills session lessons into the graph.\n\n```python\nawait cognee.improve(dataset=\"research\")\nawait cognee.improve(dataset=\"research\", session_ids=[\"chat_1\"])\nawait cognee.improve(dataset=\"research\", build_global_context_index=True)\n```\n\n### Delete data\n\n`forget()` is the single deletion entry point.\n\n```python\nawait cognee.forget(data_id=data_id, dataset_id=dataset_id)  # one document\nawait cognee.forget(dataset=\"research\")  # a dataset: raw data + graph + vectors\nawait cognee.forget(dataset=\"research\", memory_only=True)  # graph + vectors only, keep raw files\nawait cognee.forget(everything=True)  # everything the current user owns\n```\n\n### Update a document in place\n\n```python\nawait cognee.update(data_id=data_id, data=\"Updated content\", dataset_id=dataset_id)\n```\n\nThe document keeps its `data_id`; only the chunks the edit touched are re-extracted.\n\n### Create domain-specific structures\n\nPass a `DataPoint`-derived Pydantic model as `graph_model` and the LLM fills it instead of the\ngeneric knowledge graph:\n\n```python\nfrom cognee.infrastructure.engine import DataPoint\n\n\nclass Person(DataPoint):\n    name: str\n    role: str\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nclass Company(DataPoint):\n    name: str\n    employs: list[Person] = []  # a DataPoint field becomes an edge named after the field\n    metadata: dict = {\"index_fields\": [\"name\"], \"identity_fields\": [\"name\"]}\n\n\nawait cognee.remember(\"...\", dataset_name=\"org\", graph_model=Company)\n```\n\nInsert structured Python objects directly, bypassing text extraction:\n\n```python\nfrom cognee.tasks.storage import add_data_points\n\nawait add_data_points([Person(name=\"Ada\", role=\"Engineer\")])\n```\n\nSee `examples/guides/custom_graph_model.py` and `examples/guides/custom_data_models.py`.\n\n### Run custom pipelines\n\nUse `run_custom_pipeline(...)` when the user needs explicit sequential task control.\n\n```python\nfrom cognee.modules.pipelines.tasks.task import Task\n\n\nasync def my_task(data):\n    return data\n\n\nawait cognee.run_custom_pipeline(\n    tasks=[Task(my_task)],\n    data=\"input\",\n    dataset=\"research\",\n)\n```\n\n## DataPoints\n\nA `DataPoint` is the **atomic unit of knowledge** in Cognee.\n\nUse this concept whenever the user asks how Cognee represents structured data internally or how\nto insert graph objects directly.\n\nKey ideas:\n\n- A `DataPoint` is a Pydantic model that represents one meaningful unit of information.\n- When inserted, DataPoints become graph nodes; fields holding other DataPoints become edges.\n- `metadata = {\"index_fields\": [...]}` controls which fields are embedded for semantic search.\n- `metadata = {\"identity_fields\": [...]}` makes the node id deterministic so repeated inserts\n  merge instead of duplicating.\n\nUse `DataPoint` when the user wants:\n\n- schema-shaped memory\n- exact control over graph structure\n- programmatic relationship creation\n- custom domain entities such as papers, customers, incidents, policies, products, or workflows\n\nPrefer plain `remember(...)` for unstructured documents. Prefer `graph_model=` when the text\nshould be extracted into a schema. Prefer `DataPoint` models plus `add_data_points(...)` when the\nuser already has structured Python objects.\n\n## NodeSets\n\nUse NodeSets when the user wants a lightweight way to **tag, group, and scope memory**.\n\nA NodeSet starts as a list of tags passed through `node_set=[...]` to `remember(...)`; after the\ngraph is built those tags are first-class graph nodes, and `recall(node_name=[...])` restricts\nretrieval to them.\n\n### Good NodeSet patterns\n\n- per customer: `[\"customer_123\"]`\n- per workflow: `[\"support_bot\", \"refund_flow\"]`\n- per topic: `[\"contracts\", \"vendor_risk\"]`\n- per environment: `[\"prod\", \"staging\"]`\n- per user memory: `[\"user_42\", \"preferences\"]`\n\n### Example\n\n```python\nawait cognee.remember(\n    [\n        \"Alice prefers terse answers and email follow-ups.\",\n        \"Alice escalates billing issues to finance first.\",\n        \"Bob prefers detailed technical explanations.\",\n    ],\n    dataset_name=\"agent_memory\",\n    node_set=[\"crm\", \"user_profiles\"],\n)\n\nresults = await cognee.recall(\n    \"How should I respond to Alice?\",\n    datasets=[\"agent_memory\"],\n    node_name=[\"crm\", \"user_profiles\"],\n)\n```\n\nUse NodeSets by default whenever the user says things like:\n\n- \"scope memory by customer\"\n- \"separate projects without making separate databases\"\n- \"let the agent search only its own memories\"\n- \"group facts by workflow or team\"\n\n## SearchType selection guide\n\n`recall()` routes automatically when `query_type` is omitted. When the user needs a specific\nstrategy, pick from `cognee.SearchType` (all 20 values):\n\nCompletion types (an LLM writes the answer):\n\n- `HYBRID_COMPLETION`: document passages plus entity neighbourhoods; the default when routing is off\n- `GRAPH_COMPLETION`: graph traversal + completion; the best general graph-aware Q&A\n- `GRAPH_COMPLETION_COT`: deeper chain-of-thought reasoning over graph context\n- `GRAPH_COMPLETION_CONTEXT_EXTENSION`: broader graph context retrieval\n- `GRAPH_COMPLETION_DECOMPOSITION`: splits the question into sub-queries first\n- `GRAPH_SUMMARY_COMPLETION`: graph context + pre-computed summaries\n- `RAG_COMPLETION`: traditional RAG over document chunks\n- `TEMPORAL`: time-aware graph search\n- `AGENTIC_COMPLETION`: multi-step loop that can load `skills` and call `tools`\n\nRetrieval-only types (no LLM call):\n\n- `CHUNKS`: semantic retrieval over chunks\n- `CHUNKS_LEXICAL`: exact-term / keyword (BM25) matching\n- `SUMMARIES`: pre-computed document summaries\n- `SKILLS`: discover SKILL.md playbooks (metadata only; exactly one dataset)\n- `CODE`: deterministic code-graph operations via `code_query` (callers, paths, impact analysis)\n\nOther:\n\n- `CYPHER`: raw Cypher, off by default (`ALLOW_CYPHER_QUERY=true` enables it; not on the Postgres demo graph)\n- `NATURAL_LANGUAGE`: natural language to graph query, off by default (same `ALLOW_CYPHER_QUERY=true` flag)\n- `CODING_RULES`: retrieve stored coding rules\n- `GRAPH_REPORT`: graph insight report (hubs, cross-source links, suggested questions)\n- `FEELING_LUCKY`: let Cognee choose\n\nThe CLI exposes 10 of these (`cognee-cli recall --query-type`); the rest are SDK-only.\n\n## Sessions, feedback, and self-improvement\n\nCognee has two memory tiers:\n\n- **Permanent memory**: `remember(...)` without `session_id` — the knowledge graph.\n- **Session memory**: `remember(..., session_id=...)` — a fast session cache written without an\n  LLM call. `recall(..., session_id=...)` searches it first and falls through to the graph.\n  Requires `CACHING=true` (the default).\n\n```python\n# Short-term: store a turn in the session cache, recall it instantly\nawait cognee.remember(\"User wants weekly summaries on Fridays.\", session_id=\"chat_1\")\nresults = await cognee.recall(\"when does the user want summaries?\", session_id=\"chat_1\")\n\n# Long-term: bridge the session into the permanent graph\nawait cognee.improve(dataset=\"main_dataset\", session_ids=[\"chat_1\"])\n```\n\n`remember(..., session_id=...)` with `self_improvement=True` (default) bridges into the graph\nin the background, so the explicit `improve()` call is only needed for control over timing.\n\n### Feedback\n\nFeedback is attached to a session Q&A entry and later folded into retrieval weights by\n`improve()`:\n\n```python\nfrom cognee import FeedbackEntry\n\n# Rate an earlier answer (qa_id is the entry_id returned by the remember() that stored it)\nawait cognee.remember(\n    FeedbackEntry(qa_id=qa_id, feedback_score=5, feedback_text=\"Captured the key themes.\"),\n    session_id=\"chat_1\",\n)\n# Equivalent helper API\nawait cognee.session.add_feedback(session_id=\"chat_1\", qa_id=qa_id, feedback_score=5)\nhistory = await cognee.session.get_session(session_id=\"chat_1\")\n```\n\nWith `AUTO_FEEDBACK=true` (default) every answered turn is also analysed for implicit feedback\nby one structured-output LLM call. Set `AUTO_FEEDBACK=false` for low-latency reads.\n\n### Wrap an agent\n\n`@cognee.agent_memory` records an agent function's calls as session traces and recalls context\nbefore each call. See `examples/guides/agent_memory_quickstart.py`.\n\n## Agentic workflows and feedback-driven improvement\n\nUse Cognee as the **memory layer for agent systems** that need to improve over time through\nbetter recall, better reuse of prior work, and better retrieval of successful past behavior.\n\nThe key idea is simple:\n\n- keep the **agent workflow itself constant**\n- keep the **prompt and tools constant**\n- change only what the agent can remember and retrieve\n\n\"Improvement\" comes from **memory reuse and retrieval quality**, not from changing the model.\n\n### General agent loop\n\n1. **Observe** — capture inputs, events, preferences, outcomes, errors, decisions.\n2. **Store** — `remember(...)` them, with `session_id` for the active run and without it for\n   durable facts.\n3. **Organize** — use datasets and NodeSets to separate memory by customer, workflow, team,\n   agent, or topic.\n4. **Recall before acting** — `recall(...)` before planning, tool use, synthesis, or response\n   generation.\n5. **Capture feedback** — `FeedbackEntry` / `session.add_feedback` for what worked and what\n   did not.\n6. **Consolidate** — `improve(dataset, session_ids=[...])` so session history and lessons become\n   long-term graph memory.\n7. **Reuse** — future runs benefit from richer context and more informed retrieval.\n\n### Minimal example pattern\n\n```python\nimport cognee\n\n# 1) Store a durable observation\nawait cognee.remember(\n    \"Customer 123 prefers concise status updates and Slack notifications.\",\n    dataset_name=\"agent_memory\",\n    node_set=[\"customer_123\", \"preferences\", \"support_agent\"],\n)\n\n# 2) Recall before acting, inside a session\ncontext = await cognee.recall(\n    \"What should I know before replying to customer 123?\",\n    datasets=[\"agent_memory\"],\n    session_id=\"support-session-123\",\n)\n\n# 3) Continue work in the same session\nanswer = await cognee.recall(\n    \"Draft the best reply for customer 123.\",\n    datasets=[\"agent_memory\"],\n    session_id=\"support-session-123\",\n)\n\n# 4) Consolidate the session into long-term memory later\nawait cognee.improve(dataset=\"agent_memory\", session_ids=[\"support-session-123\"])\n```\n\n### Best default explanation\n\nIf the user asks how Cognee helps agents improve over time:\n\n**Cognee lets agents improve by remembering more useful things, organizing them into searchable\ngraph memory, and reusing successful past work in future runs.**\n\n## Configuration help\n\nUse Cognee config helpers or environment variables when the user needs provider or backend setup.\n\n```python\ncognee.config.set_llm_provider(\"openai\")\ncognee.config.set_llm_model(\"gpt-5-mini\")\ncognee.config.set_llm_api_key(\"sk-...\")\n```\n\nEnvironment variables (`.env`): `LLM_API_KEY`, `LLM_MODEL`, `LLM_PROVIDER`, `EMBEDDING_*`,\n`GRAPH_DATABASE_PROVIDER` (ladybug default, neo4j, neptune, postgres_demo), `VECTOR_DB_PROVIDER`\n(lancedb default, pgvector, turso), `DB_PROVIDER` (sqlite default, postgres), `CACHE_BACKEND`.\nIf only the LLM or only embeddings are configured, the other defaults to OpenAI.\n\n## Dataset and lifecycle operations\n\n```python\ndatasets = await cognee.datasets.list_datasets()\ndata = await cognee.datasets.list_data(dataset_id)\nawait cognee.forget(dataset=\"research\")  # preferred over datasets.empty_dataset / delete_all\n```\n\n## Visualization\n\n`visualize_graph` renders a **bounded subgraph** by default (seed nodes + a k-hop neighborhood,\ncapped at `max_nodes`) instead of the whole graph.\n\n```python\n# Default: bounded subgraph. Seed by a query, explicit ids, or a recall result;\n# with none of those, the highest-degree nodes seed a representative view.\nawait cognee.visualize_graph(\"/path/to/output.html\")\nawait cognee.visualize_graph(\"/path/to/output.html\", query=\"What relates to Python?\")\nawait cognee.visualize_graph(\"/path/to/output.html\", seed_node_ids=[\"node-id-1\"])\nawait cognee.visualize_graph(\"/path/to/output.html\", recall_result=recall_output)\n\n# Legacy whole-graph render.\nawait cognee.visualize_graph(\"/path/to/output.html\", full=True)\n\nawait cognee.start_visualization_server(port=8080)\nawait cognee.start_ui()\n```\n\nCaps: `neighborhood_depth=2`, `neighborhood_seed_top_k=10`, `max_nodes=500`.\nSee `examples/guides/graph_visualization.py`.\n\n## Full reset (tests only)\n\n`forget(everything=True)` removes the user's data and memory. To also drop users, ACLs and the\ndataset registry — full test teardown — use prune:\n\n```python\nawait cognee.prune.prune_data()\nawait cognee.prune.prune_system(graph=True, vector=True, metadata=True, cache=True)\n```\n\n## Important behavior notes\n\n- Cognee APIs are **async**.\n- Prefer **remember -> recall** (+ `improve`, `forget`) unless the user needs one low-level stage.\n- Use `node_set` early when the user may later need scoped retrieval.\n- Use `session_id` for short-term memory and conversation continuity; `improve(session_ids=...)`\n  to make it permanent.\n- Use `graph_model=` or `DataPoint` types only when the user needs schema-shaped extraction.\n- Use `CYPHER` only when Cypher querying is enabled in config.\n- Keep examples minimal and runnable.\n\n## Do not overcomplicate\n\nDo not jump straight to advanced backends, ontology configuration, or custom pipelines unless the\nuser asks for them or the problem clearly requires them. Prefer the smallest correct Cognee\nsolution first, then extend it.\n\n<!-- File: evals/old/cognee_01042025/aggregate_metrics_v_deepeval.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/aggregate_metrics_v_deepeval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/aggregate_metrics_v_deepeval.json)\n\n<!-- File: evals/old/cognee_01042025/aggregate_metrics_v_direct_llm.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/aggregate_metrics_v_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/aggregate_metrics_v_direct_llm.json)\n\n<!-- File: evals/old/cognee_01042025/metrics_output_cognee_direct_llm.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/metrics_output_cognee_direct_llm.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/metrics_output_cognee_direct_llm.json)\n\n<!-- File: evals/old/cognee_01042025/metrics_output_cognee_human_eval.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/metrics_output_cognee_human_eval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/metrics_output_cognee_human_eval.json)\n\n<!-- File: evals/old/cognee_01042025/metrics_output_cognee.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Cognee_01042025 Skill\n\nPath: `evals/old/cognee_01042025/metrics_output_cognee.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_01042025/metrics_output_cognee.json)\n\n<!-- File: evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short_deepeval.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short_deepeval.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short_deepeval.json)\n\n<!-- File: evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Cognee_optimized_01042025 Skill\n\nPath: `evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/topoteretes/cognee/HEAD/evals/old/cognee_optimized_01042025/aggregate_metrics_4o_cognee_10_short.json)\n\n<!-- ... +41 more modular skills available via /api/skills/topoteretes/cognee?path={path} -->\n</yakaai_skills>"}