chore: import upstream snapshot with attribution
Test Suites / Build CI Environment (push) Has been cancelled
Test Suites / Basic Tests (push) Has been cancelled
Test Suites / End-to-End Tests (push) Has been cancelled
Test Suites / CLI Tests (push) Has been cancelled
Test Suites / Slow End-to-End Tests (push) Has been cancelled
Test Suites / Graph Database Tests (push) Has been cancelled
Test Suites / Vector DB Tests (push) Has been cancelled
Test Suites / Temporal Graph Test (push) Has been cancelled
Test Suites / Search Test on Different DBs (push) Has been cancelled
Test Suites / Example Tests (push) Has been cancelled
Test Suites / Notebook Tests (push) Has been cancelled
Test Suites / OS and Python Tests Ubuntu (push) Has been cancelled
Test Suites / OS and Python Tests Extended (push) Has been cancelled
Test Suites / LLM Test Suite (push) Has been cancelled
Test Suites / S3 File Storage Test (push) Has been cancelled
Test Suites / Run Integration Tests (push) Has been cancelled
Test Suites / MCP Tests (push) Has been cancelled
Test Suites / Docker Compose Test (push) Has been cancelled
Test Suites / Docker CI test (push) Has been cancelled
Test Suites / Relational DB Migration Tests (push) Has been cancelled
Test Suites / Distributed Cognee Test (push) Has been cancelled
Test Suites / DB Examples Tests (push) Has been cancelled
Test Suites / Test Completion Status (push) Has been cancelled
Test Suites / Claude Code Review (push) Has been cancelled
Test Suites / basic checks (push) Has been cancelled
build | Build and Push Cognee MCP Docker Image to dockerhub / docker-build-and-push (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
build | Build and Push Docker Image to dockerhub / docker-build-and-push (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Core Functionality (3.11) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Core Functionality (3.12) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges with Different Graph Databases (kuzu, kuzu) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges with Different Graph Databases (neo4j, neo4j) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Examples (push) Has been cancelled
Weighted Edges Tests / Code Quality for Weighted Edges (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:02:24 +08:00
commit c889a57b6b
2544 changed files with 402845 additions and 0 deletions
+114
View File
@@ -0,0 +1,114 @@
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
# .coderabbit.yaml
language: en
early_access: false
enable_free_tier: true
reviews:
profile: chill
instructions: >-
# Code Review Instructions
- Ensure the code follows best practices and coding standards.
- For **Python** code, follow
[PEP 20](https://www.python.org/dev/peps/pep-0020/) and
[CEP-8](https://gist.github.com/reactive-firewall/b7ee98df9e636a51806e62ef9c4ab161)
standards.
# Documentation Review Instructions
- Verify that documentation and comments are clear and comprehensive.
- Verify that documentation and comments are free of spelling mistakes.
# Test Code Review Instructions
- Ensure that test code is automated, comprehensive, and follows testing best practices.
- Verify that all critical functionality is covered by tests.
- Ensure that test code follow
[CEP-8](https://gist.github.com/reactive-firewall/d840ee9990e65f302ce2a8d78ebe73f6)
# Misc.
- Confirm that the code meets the project's requirements and objectives.
- Confirm that copyright years are up-to date whenever a file is changed.
request_changes_workflow: false
high_level_summary: true
high_level_summary_placeholder: '@coderabbitai summary'
auto_title_placeholder: '@coderabbitai'
review_status: true
poem: false
collapse_walkthrough: false
sequence_diagrams: false
changed_files_summary: true
path_filters: ['!*.xc*/**', '!node_modules/**', '!dist/**', '!build/**', '!.git/**', '!venv/**', '!__pycache__/**']
path_instructions:
- path: README.md
instructions: >-
1. Consider the file 'README.md' the overview/introduction of the project.
Also consider the 'README.md' file the first place to look for project documentation.
2. When reviewing the file 'README.md' it should be linted with help
from the tools `markdownlint` and `languagetool`, pointing out any issues.
3. You may assume the file 'README.md' will contain GitHub flavor Markdown.
- path: '**/*.py'
instructions: >-
When reviewing Python code for this project:
1. Prioritize portability over clarity, especially when dealing with cross-Python compatibility. However, with the priority in mind, do still consider improvements to clarity when relevant.
2. As a general guideline, consider the code style advocated in the PEP 8 standard (excluding the use of spaces for indentation) and evaluate suggested changes for code style compliance.
3. As a style convention, consider the code style advocated in [CEP-8](https://gist.github.com/reactive-firewall/b7ee98df9e636a51806e62ef9c4ab161) and evaluate suggested changes for code style compliance.
4. As a general guideline, try to provide any relevant, official, and supporting documentation links to any tool's suggestions in review comments. This guideline is important for posterity.
5. As a general rule, undocumented function definitions and class definitions in the project's Python code are assumed incomplete. Please consider suggesting a short summary of the code for any of these incomplete definitions as docstrings when reviewing.
- path: cognee/tests/*
instructions: >-
When reviewing test code:
1. Prioritize portability over clarity, especially when dealing with cross-Python compatibility. However, with the priority in mind, do still consider improvements to clarity when relevant.
2. As a general guideline, consider the code style advocated in the PEP 8 standard (excluding the use of spaces for indentation) and evaluate suggested changes for code style compliance.
3. As a style convention, consider the code style advocated in [CEP-8](https://gist.github.com/reactive-firewall/b7ee98df9e636a51806e62ef9c4ab161) and evaluate suggested changes for code style compliance, pointing out any violations discovered.
4. As a general guideline, try to provide any relevant, official, and supporting documentation links to any tool's suggestions in review comments. This guideline is important for posterity.
5. As a project rule, Python source files with names prefixed by the string "test_" and located in the project's "tests" directory are the project's unit-testing code. It is safe, albeit a heuristic, to assume these are considered part of the project's minimal acceptance testing unless a justifying exception to this assumption is documented.
6. As a project rule, any files without extensions and with names prefixed by either the string "check_" or the string "test_", and located in the project's "tests" directory, are the project's non-unit test code. "Non-unit test" in this context refers to any type of testing other than unit testing, such as (but not limited to) functional testing, style linting, regression testing, etc. It can also be assumed that non-unit testing code is usually written as Bash shell scripts.
- path: requirements.txt
instructions: >-
* The project's own Python dependencies are recorded in 'requirements.txt' for production code.
* The project's testing-specific Python dependencies are recorded in 'tests/requirements.txt' and are used for testing the project.
* The project's documentation-specific Python dependencies are recorded in 'docs/requirements.txt' and are used only for generating Python-focused documentation for the project. 'docs/requirements.txt' may be absent if not applicable.
Consider these 'requirements.txt' files the records of truth regarding project dependencies.
- path: .github/**
instructions: >-
* When the project is hosted on GitHub: All GitHub-specific configurations, templates, and tools should be found in the '.github' directory tree.
* 'actionlint' erroneously generates false positives when dealing with GitHub's `${{ ... }}` syntax in conditionals.
* 'actionlint' erroneously generates incorrect solutions when suggesting the removal of valid `${{ ... }}` syntax.
abort_on_close: true
auto_review:
enabled: true
auto_incremental_review: true
ignore_title_keywords: []
labels: []
drafts: false
base_branches:
- dev
- main
tools:
shellcheck:
enabled: true
ruff:
enabled: true
markdownlint:
enabled: true
yamllint:
enabled: true
chat:
auto_reply: true
+29
View File
@@ -0,0 +1,29 @@
{
"name": "Cognee Development",
"image": "ghcr.io/astral-sh/uv:python3.12-bookworm",
"features": {
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"postCreateCommand": "uv sync && cp cognee/.env.template cognee/.env && echo 'Set LLM_API_KEY in cognee/.env to get started'",
"forwardPorts": [8000, 3000],
"portsAttributes": {
"8000": {"label": "Cognee API", "onAutoForward": "notify"},
"3000": {"label": "Cognee UI", "onAutoForward": "notify"}
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"charliermarsh.ruff"
],
"settings": {
"python.defaultInterpreterPath": ".venv/bin/python"
}
}
},
"remoteEnv": {
"PYTHONPATH": "/workspaces/cognee"
}
}
+16
View File
@@ -0,0 +1,16 @@
bin
dist
docs
evals
tests
tools
assets
notebooks
cognee-frontend
examples/python/.dlt
.venv
.github
.idea
.vscode
+4
View File
@@ -0,0 +1,4 @@
*
!pyproject.toml
!uv.lock
!README.md
+11
View File
@@ -0,0 +1,11 @@
# Deprecated: use .env.template as the canonical environment template.
#
# To configure Cognee, copy .env.template to .env and fill in the values you need:
#
# cp .env.template .env
#
# This file is kept for backwards compatibility with older setup instructions.
LLM_API_KEY="your_api_key"
LLM_MODEL="openai/gpt-5-mini"
LLM_PROVIDER="openai"
+629
View File
@@ -0,0 +1,629 @@
###############################################################################
# TIER 1 — QUICK START
# Set this one variable and you're done. Everything else has working defaults.
# Default databases (SQLite, LanceDB, KuzuDB) are file-based, no setup needed.
###############################################################################
LLM_API_KEY="your_api_key"
###############################################################################
# TIER 2 — COMMON OVERRIDES (uncomment to customize)
# Most users only need a few of these.
###############################################################################
# -- LLM Provider & Model ----------------------------------------------------
#LLM_MODEL="openai/gpt-5-mini"
#LLM_PROVIDER="openai"
#LLM_ENDPOINT=""
# -- Embedding Provider -------------------------------------------------------
#EMBEDDING_PROVIDER="openai"
#EMBEDDING_MODEL="openai/text-embedding-3-large"
#EMBEDDING_DIMENSIONS=3072
# -- Tokenizer (chunk sizing) -------------------------------------------------
# The tokenizer used to count tokens for chunking is auto-selected to match the
# embedding model: openai/gemini use TikToken, mistral uses the Mistral
# tokenizer, and fastembed / openai-compatible models use the embedding model's
# own HuggingFace tokenizer. cognee warns (and falls back to TikToken) when it
# cannot match one, since a mismatched tokenizer mis-sizes chunks and skews the
# --dry-run estimate. For providers whose model id is not a HuggingFace repo
# (e.g. Ollama), set HUGGINGFACE_TOKENIZER to a tokenizer matching your model:
#HUGGINGFACE_TOKENIZER="Salesforce/SFR-Embedding-Mistral"
# -- Database Providers (switch from file-based defaults) ---------------------
#DB_PROVIDER="postgres"
#DB_HOST=127.0.0.1
#DB_PORT=5432
#DB_USERNAME=cognee
#DB_PASSWORD=cognee
#DB_NAME=cognee_db
#GRAPH_DATABASE_PROVIDER="neo4j"
#VECTOR_DB_PROVIDER="lancedb"
###############################################################################
# TIER 3 — ADVANCED (grouped by subsystem)
# Most users never need to change anything below this line.
###############################################################################
################################################################################
# LLM — Advanced Settings
# Tune these when switching providers, adjusting structured output, or
# rate-limiting LLM calls.
################################################################################
# Structured output framework: "instructor" (default, via litellm) or "baml"
STRUCTURED_OUTPUT_FRAMEWORK="instructor"
# Instructor's mode determines how structured data is extracted from LLM responses.
# Each LLM has its own default (e.g. gpt-5 models use "json_schema_mode").
#LLM_INSTRUCTOR_MODE=""
# Cognee uses this to determine optimal chunk size (not forwarded in LLM calls).
#LLM_MAX_COMPLETION_TOKENS="16384"
# LLM API version (needed for Azure OpenAI)
#LLM_API_VERSION=""
# Extra kwargs passed to every LLM completion call (JSON string).
# Examples: LLM_ARGS='{"max_tokens": 16384, "temperature": 0.7}'
#LLM_ARGS='{}'
# LLM rate limiting
#LLM_RATE_LIMIT_ENABLED=true
#LLM_RATE_LIMIT_REQUESTS=60
#LLM_RATE_LIMIT_INTERVAL=60
# Per-stage model routing (optional). Unset means the stage uses the base LLM_* config above.
# Route a cheap or local model to extraction (it runs per chunk and dominates token use),
# and keep a stronger model for summarization and query-time reasoning.
#LLM_EXTRACTION_MODEL="ollama_chat/llama3.1"
#LLM_EXTRACTION_PROVIDER="ollama"
#LLM_EXTRACTION_ENDPOINT="http://localhost:11434"
#LLM_EXTRACTION_API_KEY=""
#LLM_SUMMARIZATION_MODEL="openai/gpt-5-mini"
#LLM_SUMMARIZATION_PROVIDER="openai"
#LLM_QUERY_MODEL="openai/gpt-5-mini"
#LLM_QUERY_PROVIDER="openai"
################################################################################
# Embedding — Advanced Settings
# Tune these when using non-default embedding providers.
################################################################################
#EMBEDDING_ENDPOINT=""
#EMBEDDING_API_VERSION=""
#EMBEDDING_MAX_COMPLETION_TOKENS=8191
#EMBEDDING_BATCH_SIZE=36
# If not provided, LLM_API_KEY is used for embeddings too.
#EMBEDDING_API_KEY="your_api_key"
################################################################################
# BAML Structured Output
# Only needed when STRUCTURED_OUTPUT_FRAMEWORK="baml".
################################################################################
#BAML_LLM_PROVIDER=openai
#BAML_LLM_MODEL="gpt-5-mini"
#BAML_LLM_ENDPOINT=""
#BAML_LLM_API_KEY="your_api_key"
#BAML_LLM_API_VERSION=""
################################################################################
# Root Directories
# Override where Cognee stores files and databases (default: .venv).
################################################################################
#DATA_ROOT_DIRECTORY='/Users/<user>/Desktop/cognee/.cognee_data/'
#SYSTEM_ROOT_DIRECTORY='/Users/<user>/Desktop/cognee/.cognee_system/'
################################################################################
# Storage Backend
# Switch from local filesystem to S3.
################################################################################
#STORAGE_BACKEND="local"
#STORAGE_BACKEND="s3"
#STORAGE_BUCKET_NAME="your-bucket-name"
#AWS_REGION="us-east-1"
#AWS_ACCESS_KEY_ID="your-access-key"
#AWS_SECRET_ACCESS_KEY="your-secret-key"
#DATA_ROOT_DIRECTORY="s3://your-bucket/cognee/data"
#SYSTEM_ROOT_DIRECTORY="s3://your-bucket/cognee/system"
#CACHE_ROOT_DIRECTORY="s3://your-bucket/cognee/cache"
################################################################################
# Relational Database — Advanced
# Connection tuning, pool sizes, SSL.
################################################################################
DB_PROVIDER="sqlite"
DB_NAME=cognee_db
# Custom connection arguments (JSON). Useful for SSL, timeouts.
#DATABASE_CONNECT_ARGS='{"sslmode": "require", "connect_timeout": 10}'
# Connection pool tuning (JSON).
#POOL_ARGS='{"pool_size": 5, "max_overflow": 10, "pool_recycle": -1, "pool_timeout": 30}'
################################################################################
# Graph Database — Advanced
# Provider-specific connection details.
################################################################################
GRAPH_DATABASE_PROVIDER="kuzu"
# Handler for multi-user access control (per-dataset DB creation).
GRAPH_DATASET_DATABASE_HANDLER="kuzu"
# Remote Kuzu
#GRAPH_DATABASE_PROVIDER="kuzu-remote"
#GRAPH_DATABASE_URL="http://localhost:8000"
#GRAPH_DATABASE_USERNAME=XXX
#GRAPH_DATABASE_PASSWORD=YYY
# Neo4j
#GRAPH_DATABASE_PROVIDER="neo4j"
#GRAPH_DATABASE_URL=bolt://localhost:7687
#GRAPH_DATABASE_NAME="neo4j"
#GRAPH_DATABASE_USERNAME=neo4j
#GRAPH_DATABASE_PASSWORD=pleaseletmein
################################################################################
# Vector Database — Advanced
# Provider-specific connection details.
################################################################################
# Supported (built-in): pgvector | lancedb
# Community adapters (separate packages): qdrant | weaviate | milvus | chromadb
VECTOR_DB_PROVIDER="lancedb"
#VECTOR_DB_URL=
#VECTOR_DB_KEY=
# Handler for multi-user access control (per-dataset DB creation).
VECTOR_DATASET_DATABASE_HANDLER="lancedb"
# Connection pool tuning for PGVector per-dataset engines (JSON).
# When ENABLE_BACKEND_ACCESS_CONTROL=true each dataset gets its own engine; this controls
# its pool size independently from POOL_ARGS (default: pool_size=2, max_overflow=2).
#VECTOR_POOL_ARGS='{"pool_size": 2, "max_overflow": 5, "pool_recycle": 1800}'
################################################################################
# Ontology Resolver
# Use when grounding extraction against an OWL ontology.
################################################################################
#ONTOLOGY_RESOLVER=rdflib
#MATCHING_STRATEGY=fuzzy
#ONTOLOGY_FILE_PATH=YOUR_FULL_FILE_PATH
################################################################################
# Database Adapter Caching
# Max graph / vector / relational engine instances held in the LRU cache
# (one per unique connection key, e.g. per dataset in multi-tenant mode).
# In subprocess mode, this also caps how many child processes (Kuzu/LanceDB
# workers) can be alive at once — eviction shuts down the subprocess.
# Also the default for DATASET_QUEUE_MAX_CONCURRENT when that is unset.
# Engines of datasets currently admitted by the dataset queue are pinned and
# never evicted by capacity pressure; when every entry is pinned the cache
# briefly exceeds this size (bounded by DATASET_QUEUE_MAX_CONCURRENT).
# Lower values save memory; raise when running many datasets concurrently.
################################################################################
#DATABASE_MAX_LRU_CACHE_SIZE=6
################################################################################
# Dataset Queue
# Semaphore-backed queue that limits how many datasets can be processed at
# once (cognify, search, etc.). Prevents resource exhaustion when many
# datasets run in parallel. When the limit is reached, new datasets wait
# until a slot is freed.
################################################################################
#DATASET_QUEUE_ENABLED=true
# Max concurrent dataset slots. Defaults to DATABASE_MAX_LRU_CACHE_SIZE.
#DATASET_QUEUE_MAX_CONCURRENT=6
################################################################################
# Translation
# Use when ingesting non-English content.
################################################################################
TRANSLATION_PROVIDER="llm"
TARGET_LANGUAGE="en"
CONFIDENCE_THRESHOLD=0.8
#GOOGLE_TRANSLATE_API_KEY="your-google-api-key"
#GOOGLE_PROJECT_ID="your-google-project-id"
#AZURE_TRANSLATOR_KEY="your-azure-translator-key"
#AZURE_TRANSLATOR_REGION="westeurope"
#AZURE_TRANSLATOR_ENDPOINT="https://api.cognitive.microsofttranslator.com"
#TRANSLATION_BATCH_SIZE=10
#TRANSLATION_MAX_RETRIES=3
#TRANSLATION_TIMEOUT_SECONDS=30
################################################################################
# Data Migrations (graph/vector revision chain)
################################################################################
# Cognee runs its data migrations automatically on startup (FastAPI lifespan,
# first remember()/cognify() call in an SDK process). Set to false to disable
# ALL automatic runs and migrate explicitly via `cognee-cli upgrade` instead
# (e.g. operator-driven deployments, or tests on deliberately old-format data).
#ENABLE_AUTO_MIGRATIONS=true
################################################################################
# Migration (Relational -> Graph)
################################################################################
MIGRATION_DB_PATH="/path/to/migration/directory"
MIGRATION_DB_NAME="migration_database.sqlite"
MIGRATION_DB_PROVIDER="sqlite"
#MIGRATION_DB_USERNAME=cognee
#MIGRATION_DB_PASSWORD=cognee
#MIGRATION_DB_HOST="127.0.0.1"
#MIGRATION_DB_PORT=5432
################################################################################
# Security
################################################################################
# -- JWT Authentication -------------------------------------------------------
# Secret used to sign and verify JWT tokens. Must be the same across all instances
# (e.g. all Kubernetes pods) for tokens issued by one instance to be accepted by another.
# Change this to a long random string in production. Never commit the real value to git.
FASTAPI_USERS_JWT_SECRET="super_secret"
# How long a JWT token remains valid, in seconds. After expiry the user must log in again.
# The same lifetime applies to both cookie and bearer token auth.
# Default: 3600 (1 hour)
JWT_LIFETIME_SECONDS=3600
# -- API Key Authentication ---------------------------------------------------
# When HASH_API_KEY=true, API keys are hashed with SHA-256 before being stored in the database.
# This means the raw key is shown to the user only once at creation time and cannot be recovered.
#
# ⚠️ Migration note: if you enable this on a running system that already has API keys stored
# in plaintext, those existing keys will stop working immediately because the lookup will
# hash the incoming value and find no match. You must either:
# 1. Delete and re-issue all existing API keys, or
# 2. Write a one-off migration to SHA-256 hash the existing api_key column values.
#
# Default: false (keys are stored in plaintext)
HASH_API_KEY="False"
# When set to false don't allow adding of local system files to Cognee. Should be set to False when Cognee is used as a backend.
ACCEPT_LOCAL_FILE_PATH=True
ALLOW_HTTP_REQUESTS=True
ALLOW_CYPHER_QUERY=True
RAISE_INCREMENTAL_LOADING_ERRORS=True
# Authentication & access control.
#
# ENABLE_BACKEND_ACCESS_CONTROL is the canonical posture switch:
# true (default) - multi-tenant mode: per-user/dataset isolated DBs AND
# API endpoints require an authenticated user.
# false - single-user mode: shared DB AND auth requirement off.
#
# REQUIRE_AUTHENTICATION is an explicit override on the auth requirement only:
# unset (default) - follow ENABLE_BACKEND_ACCESS_CONTROL.
# true - force auth on (sane for single-user behind a token).
# false - force auth off — IGNORED if ENABLE_BACKEND_ACCESS_CONTROL
# is true (multi-tenant always requires auth; a warning is
# logged at startup).
#
# Startup logs an "auth posture: ..." line with the resolved decision so you
# can verify what's actually in effect.
REQUIRE_AUTHENTICATION=False
# Set this variable to True to enforce usage of backend access control for Cognee
# Note: This is only currently supported by the following databases:
# Relational: SQLite, Postgres
# Vector: LanceDB, pgvector
# Graph: KuzuDB, neo4j_aura_dev
#
# It enforces creation of databases per Cognee user + dataset. Does not work with some graph and database providers.
# Disable mode when using not supported graph/vector databases.
ENABLE_BACKEND_ACCESS_CONTROL=True
################################################################################
# Cloud Sync
################################################################################
COGNEE_CLOUD_API_URL="http://localhost:8001"
COGNEE_CLOUD_AUTH_TOKEN="your-api-key"
################################################################################
# UI
################################################################################
UI_APP_URL=http://localhost:3000
################################################################################
# DLT Ingestion
################################################################################
#DLT_MAX_ROWS_PER_TABLE=50
################################################################################
# Dev / Debug
################################################################################
ENV="local"
#ENABLE_LAST_ACCESSED="false"
TOKENIZERS_PARALLELISM="false"
# -- Search History ------------------------------------------------------------
# Set to false to disable search query/result logging (recommended for daemons)
#COGNEE_LOG_SEARCH_HISTORY="true"
# LITELLM Logging Level. Set to quiet down logging
LITELLM_LOG="ERROR"
#TELEMETRY_DISABLED=1
#DEFAULT_USER_EMAIL=""
#DEFAULT_USER_PASSWORD=""
# -- Cognee Logging -----------------------------------------------------------
# Console log level: DEBUG, INFO, WARNING, ERROR, CRITICAL (default: INFO)
#LOG_LEVEL="INFO"
# Set to false to disable file logging entirely (console-only)
#COGNEE_LOG_FILE="true"
# Override the log directory (default: ~/.cognee/logs)
#COGNEE_LOGS_DIR="/var/log/cognee"
# Max size per log file before rotation, in bytes (default: 50 MB)
#COGNEE_LOG_MAX_BYTES=52428800
# Number of rotated log files to keep (default: 5 → 300 MB total cap)
#COGNEE_LOG_BACKUP_COUNT=5
################################################################################
# AWS
################################################################################
#AWS_REGION=""
#AWS_ENDPOINT_URL=""
#AWS_ACCESS_KEY_ID=""
#AWS_SECRET_ACCESS_KEY=""
#AWS_SESSION_TOKEN=""
################################################################################
# Web Scraper
################################################################################
WEB_SCRAPER_TIMEOUT=15.0
WEB_SCRAPER_MAX_DELAY=10.0
################################################################################
# OpenTelemetry / Tracing
################################################################################
# -- To export traces to an OTLP-compatible backend (Dash0, Grafana, Jaeger, etc.),
# set the endpoint and optional auth headers: ---------------------
# COGNEE_TRACING_ENABLED=true
# OTEL_EXPORTER_OTLP_ENDPOINT="https://ingress.eu-west.dash0.com:4317"
# OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer <your-token>"
# Override the service name reported in traces (default: "cognee")
# OTEL_SERVICE_NAME="cognee"
# Add extra resource attributes (useful for Kubernetes, multi-instance deployments)
# OTEL_RESOURCE_ATTRIBUTES="service.namespace=my-team,service.version=1.0"
# Session cache settings
# To switch to Redis caching check our documentation page sessions-and-caching
# CACHING=true
# Backends: sqlite (default), postgres, redis, fs, tapes
# CACHE_BACKEND=sqlite
# CACHE_BACKEND=postgres
# Optional explicit SQLAlchemy async URL for the sqlite/postgres backends.
# sqlite default: cache.db next to the relational SQLite database.
# postgres default: falls back to DB_* settings when DB_PROVIDER=postgres.
# CACHE_DB_URL=sqlite+aiosqlite:///path/to/databases/cache.db
# CACHE_DB_URL=postgresql+asyncpg://cognee:cognee@localhost:5432/cognee_db
# Minimum seconds between global TTL purge sweeps (sqlite/postgres backends)
# CACHE_PURGE_INTERVAL_SECONDS=900
################################################################################
# ADDITIONAL MANAGED SETTINGS (previously undocumented)
# These are all read by Cognee's config classes (pydantic BaseSettings) but
# were missing from this template. Defaults shown; uncomment to override.
################################################################################
# -- LLM tuning ---------------------------------------------------------------
#LLM_TEMPERATURE=0.0
#LLM_STREAMING=false
# Optional fallback model used when the primary completion fails.
#FALLBACK_MODEL=""
#FALLBACK_API_KEY=""
#FALLBACK_ENDPOINT=""
# Audio transcription model.
#TRANSCRIPTION_MODEL="whisper-1"
# -- Embedding rate limiting (mirrors the LLM_RATE_LIMIT_* knobs) -------------
#EMBEDDING_RATE_LIMIT_ENABLED=false
#EMBEDDING_RATE_LIMIT_REQUESTS=60
#EMBEDDING_RATE_LIMIT_INTERVAL=60
#EMBEDDING_RATE_LIMIT_TOKENS=0
# Token-based LLM limit (0 = disabled; requests/interval already documented above).
#LLM_RATE_LIMIT_TOKENS=0
# -- Chunking -----------------------------------------------------------------
#CHUNK_SIZE=1500
#CHUNK_OVERLAP=10
#CHUNK_STRATEGY="paragraph"
# -- Triplet embedding (extra triplet-level vectors during cognify) -----------
#TRIPLET_EMBEDDING=false
# -- Session cache (Redis backend + session/usage tuning) ---------------------
# Used when CACHE_BACKEND=redis; also the host/port for a remote cache.
#CACHE_HOST="localhost"
#CACHE_PORT=6379
#CACHE_USERNAME=""
#CACHE_PASSWORD=""
# Session lifetime in the cache (default 7 days) and per-turn context cap.
#SESSION_TTL_SECONDS=604800
#MAX_SESSION_CONTEXT_CHARS=
# Self-improvement: absorb per-turn feedback/guidance automatically (default on).
#AUTO_FEEDBACK=true
# Per-process LLM usage logging into the cache.
#USAGE_LOGGING=false
#USAGE_LOGGING_TTL=604800
# Cross-process locks for file-based embedded graph backends.
#SHARED_KUZU_LOCK=false
#SHARED_LADYBUG_LOCK=false
# -- Graph database — advanced connection / Kuzu tuning -----------------------
#GRAPH_DATABASE_HOST=""
#GRAPH_DATABASE_PORT=
#GRAPH_DATABASE_KEY=""
#GRAPH_DATABASE_ALLOW_ANONYMOUS=false
# Run the embedded graph engine (Kuzu/Ladybug) in a worker subprocess.
#GRAPH_DATABASE_SUBPROCESS_ENABLED=true
# Kuzu performance tuning (0/auto by default).
#KUZU_NUM_THREADS=0
#KUZU_BUFFER_POOL_SIZE=
#KUZU_MAX_DB_SIZE=
# -- Vector database — advanced connection ------------------------------------
#VECTOR_DB_HOST=""
#VECTOR_DB_PORT=1234
#VECTOR_DB_NAME=""
#VECTOR_DB_USERNAME=""
#VECTOR_DB_PASSWORD=""
#VECTOR_DB_SUBPROCESS_ENABLED=true
# -- Database subprocess workers — advanced tuning ----------------------------
# The embedded DB engines (Kuzu/Ladybug graph, LanceDB vector) run their native
# client in a dedicated worker process. These knobs tune that harness.
# Per-RPC deadline guarding against a hung native call (seconds; <=0 disables).
#SUBPROCESS_CALL_TIMEOUT=300
# How many times a failed subprocess RPC is retried (respawning the worker).
#SUBPROCESS_MAX_RETRIES=2
# Backstop for the brief window where one graph worker is still releasing a
# file lock while another opens the same DB path: the worker retries the open
# this many times, with exponential backoff starting at this many seconds
# (per-attempt backoff is capped internally).
#SUBPROCESS_OPEN_LOCK_RETRIES=10
#SUBPROCESS_OPEN_LOCK_BACKOFF=0.1
# -- AWS / Bedrock extras (in addition to the AWS section above) --------------
#AWS_PROFILE_NAME=""
#AWS_BEDROCK_RUNTIME_ENDPOINT=""
# -- Local llama.cpp provider -------------------------------------------------
#LLAMA_CPP_MODEL_PATH=""
#LLAMA_CPP_N_CTX=2048
#LLAMA_CPP_N_GPU_LAYERS=0
#LLAMA_CPP_CHAT_FORMAT="chatml"
# -- Security: additional auth-token secrets ----------------------------------
# Like FASTAPI_USERS_JWT_SECRET above, these default to the INSECURE value
# "super_secret". Override BOTH with long random strings in production.
#FASTAPI_USERS_VERIFICATION_TOKEN_SECRET="change_me_in_production"
#FASTAPI_USERS_RESET_PASSWORD_TOKEN_SECRET="change_me_in_production"
################################################################################
# Docker / MCP Runtime
# Configure the cognee API image (cognee/cognee) and the MCP image
# (cognee/cognee-mcp) when running `docker run` / `docker compose`.
# Unless noted "read by the app", these are consumed by the container
# entrypoints/compose and have defaults baked into the images — set them only
# to override. (docker-compose.yml already sets sensible values for most.)
################################################################################
# -- API server (cognee/cognee image) ----------------------------------------
# CORS allow-list for the FastAPI server: comma-separated origins. Read by the
# app (cognee/api/client.py). Default '*' (all origins) — set explicit domains
# in production.
#CORS_ALLOWED_ORIGINS="https://yourdomain.com,https://another.com"
# Server bind/port inside the container (entrypoint defaults shown).
#HTTP_PORT=8000
#BIND_ADDRESS=0.0.0.0
# -- MCP server (cognee/cognee-mcp image) -------------------------------------
# Transport the MCP container serves. The Docker image reads TRANSPORT_MODE;
# the direct `cognee-mcp` CLI uses --transport instead.
#TRANSPORT_MODE=stdio # stdio | sse | http
# Comma-separated optional extras to pip-install at container startup.
#EXTRAS=aws,postgres
# MCP "API mode": point the MCP server at an already-running cognee API server.
#API_URL=http://localhost:8000
#API_TOKEN=""
# MCP "Cloud mode": point the MCP server at a managed Cognee Cloud instance.
# These are the canonical cloud-connection variables, shared across serve(),
# push(), the MCP server, and sync. COGNEE_CLOUD_API_URL / COGNEE_CLOUD_AUTH_TOKEN
# (above) remain as deprecated fallbacks.
#COGNEE_SERVICE_URL=""
#COGNEE_API_KEY=""
# -- Debug (both images) ------------------------------------------------------
# DEBUG=true together with ENV in {dev,local} starts the container under
# debugpy, listening on DEBUG_PORT. ENV is the canonical environment variable
# (set it in the Dev/Debug section above); ENVIRONMENT is a deprecated alias
# still accepted by the container entrypoints.
#DEBUG=false
#DEBUG_PORT=5678
# -- Frontend (cognee-frontend image / compose `ui` profile) ------------------
#NEXT_PUBLIC_BACKEND_API_URL=http://localhost:8000
###############################################################################
# TIER 4 — EXAMPLE PROVIDER OVERRIDES (commented out)
# Uncomment + fill values to switch providers.
###############################################################################
########## Azure OpenAI (API key auth) ########################################
#LLM_PROVIDER="azure"
#LLM_MODEL="azure/gpt-5-mini"
#LLM_ENDPOINT="https://YOUR-RESOURCE.openai.azure.com"
#LLM_API_KEY="your-azure-api-key"
#LLM_API_VERSION="2024-12-01-preview"
#LLM_MAX_COMPLETION_TOKENS="16384"
########## Azure OpenAI (managed identity / DefaultAzureCredential) ###########
# Uses DefaultAzureCredential - no API key needed (for Azure VMs, App Service, etc.)
# Requires: pip install azure-identity
#LLM_PROVIDER="azure"
#LLM_MODEL="azure/gpt-5-mini"
#LLM_ENDPOINT="https://YOUR-RESOURCE.openai.azure.com"
#LLM_API_VERSION="2024-12-01-preview"
#LLM_AZURE_USE_MANAGED_IDENTITY=true
#EMBEDDING_MODEL="azure/text-embedding-3-large"
#EMBEDDING_ENDPOINT="https://YOUR-RESOURCE.openai.azure.com/openai/deployments/text-embedding-3-large"
#EMBEDDING_API_KEY="your-azure-api-key"
#EMBEDDING_API_VERSION="2024-12-01-preview"
#EMBEDDING_DIMENSIONS=3072
#EMBEDDING_MAX_COMPLETION_TOKENS=8191
########## Local LLM via Ollama ###############################################
#LLM_API_KEY ="ollama"
#LLM_MODEL="llama3.1:8b"
#LLM_PROVIDER="ollama"
#LLM_ENDPOINT="http://localhost:11434/v1"
#EMBEDDING_PROVIDER="ollama"
#EMBEDDING_MODEL="nomic-embed-text:latest"
#EMBEDDING_ENDPOINT="http://localhost:11434/api/embed"
#EMBEDDING_DIMENSIONS=768
#HUGGINGFACE_TOKENIZER="nomic-ai/nomic-embed-text-v1.5"
########## OpenRouter (also free) #############################################
#LLM_API_KEY="<<go-get-one-yourself"
#LLM_PROVIDER="custom"
#LLM_MODEL="openrouter/google/gemini-2.0-flash-lite-preview-02-05:free"
#LLM_ENDPOINT="https://openrouter.ai/api/v1"
########## DeepInfra ##########################################################
#LLM_API_KEY="<<>>"
#LLM_PROVIDER="custom"
#LLM_MODEL="deepinfra/meta-llama/Meta-Llama-3-8B-Instruct"
#LLM_ENDPOINT="https://api.deepinfra.com/v1/openai"
#EMBEDDING_PROVIDER="openai"
#EMBEDDING_API_KEY="<<>>"
#EMBEDDING_MODEL="deepinfra/BAAI/bge-base-en-v1.5"
#EMBEDDING_ENDPOINT=""
#EMBEDDING_API_VERSION=""
#EMBEDDING_DIMENSIONS=3072
#EMBEDDING_MAX_COMPLETION_TOKENS=8191
+5
View File
@@ -0,0 +1,5 @@
# ignore jupyter notebooks in the language bar on github
notebooks/** linguist-vendored
# Ensure shell scripts always use LF line endings (fixes Docker on Windows)
*.sh text eol=lf
+26
View File
@@ -0,0 +1,26 @@
# .gitguardian.yml
version: 2
secret:
# Ignore specific file paths from scanning
ignored-paths:
- ".env.template"
- ".github/workflows/*.yml"
- "examples/**"
- "tests/**"
- "docker-compose.yml"
- "deployment/helm/docker-compose-helm.yml"
# Ignore specific detector types (test/CI credentials, not real secrets)
ignored-detectors:
- generic_password
- generic_high_entropy_secret
# Ignore specific known false-positive matches
ignored-matches:
- name: "CI test postgres credentials in e2e_tests.yml"
match: "cognee"
- name: "CI test postgres credentials in search_db_tests.yml"
match: "cognee"
- name: "Docker compose neo4j test password"
match: "pleaseletmein"
+71
View File
@@ -0,0 +1,71 @@
# Code owners for the cognee repository.
#
# GitHub auto-requests reviews from these owners when a PR touches their paths.
# Order matters: the LAST matching pattern wins. Keep most-specific rules at the
# bottom.
#
# To update this file, please confirm the change with the affected owners
# before merging. Tracking ticket: COG-4900.
# -----------------------------------------------------------------------------
# Default fallback — picked when no other rule matches.
# -----------------------------------------------------------------------------
* @Vasilije1990
# -----------------------------------------------------------------------------
# Public API surface (V1 + V2)
# -----------------------------------------------------------------------------
/cognee/api/v1/ @dexters1 @Vasilije1990
/cognee/api/v1/cognify/ @dexters1
/cognee/api/v1/remember/ @dexters1 @Vasilije1990
/cognee/api/v1/recall/ @dexters1 @Vasilije1990
# -----------------------------------------------------------------------------
# Retrieval / memory tasks (V2 memory + agentic retrievers)
# -----------------------------------------------------------------------------
/cognee/modules/retrieval/ @hajdul88 @lxobr
/cognee/tasks/memify/ @lxobr @hajdul88
/cognee/tasks/temporal_awareness/ @lxobr @hajdul88
/cognee/tasks/temporal_graph/ @lxobr @hajdul88
# -----------------------------------------------------------------------------
# Pipelines & tasks (the cognify ECL pipeline + composable tasks)
# -----------------------------------------------------------------------------
/cognee/pipelines/ @Vasilije1990
/cognee/tasks/ @Vasilije1990 @siillee
# -----------------------------------------------------------------------------
# Infrastructure adapters
# -----------------------------------------------------------------------------
/cognee/infrastructure/databases/vector/ @siillee @dexters1
/cognee/infrastructure/databases/graph/ @siillee
/cognee/infrastructure/databases/graph/ladybug/ @siillee @hajdul88
/cognee/infrastructure/databases/cache/ @Vasilije1990
# -----------------------------------------------------------------------------
# MCP server
# -----------------------------------------------------------------------------
/cognee-mcp/ @Vasilije1990 @dexters1
# -----------------------------------------------------------------------------
# Frontend (Next.js UI)
# -----------------------------------------------------------------------------
/cognee-frontend/ @LStromann
# -----------------------------------------------------------------------------
# Build, packaging, CI
# -----------------------------------------------------------------------------
/Dockerfile @Vasilije1990
/distributed/Dockerfile @Vasilije1990
/.github/workflows/ @dexters1 @siillee
/.github/actions/ @dexters1
/pyproject.toml @Vasilije1990 @dexters1
/uv.lock @Vasilije1990 @dexters1
# -----------------------------------------------------------------------------
# Contributor experience (this file, CONTRIBUTING.md, AGENTS.md, CLAUDE.md)
# -----------------------------------------------------------------------------
/.github/CODEOWNERS @Vasilije1990
/CONTRIBUTING.md @Vasilije1990
/AGENTS.md @Vasilije1990
/CLAUDE.md @Vasilije1990
+97
View File
@@ -0,0 +1,97 @@
name: 🐛 Bug Report
description: Report a bug or unexpected behavior
title: "[Bug]: "
labels: ["bug", "needs-triage"]
assignees: []
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report! Please provide a clear and detailed description.
- type: textarea
id: description
attributes:
label: Bug Description
description: Please provide a clear and concise description of the bug. What happened vs what you expected?
placeholder: Describe the bug in detail...
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Steps to Reproduce
description: Please provide detailed steps to reproduce the issue
placeholder: |
1. Go to...
2. Click on...
3. See error...
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected Behavior
description: What did you expect to happen?
placeholder: Describe what you expected...
validations:
required: true
- type: textarea
id: actual
attributes:
label: Actual Behavior
description: What actually happened?
placeholder: Describe what actually happened...
validations:
required: true
- type: textarea
id: environment
attributes:
label: Environment
description: Please provide your environment details
placeholder: |
- OS: [e.g. macOS 13.0, Ubuntu 20.04]
- Python version: [e.g. 3.9.0]
- Cognee version: [e.g. 0.1.0]
- LLM Provider: [e.g. OpenAI, Ollama]
- Database: [e.g. Neo4j]
validations:
required: true
- type: textarea
id: logs
attributes:
label: Logs/Error Messages
description: Please include any relevant logs or error messages
placeholder: Paste logs here...
render: shell
validations:
required: false
- type: textarea
id: additional
attributes:
label: Additional Context
description: Add any other context about the problem here
placeholder: Any additional information...
validations:
required: false
- type: checkboxes
id: checklist
attributes:
label: Pre-submission Checklist
description: Please confirm the following before submitting
options:
- label: I have searched existing issues to ensure this bug hasn't been reported already
required: true
- label: I have provided a clear and detailed description of the bug
required: true
- label: I have included steps to reproduce the issue
required: true
- label: I have included my environment details
required: true
+8
View File
@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: 💬 Discord Community
url: https://discord.gg/NQtRemgQVD
about: Join our Discord community for questions, discussions, and support
- name: 📖 Documentation
url: https://docs.cognee.ai
about: Check our documentation for guides and API references
+73
View File
@@ -0,0 +1,73 @@
name: 📚 Documentation Issue
description: Report an issue with documentation or suggest documentation improvements
title: "[Docs]: "
labels: ["documentation", "needs-triage"]
assignees: []
body:
- type: markdown
attributes:
value: |
Thanks for helping improve our documentation! Please provide details about the documentation issue or improvement.
- type: dropdown
id: doc-type
attributes:
label: Documentation Type
description: What type of documentation issue is this?
options:
- Missing documentation
- Incorrect documentation
- Unclear documentation
- Documentation improvement
- New documentation request
validations:
required: true
- type: textarea
id: location
attributes:
label: Documentation Location
description: Where is the documentation issue located? (URL, file path, section, etc.)
placeholder: https://cognee.ai/docs/... or specific file/section
validations:
required: true
- type: textarea
id: issue
attributes:
label: Issue Description
description: Please describe the documentation issue or improvement needed
placeholder: The documentation is unclear about...
validations:
required: true
- type: textarea
id: suggestion
attributes:
label: Suggested Improvement
description: How would you improve this documentation?
placeholder: I suggest changing this to...
validations:
required: false
- type: textarea
id: additional
attributes:
label: Additional Context
description: Add any other context about the documentation issue
placeholder: Additional context...
validations:
required: false
- type: checkboxes
id: checklist
attributes:
label: Pre-submission Checklist
description: Please confirm the following before submitting
options:
- label: I have searched existing issues to ensure this documentation issue hasn't been reported already
required: true
- label: I have provided a clear description of the documentation issue
required: true
- label: I have specified the location of the documentation issue
required: true
@@ -0,0 +1,77 @@
name: 🚀 Feature Request
description: Suggest a new feature or enhancement
title: "[Feature]: "
labels: ["enhancement", "needs-triage"]
assignees: []
body:
- type: markdown
attributes:
value: |
Thanks for suggesting a new feature! Please provide a clear and detailed description of your idea.
- type: textarea
id: problem
attributes:
label: Problem Statement
description: Is your feature request related to a problem? Please describe the problem you're trying to solve.
placeholder: I'm always frustrated when...
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed Solution
description: Describe the solution you'd like to see implemented
placeholder: I would like to see...
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives Considered
description: Describe any alternative solutions or features you've considered
placeholder: I have also considered...
validations:
required: false
- type: textarea
id: use-case
attributes:
label: Use Case
description: Describe your specific use case and how this feature would help
placeholder: This feature would help me...
validations:
required: true
- type: textarea
id: implementation
attributes:
label: Implementation Ideas
description: If you have ideas about how this could be implemented, please share them
placeholder: This could be implemented by...
validations:
required: false
- type: textarea
id: additional
attributes:
label: Additional Context
description: Add any other context, screenshots, or examples about the feature request
placeholder: Additional context...
validations:
required: false
- type: checkboxes
id: checklist
attributes:
label: Pre-submission Checklist
description: Please confirm the following before submitting
options:
- label: I have searched existing issues to ensure this feature hasn't been requested already
required: true
- label: I have provided a clear problem statement and proposed solution
required: true
- label: I have described my specific use case
required: true
+97
View File
@@ -0,0 +1,97 @@
# Workflow Migration to Test Suites
This document explains how to ensure all test workflows are only run through the central test-suites.yml workflow.
## Why Migrate to Test Suites?
1. **Prevent Duplicate Runs**: Avoid running the same tests multiple times
2. **Sequential Execution**: Ensure tests run in the correct order
3. **Centralized Control**: Manage all tests from a single place
4. **Resource Efficiency**: Run tests only when needed
## Automated Migration
We've provided a script to automatically convert individual workflows to only run when called by the test-suites.yml file:
```bash
# Make the script executable
chmod +x .github/workflows/disable_independent_workflows.sh
# Run the script
.github/workflows/disable_independent_workflows.sh
```
## Manual Migration
For each workflow file that should only run through test-suites.yml:
1. Open the workflow file
2. Find the `on:` section, which typically looks like:
```yaml
on:
workflow_dispatch:
pull_request:
types: [labeled, synchronize]
```
3. Replace it with:
```yaml
on:
workflow_call:
secrets:
inherit: true
```
4. Save the file
## Verification
After modifying the workflows, verify that:
1. The workflows no longer trigger on pushes or PRs
2. The workflows still run correctly when called by test-suites.yml
3. No tests are left out of the test-suites.yml orchestrator
## Example Conversion
**Before:**
```yaml
name: test | chromadb
on:
workflow_dispatch:
pull_request:
types: [labeled, synchronize]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: false
jobs:
run_chromadb_integration_test:
name: chromadb test
runs-on: ubuntu-22.04
# ...rest of workflow...
```
**After:**
```yaml
name: test | chromadb
on:
workflow_call:
secrets:
inherit: true
jobs:
run_chromadb_integration_test:
name: chromadb test
runs-on: ubuntu-22.04
# ...rest of workflow...
```
## Special Cases
- **CI/CD Workflows**: Don't modify workflows for CI/CD pipelines like cd.yaml and cd_prd.yaml
- **Shared Workflows**: Keep reusable_*.yml workflows as they are, since they're already designed to be called by other workflows
- **Infrastructure Workflows**: Don't modify workflows that handle infrastructure or deployments
+80
View File
@@ -0,0 +1,80 @@
name: cognee-setup
description: "Sets up Python, installs uv, and installs dependencies for Cognee."
inputs:
python-version:
description: "Which Python version to use"
required: false
default: "3.11.x"
extra-dependencies:
description: "Additional extra dependencies to install (space-separated)"
required: false
default: ""
rebuild-lockfile:
description: "Whether to rebuild the uv lockfile"
required: false
default: "false"
runs:
using: "composite"
steps:
- name: Detect CI container
id: detect-env
shell: bash
run: |
if [ -f "/app/.anon_id" ] && command -v uv &> /dev/null && [ -d "/app/.venv" ]; then
echo "in-container=true" >> "$GITHUB_OUTPUT"
else
echo "in-container=false" >> "$GITHUB_OUTPUT"
fi
- name: Set up Python
if: steps.detect-env.outputs.in-container != 'true'
uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}
- name: Install uv
if: steps.detect-env.outputs.in-container != 'true'
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Rebuild uv lockfile
if: ${{ inputs.rebuild-lockfile == 'true' }}
shell: bash
run: |
rm uv.lock
uv lock
- name: Install dependencies (bare runner)
if: steps.detect-env.outputs.in-container != 'true'
shell: bash
run: |
EXTRA_ARGS=""
if [ -n "${{ inputs.extra-dependencies }}" ]; then
IFS=' ' read -r -a deps <<< "${{ inputs.extra-dependencies }}"
for extra in "${deps[@]}"; do
EXTRA_ARGS="$EXTRA_ARGS --extra $extra"
done
fi
uv sync --extra api --extra docs --extra evals --extra codegraph --extra ollama --extra dev --extra neo4j --extra redis --extra tracing $EXTRA_ARGS
- name: Install dependencies (container - link project only)
if: steps.detect-env.outputs.in-container == 'true'
shell: bash
env:
UV_PROJECT_ENVIRONMENT: /app/.venv
run: |
# Persist for all subsequent steps so uv run uses /app/.venv
echo "UV_PROJECT_ENVIRONMENT=/app/.venv" >> "$GITHUB_ENV"
# Install project into the pre-built venv; --inexact keeps pre-installed extras intact
uv sync --frozen --inexact
# Prevent uv run from re-syncing and stripping extras
echo "UV_NO_SYNC=true" >> "$GITHUB_ENV"
- name: Add telemetry identifier for telemetry test and in case telemetry is enabled by accident
shell: bash
run: |
echo "test-machine" > .anon_id
+35
View File
@@ -0,0 +1,35 @@
name: 'Build Docker images for Cognee'
description: 'Build cognee-related Docker images and push to the Docker registry (AWS ECR)'
inputs:
stage:
description: 'The stage of the pipeline, such as "dev" or "prd", for the Cognee app'
required: true
aws_account_id:
description: 'The AWS account ID for the Cognee app'
required: true
should_publish:
description: 'Whether to publish the Cognee Docker image to AWS ECR; should be either "true" or "false"'
required: true
ecr_image_repo_name:
description: 'The Docker image ECR repository name for the Cognee app, such as "workflows"'
required: true
dockerfile_location:
description: 'The directory location of the Dockerfile for the Cognee app'
required: true
runs:
using: "composite"
steps:
- name: Build PromethAI App Docker image
shell: bash
env:
STAGE: ${{ inputs.stage }}
run: |
export SHA_SHORT="$(git rev-parse --short HEAD)"
export CUR_DATE="$(date +%Y%m%d%H%M%S)"
export VERSION="${{ inputs.stage }}-$CUR_DATE-$SHA_SHORT"
export STAGE="${{ inputs.stage }}"
export APP_DIR="$PWD/${{ inputs.dockerfile_location }}"
image_name="${{ inputs.ecr_image_repo_name }}" version="$VERSION" account="${{ inputs.aws_account_id }}" app_dir="$APP_DIR" publish="${{ inputs.should_publish }}" ./bin/dockerize
echo "Docker tag is: $VERSION"
echo $VERSION > /tmp/.DOCKER_IMAGE_VERSION
+55
View File
@@ -0,0 +1,55 @@
name: install_cognee
description: "Installs Cognee from local source or PyPI depending on specified version"
inputs:
python-version:
description: "Which Python version to use"
required: false
default: "3.11.x"
cognee_version:
description: "Pypi-compatible version of cognee to use. For example, 0.5.2.dev0. `local` (default) - Installing Cognee from local source"
required: false
default: "local"
runs:
using: "composite"
steps:
- name: Detect CI container
id: detect-env
shell: bash
run: |
if [ -f "/app/.anon_id" ] && command -v uv &> /dev/null && [ -d "/app/.venv" ]; then
echo "in-container=true" >> "$GITHUB_OUTPUT"
else
echo "in-container=false" >> "$GITHUB_OUTPUT"
fi
- name: Set up Python
if: steps.detect-env.outputs.in-container != 'true'
uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}
- name: Install uv
if: steps.detect-env.outputs.in-container != 'true'
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: (Re)Install Cognee
shell: bash
working-directory: cognee-mcp
env:
VIRTUAL_ENV: ${{ steps.detect-env.outputs.in-container == 'true' && '/app/.venv' || '' }}
run: |
uv pip uninstall cognee
if [ "${{ inputs.cognee_version }}" = "local" ]; then
echo "Installing Cognee from local source ..."
uv pip install --force-reinstall -e ../
else
echo "Installing Cognee version ${{ inputs.cognee_version }} from PyPI..."
uv pip install --force-reinstall "cognee==${{ inputs.cognee_version }}"
fi
echo "Installed Cognee version:"
uv pip show cognee | grep Version
+67
View File
@@ -0,0 +1,67 @@
name: 'Setup Neo4j with Graph Data Science'
description: 'Sets up a Neo4j instance with APOC and Graph Data Science plugins for testing'
inputs:
neo4j-version:
description: 'Neo4j version to use'
required: false
default: '5.21'
neo4j-password:
description: 'Password for Neo4j'
required: false
default: 'cognee_test_password'
outputs:
neo4j-url:
description: 'Neo4j connection URL'
value: 'bolt://localhost:7687'
neo4j-username:
description: 'Neo4j username'
value: 'neo4j'
neo4j-password:
description: 'Neo4j password'
value: ${{ inputs.neo4j-password }}
runs:
using: 'composite'
steps:
- name: Start Neo4j with GDS
shell: bash
run: |
docker run -d \
--name neo4j-test \
-p 7474:7474 -p 7687:7687 \
-e NEO4J_AUTH="neo4j/${{ inputs.neo4j-password }}" \
-e NEO4J_PLUGINS='["apoc", "graph-data-science"]' \
-e NEO4J_dbms_security_procedures_unrestricted="apoc.*,gds.*" \
-e NEO4J_apoc_export_file_enabled=true \
-e NEO4J_apoc_import_file_enabled=true \
neo4j:${{ inputs.neo4j-version }}
- name: Wait for Neo4j to be ready
shell: bash
run: |
echo "Waiting for Neo4j to start..."
timeout=60
counter=0
while [ $counter -lt $timeout ]; do
if docker exec neo4j-test cypher-shell -u neo4j -p "${{ inputs.neo4j-password }}" "RETURN 1" > /dev/null 2>&1; then
echo "Neo4j is ready!"
break
fi
echo "Waiting... ($counter/$timeout)"
sleep 2
counter=$((counter + 2))
done
if [ $counter -ge $timeout ]; then
echo "Neo4j failed to start within $timeout seconds"
docker logs neo4j-test
exit 1
fi
- name: Verify GDS is available
shell: bash
run: |
echo "Verifying Graph Data Science library is available..."
docker exec neo4j-test cypher-shell -u neo4j -p "${{ inputs.neo4j-password }}" \
"CALL gds.version() YIELD gdsVersion RETURN gdsVersion"
echo "GDS verification complete!"
+11
View File
@@ -0,0 +1,11 @@
# Core team GitHub logins (one per line). Lines may begin with @; case-insensitive.
borisarzentar
daukadolt
dexters1
hajdul88
hande-k
lxobr
pazone
siillee
vasilije1990
NMZivkovic
+33
View File
@@ -0,0 +1,33 @@
## How to make a release
### Dev release
#### Prepare release
1. Set the project version that will be released in [pyproject.toml](https://github.com/topoteretes/cognee/blob/dev/pyproject.toml#L4)
2. Update `uv.lock` with `uv lock` lock command
3. Update `poetry.lock` by deleting the `poetry.lock` file first and then running the `poetry lock` command. This is required to update the `poetry.lock` file with the new version of the dependencies, otherwise it does not properly update and mostly uses the cached dependency versions in the existing `poetry.lock` file.
4. Create a PR with the changes mentioned above to `dev` and merge it.
#### Perform Release
1. Go to [Release action](https://github.com/topoteretes/cognee/actions/workflows/release.yml)
2. Select `dev` branch and run the workflow.
3. Watch the logs and make sure that everything goes well
### Main release
#### Prepare release
1. Set the project version that will be released in [pyproject.toml](https://github.com/topoteretes/cognee/blob/dev/pyproject.toml#L4)
2. Update `uv.lock` with `uv lock` lock command
3. Update `poetry.lock` by deleting the `poetry.lock` file first and then running the `poetry lock` command. This is required to update the `poetry.lock` file with the new version of the dependencies, otherwise it does not properly update and mostly uses the cached dependency versions in the existing `poetry.lock` file.
4. Create a PR with the changes mentioned above to `main` and merge it.
#### Perform Release
1. Go to [Release action](https://github.com/topoteretes/cognee/actions/workflows/release.yml)
2. Select `main` branch and run the workflow.
3. Watch the logs and make sure that everything goes well
### Release validation
1. Make sure that the correct image is published to [Docker Hub](https://hub.docker.com/r/cognee/cognee)
2. Python package is published to [PyPi](https://pypi.org/project/cognee/)
3. Find the created github release in [GitHub releases](https://github.com/topoteretes/cognee/releases). Edit/prettify the release notes if required.
+34
View File
@@ -0,0 +1,34 @@
You are a documentation improvement agent for the Cognee project.
Update the existing Cognee documentation to reflect this merged PR. Your job is to document the actual behavior and API changes introduced by this PR, not to make adjacent or generic documentation improvements.
## Required inputs
Read these first:
- Documentation scope plan
- Branch notes
- Documentation assessment
## Available resources
- **Documentation repo** (`./docs-repo`): Contains the documentation pages. Use existing `.md` and `.mdx` pages as the primary targets for edits. Read `./docs-repo/docs.json` only if the scope plan requires navigation context.
- **Cognee source code** (current workspace root): Use the source code to verify actual implementation details, defaults, supported options, function signatures, env vars, and behavior.
## Editing rules
1. Follow the documentation scope plan.
2. If the scope plan says `Docs Needed` is `false`, make no documentation edits and print the reason.
3. Inspect only the source files listed in the scope plan unless they are insufficient to verify a specific planned edit.
4. Edit only docs files listed in the scope plan unless they are clearly the wrong target; if so, choose the smallest better existing docs target.
5. Document only user-facing behavior, public API changes, examples, or developer-facing semantics that actually changed in this PR.
6. If a proposed docs edit cannot be traced back to a concrete source diff in this PR, do not make that edit.
7. Do not present pre-existing behavior as if this PR introduced it.
8. Do not make unrelated cleanup edits, style edits, or generic improvements.
9. Edit at most 3 documentation files unless the scope plan explicitly justifies more.
10. Prefer updating existing pages over creating new ones.
11. Do not edit `docs.json` unless the scope plan says a new docs page is strictly required.
12. Only edit documentation files inside `./docs-repo`. Do NOT modify the source repository files, workflow files, or non-documentation assets.
13. Do NOT create git commits.
When done, print a short summary of what you changed and which existing documentation pages you updated.
+46
View File
@@ -0,0 +1,46 @@
You are a documentation scope planner for the Cognee project.
Analyze this merged PR and produce a small documentation edit plan. Do not edit documentation files.
## Available resources
- **Documentation repo** (`./docs-repo`): Contains the documentation pages. Use existing `.md` and `.mdx` pages as the primary targets for edits. Read `./docs-repo/docs.json` if it exists to understand the documentation structure.
- **Cognee source code** (current workspace root): Use the source code to verify actual implementation details, defaults, supported options, function signatures, env vars, and behavior.
- **Prepared documentation edit scope**: Curated source files, docs candidates, documentation signals, assessment summary, and out-of-scope files produced by the workflow.
## Planning task
1. Read the prepared documentation edit scope first.
2. Use the prepared scope as your primary evidence. Do not re-classify the full PR changed-file list.
3. Read only the source files listed in `Source Files To Inspect` unless one listed file is insufficient to verify a specific planned edit.
4. Read only the documentation files listed in `Candidate Documentation Files` unless they are clearly the wrong target.
5. Do not run shell commands or inspect the full diff. If the prepared scope is still too broad, produce a conservative small plan instead of exploring further.
6. Treat files listed in `Out Of Scope Files` as skipped unless one is explicitly needed to verify a planned edit.
7. Identify the smallest docs edit surface that could cover the public-facing changes.
Write the final plan to the scope plan output path provided by the workflow prompt.
The plan must be Markdown with these exact sections:
# Documentation Scope Plan
## Docs Needed
`true` or `false`
## Reason
One concise paragraph.
## Documentation-Worthy Changes
Bullets. Each bullet must name the change, the source files proving it, and the recommended docs page type.
## Files To Edit
Bullets of existing docs files to edit. Use paths relative to `docs-repo`. Leave empty if none.
## Source Files To Inspect During Editing
Bullets of source files the editing step should inspect. Keep this list short and exclude tests/assets/lockfiles.
## Out Of Scope
Bullets for changes intentionally skipped.
Do not edit files inside `./docs-repo`.
Do not create commits.
+38
View File
@@ -0,0 +1,38 @@
<!-- .github/pull_request_template.md -->
## Description
<!--
Please provide a clear, human-generated description of the changes in this PR.
DO NOT use AI-generated descriptions. We want to understand your thought process and reasoning.
-->
## Acceptance Criteria
<!--
* Key requirements to the new feature or modification;
* Proof that the changes work and meet the requirements;
-->
## Type of Change
<!-- Please check the relevant option -->
- [ ] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Code refactoring
- [ ] Other (please specify):
## Screenshots
<!-- ADD SCREENSHOT OF LOCAL TESTS PASSING-->
## Pre-submission Checklist
<!-- Please check all boxes that apply before submitting your PR -->
- [ ] **I have tested my changes thoroughly before submitting this PR** (See `CONTRIBUTING.md`)
- [ ] **This PR contains minimal changes necessary to address the issue/feature**
- [ ] My code follows the project's coding standards and style guidelines
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] I have added necessary documentation (if applicable)
- [ ] All new and existing tests pass
- [ ] I have searched existing PRs to ensure this change hasn't been submitted already
- [ ] I have linked any relevant issues in the description
- [ ] My commits have clear and descriptive messages
## DCO Affirmation
I affirm that all code in every commit of this pull request conforms to the terms of the Topoteretes Developer Certificate of Origin.
+20
View File
@@ -0,0 +1,20 @@
name-template: 'v$NEXT_PATCH_VERSION'
tag-template: 'v$NEXT_PATCH_VERSION'
categories:
- title: 'Features'
labels: ['feature', 'enhancement']
- title: 'Bug Fixes'
labels: ['bug', 'fix']
- title: 'Maintenance'
labels: ['chore', 'refactor', 'ci']
change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
template: |
## Whats Changed
$CHANGES
## Contributors
$CONTRIBUTORS
+291
View File
@@ -0,0 +1,291 @@
name: Reusable Adapter Caching Tests
permissions:
contents: read
packages: read
on:
workflow_call:
inputs:
databases:
required: false
type: string
default: "all"
description: "Which provider combos to test (comma-separated list or 'all')"
python-version:
required: false
type: string
default: '3.11.x'
description: "Python version to test"
ci-image:
required: false
type: string
default: ''
description: "Container image for CI (empty string means no container)"
secrets:
LLM_MODEL:
required: true
LLM_ENDPOINT:
required: true
LLM_API_KEY:
required: true
LLM_ARGS:
required: false
LLM_API_VERSION:
required: true
EMBEDDING_MODEL:
required: true
EMBEDDING_API_KEY:
required: true
jobs:
run-ladybug-lance-sqlite-caching:
name: Adapter caching — Ladybug + LanceDB + Sqlite
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'ladybug/lance/sqlite') }}
steps:
- name: Check out
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
- name: Run adapter caching test
env:
ENV: 'dev'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
GRAPH_DATABASE_PROVIDER: 'ladybug'
VECTOR_DB_PROVIDER: 'lancedb'
DB_PROVIDER: 'sqlite'
run: uv run python ./cognee/tests/test_adapter_object_caching.py
run-neo4j-lance-sqlite-caching:
name: Adapter caching — Neo4j + LanceDB + Sqlite
runs-on: ubuntu-22.04
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'neo4j/lance/sqlite') }}
steps:
- name: Check out
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
- name: Setup Neo4j with GDS
uses: ./.github/actions/setup_neo4j
id: neo4j
- name: Run adapter caching test
env:
ENV: 'dev'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
GRAPH_DATABASE_PROVIDER: 'neo4j'
VECTOR_DB_PROVIDER: 'lancedb'
DB_PROVIDER: 'sqlite'
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
GRAPH_DATABASE_URL: ${{ steps.neo4j.outputs.neo4j-url }}
GRAPH_DATABASE_USERNAME: ${{ steps.neo4j.outputs.neo4j-username }}
GRAPH_DATABASE_PASSWORD: ${{ steps.neo4j.outputs.neo4j-password }}
run: uv run python ./cognee/tests/test_adapter_object_caching.py
run-ladybug-pgvector-postgres-caching:
name: Adapter caching — Ladybug + PGVector + Postgres
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'ladybug/pgvector/postgres') }}
services:
postgres:
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: cognee
POSTGRES_DB: cognee_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Check out
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
extra-dependencies: "postgres"
- name: Run adapter caching test
env:
ENV: 'dev'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
GRAPH_DATABASE_PROVIDER: 'ladybug'
VECTOR_DB_PROVIDER: 'pgvector'
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
DB_PROVIDER: 'postgres'
DB_NAME: 'cognee_db'
DB_HOST: ${{ inputs.ci-image != '' && 'postgres' || '127.0.0.1' }}
DB_PORT: 5432
DB_USERNAME: cognee
DB_PASSWORD: cognee
run: uv run python ./cognee/tests/test_adapter_object_caching.py
run-neo4j-pgvector-postgres-caching:
name: Adapter caching — Neo4j + PGVector + Postgres
runs-on: ubuntu-22.04
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'neo4j/pgvector/postgres') }}
services:
postgres:
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: cognee
POSTGRES_DB: cognee_db
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries=5
steps:
- name: Check out
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
extra-dependencies: "postgres"
- name: Setup Neo4j with GDS
uses: ./.github/actions/setup_neo4j
id: neo4j
- name: Run adapter caching test
env:
ENV: 'dev'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
GRAPH_DATABASE_PROVIDER: 'neo4j'
VECTOR_DB_PROVIDER: 'pgvector'
DB_PROVIDER: 'postgres'
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
GRAPH_DATABASE_URL: ${{ steps.neo4j.outputs.neo4j-url }}
GRAPH_DATABASE_USERNAME: ${{ steps.neo4j.outputs.neo4j-username }}
GRAPH_DATABASE_PASSWORD: ${{ steps.neo4j.outputs.neo4j-password }}
DB_NAME: cognee_db
DB_HOST: 127.0.0.1
DB_PORT: 5432
DB_USERNAME: cognee
DB_PASSWORD: cognee
run: uv run python ./cognee/tests/test_adapter_object_caching.py
run-postgres-pgvector-postgres-caching:
name: Adapter caching — Postgres graph + PGVector + Postgres (access control)
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'postgres/pgvector/postgres') }}
services:
postgres:
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: cognee
POSTGRES_DB: cognee_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Check out
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
extra-dependencies: "postgres"
- name: Run adapter caching test
env:
ENV: 'dev'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
# Access control mode: every dataset gets its own physical Postgres
# database (named after the deterministic dataset id) that is created
# on add and dropped on delete — the engine-cache lifecycle across
# that drop/recreate boundary is what this job guards.
ENABLE_BACKEND_ACCESS_CONTROL: 'true'
DB_PROVIDER: 'postgres'
DB_NAME: 'cognee_db'
DB_HOST: ${{ inputs.ci-image != '' && 'postgres' || '127.0.0.1' }}
DB_PORT: 5432
DB_USERNAME: cognee
DB_PASSWORD: cognee
VECTOR_DB_PROVIDER: 'pgvector'
VECTOR_DB_NAME: 'cognee_db'
VECTOR_DB_HOST: ${{ inputs.ci-image != '' && 'postgres' || '127.0.0.1' }}
VECTOR_DB_PORT: 5432
VECTOR_DB_USERNAME: cognee
VECTOR_DB_PASSWORD: cognee
VECTOR_DATASET_DATABASE_HANDLER: 'pgvector'
GRAPH_DATABASE_PROVIDER: 'postgres'
GRAPH_DATABASE_NAME: 'cognee_db'
GRAPH_DATABASE_HOST: ${{ inputs.ci-image != '' && 'postgres' || '127.0.0.1' }}
GRAPH_DATABASE_PORT: 5432
GRAPH_DATABASE_USERNAME: cognee
GRAPH_DATABASE_PASSWORD: cognee
GRAPH_DATASET_DATABASE_HANDLER: 'postgres_graph'
run: uv run python ./cognee/tests/test_adapter_object_caching.py
+40
View File
@@ -0,0 +1,40 @@
name: community | DCO Check
on:
pull_request:
types: [opened, edited, reopened, synchronize, ready_for_review]
jobs:
check-dco:
runs-on: ubuntu-latest
steps:
- name: Validate Developer Certificate of Origin statement
uses: actions/github-script@v8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prUser = context.payload.pull_request.user.login;
const prBody = context.payload.pull_request.body || '';
const authorAssociation = context.payload.pull_request.author_association;
// Exact text you require in the PR body
const requiredStatement = "I affirm that all code in every commit of this pull request conforms to the terms of the Topoteretes Developer Certificate of Origin";
// 1. Check if user is an org member via author_association
// (available on the PR payload without extra API calls or permissions)
// OWNER, MEMBER, and COLLABORATOR are trusted roles.
const trustedRoles = ['OWNER', 'MEMBER', 'COLLABORATOR', 'CONTRIBUTOR'];
const isTrusted = trustedRoles.includes(authorAssociation);
if (isTrusted) {
console.log(`${prUser} has association '${authorAssociation}'. Skipping DCO check.`);
} else {
console.log(`${prUser} has association '${authorAssociation}'. Enforcing DCO check.`);
// 2. If user is not trusted, enforce the DCO statement
if (!prBody.includes(requiredStatement)) {
core.setFailed(
`DCO check failed. The PR body must include the following statement:\n\n${requiredStatement}`
);
}
}
@@ -0,0 +1,27 @@
name: build test | Docker image
on:
workflow_call:
env:
AWS_ACCOUNT_ID_DEV: "463722570299"
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
build_docker:
name: Build Cognee Backend Docker App Image
runs-on: ubuntu-22.04
steps:
- name: Check out Cognee code
uses: actions/checkout@v6
- name: Build Cognee Docker image
id: cognee-docker-tag
run: |
export SHA_SHORT="$(git rev-parse --short HEAD)"
export CUR_DATE="$(date +%Y%m%d%H%M%S)"
export VERSION="dev-$CUR_DATE-$SHA_SHORT"
image_name="cognee" docker_login="false" version="$VERSION" account="${{ env.AWS_ACCOUNT_ID_DEV }}" app_dir="." publish="false" ./bin/dockerize
export DOCKER_TAG=$(cat /tmp/.DOCKER_IMAGE_VERSION)
echo "Successfully built cognee Docker image. Tag is: $DOCKER_TAG"
+139
View File
@@ -0,0 +1,139 @@
name: Reusable Basic Tests
on:
workflow_call:
inputs:
python-version:
required: false
type: string
default: '3.11.x'
ci-image:
required: false
type: string
default: ''
secrets:
LLM_PROVIDER:
required: true
LLM_MODEL:
required: true
LLM_ENDPOINT:
required: true
LLM_API_KEY:
required: true
LLM_ARGS:
required: false
LLM_API_VERSION:
required: true
EMBEDDING_PROVIDER:
required: true
EMBEDDING_MODEL:
required: true
EMBEDDING_API_KEY:
required: true
env:
RUNTIME__LOG_LEVEL: ERROR
ENV: 'dev'
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
unit-tests:
name: Run Unit Tests
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
env:
ENV: 'dev'
LLM_PROVIDER: openai
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_PROVIDER: openai
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
- name: Run Unit Tests
run: uv run pytest cognee/tests/unit/ --timeout=300 --timeout-method=thread
simple-examples:
name: Run Simple Examples
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
env:
ENV: 'dev'
LLM_PROVIDER: openai
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_PROVIDER: openai
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
- name: Run Simple Examples
run: uv run python ./examples/demos/simple_cognee_example.py
simple-examples-baml:
name: Run Simple Examples BAML
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
env:
ENV: 'dev'
STRUCTURED_OUTPUT_FRAMEWORK: "BAML"
BAML_LLM_PROVIDER: openai
BAML_LLM_MODEL: ${{ secrets.OPENAI_MODEL }}
BAML_LLM_ENDPOINT: ${{ secrets.OPENAI_ENDPOINT }}
BAML_LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
# BAML_LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
LLM_PROVIDER: openai
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_PROVIDER: openai
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
extra-dependencies: "baml"
- name: Run Simple Examples
run: uv run python ./examples/demos/simple_cognee_example.py
+32
View File
@@ -0,0 +1,32 @@
name: clean | remove stale PRs
on:
# Run this action periodically (daily at 0:00 UTC).
schedule:
- cron: "0 0 * * *"
# Optionally, also run when pull requests are labeled, unlabeled, synchronized, or reopened
# to update the stale timer as needed. Uncomment if desired.
# pull_request:
# types: [labeled, unlabeled, synchronize, reopened]
jobs:
stale:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Mark and Close Stale PRs
uses: actions/stale@v10
with:
# Number of days of inactivity before the pull request is marked stale
days-before-stale: 60
# Number of days of inactivity after being marked stale before the pull request is closed
days-before-close: 7
# Comment to post when marking as stale
stale-pr-message: "This pull request has been automatically marked as stale due to inactivity. It will be closed in 7 days if no further activity occurs."
# Comment to post when closing a stale pull request
close-pr-message: "This pull request has been closed due to prolonged inactivity."
# Labels for stale and closed PRs
stale-pr-label: "stale"
exempt-pr-labels: "keep-open"
+171
View File
@@ -0,0 +1,171 @@
name: test | cli
on:
workflow_call:
inputs:
python-version:
required: false
type: string
default: '3.11.x'
cognee_version:
required: false
type: string
default: "local"
description: "Pypi-compatible version of cognee to use. For example, 0.5.2.dev0. `local` (default) - Installing Cognee from local source"
ci-image:
required: false
type: string
default: ''
secrets:
LLM_PROVIDER:
required: true
LLM_MODEL:
required: true
LLM_ENDPOINT:
required: true
LLM_API_KEY:
required: true
LLM_ARGS:
required: false
LLM_API_VERSION:
required: true
EMBEDDING_PROVIDER:
required: true
EMBEDDING_MODEL:
required: true
EMBEDDING_API_KEY:
required: true
env:
RUNTIME__LOG_LEVEL: ERROR
ENV: 'dev'
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
cli-unit-tests:
name: CLI Unit Tests
if: ${{ inputs.cognee_version == 'local' }}
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
env:
ENV: 'dev'
LLM_PROVIDER: openai
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
- name: Run CLI Unit Tests
run: uv run pytest cognee/tests/cli_tests/cli_unit_tests/ -v
cli-integration-tests:
name: CLI Integration Tests
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
env:
ENV: 'dev'
LLM_PROVIDER: openai
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
- name: Install Cognee
uses: ./.github/actions/install_cognee
with:
python-version: ${{ inputs.python-version }}
cognee_version: ${{ inputs.cognee_version }}
- name: Run CLI Integration Tests
run: uv run pytest cognee/tests/cli_tests/cli_integration_tests/ -v
cli-functionality-tests:
name: CLI Functionality Tests
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
env:
ENV: 'dev'
LLM_PROVIDER: openai
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
- name: Install Cognee
uses: ./.github/actions/install_cognee
with:
python-version: ${{ inputs.python-version }}
cognee_version: ${{ inputs.cognee_version }}
- name: Test CLI Help Commands
run: |
uv run python -m cognee.cli._cognee --help
uv run python -m cognee.cli._cognee --version
uv run python -m cognee.cli._cognee add --help
uv run python -m cognee.cli._cognee search --help
uv run python -m cognee.cli._cognee cognify --help
uv run python -m cognee.cli._cognee delete --help
uv run python -m cognee.cli._cognee config --help
- name: Test CLI Config Subcommands
run: |
uv run python -m cognee.cli._cognee config get --help
uv run python -m cognee.cli._cognee config set --help
uv run python -m cognee.cli._cognee config list --help
uv run python -m cognee.cli._cognee config unset --help
uv run python -m cognee.cli._cognee config reset --help
- name: Test CLI Error Handling
run: |
# Test invalid command (should fail gracefully)
! uv run python -m cognee.cli._cognee invalid_command
# Test missing required arguments (should fail gracefully)
! uv run python -m cognee.cli._cognee search
# Test invalid search type (should fail gracefully)
! uv run python -m cognee.cli._cognee search "test" --query-type INVALID_TYPE
# Test invalid chunker (should fail gracefully)
! uv run python -m cognee.cli._cognee cognify --chunker InvalidChunker
+25
View File
@@ -0,0 +1,25 @@
name: community | Greetings
on:
issues:
types: [opened]
pull_request_target:
types: [opened]
permissions:
issues: write
pull-requests: write
jobs:
greeting:
if: github.actor != 'github-actions[bot]' && github.actor != 'dependabot[bot]' && !contains(github.event.pull_request.body, 'Generated with [Claude Code]')
runs-on: ubuntu-22.04
steps:
- uses: actions/first-interaction@v3
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
pr_message: 'Hello @${{ github.actor }}, thank you for submitting a PR! We will respond as soon as possible.'
issue_message: |
Hello @${{ github.actor }}, thank you for your interest in our work!
If this is a bug report, please provide screenshots and **minimum viable code to reproduce your issue**, otherwise we can not help you.
+180
View File
@@ -0,0 +1,180 @@
name: Community Tests (No Secrets)
# Runs on ALL pull requests, including forks.
# No secrets required — only fully mocked unit tests and code quality checks.
# This gives community contributors fast feedback on their changes.
on:
pull_request:
branches: [ main, dev ]
types: [opened, synchronize, reopened]
permissions:
contents: read
concurrency:
group: community-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
RUNTIME__LOG_LEVEL: ERROR
ENV: 'dev'
jobs:
code-quality:
name: Code Quality
runs-on: ubuntu-22.04
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Validate uv lockfile
run: uv lock --check || { echo "'uv lock --check' failed. Run 'uv lock' and push your changes."; exit 1; }
- name: Run pre-commit hooks
uses: pre-commit/action@v3.0.1
- name: Install dependencies
run: uv sync --extra dev
- name: Ruff check
run: uv run ruff check .
- name: Ruff format check
run: uv run ruff format --check .
- name: Ty type check
run: uv run ty check .
unit-tests:
name: Unit Tests (Mocked, No Secrets)
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
python-version: ['3.11.x']
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Install dependencies
# postgres is needed so the SQL cache adapter tests run instead of skipping.
run: uv sync --extra dev --extra postgres
- name: Run mocked unit tests
run: |
uv run pytest \
cognee/tests/unit/processing/ \
cognee/tests/unit/entity_extraction/ \
cognee/tests/unit/modules/graph/ \
cognee/tests/unit/modules/chunking/ \
cognee/tests/unit/modules/data/ \
cognee/tests/unit/modules/retrieval/ \
--ignore=cognee/tests/unit/modules/retrieval/graph_completion_retriever_cot_test.py \
--ignore=cognee/tests/unit/modules/retrieval/temporal_retriever_test.py \
--ignore=cognee/tests/unit/modules/retrieval/triplet_retriever_test.py \
cognee/tests/unit/modules/search/ \
cognee/tests/unit/modules/pipelines/ \
cognee/tests/unit/modules/visualization/ \
cognee/tests/unit/modules/ontology/ \
cognee/tests/unit/modules/observability/ \
cognee/tests/unit/modules/users/ \
cognee/tests/unit/modules/memify_tasks/ \
cognee/tests/unit/interfaces/graph/ \
cognee/tests/unit/infrastructure/databases/cache/ \
cognee/tests/unit/infrastructure/databases/vector/test_vector_db_config.py \
cognee/tests/unit/infrastructure/databases/relational/ \
cognee/tests/unit/infrastructure/databases/test_unified_store_engine.py \
cognee/tests/unit/infrastructure/session/ \
cognee/tests/unit/infrastructure/llm/ \
cognee/tests/unit/infrastructure/test_rate_limiting_retry.py \
cognee/tests/unit/tasks/storage/test_add_data_points.py \
cognee/tests/unit/shared/ \
-v --tb=short
cli-unit-tests:
name: CLI Unit Tests (Mocked, No Secrets)
runs-on: ubuntu-22.04
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11.x'
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Install dependencies
run: uv sync --extra dev
- name: Run CLI unit tests
run: uv run pytest cognee/tests/cli_tests/cli_unit_tests/ -v --tb=short
telemetry-test:
name: Telemetry Test (Mocked, No Secrets)
runs-on: ubuntu-22.04
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11.x'
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Install dependencies
run: uv sync --extra dev
- name: Run telemetry test
run: uv run pytest cognee/tests/test_telemetry.py -v --tb=short
notify:
name: Community Tests Status
needs: [code-quality, unit-tests, cli-unit-tests, telemetry-test]
runs-on: ubuntu-latest
if: ${{ !cancelled() }}
steps:
- name: Check Status
run: |
if [[ "${{ needs.code-quality.result }}" == "success" &&
"${{ needs.unit-tests.result }}" == "success" &&
"${{ needs.cli-unit-tests.result }}" == "success" &&
"${{ needs.telemetry-test.result }}" == "success" ]]; then
echo "All community tests passed!"
else
echo "One or more community tests failed."
exit 1
fi
+165
View File
@@ -0,0 +1,165 @@
name: Reusable DB Examples Tests
on:
workflow_call:
inputs:
databases:
required: false
type: string
default: "all"
description: "Which databases to run (comma-separated or 'all')"
python-version:
required: false
type: string
default: "3.11.x"
ci-image:
required: false
type: string
default: ''
secrets:
LLM_MODEL:
required: true
LLM_ENDPOINT:
required: true
LLM_API_KEY:
required: true
LLM_ARGS:
required: false
LLM_API_VERSION:
required: true
EMBEDDING_MODEL:
required: true
EMBEDDING_API_KEY:
required: true
POSTGRES_PASSWORD:
required: false
NEO4J_API_URL:
required: false
NEO4J_API_KEY:
required: false
env:
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
run-db-example-neo4j:
name: "Neo4j DB Example Test"
runs-on: ubuntu-22.04
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'neo4j') }}
steps:
- name: Check out
uses: actions/checkout@master
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
- name: Setup Neo4j with GDS
uses: ./.github/actions/setup_neo4j
id: neo4j
- name: Run Neo4j Example
env:
ENV: 'dev'
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
GRAPH_DATABASE_PROVIDER: "neo4j"
GRAPH_DATABASE_URL: ${{ steps.neo4j.outputs.neo4j-url }}
GRAPH_DATABASE_USERNAME: ${{ steps.neo4j.outputs.neo4j-username }}
GRAPH_DATABASE_PASSWORD: ${{ steps.neo4j.outputs.neo4j-password }}
run: |
uv run python examples/database_examples/neo4j_example.py
run-db-example-ladybug:
name: "Ladybug DB Example Test"
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'ladybug') || contains(inputs.databases, 'kuzu') }}
steps:
- name: Check out
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
- name: Dependencies already installed
run: echo "Dependencies already installed in setup"
- name: Run Ladybug Example
env:
ENV: 'dev'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
GRAPH_DATABASE_PROVIDER: "ladybug"
run: |
uv run python examples/database_examples/ladybug_example.py
run-db-example-pgvector:
name: "PostgreSQL PGVector DB Example Test"
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'postgres') }}
services:
postgres:
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
POSTGRES_DB: cognee_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
extra-dependencies: "postgres"
- name: Run PGVector Example
env:
ENV: 'dev'
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
DB_HOST: ${{ inputs.ci-image != '' && 'postgres' || '127.0.0.1' }}
run: |
uv run python examples/database_examples/pgvector_example.py
+123
View File
@@ -0,0 +1,123 @@
name: Dev Canary Release
on:
schedule:
# Every Monday at 06:00 UTC
- cron: "0 6 * * 1"
workflow_dispatch:
workflow_call:
concurrency:
group: dev-canary-release
cancel-in-progress: true
permissions:
contents: read
packages: write
jobs:
# ── Gate: run core test suites before publishing ────────────────────
test-gate:
name: Canary Test Gate
uses: ./.github/workflows/basic_tests.yml
with:
ci-image: ""
secrets: inherit
# ── Compute canary version ──────────────────────────────────────────
prepare:
name: Prepare Canary Version
runs-on: ubuntu-latest
needs: test-gate
outputs:
version: ${{ steps.version.outputs.version }}
canary_version: ${{ steps.version.outputs.canary_version }}
steps:
- name: Check out dev
uses: actions/checkout@v6
with:
ref: dev
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Install Python
run: uv python install
- name: Compute canary version
id: version
run: |
BASE_VERSION="$(uv version --short)"
# Strip any existing .devN suffix to get the base
CLEAN_VERSION="${BASE_VERSION%%\.dev*}"
# PEP 440 dev release: 0.5.4.dev20260309
CANARY_VERSION="${CLEAN_VERSION}.dev$(date -u +%Y%m%d)"
echo "version=${CLEAN_VERSION}" >> "$GITHUB_OUTPUT"
echo "canary_version=${CANARY_VERSION}" >> "$GITHUB_OUTPUT"
echo "Canary version: ${CANARY_VERSION}"
# ── Publish to PyPI ─────────────────────────────────────────────────
release-pypi:
name: Publish Dev Canary to PyPI
needs: prepare
runs-on: ubuntu-latest
steps:
- name: Check out dev
uses: actions/checkout@v6
with:
ref: dev
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Install Python
run: uv python install
- name: Set canary version in pyproject.toml
run: uv version "${{ needs.prepare.outputs.canary_version }}"
- name: Install dependencies
run: uv sync --all-extras
- name: Build distributions
run: uv build
- name: Publish to PyPI
env:
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
run: uv publish
# ── Publish Docker image ────────────────────────────────────────────
release-docker:
name: Publish Dev Canary Docker Image
needs: prepare
runs-on: ubuntu-latest
steps:
- name: Check out dev
uses: actions/checkout@v6
with:
ref: dev
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: |
cognee/cognee:dev-canary
cognee/cognee:${{ needs.prepare.outputs.canary_version }}
labels: |
version=${{ needs.prepare.outputs.canary_version }}
flavour=dev-canary
cache-from: type=registry,ref=cognee/cognee:buildcache
cache-to: type=registry,ref=cognee/cognee:buildcache,mode=max
@@ -0,0 +1,351 @@
name: automation | Draft Docs PRs For Previous Day Dev PRs
on:
workflow_dispatch:
inputs:
lookback_days:
description: Number of UTC calendar days to look back when scanning merged PRs
required: false
default: "1"
anchor_date:
description: Optional UTC date to scan, in YYYY-MM-DD format
required: false
default: ""
schedule:
- cron: "59 23 * * *"
permissions:
contents: read
pull-requests: read
env:
lookback_days: ${{ github.event.inputs.lookback_days || vars.lookback_days || '1' }}
jobs:
prepare-merged-branches:
runs-on: ubuntu-22.04
timeout-minutes: 10
outputs:
start_date: ${{ steps.prepare.outputs.start_date }}
end_date: ${{ steps.prepare.outputs.end_date }}
has_merges: ${{ steps.prepare.outputs.has_merges }}
merge_summary: ${{ steps.prepare.outputs.merge_summary }}
matrix: ${{ steps.prepare.outputs.matrix }}
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Fetch latest dev branch
run: git fetch origin dev:refs/remotes/origin/dev --no-tags
- name: Prepare merged PRs
id: prepare
shell: bash
env:
INPUT_ANCHOR_DATE: ${{ github.event.inputs.anchor_date || '' }}
GITHUB_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
args=(
--branch origin/dev
--lookback-days "${lookback_days}"
)
anchor_date="${INPUT_ANCHOR_DATE}"
if [ "${{ github.event_name }}" = "schedule" ]; then
anchor_date="$(date -u -d 'yesterday' +%F)"
fi
if [ -n "${anchor_date}" ]; then
echo "Using anchor date ${anchor_date}"
args+=(--anchor-date "${anchor_date}")
fi
python3 tools/prepare_merged_branches.py "${args[@]}"
create-docs-prs:
needs:
- prepare-merged-branches
if: ${{ needs.prepare-merged-branches.outputs.has_merges == 'true' }}
runs-on: ubuntu-22.04
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
include: ${{ fromJSON(needs.prepare-merged-branches.outputs.matrix) }}
steps:
- name: Check out core repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Set up uv
uses: astral-sh/setup-uv@v7
- name: Install workflow dependencies
run: uv sync --locked
- name: Fetch latest dev branch
run: git fetch origin dev:refs/remotes/origin/dev --no-tags
- name: Prepare branch note paths
id: branch_paths
run: |
OUTPUT_DIR="branch-dev-notes/${{ matrix.safe_branch }}-${{ matrix.short_sha }}"
mkdir -p "${OUTPUT_DIR}"
echo "output_dir=${OUTPUT_DIR}" >> "${GITHUB_OUTPUT}"
echo "notes_json=${OUTPUT_DIR}/branch_notes.json" >> "${GITHUB_OUTPUT}"
echo "notes_markdown=${OUTPUT_DIR}/branch_notes.md" >> "${GITHUB_OUTPUT}"
echo "assessment_json=${OUTPUT_DIR}/docs_assessment.json" >> "${GITHUB_OUTPUT}"
echo "assessment_markdown=${OUTPUT_DIR}/docs_assessment.md" >> "${GITHUB_OUTPUT}"
echo "docs_edit_scope_json=${OUTPUT_DIR}/docs_edit_scope.json" >> "${GITHUB_OUTPUT}"
echo "docs_edit_scope_markdown=${OUTPUT_DIR}/docs_edit_scope.md" >> "${GITHUB_OUTPUT}"
echo "docs_scope_plan=${OUTPUT_DIR}/docs_scope_plan.md" >> "${GITHUB_OUTPUT}"
- name: Generate branch notes
env:
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY || secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_MODEL: ${{ vars.LLM_MODEL || secrets.LLM_MODEL || 'openai/gpt-4o-mini' }}
NOTES_JSON: ${{ steps.branch_paths.outputs.notes_json }}
NOTES_MARKDOWN: ${{ steps.branch_paths.outputs.notes_markdown }}
PR_NUMBER: ${{ matrix.pr_number }}
PR_TITLE: ${{ matrix.pr_title }}
PR_BODY_B64: ${{ matrix.pr_body_b64 }}
PR_URL: ${{ matrix.pr_url }}
run: |
uv run python tools/generate_branch_notes.py \
--branch-name "${{ matrix.branch_name }}" \
--merge-sha "${{ matrix.merge_sha }}" \
--first-parent "${{ matrix.first_parent }}" \
--second-parent "${{ matrix.second_parent }}" \
--pr-number "${PR_NUMBER}" \
--pr-title "${PR_TITLE}" \
--pr-body-base64 "${PR_BODY_B64}" \
--pr-url "${PR_URL}" \
--json-output "${NOTES_JSON}" \
--markdown-output "${NOTES_MARKDOWN}"
- name: Assess documentation impact for branch
id: assessment
env:
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY || secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_MODEL: ${{ vars.LLM_MODEL || secrets.LLM_MODEL || 'openai/gpt-4o-mini' }}
NOTES_JSON: ${{ steps.branch_paths.outputs.notes_json }}
NOTES_MARKDOWN: ${{ steps.branch_paths.outputs.notes_markdown }}
ASSESSMENT_JSON: ${{ steps.branch_paths.outputs.assessment_json }}
ASSESSMENT_MARKDOWN: ${{ steps.branch_paths.outputs.assessment_markdown }}
run: |
uv run python tools/assess_branch_notes.py \
--notes-json "${NOTES_JSON}" \
--notes-markdown "${NOTES_MARKDOWN}" \
--json-output "${ASSESSMENT_JSON}" \
--markdown-output "${ASSESSMENT_MARKDOWN}"
python3 tools/write_docs_assessment_outputs.py \
--assessment-json "${ASSESSMENT_JSON}" \
--branch-slug "${{ matrix.safe_branch }}" \
--short-sha "${{ matrix.short_sha }}" \
--pr-number "${{ matrix.pr_number }}"
- name: Check out docs repository
if: ${{ steps.assessment.outputs.needs_update == 'true' }}
uses: actions/checkout@v6
with:
repository: topoteretes/cognee-docs
token: ${{ secrets.REPO_DISPATCH_PAT_TOKEN }}
ref: main
path: docs-repo
- name: Prepare docs branch
if: ${{ steps.assessment.outputs.needs_update == 'true' }}
working-directory: docs-repo
run: |
git fetch origin "${{ steps.assessment.outputs.docs_branch }}" || true
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
if git show-ref --verify --quiet "refs/remotes/origin/${{ steps.assessment.outputs.docs_branch }}"; then
git checkout -B "${{ steps.assessment.outputs.docs_branch }}" "origin/${{ steps.assessment.outputs.docs_branch }}"
else
git checkout -B "${{ steps.assessment.outputs.docs_branch }}"
fi
- name: Prepare docs edit scope
if: ${{ steps.assessment.outputs.needs_update == 'true' }}
id: docs_scope
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
python3 tools/prepare_docs_edit_scope.py \
--repo "${{ github.repository }}" \
--pr-number "${{ matrix.pr_number }}" \
--docs-root docs-repo \
--notes-json "${{ steps.branch_paths.outputs.notes_json }}" \
--assessment-json "${{ steps.branch_paths.outputs.assessment_json }}" \
--scope-json-output "${{ steps.branch_paths.outputs.docs_edit_scope_json }}" \
--scope-markdown-output "${{ steps.branch_paths.outputs.docs_edit_scope_markdown }}"
- name: Plan docs changes with Claude
if: ${{ steps.assessment.outputs.needs_update == 'true' }}
id: claude_scope
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
prompt: |
Read and follow `.github/prompts/docs_scope_plan.md`.
- Branch: `${{ matrix.branch_name }}`
- PR: `#${{ matrix.pr_number }} ${{ matrix.pr_title }}`
- Merge SHA: `${{ matrix.merge_sha }}`
- Short SHA: `${{ matrix.short_sha }}`
- First parent: `${{ matrix.first_parent }}`
- Second parent: `${{ matrix.second_parent }}`
- Scope plan output: `./${{ steps.branch_paths.outputs.docs_scope_plan }}`
- **Prepared documentation edit scope** (`./${{ steps.branch_paths.outputs.docs_edit_scope_markdown }}`): Curated source files, docs candidates, assessment summary, and out-of-scope files.
- **Prepared documentation edit scope JSON** (`./${{ steps.branch_paths.outputs.docs_edit_scope_json }}`): Machine-readable copy of the prepared scope.
claude_args: "--allowed-tools Read,Write,Glob,Grep --max-turns 35"
- name: Validate docs scope plan
if: ${{ steps.assessment.outputs.needs_update == 'true' }}
run: |
test -s "${{ steps.branch_paths.outputs.docs_scope_plan }}"
if [ -n "$(git -C docs-repo status --short)" ]; then
echo "The docs planning step modified docs-repo, but planning must not edit documentation." >&2
git -C docs-repo status --short >&2
exit 1
fi
- name: Read docs scope plan outputs
if: ${{ steps.assessment.outputs.needs_update == 'true' }}
id: scope_plan
run: |
python3 tools/write_docs_scope_plan_outputs.py \
--scope-plan "${{ steps.branch_paths.outputs.docs_scope_plan }}"
- name: Generate docs changes with Claude
if: ${{ steps.assessment.outputs.needs_update == 'true' && steps.scope_plan.outputs.docs_needed == 'true' }}
id: claude
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
prompt: |
Read and follow `.github/prompts/docs_edit.md`.
- Branch: `${{ matrix.branch_name }}`
- PR: `#${{ matrix.pr_number }} ${{ matrix.pr_title }}`
- Merge SHA: `${{ matrix.merge_sha }}`
- Short SHA: `${{ matrix.short_sha }}`
- First parent: `${{ matrix.first_parent }}`
- Second parent: `${{ matrix.second_parent }}`
## Required inputs
Read these first:
- **Documentation scope plan** (`./${{ steps.branch_paths.outputs.docs_scope_plan }}`)
- **Branch notes** (`./${{ steps.branch_paths.outputs.notes_markdown }}`)
- **Documentation assessment** (`./${{ steps.branch_paths.outputs.assessment_markdown }}`)
claude_args: "--allowed-tools Read,Edit,Write,Glob,Grep,Bash --max-turns 50"
- name: Prepare docs PR content
if: ${{ steps.assessment.outputs.needs_update == 'true' && steps.scope_plan.outputs.docs_needed == 'true' }}
id: pr_content
env:
NOTES_JSON: ${{ steps.branch_paths.outputs.notes_json }}
ASSESSMENT_JSON: ${{ steps.branch_paths.outputs.assessment_json }}
BRANCH_NAME: ${{ matrix.branch_name }}
SHORT_SHA: ${{ matrix.short_sha }}
DEFAULT_PR_TITLE: ${{ steps.assessment.outputs.pr_title }}
run: |
python3 tools/prepare_docs_pr_content.py \
--notes-json "${NOTES_JSON}" \
--assessment-json "${ASSESSMENT_JSON}" \
--branch-name "${BRANCH_NAME}" \
--short-sha "${SHORT_SHA}" \
--default-pr-title "${DEFAULT_PR_TITLE}" \
--docs-root docs-repo
- name: Create docs draft commit
if: ${{ steps.assessment.outputs.needs_update == 'true' && steps.scope_plan.outputs.docs_needed == 'true' }}
id: commit_docs
working-directory: docs-repo
run: |
git add -A
if git diff --cached --quiet; then
echo "changes_made=false" >> "$GITHUB_OUTPUT"
exit 0
fi
git commit -m "${{ steps.pr_content.outputs.pr_title }}"
echo "changes_made=true" >> "$GITHUB_OUTPUT"
- name: Push docs draft branch
if: ${{ steps.assessment.outputs.needs_update == 'true' && steps.scope_plan.outputs.docs_needed == 'true' && steps.commit_docs.outputs.changes_made == 'true' }}
working-directory: docs-repo
run: git push --force-with-lease origin "${{ steps.assessment.outputs.docs_branch }}"
- name: Create or update docs pull request
if: ${{ steps.assessment.outputs.needs_update == 'true' && steps.scope_plan.outputs.docs_needed == 'true' }}
id: manage_pr
env:
GH_TOKEN: ${{ secrets.REPO_DISPATCH_PAT_TOKEN }}
HEAD_BRANCH: ${{ steps.assessment.outputs.docs_branch }}
PR_TITLE: ${{ steps.pr_content.outputs.pr_title }}
PR_BODY: ${{ steps.pr_content.outputs.pr_body }}
CHANGES_MADE: ${{ steps.commit_docs.outputs.changes_made }}
run: |
python3 tools/manage_docs_pr.py \
--target-repo topoteretes/cognee-docs \
--head-branch "${HEAD_BRANCH}" \
--pr-title "${PR_TITLE}" \
--pr-body "${PR_BODY}" \
--changes-made "${CHANGES_MADE}"
- name: Summarize docs PR result
if: ${{ steps.assessment.outputs.needs_update == 'true' && steps.scope_plan.outputs.docs_needed == 'true' }}
env:
CHANGED_FILES: ${{ steps.pr_content.outputs.changed_files }}
run: |
{
echo "## PR docs review: #${{ matrix.pr_number }} ${{ matrix.pr_title }}"
echo
echo "- Branch: \`${{ matrix.branch_name }}\`"
echo "- Merge commit: \`${{ matrix.merge_sha }}\`"
echo "- Needs documentation update: \`${{ steps.assessment.outputs.needs_update }}\`"
if [ "${{ steps.assessment.outputs.needs_update }}" = "true" ]; then
echo "- Docs branch: \`${{ steps.assessment.outputs.docs_branch }}\`"
if [ -n "${CHANGED_FILES}" ]; then
echo "- Updated docs files:"
printf '%s\n' "${CHANGED_FILES}" | while IFS= read -r changed_file; do
[ -n "${changed_file}" ] || continue
echo " - \`${changed_file}\`"
done
else
echo "- Updated docs files: none"
fi
if [ -n "${{ steps.manage_pr.outputs.pr_url }}" ]; then
echo "- Pull request: ${{ steps.manage_pr.outputs.pr_url }}"
else
echo "- Pull request: not created"
fi
fi
echo
echo "### Documentation assessment"
echo
cat "${{ steps.branch_paths.outputs.assessment_markdown }}"
} >> "${GITHUB_STEP_SUMMARY}"
+83
View File
@@ -0,0 +1,83 @@
#!/bin/bash
# Navigate to the workflows directory
cd "$(dirname "$0")"
# List of workflows that should only be triggered via test-suites.yml
WORKFLOWS=(
"test_weaviate.yml"
"test_kuzu.yml"
"test_multimetric_qa_eval_run.yaml"
"test_graphrag_vs_rag_notebook.yml"
"test_llms.yml"
"test_multimedia_example.yaml"
"test_deduplication.yml"
"test_eval_framework.yml"
"test_descriptive_graph_metrics.yml"
"test_llama_index_cognee_integration_notebook.yml"
"test_cognee_llama_index_notebook.yml"
"test_cognee_multimedia_notebook.yml"
"test_cognee_server_start.yml"
"test_telemetry.yml"
"test_neo4j.yml"
"test_pgvector.yml"
"test_ollama.yml"
"test_notebook.yml"
"test_simple_example.yml"
"test_code_graph_example.yml"
)
for workflow in "${WORKFLOWS[@]}"; do
if [ -f "$workflow" ]; then
echo "Processing $workflow..."
# Create a backup
cp "$workflow" "${workflow}.bak"
# Check if the file begins with a workflow_call trigger
if grep -q "workflow_call:" "$workflow"; then
echo "$workflow already has workflow_call trigger, skipping..."
continue
fi
# Get the content after the 'on:' section
on_line=$(grep -n "^on:" "$workflow" | cut -d ':' -f1)
if [ -z "$on_line" ]; then
echo "Warning: No 'on:' section found in $workflow, skipping..."
continue
fi
# Create a new file with the modified content
{
# Copy the part before 'on:'
head -n $((on_line-1)) "$workflow"
# Add the new on: section that only includes workflow_call
echo "on:"
echo " workflow_call:"
echo " secrets:"
echo " inherit: true"
# Find where to continue after the original 'on:' section
next_section=$(awk "NR > $on_line && /^[a-z]/ {print NR; exit}" "$workflow")
if [ -z "$next_section" ]; then
next_section=$(wc -l < "$workflow")
next_section=$((next_section+1))
fi
# Copy the rest of the file starting from the next section
tail -n +$next_section "$workflow"
} > "${workflow}.new"
# Replace the original with the new version
mv "${workflow}.new" "$workflow"
echo "Modified $workflow to only run when called from test-suites.yml"
else
echo "Warning: $workflow not found, skipping..."
fi
done
echo "Finished modifying workflows!"
+81
View File
@@ -0,0 +1,81 @@
name: Distributed Cognee test with modal
permissions:
contents: read
packages: read
on:
workflow_call:
inputs:
python-version:
required: false
type: string
default: '3.13.x'
ci-image:
required: false
type: string
default: ''
secrets:
LLM_MODEL:
required: true
LLM_ENDPOINT:
required: true
LLM_API_KEY:
required: true
LLM_ARGS:
required: false
LLM_API_VERSION:
required: true
EMBEDDING_MODEL:
required: true
EMBEDDING_API_KEY:
required: true
OPENAI_API_KEY:
required: true
env:
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
run-server-start-test:
name: Distributed Cognee test (Modal)
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.13.x'
extra-dependencies: "distributed postgres"
- name: Run Distributed Cognee (Modal)
env:
ENV: 'dev'
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
MODAL_TOKEN_ID: ${{ secrets.MODAL_TOKEN_ID }}
MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }}
MODAL_SECRET_NAME: ${{ secrets.MODAL_SECRET_NAME }}
GRAPH_DATABASE_PROVIDER: "neo4j"
GRAPH_DATABASE_URL: ${{ secrets.AZURE_NEO4j_URL }}
GRAPH_DATABASE_USERNAME: ${{ secrets.AZURE_NEO4J_USERNAME }}
GRAPH_DATABASE_PASSWORD: ${{ secrets.AZURE_NEO4J_PW }}
DB_PROVIDER: "postgres"
DB_NAME: ${{ secrets.AZURE_POSTGRES_DB_NAME }}
DB_HOST: ${{ secrets.AZURE_POSTGRES_HOST }}
DB_PORT: ${{ secrets.AZURE_POSTGRES_PORT }}
DB_USERNAME: ${{ secrets.AZURE_POSTGRES_USERNAME }}
DB_PASSWORD: ${{ secrets.AZURE_POSTGRES_PW }}
VECTOR_DB_PROVIDER: "pgvector"
COGNEE_DISTRIBUTED: "true"
run: uv run modal run ./distributed/entrypoint.py
+108
View File
@@ -0,0 +1,108 @@
name: test | docker compose
on:
workflow_call:
env:
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
docker-compose-test:
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@master
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Docker images
env:
ENV: dev
run: |
docker compose -f docker-compose.yml build
- name: Create container .env
# docker-compose.yml bind-mounts ./.env into the container; CI has no
# checked-in .env, so provide the runtime credentials the server needs.
# Secrets flow through the env block so the script body never renders
# secret material (GitHub's log masking then only has exact values to hide).
env:
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: |
printenv | grep -E '^(LLM_|EMBEDDING_)' > .env
echo "EMBEDDING_DIMENSIONS=300" >> .env
echo "COGNEE_SKIP_CONNECTION_TEST=true" >> .env
- name: Run Docker Compose
env:
ENV: dev
run: |
docker compose -f docker-compose.yml up -d
- name: Wait for server health
run: |
for attempt in $(seq 1 60); do
if curl -sf http://localhost:8000/health >/dev/null; then
echo "server healthy after ~$((attempt * 3))s"
exit 0
fi
if [ "$(docker inspect -f '{{.State.Running}}' cognee 2>/dev/null)" != "true" ]; then
echo "cognee container is not running"
docker compose -f docker-compose.yml logs cognee | tail -60
exit 1
fi
sleep 3
done
echo "server did not become healthy in time"
docker compose -f docker-compose.yml logs cognee | tail -60
exit 1
- name: Verify remember and recall round-trip
run: |
TOKEN=$(curl -sf -X POST http://localhost:8000/api/v1/auth/login \
-d "username=default_user@example.com&password=default_password" | jq -r .access_token)
[ -n "$TOKEN" ] && [ "$TOKEN" != "null" ] || { echo "login failed"; exit 1; }
FACT="The glassblower Odene Marsk crafted the twin cobalt lanterns of the Vellinge lighthouse in 1931."
echo "$FACT" > fact.txt
REMEMBERED=$(curl -sf -X POST http://localhost:8000/api/v1/remember \
-H "Authorization: Bearer $TOKEN" \
-F "datasetName=compose_smoke" \
-F "data=@fact.txt;type=text/plain")
echo "$REMEMBERED" | jq -e '.dataset_id != null' >/dev/null \
|| { echo "remember returned no dataset_id"; echo "$REMEMBERED"; exit 1; }
echo "remember: ingested into $(echo "$REMEMBERED" | jq -r .dataset_id)"
# Deterministic check: CHUNKS recall returns the raw stored text, no
# LLM involved — the full stored fact must come back verbatim.
CHUNKS=$(curl -sf -X POST http://localhost:8000/api/v1/recall \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"query":"cobalt lanterns lighthouse","searchType":"CHUNKS","datasets":["compose_smoke"]}')
echo "$CHUNKS" | grep -qF "$FACT" || { echo "CHUNKS recall missing stored fact"; echo "$CHUNKS"; exit 1; }
echo "recall (CHUNKS): stored fact retrieved verbatim"
# End-to-end answer check: the graph-grounded completion must name the entity.
ANSWER=$(curl -sf -X POST http://localhost:8000/api/v1/recall \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"query":"Who crafted the twin cobalt lanterns of the Vellinge lighthouse, and in which year?","searchType":"GRAPH_COMPLETION","datasets":["compose_smoke"]}')
echo "recall (GRAPH_COMPLETION): $ANSWER"
echo "$ANSWER" | grep -qi "Marsk" || { echo "graph completion did not mention the remembered entity"; exit 1; }
- name: Show server logs on failure
if: failure()
# Filter key-shaped lines: GitHub masks exact secret values, but partial
# or transformed echoes (e.g. provider auth errors) would slip through.
run: docker compose -f docker-compose.yml logs cognee | grep -viE "api[-_]?key|authorization|bearer" | tail -100
- name: Shut down Docker Compose
if: always()
run: |
docker compose -f docker-compose.yml down
+65
View File
@@ -0,0 +1,65 @@
name: build | Build and Push Cognee MCP Docker Image to dockerhub
on:
push:
branches:
- main
jobs:
docker-build-and-push:
runs-on:
group: Default
labels:
- docker_build_runner
steps:
- name: Check and free disk space before build
run: |
echo "=== Before cleanup ==="
df -h
echo "Removing unused preinstalled SDKs to free space..."
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc || true
docker system prune -af || true
echo "=== After cleanup ==="
df -h
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
buildkitd-flags: --root /tmp/buildkit
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: cognee/cognee-mcp
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push
id: build
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
file: cognee-mcp/Dockerfile
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=cognee/cognee-mcp:buildcache
cache-to: type=registry,ref=cognee/cognee-mcp:buildcache,mode=max
- name: Image digest
run: echo ${{ steps.build.outputs.digest }}
+48
View File
@@ -0,0 +1,48 @@
name: build | Build and Push Docker Image to dockerhub
on:
push:
branches:
- main
jobs:
docker-build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: cognee/cognee
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push
id: build
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=cognee/cognee:buildcache
cache-to: type=registry,ref=cognee/cognee:buildcache,mode=max
- name: Image digest
run: echo ${{ steps.build.outputs.digest }}
File diff suppressed because it is too large Load Diff
+384
View File
@@ -0,0 +1,384 @@
name: Reusable Examples Tests
permissions:
contents: read
packages: read
on:
workflow_call:
inputs:
ci-image:
required: false
type: string
default: ''
env:
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
test-multimedia-example:
name: Run Multimedia Example
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
- name: Run Multimedia Example
env:
ENV: 'dev'
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: uv run python ./examples/demos/multimedia_processing/multimedia_audio_image_processing_example.py
test-eval-example:
name: Run Eval Example
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
extra-dependencies: "deepeval"
- name: Run Evaluation Framework Example
env:
ENV: 'dev'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./cognee/eval_framework/run_eval.py
test-descriptive-metrics:
name: Run Descriptive Metrics Example
runs-on: ubuntu-22.04
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
- name: Setup Neo4j with GDS
uses: ./.github/actions/setup_neo4j
id: neo4j
- name: Run Descriptive Graph Metrics Example
env:
ENV: 'dev'
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
GRAPH_DATABASE_PROVIDER: "neo4j"
GRAPH_DATABASE_URL: ${{ steps.neo4j.outputs.neo4j-url }}
GRAPH_DATABASE_USERNAME: ${{ steps.neo4j.outputs.neo4j-username }}
GRAPH_DATABASE_PASSWORD: ${{ steps.neo4j.outputs.neo4j-password }}
run: uv run python ./cognee/tests/tasks/descriptive_metrics/neo4j_metrics_test.py
test-temporal-example:
name: Run Temporal Tests
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
- name: Run Temporal Example
env:
ENV: 'dev'
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./examples/demos/temporal_awareness_example/temporal_awareness_example.py
test-ontology-example:
name: Run Ontology Tests
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
- name: Run Ontology Demo Example
env:
ENV: 'dev'
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./examples/demos/ontology_reference_vocabulary/ontology_as_reference_vocabulary_example.py
test-feedback-score-shifting-example:
name: Run Feedback Score Shifting Example
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
- name: Run Feedback Score Shifting Example
env:
ENV: 'dev'
CACHING: 'true'
CACHE_BACKEND: 'fs'
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./examples/demos/feedback_score_shifting_example.py
test-agentic-reasoning:
name: Run Agentic Reasoning Tests
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
- name: Run Agentic Reasoning Example
env:
ENV: 'dev'
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./examples/custom_pipelines/agentic_reasoning_procurement_example.py
test-memify:
name: Run Memify Example
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
- name: Run Memify Tests
env:
ENV: 'dev'
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./examples/custom_pipelines/memify_coding_agent_rule_extraction_example.py
test-custom-pipeline:
name: Run Custom Pipeline Example
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
- name: Run Custom Pipeline Example
env:
ENV: 'dev'
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./examples/custom_pipelines/custom_cognify_pipeline_example.py
test-permissions-example:
name: Run Permissions Example
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
- name: Run Permissions Example
env:
ENV: 'dev'
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./examples/configurations/permissions_example/user_permissions_and_access_control_example.py
test-s3-permissions-example: # Make sure permission and multi-user mode work with S3 file system
name: Run Permissions Example
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
defaults:
run:
shell: bash
services:
postgres: # Using postgres to avoid storing and using SQLite from S3
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: cognee
POSTGRES_DB: cognee_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
extra-dependencies: "postgres aws"
- name: Run S3 Permissions Example
env:
ENV: 'dev'
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
STORAGE_BACKEND: 's3'
AWS_REGION: eu-west-1
AWS_ENDPOINT_URL: https://s3-eu-west-1.amazonaws.com
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_S3_DEV_USER_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_S3_DEV_USER_SECRET_KEY }}
STORAGE_BUCKET_NAME: github-runner-cognee-tests
DATA_ROOT_DIRECTORY: "s3://github-runner-cognee-tests/cognee/data"
SYSTEM_ROOT_DIRECTORY: "s3://github-runner-cognee-tests/cognee/system"
DB_PROVIDER: 'postgres'
DB_NAME: 'cognee_db'
DB_HOST: ${{ inputs.ci-image != '' && 'postgres' || '127.0.0.1' }}
DB_PORT: 5432
DB_USERNAME: cognee
DB_PASSWORD: cognee
run: uv run python ./examples/configurations/permissions_example/user_permissions_and_access_control_example.py
# Docling test - NO container (runs on macOS, container only works on Linux)
test_docling_add:
name: Run Add with Docling Test
runs-on: macos-15
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
extra-dependencies: 'docling'
- name: Run Docling Test
env:
ENV: 'dev'
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: |
uv sync --extra docling
uv run python ./cognee/tests/test_add_docling_document.py
+225
View File
@@ -0,0 +1,225 @@
name: Reusable Graph DB Tests
permissions:
contents: read
packages: read
on:
workflow_call:
inputs:
databases:
required: false
type: string
default: "all"
description: "Which vector databases to test (comma-separated list or 'all')"
python-version:
required: false
type: string
default: "3.11.x"
description: "Python version to use for testing"
ci-image:
required: false
type: string
default: ''
env:
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
run-kuzu-tests:
name: Kuzu Tests
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'kuzu') }}
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
- name: Dependencies already installed
run: echo "Dependencies already installed in setup"
- name: Run Kuzu Tests
env:
ENV: 'dev'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./cognee/tests/test_kuzu.py
- name: Run Weighted Edges Tests with Kuzu
env:
ENV: 'dev'
GRAPH_DATABASE_PROVIDER: "kuzu"
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run pytest cognee/tests/unit/interfaces/graph/test_weighted_edges.py -v
run-postgres-tests:
name: Postgres Graph Tests
runs-on: ubuntu-22.04
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'postgres') }}
services:
postgres:
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: cognee
POSTGRES_DB: cognee_db
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
extra-dependencies: postgres
- name: Run Postgres Adapter Unit Tests
env:
DB_PROVIDER: postgres
DB_HOST: localhost
DB_PORT: 5432
DB_USERNAME: cognee
DB_PASSWORD: cognee
DB_NAME: cognee_db
run: uv run pytest cognee/tests/e2e/postgres/test_postgres_adapter.py -v
- name: Run Postgres Graph E2E Test
env:
ENV: 'dev'
GRAPH_DATABASE_PROVIDER: "postgres"
GRAPH_DATABASE_URL: "postgresql+asyncpg://cognee:cognee@localhost:5432/cognee_db"
DB_PROVIDER: postgres
DB_HOST: localhost
DB_PORT: 5432
DB_USERNAME: cognee
DB_PASSWORD: cognee
DB_NAME: cognee_db
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./cognee/tests/e2e/postgres/test_graphdb_postgres.py
# - name: Run Postgres Hybrid Adapter Tests
# env:
# ENV: 'dev'
# DB_PROVIDER: postgres
# DB_HOST: localhost
# DB_PORT: 5432
# DB_USERNAME: cognee
# DB_PASSWORD: cognee
# DB_NAME: cognee_db
# EMBEDDING_DIMENSIONS: 300
# EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
# EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
# run: uv run pytest cognee/tests/e2e/postgres/test_postgres_hybrid_adapter.py -v
#
# - name: Run Postgres Hybrid E2E Test
# env:
# ENV: 'dev'
# USE_UNIFIED_PROVIDER: "pghybrid"
# DB_PROVIDER: postgres
# DB_HOST: localhost
# DB_PORT: 5432
# DB_USERNAME: cognee
# DB_PASSWORD: cognee
# DB_NAME: cognee_db
# ENABLE_BACKEND_ACCESS_CONTROL: 'false'
# LLM_MODEL: ${{ secrets.LLM_MODEL }}
# LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
# LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
# LLM_ARGS: ${{ secrets.LLM_ARGS }}
# LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
# EMBEDDING_DIMENSIONS: 300
# EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
# EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
# run: uv run python ./cognee/tests/e2e/postgres/test_pghybrid.py
run-neo4j-tests:
name: Neo4j Tests
runs-on: ubuntu-22.04
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'neo4j') }}
steps:
- name: Check out
uses: actions/checkout@master
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
- name: Setup Neo4j with GDS
uses: ./.github/actions/setup_neo4j
id: neo4j
- name: Run default Neo4j
env:
ENV: 'dev'
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
GRAPH_DATABASE_PROVIDER: "neo4j"
GRAPH_DATABASE_URL: ${{ steps.neo4j.outputs.neo4j-url }}
GRAPH_DATABASE_USERNAME: ${{ steps.neo4j.outputs.neo4j-username }}
GRAPH_DATABASE_PASSWORD: ${{ steps.neo4j.outputs.neo4j-password }}
run: uv run python ./cognee/tests/test_neo4j.py
- name: Run Weighted Edges Tests with Neo4j
env:
ENV: 'dev'
GRAPH_DATABASE_PROVIDER: "neo4j"
GRAPH_DATABASE_URL: ${{ secrets.NEO4J_API_URL }}
GRAPH_DATABASE_PASSWORD: ${{ secrets.NEO4J_API_KEY }}
GRAPH_DATABASE_USERNAME: "neo4j"
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run pytest cognee/tests/unit/interfaces/graph/test_weighted_edges.py -v
+192
View File
@@ -0,0 +1,192 @@
name: Reusable Integration Tests
permissions:
contents: read
packages: read
on:
workflow_call:
inputs:
ci-image:
required: false
type: string
default: ''
env:
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
integration-retrieval:
name: Integration - Retrieval (${{ matrix.split-group }}/4)
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
split-group: [1, 2, 3, 4]
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
env:
ENV: 'dev'
LLM_PROVIDER: openai
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
extra-dependencies: "scraping fastembed"
- name: Run Retrieval Tests
run: uv run pytest cognee/tests/integration/retrieval/ --splits 4 --group ${{ matrix.split-group }}
integration-documents-tasks:
name: Integration - Documents & Tasks (${{ matrix.split-group }}/2)
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
split-group: [1, 2]
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
env:
ENV: 'dev'
LLM_PROVIDER: openai
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
extra-dependencies: "scraping"
- name: Run Document & Task Tests
run: uv run pytest cognee/tests/integration/documents/ cognee/tests/integration/tasks/ --splits 2 --group ${{ matrix.split-group }}
integration-infra:
name: Integration - Infrastructure (${{ matrix.split-group }}/3)
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
split-group: [1, 2, 3]
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
env:
ENV: 'dev'
LLM_PROVIDER: openai
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
# fastembed so the embedding tokenizer delegation tests can import
# FastembedEmbeddingEngine.
extra-dependencies: "scraping fastembed"
- name: Run Infrastructure Tests
run: uv run pytest cognee/tests/integration/infrastructure/ --splits 3 --group ${{ matrix.split-group }}
integration-web:
name: Integration - Web
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
env:
ENV: 'dev'
LLM_PROVIDER: openai
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
extra-dependencies: "scraping"
- name: Run Web Integration Tests
run: uv run pytest cognee/tests/integration/web_url_crawler/
integration-other:
name: Integration - Deletion & Misc
runs-on: ubuntu-22.04
services:
redis:
image: redis:7
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 3s
--health-retries 5
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
env:
ENV: 'dev'
LLM_PROVIDER: openai
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
CACHE_HOST: redis
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
extra-dependencies: "scraping redis"
- name: Run Deletion & Misc Tests
run: uv run pytest cognee/tests/integration/test_delete_edge_cases.py cognee/tests/integration/shared/
+74
View File
@@ -0,0 +1,74 @@
name: Label PRs from core team
on:
pull_request_target:
types: [opened, reopened, synchronize, ready_for_review, edited]
permissions:
contents: read
issues: write
jobs:
label-core-team:
if: ${{ !github.event.pull_request.draft }}
runs-on: ubuntu-latest
steps:
- name: Check out base repository
uses: actions/checkout@v6
with:
repository: ${{ github.repository }}
ref: ${{ github.event.pull_request.base.ref }}
- name: Determine if PR author is a core team member
id: check_core
shell: bash
run: |
AUTHOR="${{ github.event.pull_request.user.login }}"
LIST_FILE=".github/core-team.txt"
if [ ! -f "$LIST_FILE" ]; then
echo "core=false" >> "$GITHUB_OUTPUT"
exit 0
fi
# Normalize author to lowercase and strip leading '@'
AUTHOR_NORM="$(echo "$AUTHOR" | tr '[:upper:]' '[:lower:]' | sed 's/^@//')"
# Compare against normalized list values (ignore comments/blank lines)
if awk -v author="$AUTHOR_NORM" '
BEGIN { found=0 }
{
line=$0
sub(/^[ \t]+|[ \t]+$/, "", line)
if (line ~ /^#/ || line == "") next
sub(/^@/, "", line)
line=tolower(line)
if (line == author) { found=1; exit }
}
END { exit(found ? 0 : 1) }
' "$LIST_FILE"; then
echo "core=true" >> "$GITHUB_OUTPUT"
else
echo "core=false" >> "$GITHUB_OUTPUT"
fi
- name: Add core-team label
if: steps.check_core.outputs.core == 'true'
uses: actions/github-script@v8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const label = 'core-team';
const { owner, repo } = context.repo;
const prNumber = context.payload.pull_request.number;
try {
await github.rest.issues.addLabels({
owner,
repo,
issue_number: prNumber,
labels: [label],
});
core.info(`Label '${label}' added to PR #${prNumber}`);
} catch (error) {
core.warning(`Failed to add label: ${error.message}`);
}
+73
View File
@@ -0,0 +1,73 @@
name: Load tests
permissions:
contents: read
packages: read
on:
workflow_dispatch:
workflow_call:
inputs:
ci-image:
required: false
type: string
default: ''
secrets:
LLM_MODEL:
required: true
LLM_ENDPOINT:
required: true
LLM_API_KEY:
required: true
LLM_ARGS:
required: false
LLM_API_VERSION:
required: true
EMBEDDING_MODEL:
required: true
EMBEDDING_API_KEY:
required: true
OPENAI_API_KEY:
required: true
AWS_ACCESS_KEY_ID:
required: true
AWS_SECRET_ACCESS_KEY:
required: true
jobs:
test-load:
name: Test Load
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
timeout-minutes: 60
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
extra-dependencies: "aws"
- name: Verify File Descriptor Limit
run: ulimit -n
- name: Run Load Test
env:
ENV: 'dev'
ENABLE_BACKEND_ACCESS_CONTROL: True
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
STORAGE_BACKEND: s3
AWS_REGION: eu-west-1
AWS_ENDPOINT_URL: https://s3-eu-west-1.amazonaws.com
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_S3_DEV_USER_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_S3_DEV_USER_SECRET_KEY }}
run: uv run python ./cognee/tests/test_load.py
+54
View File
@@ -0,0 +1,54 @@
name: Mirror external images to GHCR
# Copies the pinned third-party images CI depends on (pgvector) into GHCR, so the
# PR / test hot path never pulls from Docker Hub — which is rate-limited and flaky
# from GitHub Actions (intermittent `registry-1.docker.io ... timeout` on service
# container setup). The test workflows reference ghcr.io/<owner>/pgvector:pg17.
#
# Runs weekly for freshness and on-demand. IMPORTANT: run this once (Actions ->
# "Mirror external images to GHCR" -> Run workflow) BEFORE the GHCR references go
# live, so the image exists. Ensure the resulting GHCR package is accessible to
# this repo (public, or repo-linked) so service pulls with GITHUB_TOKEN succeed.
on:
schedule:
- cron: "0 6 * * 1" # Mondays 06:00 UTC
workflow_dispatch: {}
permissions:
contents: read
packages: write
jobs:
mirror:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
image:
- pgvector/pgvector:pg17
steps:
- name: Log in to Docker Hub (authenticated source pulls)
uses: docker/login-action@v3
continue-on-error: true # best-effort: fall back to anonymous if unset
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Mirror ${{ matrix.image }} -> GHCR
run: |
set -euo pipefail
SRC="${{ matrix.image }}"
DST="ghcr.io/${{ github.repository_owner }}/${SRC##*/}"
echo "Mirroring $SRC -> $DST"
docker pull "$SRC"
docker tag "$SRC" "$DST"
docker push "$DST"
echo "Done: $DST"
+246
View File
@@ -0,0 +1,246 @@
name: Nightly Tests
permissions:
contents: read
packages: write
on:
schedule:
- cron: '0 3 * * *'
workflow_dispatch:
# Note: Run Nightly CI on change to any of the following files.
pull_request:
paths:
- '.github/workflows/nightly_tests.yml'
- '.github/workflows/performance_report.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
RUNTIME__LOG_LEVEL: ERROR
ENV: 'dev'
jobs:
ollama-tests:
name: Ollama Tests
uses: ./.github/workflows/test_ollama.yml
secrets: inherit
llamacpp-tests:
name: Llama-cpp Tests
uses: ./.github/workflows/test_llamacpp.yml
secrets: inherit
# ══ Performance: each caller runs BOTH file_based and postgres backends ════
perf-small-llm:
name: Performance — 50 Small Documents (real LLM)
uses: ./.github/workflows/performance_report.yml
with:
mode: llm
label: 50_small_documents
runs: '3'
num_memories: '50'
memories_key: nightly_ci_artifacts/performance_test_artifacts/memories.json
secrets: inherit
perf-small-mock:
name: Performance — 50 Small Documents (mock LLM)
uses: ./.github/workflows/performance_report.yml
with:
mode: mock_llm
label: 50_small_documents
runs: '3'
num_memories: '50'
memories_key: nightly_ci_artifacts/performance_test_artifacts/memories.json
mock_memories_key: nightly_ci_artifacts/performance_test_artifacts/mock_memories.json
secrets: inherit
perf-wap-llm:
name: Performance — War and Peace (real LLM)
uses: ./.github/workflows/performance_report.yml
with:
mode: llm
label: war_and_peace
runs: '3'
memories_key: nightly_ci_artifacts/performance_test_artifacts/war_and_peace.json
secrets: inherit
perf-wap-mock:
name: Performance — War and Peace (mock LLM)
uses: ./.github/workflows/performance_report.yml
with:
mode: mock_llm
label: war_and_peace
runs: '3'
memories_key: nightly_ci_artifacts/performance_test_artifacts/war_and_peace.json
mock_memories_key: nightly_ci_artifacts/performance_test_artifacts/mock_war_and_peace.json
secrets: inherit
notify:
name: Test Completion Status
needs: [
ollama-tests,
llamacpp-tests,
perf-small-llm,
perf-small-mock,
perf-wap-llm,
perf-wap-mock,
]
runs-on: ubuntu-latest
if: ${{ !cancelled() }}
steps:
- name: Determine status
id: status
run: |
if [[ "${{ needs.ollama-tests.result }}" == "success" &&
"${{ needs.llamacpp-tests.result }}" == "success" &&
"${{ needs.perf-small-llm.result }}" == "success" &&
"${{ needs.perf-small-mock.result }}" == "success" &&
"${{ needs.perf-wap-llm.result }}" == "success" &&
"${{ needs.perf-wap-mock.result }}" == "success" ]]; then
echo "passed=true" >> "$GITHUB_OUTPUT"
echo "emoji=✅" >> "$GITHUB_OUTPUT"
echo "summary=All nightly test suites completed successfully!" >> "$GITHUB_OUTPUT"
else
echo "passed=false" >> "$GITHUB_OUTPUT"
echo "emoji=❌" >> "$GITHUB_OUTPUT"
echo "summary=One or more nightly test suites failed." >> "$GITHUB_OUTPUT"
fi
echo "ran_at=$(date -u '+%Y-%m-%d %H:%M UTC')" >> "$GITHUB_OUTPUT"
- name: Presign performance report links
id: presign
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_S3_DEV_USER_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_S3_DEV_USER_SECRET_KEY }}
AWS_DEFAULT_REGION: eu-west-1
BUCKET: github-runner-cognee-tests
# "<slack-output-name> <s3-key>" per line. The key already encodes the
# backend (file_based/ or postgres/), so presigning is fully generic.
REPORT_KEYS: |
url_file_small_llm ${{ needs.perf-small-llm.outputs.file_based_html_key }}
url_file_small_mock ${{ needs.perf-small-mock.outputs.file_based_html_key }}
url_file_wap_llm ${{ needs.perf-wap-llm.outputs.file_based_html_key }}
url_file_wap_mock ${{ needs.perf-wap-mock.outputs.file_based_html_key }}
url_pg_small_llm ${{ needs.perf-small-llm.outputs.postgres_html_key }}
url_pg_small_mock ${{ needs.perf-small-mock.outputs.postgres_html_key }}
url_pg_wap_llm ${{ needs.perf-wap-llm.outputs.postgres_html_key }}
url_pg_wap_mock ${{ needs.perf-wap-mock.outputs.postgres_html_key }}
run: |
set -euo pipefail
# 7 days = 604800s is the maximum lifetime for an IAM-user presigned URL.
# Skip empty keys (a failed perf job produces no report).
while read -r name key; do
[ -n "${key:-}" ] || continue
echo "$name=$(aws s3 presign "s3://$BUCKET/$key" --expires-in 604800)" >> "$GITHUB_OUTPUT"
done <<< "$REPORT_KEYS"
- name: Post status to Slack
uses: slackapi/slack-github-action@v2.1.0
with:
method: chat.postMessage
token: ${{ secrets.SLACK_NIGHTLY_BOT_TOKEN }}
payload: |
channel: ${{ secrets.SLACK_NIGHTLY_CHANNEL_ID }}
text: "${{ steps.status.outputs.emoji }} Nightly Tests (${{ steps.status.outputs.ran_at }}): ${{ steps.status.outputs.summary }}"
blocks:
- type: "section"
text:
type: "mrkdwn"
text: |
${{ steps.status.outputs.emoji }} *Nightly Tests* — ${{ steps.status.outputs.summary }}
*Ran at:* `${{ steps.status.outputs.ran_at }}`
*Ollama:* `${{ needs.ollama-tests.result }}` • *Llama-cpp:* `${{ needs.llamacpp-tests.result }}`
- type: "section"
text:
type: "mrkdwn"
text: |
*📊 File Based — 50 Small Documents — Real LLM* (`${{ needs.perf-small-llm.result }}`) • runs `${{ fromJSON(needs.perf-small-llm.outputs.file_based_metrics || '{}').success }}`
add p50 `${{ fromJSON(needs.perf-small-llm.outputs.file_based_metrics || '{}').add.p50 }}s` • p90 `${{ fromJSON(needs.perf-small-llm.outputs.file_based_metrics || '{}').add.p90 }}s` • p99 `${{ fromJSON(needs.perf-small-llm.outputs.file_based_metrics || '{}').add.p99 }}s`
cognify p50 `${{ fromJSON(needs.perf-small-llm.outputs.file_based_metrics || '{}').cognify.p50 }}s` • p90 `${{ fromJSON(needs.perf-small-llm.outputs.file_based_metrics || '{}').cognify.p90 }}s` • p99 `${{ fromJSON(needs.perf-small-llm.outputs.file_based_metrics || '{}').cognify.p99 }}s`
search p50 `${{ fromJSON(needs.perf-small-llm.outputs.file_based_metrics || '{}').search.p50 }}s` • p90 `${{ fromJSON(needs.perf-small-llm.outputs.file_based_metrics || '{}').search.p90 }}s` • p99 `${{ fromJSON(needs.perf-small-llm.outputs.file_based_metrics || '{}').search.p99 }}s`
total p50 `${{ fromJSON(needs.perf-small-llm.outputs.file_based_metrics || '{}').total.p50 }}s` • p90 `${{ fromJSON(needs.perf-small-llm.outputs.file_based_metrics || '{}').total.p90 }}s` • p99 `${{ fromJSON(needs.perf-small-llm.outputs.file_based_metrics || '{}').total.p99 }}s`
<${{ steps.presign.outputs.url_file_small_llm }}|HTML report>
- type: "section"
text:
type: "mrkdwn"
text: |
*📊 File Based — 50 Small Documents — Mock LLM* (`${{ needs.perf-small-mock.result }}`) • runs `${{ fromJSON(needs.perf-small-mock.outputs.file_based_metrics || '{}').success }}`
add p50 `${{ fromJSON(needs.perf-small-mock.outputs.file_based_metrics || '{}').add.p50 }}s` • p90 `${{ fromJSON(needs.perf-small-mock.outputs.file_based_metrics || '{}').add.p90 }}s` • p99 `${{ fromJSON(needs.perf-small-mock.outputs.file_based_metrics || '{}').add.p99 }}s`
cognify p50 `${{ fromJSON(needs.perf-small-mock.outputs.file_based_metrics || '{}').cognify.p50 }}s` • p90 `${{ fromJSON(needs.perf-small-mock.outputs.file_based_metrics || '{}').cognify.p90 }}s` • p99 `${{ fromJSON(needs.perf-small-mock.outputs.file_based_metrics || '{}').cognify.p99 }}s`
search p50 `${{ fromJSON(needs.perf-small-mock.outputs.file_based_metrics || '{}').search.p50 }}s` • p90 `${{ fromJSON(needs.perf-small-mock.outputs.file_based_metrics || '{}').search.p90 }}s` • p99 `${{ fromJSON(needs.perf-small-mock.outputs.file_based_metrics || '{}').search.p99 }}s`
total p50 `${{ fromJSON(needs.perf-small-mock.outputs.file_based_metrics || '{}').total.p50 }}s` • p90 `${{ fromJSON(needs.perf-small-mock.outputs.file_based_metrics || '{}').total.p90 }}s` • p99 `${{ fromJSON(needs.perf-small-mock.outputs.file_based_metrics || '{}').total.p99 }}s`
<${{ steps.presign.outputs.url_file_small_mock }}|HTML report>
- type: "section"
text:
type: "mrkdwn"
text: |
*📚 File Based — War and Peace — Real LLM* (`${{ needs.perf-wap-llm.result }}`) • runs `${{ fromJSON(needs.perf-wap-llm.outputs.file_based_metrics || '{}').success }}`
add p50 `${{ fromJSON(needs.perf-wap-llm.outputs.file_based_metrics || '{}').add.p50 }}s` • p90 `${{ fromJSON(needs.perf-wap-llm.outputs.file_based_metrics || '{}').add.p90 }}s` • p99 `${{ fromJSON(needs.perf-wap-llm.outputs.file_based_metrics || '{}').add.p99 }}s`
cognify p50 `${{ fromJSON(needs.perf-wap-llm.outputs.file_based_metrics || '{}').cognify.p50 }}s` • p90 `${{ fromJSON(needs.perf-wap-llm.outputs.file_based_metrics || '{}').cognify.p90 }}s` • p99 `${{ fromJSON(needs.perf-wap-llm.outputs.file_based_metrics || '{}').cognify.p99 }}s`
search p50 `${{ fromJSON(needs.perf-wap-llm.outputs.file_based_metrics || '{}').search.p50 }}s` • p90 `${{ fromJSON(needs.perf-wap-llm.outputs.file_based_metrics || '{}').search.p90 }}s` • p99 `${{ fromJSON(needs.perf-wap-llm.outputs.file_based_metrics || '{}').search.p99 }}s`
total p50 `${{ fromJSON(needs.perf-wap-llm.outputs.file_based_metrics || '{}').total.p50 }}s` • p90 `${{ fromJSON(needs.perf-wap-llm.outputs.file_based_metrics || '{}').total.p90 }}s` • p99 `${{ fromJSON(needs.perf-wap-llm.outputs.file_based_metrics || '{}').total.p99 }}s`
<${{ steps.presign.outputs.url_file_wap_llm }}|HTML report>
- type: "section"
text:
type: "mrkdwn"
text: |
*📚 File Based — War and Peace — Mock LLM* (`${{ needs.perf-wap-mock.result }}`) • runs `${{ fromJSON(needs.perf-wap-mock.outputs.file_based_metrics || '{}').success }}`
add p50 `${{ fromJSON(needs.perf-wap-mock.outputs.file_based_metrics || '{}').add.p50 }}s` • p90 `${{ fromJSON(needs.perf-wap-mock.outputs.file_based_metrics || '{}').add.p90 }}s` • p99 `${{ fromJSON(needs.perf-wap-mock.outputs.file_based_metrics || '{}').add.p99 }}s`
cognify p50 `${{ fromJSON(needs.perf-wap-mock.outputs.file_based_metrics || '{}').cognify.p50 }}s` • p90 `${{ fromJSON(needs.perf-wap-mock.outputs.file_based_metrics || '{}').cognify.p90 }}s` • p99 `${{ fromJSON(needs.perf-wap-mock.outputs.file_based_metrics || '{}').cognify.p99 }}s`
search p50 `${{ fromJSON(needs.perf-wap-mock.outputs.file_based_metrics || '{}').search.p50 }}s` • p90 `${{ fromJSON(needs.perf-wap-mock.outputs.file_based_metrics || '{}').search.p90 }}s` • p99 `${{ fromJSON(needs.perf-wap-mock.outputs.file_based_metrics || '{}').search.p99 }}s`
total p50 `${{ fromJSON(needs.perf-wap-mock.outputs.file_based_metrics || '{}').total.p50 }}s` • p90 `${{ fromJSON(needs.perf-wap-mock.outputs.file_based_metrics || '{}').total.p90 }}s` • p99 `${{ fromJSON(needs.perf-wap-mock.outputs.file_based_metrics || '{}').total.p99 }}s`
<${{ steps.presign.outputs.url_file_wap_mock }}|HTML report>
- type: "section"
text:
type: "mrkdwn"
text: |
*📊 Full Postgres — 50 Small Documents — Real LLM* (`${{ needs.perf-small-llm.result }}`) • runs `${{ fromJSON(needs.perf-small-llm.outputs.postgres_metrics || '{}').success }}`
add p50 `${{ fromJSON(needs.perf-small-llm.outputs.postgres_metrics || '{}').add.p50 }}s` • p90 `${{ fromJSON(needs.perf-small-llm.outputs.postgres_metrics || '{}').add.p90 }}s` • p99 `${{ fromJSON(needs.perf-small-llm.outputs.postgres_metrics || '{}').add.p99 }}s`
cognify p50 `${{ fromJSON(needs.perf-small-llm.outputs.postgres_metrics || '{}').cognify.p50 }}s` • p90 `${{ fromJSON(needs.perf-small-llm.outputs.postgres_metrics || '{}').cognify.p90 }}s` • p99 `${{ fromJSON(needs.perf-small-llm.outputs.postgres_metrics || '{}').cognify.p99 }}s`
search p50 `${{ fromJSON(needs.perf-small-llm.outputs.postgres_metrics || '{}').search.p50 }}s` • p90 `${{ fromJSON(needs.perf-small-llm.outputs.postgres_metrics || '{}').search.p90 }}s` • p99 `${{ fromJSON(needs.perf-small-llm.outputs.postgres_metrics || '{}').search.p99 }}s`
total p50 `${{ fromJSON(needs.perf-small-llm.outputs.postgres_metrics || '{}').total.p50 }}s` • p90 `${{ fromJSON(needs.perf-small-llm.outputs.postgres_metrics || '{}').total.p90 }}s` • p99 `${{ fromJSON(needs.perf-small-llm.outputs.postgres_metrics || '{}').total.p99 }}s`
<${{ steps.presign.outputs.url_pg_small_llm }}|HTML report>
- type: "section"
text:
type: "mrkdwn"
text: |
*📊 Full Postgres — 50 Small Documents — Mock LLM* (`${{ needs.perf-small-mock.result }}`) • runs `${{ fromJSON(needs.perf-small-mock.outputs.postgres_metrics || '{}').success }}`
add p50 `${{ fromJSON(needs.perf-small-mock.outputs.postgres_metrics || '{}').add.p50 }}s` • p90 `${{ fromJSON(needs.perf-small-mock.outputs.postgres_metrics || '{}').add.p90 }}s` • p99 `${{ fromJSON(needs.perf-small-mock.outputs.postgres_metrics || '{}').add.p99 }}s`
cognify p50 `${{ fromJSON(needs.perf-small-mock.outputs.postgres_metrics || '{}').cognify.p50 }}s` • p90 `${{ fromJSON(needs.perf-small-mock.outputs.postgres_metrics || '{}').cognify.p90 }}s` • p99 `${{ fromJSON(needs.perf-small-mock.outputs.postgres_metrics || '{}').cognify.p99 }}s`
search p50 `${{ fromJSON(needs.perf-small-mock.outputs.postgres_metrics || '{}').search.p50 }}s` • p90 `${{ fromJSON(needs.perf-small-mock.outputs.postgres_metrics || '{}').search.p90 }}s` • p99 `${{ fromJSON(needs.perf-small-mock.outputs.postgres_metrics || '{}').search.p99 }}s`
total p50 `${{ fromJSON(needs.perf-small-mock.outputs.postgres_metrics || '{}').total.p50 }}s` • p90 `${{ fromJSON(needs.perf-small-mock.outputs.postgres_metrics || '{}').total.p90 }}s` • p99 `${{ fromJSON(needs.perf-small-mock.outputs.postgres_metrics || '{}').total.p99 }}s`
<${{ steps.presign.outputs.url_pg_small_mock }}|HTML report>
- type: "section"
text:
type: "mrkdwn"
text: |
*📚 Full Postgres — War and Peace — Real LLM* (`${{ needs.perf-wap-llm.result }}`) • runs `${{ fromJSON(needs.perf-wap-llm.outputs.postgres_metrics || '{}').success }}`
add p50 `${{ fromJSON(needs.perf-wap-llm.outputs.postgres_metrics || '{}').add.p50 }}s` • p90 `${{ fromJSON(needs.perf-wap-llm.outputs.postgres_metrics || '{}').add.p90 }}s` • p99 `${{ fromJSON(needs.perf-wap-llm.outputs.postgres_metrics || '{}').add.p99 }}s`
cognify p50 `${{ fromJSON(needs.perf-wap-llm.outputs.postgres_metrics || '{}').cognify.p50 }}s` • p90 `${{ fromJSON(needs.perf-wap-llm.outputs.postgres_metrics || '{}').cognify.p90 }}s` • p99 `${{ fromJSON(needs.perf-wap-llm.outputs.postgres_metrics || '{}').cognify.p99 }}s`
search p50 `${{ fromJSON(needs.perf-wap-llm.outputs.postgres_metrics || '{}').search.p50 }}s` • p90 `${{ fromJSON(needs.perf-wap-llm.outputs.postgres_metrics || '{}').search.p90 }}s` • p99 `${{ fromJSON(needs.perf-wap-llm.outputs.postgres_metrics || '{}').search.p99 }}s`
total p50 `${{ fromJSON(needs.perf-wap-llm.outputs.postgres_metrics || '{}').total.p50 }}s` • p90 `${{ fromJSON(needs.perf-wap-llm.outputs.postgres_metrics || '{}').total.p90 }}s` • p99 `${{ fromJSON(needs.perf-wap-llm.outputs.postgres_metrics || '{}').total.p99 }}s`
<${{ steps.presign.outputs.url_pg_wap_llm }}|HTML report>
- type: "section"
text:
type: "mrkdwn"
text: |
*📚 Full Postgres — War and Peace — Mock LLM* (`${{ needs.perf-wap-mock.result }}`) • runs `${{ fromJSON(needs.perf-wap-mock.outputs.postgres_metrics || '{}').success }}`
add p50 `${{ fromJSON(needs.perf-wap-mock.outputs.postgres_metrics || '{}').add.p50 }}s` • p90 `${{ fromJSON(needs.perf-wap-mock.outputs.postgres_metrics || '{}').add.p90 }}s` • p99 `${{ fromJSON(needs.perf-wap-mock.outputs.postgres_metrics || '{}').add.p99 }}s`
cognify p50 `${{ fromJSON(needs.perf-wap-mock.outputs.postgres_metrics || '{}').cognify.p50 }}s` • p90 `${{ fromJSON(needs.perf-wap-mock.outputs.postgres_metrics || '{}').cognify.p90 }}s` • p99 `${{ fromJSON(needs.perf-wap-mock.outputs.postgres_metrics || '{}').cognify.p99 }}s`
search p50 `${{ fromJSON(needs.perf-wap-mock.outputs.postgres_metrics || '{}').search.p50 }}s` • p90 `${{ fromJSON(needs.perf-wap-mock.outputs.postgres_metrics || '{}').search.p90 }}s` • p99 `${{ fromJSON(needs.perf-wap-mock.outputs.postgres_metrics || '{}').search.p99 }}s`
total p50 `${{ fromJSON(needs.perf-wap-mock.outputs.postgres_metrics || '{}').total.p50 }}s` • p90 `${{ fromJSON(needs.perf-wap-mock.outputs.postgres_metrics || '{}').total.p90 }}s` • p99 `${{ fromJSON(needs.perf-wap-mock.outputs.postgres_metrics || '{}').total.p99 }}s`
<${{ steps.presign.outputs.url_pg_wap_mock }}|HTML report>
- type: "section"
text:
type: "mrkdwn"
text: |
<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View run>
- name: Fail if any suite failed
if: ${{ steps.status.outputs.passed != 'true' }}
run: |
echo "One or more nightly test suites failed."
exit 1
+28
View File
@@ -0,0 +1,28 @@
name: Reusable Notebook Tests
on:
workflow_call:
inputs:
ci-image:
required: false
type: string
default: ''
env:
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
# run-main-notebook:
# name: Main Notebook Test
# uses: ./.github/workflows/reusable_notebook.yml
# with:
# notebook-location: notebooks/cognee_demo.ipynb
# secrets: inherit
run-cognee-multimedia:
name: Cognee Multimedia Notebook
uses: ./.github/workflows/reusable_notebook.yml
with:
notebook-location: notebooks/cognee_multimedia_demo.ipynb
ci-image: ${{ inputs.ci-image }}
secrets: inherit
+298
View File
@@ -0,0 +1,298 @@
name: performance report
# Reusable workflow: runs the percentile performance report once for a given
# dataset + mode, uploads the JSON + HTML artifacts to S3, and exposes the
# headline metrics + HTML object key as outputs for the caller (the Slack bot in
# nightly_tests.yml).
#
# Both backends run on every call, as two separate jobs:
# - file_based : cognee defaults (SQLite + Kuzu + LanceDB), no services.
# - postgres : full Postgres (relational + PGVector + Postgres graph) via a
# `services: postgres` container (mirrors e2e_tests.yml).
# Each job exposes its own metrics + html_key outputs (file_based_* / postgres_*).
on:
workflow_call:
inputs:
mode:
description: "Run mode: 'mock_llm' (no API calls) or 'llm' (real LLM)."
required: true
type: string
label:
description: "Dataset label, used in the S3 output path and display name."
required: true
type: string
runs:
description: "Number of sequential benchmark runs."
required: false
type: string
default: '10'
num_memories:
description: "If set, forwarded as --num-memories (limit input documents)."
required: false
type: string
default: ''
memories_key:
description: "S3 object key (under the bucket) downloaded and used as --memories."
required: true
type: string
mock_memories_key:
description: "If set, S3 object key downloaded and used as --mock-memories."
required: false
type: string
default: ''
outputs:
file_based_metrics:
description: "File-based run: success + add/cognify/search/total p50/p90/p99."
value: ${{ jobs.file_based.outputs.metrics }}
file_based_html_key:
description: "File-based run: S3 object key of the HTML report."
value: ${{ jobs.file_based.outputs.html_key }}
postgres_metrics:
description: "Postgres run: success + add/cognify/search/total p50/p90/p99."
value: ${{ jobs.postgres.outputs.metrics }}
postgres_html_key:
description: "Postgres run: S3 object key of the HTML report."
value: ${{ jobs.postgres.outputs.html_key }}
env:
ENV: 'dev'
COGNEE_SKIP_CONNECTION_TEST: 'true'
RUNTIME__LOG_LEVEL: ERROR
BUCKET: github-runner-cognee-tests
jobs:
# ── File-based backend: SQLite + Kuzu + LanceDB (cognee defaults) ────────────
file_based:
name: file_based — ${{ inputs.label }} (${{ inputs.mode }})
runs-on: ubuntu-22.04
outputs:
metrics: ${{ steps.parse.outputs.metrics }}
html_key: ${{ steps.upload.outputs.html_key }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
- name: Download dataset from S3
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_S3_DEV_USER_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_S3_DEV_USER_SECRET_KEY }}
AWS_DEFAULT_REGION: eu-west-1
MEMORIES_KEY: ${{ inputs.memories_key }}
MOCK_MEMORIES_KEY: ${{ inputs.mock_memories_key }}
run: |
set -euo pipefail
mkdir -p performance_datasets
aws s3 cp "s3://$BUCKET/$MEMORIES_KEY" performance_datasets/memories.json
echo "MEMORIES_FILE=$PWD/performance_datasets/memories.json" >> "$GITHUB_ENV"
if [ -n "$MOCK_MEMORIES_KEY" ]; then
aws s3 cp "s3://$BUCKET/$MOCK_MEMORIES_KEY" performance_datasets/mock_memories.json
echo "MOCK_MEMORIES_FILE=$PWD/performance_datasets/mock_memories.json" >> "$GITHUB_ENV"
fi
- name: Run performance report
id: run
env:
PYTHONFAULTHANDLER: 1
# LLM + embedding config via the standard CI secrets (see e2e_tests.yml).
# Only exercised for mode == 'llm'; the mock run hits no external APIs.
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: |
set -euo pipefail
TS="$(date -u '+%Y-%m-%d_%H-%M-%SZ')"
JSON_PATH="performance_results/file_based/${{ inputs.label }}/${{ inputs.mode }}_${TS}.json"
HTML_PATH="performance_results/file_based/${{ inputs.label }}/${{ inputs.mode }}_${TS}.html"
mkdir -p "$(dirname "$JSON_PATH")"
echo "JSON_PATH=$JSON_PATH" >> "$GITHUB_ENV"
echo "HTML_PATH=$HTML_PATH" >> "$GITHUB_ENV"
ARGS=(--runs "${{ inputs.runs }}" --memories "$MEMORIES_FILE")
if [ -n "${MOCK_MEMORIES_FILE:-}" ]; then
ARGS+=(--mock-memories "$MOCK_MEMORIES_FILE")
fi
if [ "${{ inputs.mode }}" = "mock_llm" ]; then
ARGS+=(--mock-llm)
fi
if [ -n "${{ inputs.num_memories }}" ]; then
ARGS+=(--num-memories "${{ inputs.num_memories }}")
fi
uv run python cognee/tests/performance/statistics_percentile_report.py \
"${ARGS[@]}" \
--output "$JSON_PATH" \
--html "$HTML_PATH"
- name: Upload reports to S3
id: upload
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_S3_DEV_USER_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_S3_DEV_USER_SECRET_KEY }}
AWS_DEFAULT_REGION: eu-west-1
run: |
set -euo pipefail
aws s3 cp "$JSON_PATH" "s3://$BUCKET/$JSON_PATH" --content-type application/json
aws s3 cp "$HTML_PATH" "s3://$BUCKET/$HTML_PATH" --content-type text/html
# Presigning is done by the caller (the Slack job), NOT here: a presigned URL
# embeds the AWS access key id, and GitHub scrubs registered secrets from
# reusable-workflow outputs — which would blank the link. Pass only the
# (non-secret) object key across the boundary.
echo "html_key=$HTML_PATH" >> "$GITHUB_OUTPUT"
- name: Parse headline metrics
id: parse
run: |
set -euo pipefail
METRICS="$(jq -c '{
success: "\(.succeeded)/\(.num_runs)",
add: {p50: .stats.add_time_s.p50, p90: .stats.add_time_s.p90, p99: .stats.add_time_s.p99},
cognify: {p50: .stats.cognify_time_s.p50, p90: .stats.cognify_time_s.p90, p99: .stats.cognify_time_s.p99},
search: {p50: .stats.search_time.p50, p90: .stats.search_time.p90, p99: .stats.search_time.p99},
total: {p50: .stats.total_ingest_time_s.p50, p90: .stats.total_ingest_time_s.p90, p99: .stats.total_ingest_time_s.p99}
}' "$JSON_PATH")"
echo "metrics=$METRICS" >> "$GITHUB_OUTPUT"
# ── Postgres backend: Postgres relational + PGVector + Postgres graph ────────
postgres:
name: postgres — ${{ inputs.label }} (${{ inputs.mode }})
runs-on: ubuntu-22.04
defaults:
run:
shell: bash
services:
postgres:
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: cognee
POSTGRES_DB: cognee_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
outputs:
metrics: ${{ steps.parse.outputs.metrics }}
html_key: ${{ steps.upload.outputs.html_key }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
extra-dependencies: "postgres"
- name: Download dataset from S3
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_S3_DEV_USER_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_S3_DEV_USER_SECRET_KEY }}
AWS_DEFAULT_REGION: eu-west-1
MEMORIES_KEY: ${{ inputs.memories_key }}
MOCK_MEMORIES_KEY: ${{ inputs.mock_memories_key }}
run: |
set -euo pipefail
mkdir -p performance_datasets
aws s3 cp "s3://$BUCKET/$MEMORIES_KEY" performance_datasets/memories.json
echo "MEMORIES_FILE=$PWD/performance_datasets/memories.json" >> "$GITHUB_ENV"
if [ -n "$MOCK_MEMORIES_KEY" ]; then
aws s3 cp "s3://$BUCKET/$MOCK_MEMORIES_KEY" performance_datasets/mock_memories.json
echo "MOCK_MEMORIES_FILE=$PWD/performance_datasets/mock_memories.json" >> "$GITHUB_ENV"
fi
- name: Run performance report
id: run
env:
PYTHONFAULTHANDLER: 1
# LLM + embedding config via the standard CI secrets (see e2e_tests.yml).
# Only exercised for mode == 'llm'; the mock run hits no external APIs.
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
# Full Postgres stack (creds match the postgres service above; mirrors e2e_tests.yml).
DB_PROVIDER: 'postgres'
DB_HOST: '127.0.0.1'
DB_PORT: '5432'
DB_USERNAME: cognee
DB_PASSWORD: cognee
DB_NAME: cognee_db
VECTOR_DB_PROVIDER: 'pgvector'
VECTOR_DB_HOST: '127.0.0.1'
VECTOR_DB_PORT: '5432'
VECTOR_DB_USERNAME: cognee
VECTOR_DB_PASSWORD: cognee
VECTOR_DATASET_DATABASE_HANDLER: 'pgvector'
GRAPH_DATABASE_PROVIDER: 'postgres'
GRAPH_DATABASE_HOST: '127.0.0.1'
GRAPH_DATABASE_PORT: '5432'
GRAPH_DATABASE_USERNAME: cognee
GRAPH_DATABASE_PASSWORD: cognee
GRAPH_DATABASE_NAME: cognee_db
run: |
set -euo pipefail
TS="$(date -u '+%Y-%m-%d_%H-%M-%SZ')"
JSON_PATH="performance_results/postgres/${{ inputs.label }}/${{ inputs.mode }}_${TS}.json"
HTML_PATH="performance_results/postgres/${{ inputs.label }}/${{ inputs.mode }}_${TS}.html"
mkdir -p "$(dirname "$JSON_PATH")"
echo "JSON_PATH=$JSON_PATH" >> "$GITHUB_ENV"
echo "HTML_PATH=$HTML_PATH" >> "$GITHUB_ENV"
ARGS=(--runs "${{ inputs.runs }}" --memories "$MEMORIES_FILE")
if [ -n "${MOCK_MEMORIES_FILE:-}" ]; then
ARGS+=(--mock-memories "$MOCK_MEMORIES_FILE")
fi
if [ "${{ inputs.mode }}" = "mock_llm" ]; then
ARGS+=(--mock-llm)
fi
if [ -n "${{ inputs.num_memories }}" ]; then
ARGS+=(--num-memories "${{ inputs.num_memories }}")
fi
uv run python cognee/tests/performance/statistics_percentile_report.py \
"${ARGS[@]}" \
--output "$JSON_PATH" \
--html "$HTML_PATH"
- name: Upload reports to S3
id: upload
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_S3_DEV_USER_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_S3_DEV_USER_SECRET_KEY }}
AWS_DEFAULT_REGION: eu-west-1
run: |
set -euo pipefail
aws s3 cp "$JSON_PATH" "s3://$BUCKET/$JSON_PATH" --content-type application/json
aws s3 cp "$HTML_PATH" "s3://$BUCKET/$HTML_PATH" --content-type text/html
# Presigning is done by the caller (the Slack job), NOT here: a presigned URL
# embeds the AWS access key id, and GitHub scrubs registered secrets from
# reusable-workflow outputs — which would blank the link. Pass only the
# (non-secret) object key across the boundary.
echo "html_key=$HTML_PATH" >> "$GITHUB_OUTPUT"
- name: Parse headline metrics
id: parse
run: |
set -euo pipefail
METRICS="$(jq -c '{
success: "\(.succeeded)/\(.num_runs)",
add: {p50: .stats.add_time_s.p50, p90: .stats.add_time_s.p90, p99: .stats.add_time_s.p99},
cognify: {p50: .stats.cognify_time_s.p50, p90: .stats.cognify_time_s.p90, p99: .stats.cognify_time_s.p99},
search: {p50: .stats.search_time.p50, p90: .stats.search_time.p90, p99: .stats.search_time.p99},
total: {p50: .stats.total_ingest_time_s.p50, p90: .stats.total_ingest_time_s.p90, p99: .stats.total_ingest_time_s.p99}
}' "$JSON_PATH")"
echo "metrics=$METRICS" >> "$GITHUB_OUTPUT"
+44
View File
@@ -0,0 +1,44 @@
## Reference: https://github.com/amannn/action-semantic-pull-request
---
name: lint | PR
on:
pull_request:
types:
- opened
- reopened
- edited
- synchronize
permissions:
contents: read
jobs:
pr_title:
permissions:
pull-requests: write
statuses: write
name: Validate & Label PR
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
# Configure which types are allowed (newline-delimited).
# From: https://github.com/commitizen/conventional-commit-types/blob/master/index.json
# listing all below
types: |
chore
ci
docs
feat
fix
perf
refactor
revert
test
break
- uses: release-drafter/release-drafter@v6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+29
View File
@@ -0,0 +1,29 @@
on:
workflow_call:
permissions:
contents: read
env:
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
check-uv-lock:
name: Lockfile and Pre-commit Hooks
runs-on: ubuntu-22.04
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Validate uv lockfile and project metadata
run: uv lock --check || { echo "'uv lock --check' failed."; echo "Run 'uv lock' and push your changes."; exit 1; }
- name: Run pre-commit hooks
uses: pre-commit/action@v3.0.1
@@ -0,0 +1,248 @@
name: Relational DB Migration Tests
on:
workflow_call:
inputs:
python-version:
required: false
type: string
default: '3.11.x'
ci-image:
required: false
type: string
default: ''
secrets:
LLM_PROVIDER:
required: true
LLM_MODEL:
required: true
LLM_ENDPOINT:
required: true
LLM_API_KEY:
required: true
LLM_ARGS:
required: false
LLM_API_VERSION:
required: true
EMBEDDING_PROVIDER:
required: true
EMBEDDING_MODEL:
required: true
EMBEDDING_API_KEY:
required: true
env:
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
run-relational-db-migration-test-networkx:
name: NetworkX Relational DB Migration Test
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
defaults:
run:
shell: bash
services:
postgres:
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: cognee
POSTGRES_DB: test_migration_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
extra-dependencies: "postgres"
- name: Install specific db dependency
run: echo "Dependencies already installed in setup"
- name: Run PostgreSQL Script to create test data (Chinook_PostgreSql.sql)
env:
PGPASSWORD: cognee
PG_HOST: ${{ inputs.ci-image != '' && 'postgres' || 'localhost' }}
run: |
# Wait until the PostgreSQL service is available
until pg_isready -h $PG_HOST -p 5432; do
echo "Waiting for postgres..."
sleep 2
done
# Execute the SQL script against the test_migration_db database
psql -h $PG_HOST -U cognee -d test_migration_db -f ./cognee/tests/test_data/Chinook_PostgreSql.sql
- name: Run relational db test
env:
ENV: 'dev'
LLM_PROVIDER: openai
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_PROVIDER: openai
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
DB_HOST: ${{ inputs.ci-image != '' && 'postgres' || '127.0.0.1' }}
run: uv run python ./cognee/tests/test_relational_db_migration.py
run-relational-db-migration-test-kuzu:
name: Kuzu Relational DB Migration Test
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
defaults:
run:
shell: bash
services:
postgres:
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: cognee
POSTGRES_DB: test_migration_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
extra-dependencies: "postgres"
- name: Install specific db dependency
run: echo "Dependencies already installed in setup"
- name: Run PostgreSQL Script to create test data (Chinook_PostgreSql.sql)
env:
PGPASSWORD: cognee
PG_HOST: ${{ inputs.ci-image != '' && 'postgres' || 'localhost' }}
run: |
# Wait until the PostgreSQL service is available
until pg_isready -h $PG_HOST -p 5432; do
echo "Waiting for postgres..."
sleep 2
done
# Execute the SQL script against the test_migration_db database
psql -h $PG_HOST -U cognee -d test_migration_db -f ./cognee/tests/test_data/Chinook_PostgreSql.sql
- name: Run relational db test
env:
ENV: 'dev'
GRAPH_DATABASE_PROVIDER: 'kuzu'
LLM_PROVIDER: openai
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_PROVIDER: openai
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
DB_HOST: ${{ inputs.ci-image != '' && 'postgres' || '127.0.0.1' }}
run: uv run python ./cognee/tests/test_relational_db_migration.py
run-relational-db-migration-test-neo4j:
name: Neo4j Relational DB Migration Test
runs-on: ubuntu-22.04
defaults:
run:
shell: bash
services:
postgres:
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: cognee
POSTGRES_DB: test_migration_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
extra-dependencies: "postgres"
- name: Setup Neo4j with GDS
uses: ./.github/actions/setup_neo4j
id: neo4j
- name: Install specific db dependency
run: echo "Dependencies already installed in setup"
- name: Run PostgreSQL Script to create test data (Chinook_PostgreSql.sql)
env:
PGPASSWORD: cognee
run: |
# Wait until the PostgreSQL service is available
until pg_isready -h localhost -p 5432; do
echo "Waiting for postgres..."
sleep 2
done
# Execute the SQL script against the test_migration_db database
psql -h localhost -U cognee -d test_migration_db -f ./cognee/tests/test_data/Chinook_PostgreSql.sql
- name: Run relational db test
env:
ENV: 'dev'
GRAPH_DATABASE_PROVIDER: "neo4j"
GRAPH_DATABASE_URL: ${{ steps.neo4j.outputs.neo4j-url }}
GRAPH_DATABASE_USERNAME: ${{ steps.neo4j.outputs.neo4j-username }}
GRAPH_DATABASE_PASSWORD: ${{ steps.neo4j.outputs.neo4j-password }}
LLM_PROVIDER: openai
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_PROVIDER: openai
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./cognee/tests/test_relational_db_migration.py
+254
View File
@@ -0,0 +1,254 @@
name: release.yml
on:
workflow_dispatch:
jobs:
release-github:
name: Create GitHub Release from ${{ github.ref_name }}
outputs:
tag: ${{ steps.create_tag.outputs.tag }}
version: ${{ steps.create_tag.outputs.version }}
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- name: Check out ${{ github.ref_name }}
uses: actions/checkout@v6
with:
ref: ${{ github.ref_name }}
fetch-depth: 0 # Fetch all history for comparison
- name: Fetch main branch for comparison
if: ${{ github.ref_name == 'dev' }}
run: git fetch origin main:main
- name: Fetch dev branch for comparison
if: ${{ github.ref_name == 'main' }}
run: git fetch origin dev:dev
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Install Python
run: uv python install
- name: Install dependencies
run: uv sync --locked
- name: Create and push git tag
id: create_tag
run: |
VERSION="$(uv version --short)"
TAG="v${VERSION}"
echo "Tag to create: ${TAG}"
git config user.name "Cognee Team"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
git tag "${TAG}"
git push origin "${TAG}"
- name: Generate AI-powered release notes
id: generate_notes
env:
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_MODEL: ${{ secrets.LLM_MODEL != '' && secrets.LLM_MODEL || 'openai/gpt-4o-mini' }}
run: |
# Set PYTHONPATH to include project root
export PYTHONPATH="${GITHUB_WORKSPACE}:${PYTHONPATH}"
# Generate release notes
# Compares current branch against the latest release tag automatically
uv run python tools/generate_release_notes.py \
--version "${{ steps.create_tag.outputs.version }}" \
--github-output
- name: Create GitHub Release with AI-generated notes
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.create_tag.outputs.tag }}
name: ${{ steps.generate_notes.outputs.RELEASE_TITLE }}
body: ${{ steps.generate_notes.outputs.RELEASE_NOTES }}
prerelease: ${{ github.ref_name == 'dev' }}
env:
GITHUB_TOKEN: ${{ secrets.GH_RELEASE_TOKEN }}
release-pypi-package:
needs: release-github
name: Release PyPI Package from ${{ github.ref_name }}
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out ${{ github.ref_name }}
uses: actions/checkout@v6
with:
ref: ${{ github.ref_name }}
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Install Python
run: uv python install
- name: Install dependencies
run: uv sync --locked --all-extras
- name: Build distributions
run: uv build
- name: Publish ${{ github.ref_name }} release to PyPI
env:
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
run: uv publish
release-docker-image:
needs: release-github
name: Release Docker Image from ${{ github.ref_name }}
permissions:
contents: read
runs-on: ubuntu-latest
steps:
- name: Check out ${{ github.ref_name }}
uses: actions/checkout@v6
with:
ref: ${{ github.ref_name }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push Dev Docker Image
if: ${{ github.ref_name == 'dev' }}
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: cognee/cognee:${{ needs.release-github.outputs.version }}
labels: |
version=${{ needs.release-github.outputs.version }}
flavour=${{ github.ref_name }}
cache-from: type=registry,ref=cognee/cognee:buildcache
cache-to: type=registry,ref=cognee/cognee:buildcache,mode=max
- name: Build and push Main Docker Image
if: ${{ github.ref_name == 'main' }}
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: |
cognee/cognee:${{ needs.release-github.outputs.version }}
cognee/cognee:latest
labels: |
version=${{ needs.release-github.outputs.version }}
flavour=${{ github.ref_name }}
cache-from: type=registry,ref=cognee/cognee:buildcache
cache-to: type=registry,ref=cognee/cognee:buildcache,mode=max
- name: Build and push Dev MCP Docker Image
if: ${{ github.ref_name == 'dev' }}
uses: docker/build-push-action@v6
with:
context: .
file: cognee-mcp/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: cognee/cognee-mcp:${{ needs.release-github.outputs.version }}
labels: |
version=${{ needs.release-github.outputs.version }}
flavour=${{ github.ref_name }}
cache-from: type=registry,ref=cognee/cognee-mcp:buildcache
cache-to: type=registry,ref=cognee/cognee-mcp:buildcache,mode=max
- name: Build and push Main MCP Docker Image
if: ${{ github.ref_name == 'main' }}
uses: docker/build-push-action@v6
with:
context: .
file: cognee-mcp/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: |
cognee/cognee-mcp:${{ needs.release-github.outputs.version }}
cognee/cognee-mcp:latest
labels: |
version=${{ needs.release-github.outputs.version }}
flavour=${{ github.ref_name }}
cache-from: type=registry,ref=cognee/cognee-mcp:buildcache
cache-to: type=registry,ref=cognee/cognee-mcp:buildcache,mode=max
trigger-docs-test-suite:
needs: release-pypi-package
if: ${{ github.ref_name == 'main' }}
runs-on: ubuntu-22.04
steps:
- name: Trigger docs tests
run: |
curl -L -X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.REPO_DISPATCH_PAT_TOKEN }}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/topoteretes/cognee-docs/dispatches \
-d '{"event_type":"new-main-release","client_payload":{"caller_repo":"'"${GITHUB_REPOSITORY}"'"}}'
trigger-community-test-suite:
needs: release-pypi-package
if: ${{ github.ref_name == 'main' }}
runs-on: ubuntu-22.04
steps:
- name: Trigger community tests
run: |
curl -L -X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.REPO_DISPATCH_PAT_TOKEN }}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/topoteretes/cognee-community/dispatches \
-d '{"event_type":"new-main-release","client_payload":{"caller_repo":"'"${GITHUB_REPOSITORY}"'"}}'
notify-discord:
needs: release-github
name: Send Release to Discord
if: ${{ github.ref_name == 'main' }}
runs-on: ubuntu-22.04
steps:
- name: Send Discord notification
env:
WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }}
TAG: ${{ needs.release-github.outputs.tag }}
VERSION: ${{ needs.release-github.outputs.version }}
run: |
RELEASE_URL="https://github.com/${{ github.repository }}/releases/tag/${TAG}"
PAYLOAD=$(jq -n \
--arg content "||@everyone|| **${TAG}** has been released!" \
--arg title "Release ${TAG}" \
--arg url "$RELEASE_URL" \
--arg description "Version ${VERSION} released from \`${{ github.ref_name }}\`. [View release notes](${RELEASE_URL})" \
--argjson color 2105893 \
'{
content: $content,
embeds: [{
title: $title,
url: $url,
description: $description,
color: $color,
footer: { text: "Changelog" },
timestamp: (now | todate)
}]
}')
curl -s -H "Content-Type: application/json" -d "$PAYLOAD" "$WEBHOOK_URL"
@@ -0,0 +1,23 @@
name: automation | Send Release to Discord
on:
release:
types: [published]
jobs:
github-releases-to-discord:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Github Releases To Discord
uses: SethCohen/github-releases-to-discord@v1.19.0
with:
webhook_url: ${{ secrets.WEBHOOK_URL }}
color: "2105893"
username: "Release Changelog"
avatar_url: "https://cdn.discordapp.com/avatars/487431320314576937/bd64361e4ba6313d561d54e78c9e7171.png"
content: "||@everyone||"
footer_title: "Changelog"
footer_icon_url: "https://cdn.discordapp.com/avatars/487431320314576937/bd64361e4ba6313d561d54e78c9e7171.png"
footer_timestamp: true
+201
View File
@@ -0,0 +1,201 @@
# Long-running, heavy and resource-consuming tests for release validation.
# Runs automatically on PRs targeting main (the dev -> main promotion) and manually
# via workflow_dispatch. Fork PRs are skipped (no access to secrets).
name: Release Test Workflow
permissions:
contents: read
packages: write
on:
workflow_dispatch:
inputs:
cognee_version:
required: false
default: local
type: string
description: "Pypi-compatible version of cognee to use. For example, 0.5.2.dev0. `local` (default) - Installing Cognee from local source"
pull_request:
branches:
- main
concurrency:
group: release-tests-${{ github.head_ref || github.run_id }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
mcp-test:
name: MCP Tests
if: ${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == github.repository }}
uses: ./.github/workflows/test_mcp.yml
secrets: inherit
with:
cognee_version: ${{ inputs.cognee_version || 'local' }}
cli-test:
name: CLI Tests
if: ${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == github.repository }}
uses: ./.github/workflows/cli_tests.yml
secrets: inherit
with:
cognee_version: ${{ inputs.cognee_version || 'local' }}
cot-retriever-test:
name: COT Retriever Test
if: ${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == github.repository }}
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Install Python
run: uv python install
- name: Install dependencies
run: |
if [ "${{ inputs.cognee_version }}" = "local" ] || [ -z "${{ inputs.cognee_version }}" ]; then
uv sync --locked --all-extras
else
uv sync --locked --all-extras
uv pip install cognee==${{ inputs.cognee_version }}
fi
- name: Run COT retriever integration test
env:
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
run: |
uv run pytest cognee/tests/integration/retrieval/test_graph_completion_retriever_cot.py -v --timeout=300
# 10 parallel users against a live HTTP server with access control enabled:
# per-user dataset isolation, add/cognify/search verification via sentinel chunks
# (LLM-free CHUNKS search), delete + recreate, forget + recreate-same-name.
multi-user-e2e-default:
name: Multi-User Release E2E (default file-based DBs)
if: ${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == github.repository }}
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Check out code
uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Install Python
run: uv python install
- name: Install dependencies
run: |
if [ "${{ inputs.cognee_version }}" = "local" ] || [ -z "${{ inputs.cognee_version }}" ]; then
uv sync --locked --all-extras
else
uv sync --locked --all-extras
uv pip install cognee==${{ inputs.cognee_version }}
fi
- name: Run multi-user release E2E test
env:
ENV: 'dev'
COGNEE_SKIP_CONNECTION_TEST: 'true'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./cognee/tests/test_release_multi_user_e2e.py
multi-user-e2e-postgres:
name: Multi-User Release E2E (Postgres graph + PGVector + Postgres)
if: ${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == github.repository }}
runs-on: ubuntu-latest
timeout-minutes: 60
services:
postgres:
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: cognee
POSTGRES_DB: cognee_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Check out code
uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Install Python
run: uv python install
- name: Install dependencies
run: |
if [ "${{ inputs.cognee_version }}" = "local" ] || [ -z "${{ inputs.cognee_version }}" ]; then
uv sync --locked --all-extras
else
uv sync --locked --all-extras
uv pip install cognee==${{ inputs.cognee_version }}
fi
- name: Run multi-user release E2E test
env:
ENV: 'dev'
COGNEE_SKIP_CONNECTION_TEST: 'true'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
DB_PROVIDER: 'postgres'
DB_NAME: 'cognee_db'
DB_HOST: '127.0.0.1'
DB_PORT: 5432
DB_USERNAME: cognee
DB_PASSWORD: cognee
VECTOR_DB_PROVIDER: 'pgvector'
VECTOR_DB_NAME: 'cognee_db'
VECTOR_DB_HOST: '127.0.0.1'
VECTOR_DB_PORT: 5432
VECTOR_DB_USERNAME: cognee
VECTOR_DB_PASSWORD: cognee
VECTOR_DATASET_DATABASE_HANDLER: 'pgvector'
GRAPH_DATABASE_PROVIDER: 'postgres'
GRAPH_DATABASE_NAME: 'cognee_db'
GRAPH_DATABASE_HOST: '127.0.0.1'
GRAPH_DATABASE_PORT: 5432
GRAPH_DATABASE_USERNAME: cognee
GRAPH_DATABASE_PASSWORD: cognee
GRAPH_DATASET_DATABASE_HANDLER: 'postgres_graph'
run: uv run python ./cognee/tests/test_release_multi_user_e2e.py
load-tests:
if: false
name: Load Tests
uses: ./.github/workflows/load_tests.yml
secrets: inherit
dev-canary-release:
name: Dev Canary Release
if: ${{ github.event_name == 'workflow_dispatch' }}
needs: load-tests
uses: ./.github/workflows/dev_canary_release.yml
secrets: inherit
@@ -0,0 +1,40 @@
name: Require Linear issue
# Every INTERNAL PR must reference a Linear issue (e.g. COG-123) in its title or
# branch name — that is how Linear links a PR to a ticket. Since Linear does not
# gate merges, enforcement is a required GitHub status check: this job fails when a
# PR has no Linear key, and branch protection blocks the merge until it passes.
#
# Fork / external-contributor PRs are intentionally SKIPPED: they have no Linear
# access, and a skipped required check counts as passing, so this never blocks the
# community. Mark the `linear-issue-check` job as a required status check on
# `main` and `dev` in branch protection.
on:
pull_request:
# `synchronize` matters: a required check must re-run on the latest commit.
types: [opened, edited, reopened, synchronize]
permissions:
contents: read
jobs:
linear-issue-check: # this job name is what you mark "required" in branch protection
# Enforce for internal PRs only. Fork PRs (head repo != base repo) skip this job;
# a skipped required check is treated as passing, so external PRs are not blocked.
if: github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- name: PR title or branch must reference a Linear issue
env:
PR_TITLE: ${{ github.event.pull_request.title }}
HEAD_REF: ${{ github.head_ref }}
run: |
# List ALL your Linear team prefixes — verify against Linear ▸ Settings ▸ Teams.
KEYS='COG|SDK|CLO|COM|ENG'
if echo "$PR_TITLE $HEAD_REF" | grep -Eiq "\b(${KEYS})-[0-9]+\b"; then
echo "Linear issue reference found."
else
echo "::error::PR title or branch must reference a Linear issue, e.g. COG-123."
exit 1
fi
+71
View File
@@ -0,0 +1,71 @@
name: test-notebook
on:
workflow_call:
inputs:
notebook-location:
description: "Location of Jupyter notebook to run"
required: true
type: string
ci-image:
required: false
type: string
default: ''
secrets:
#LLM_MODEL:
# required: true
#LLM_ENDPOINT:
# required: true
LLM_API_KEY:
required: true
LLM_ARGS:
required: false
OPENAI_API_KEY:
required: true
#LLM_API_VERSION:
# required: true
EMBEDDING_MODEL:
required: true
EMBEDDING_API_KEY:
required: true
env:
RUNTIME__LOG_LEVEL: ERROR
jobs:
run_notebook_test:
name: test
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
defaults:
run:
shell: bash
steps:
- name: Check out
uses: actions/checkout@master
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
extra-dependencies: "notebook"
- name: Execute Jupyter Notebook
env:
ENV: 'dev'
#LLM_MODEL: ${{ secrets.LLM_MODEL }}
#LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} # Use OpenAI Until a multimedia model is deployed and DeepEval support for other models is added
#LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: |
uv run jupyter nbconvert \
--to notebook \
--execute ${{ inputs.notebook-location }} \
--output executed_notebook.ipynb \
--ExecutePreprocessor.timeout=1200
+78
View File
@@ -0,0 +1,78 @@
# This workflow uses actions that are not certified by GitHub. They are provided
# by a third-party and are governed by separate terms of service, privacy
# policy, and support documentation.
name: Scorecard supply-chain security
on:
# For Branch-Protection check. Only the default branch is supported. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
branch_protection_rule:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
- cron: '35 8 * * 2'
push:
branches: [ "main" ]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
# `publish_results: true` only works when run from the default branch. conditional can be removed if disabled.
if: github.event.repository.default_branch == github.ref_name || github.event_name == 'pull_request'
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Needed to publish results and get a badge (see publish_results below).
id-token: write
# Uncomment the permissions below if installing in a private repository.
# contents: read
# actions: read
steps:
- name: "Checkout code"
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
with:
results_file: results.sarif
results_format: sarif
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecard on a *private* repository
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional.
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories:
# - `publish_results` will always be set to `false`, regardless
# of the value entered here.
publish_results: true
# (Optional) Uncomment file_mode if you have a .gitattributes with files marked export-ignore
# file_mode: git
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: results.sarif
+244
View File
@@ -0,0 +1,244 @@
name: Reusable Search DB Tests
permissions:
contents: read
packages: read
on:
workflow_call:
inputs:
databases:
required: false
type: string
default: "all"
description: "Which vector databases to test (comma-separated list or 'all')"
python-versions:
required: false
type: string
default: '["3.10", "3.11", "3.12", "3.13"]'
description: "Python versions to test (JSON array)"
ci-image:
required: false
type: string
default: ''
description: "Container image for CI (empty string means no container)"
env:
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
run-kuzu-lance-sqlite-search-tests:
name: Search test for Kuzu/LanceDB/Sqlite (Python ${{ matrix.python-version }})
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'kuzu/lance/sqlite') }}
strategy:
matrix:
python-version: ${{ fromJSON(inputs.python-versions) }}
fail-fast: false
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ matrix.python-version }}
- name: Dependencies already installed
run: echo "Dependencies already installed in setup"
- name: Run Kuzu search Tests
env:
ENV: 'dev'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
GRAPH_DATABASE_PROVIDER: 'kuzu'
VECTOR_DB_PROVIDER: 'lancedb'
DB_PROVIDER: 'sqlite'
run: uv run pytest cognee/tests/test_search_db.py -v --log-level=INFO
run-neo4j-lance-sqlite-search-tests:
name: Search test for Neo4j/LanceDB/Sqlite (Python ${{ matrix.python-version }})
runs-on: ubuntu-22.04
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'neo4j/lance/sqlite') }}
strategy:
matrix:
python-version: ${{ fromJSON(inputs.python-versions) }}
fail-fast: false
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ matrix.python-version }}
- name: Setup Neo4j with GDS
uses: ./.github/actions/setup_neo4j
id: neo4j
- name: Dependencies already installed
run: echo "Dependencies already installed in setup"
- name: Run Neo4j search Tests
env:
ENV: 'dev'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
GRAPH_DATABASE_PROVIDER: 'neo4j'
VECTOR_DB_PROVIDER: 'lancedb'
DB_PROVIDER: 'sqlite'
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
GRAPH_DATABASE_URL: ${{ steps.neo4j.outputs.neo4j-url }}
GRAPH_DATABASE_USERNAME: ${{ steps.neo4j.outputs.neo4j-username }}
GRAPH_DATABASE_PASSWORD: ${{ steps.neo4j.outputs.neo4j-password }}
run: uv run pytest cognee/tests/test_search_db.py -v --log-level=INFO
run-kuzu-pgvector-postgres-search-tests:
name: Search test for Kuzu/PGVector/Postgres (Python ${{ matrix.python-version }})
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'kuzu/pgvector/postgres') }}
strategy:
matrix:
python-version: ${{ fromJSON(inputs.python-versions) }}
fail-fast: false
services:
postgres:
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: cognee
POSTGRES_DB: cognee_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ matrix.python-version }}
extra-dependencies: "postgres"
- name: Dependencies already installed
run: echo "Dependencies already installed in setup"
- name: Run Kuzu/PGVector/Postgres Tests
env:
ENV: dev
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
GRAPH_DATABASE_PROVIDER: 'kuzu'
VECTOR_DB_PROVIDER: 'pgvector'
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
DB_PROVIDER: 'postgres'
DB_NAME: 'cognee_db'
DB_HOST: ${{ inputs.ci-image != '' && 'postgres' || '127.0.0.1' }}
DB_PORT: 5432
DB_USERNAME: cognee
DB_PASSWORD: cognee
run: uv run pytest cognee/tests/test_search_db.py -v --log-level=INFO
run-neo4j-pgvector-postgres-search-tests:
name: Search test for Neo4j/PGVector/Postgres (Python ${{ matrix.python-version }})
runs-on: ubuntu-22.04
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'neo4j/pgvector/postgres') }}
strategy:
matrix:
python-version: ${{ fromJSON(inputs.python-versions) }}
fail-fast: false
services:
postgres:
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: cognee
POSTGRES_DB: cognee_db
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries=5
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ matrix.python-version }}
extra-dependencies: "postgres"
- name: Setup Neo4j with GDS
uses: ./.github/actions/setup_neo4j
id: neo4j
- name: Dependencies already installed
run: echo "Dependencies already installed in setup"
- name: Run Neo4j + PGVector + Postgres search Tests
env:
ENV: dev
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
GRAPH_DATABASE_PROVIDER: 'neo4j'
VECTOR_DB_PROVIDER: 'pgvector'
DB_PROVIDER: 'postgres'
GRAPH_DATABASE_URL: ${{ steps.neo4j.outputs.neo4j-url }}
GRAPH_DATABASE_USERNAME: ${{ steps.neo4j.outputs.neo4j-username }}
GRAPH_DATABASE_PASSWORD: ${{ steps.neo4j.outputs.neo4j-password }}
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
DB_NAME: cognee_db
DB_HOST: 127.0.0.1
DB_PORT: 5432
DB_USERNAME: cognee
DB_PASSWORD: cognee
run: uv run pytest cognee/tests/test_search_db.py -v --log-level=INFO
+93
View File
@@ -0,0 +1,93 @@
name: Slow End-to-End Tests
permissions:
contents: read
packages: read
on:
workflow_call:
inputs:
python-version:
required: false
type: string
default: '3.11.x'
ci-image:
required: false
type: string
default: ''
secrets:
LLM_MODEL:
required: true
LLM_ENDPOINT:
required: true
LLM_API_KEY:
required: true
LLM_ARGS:
required: false
LLM_API_VERSION:
required: true
EMBEDDING_MODEL:
required: true
EMBEDDING_API_KEY:
required: true
env:
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
test-edge-centered-payload:
name: Test Cognify - Edge Centered Payload
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
- name: Dependencies already installed
run: echo "Dependencies already installed in setup"
- name: Run Edge Centered Payload Test
env:
ENV: 'dev'
TRIPLET_EMBEDDING: True
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./cognee/tests/test_edge_centered_payload.py
test-deletion-on-default-graph_with_legacy_data_1_default:
name: Delete default graph with legacy data test 1 in Kuzu case
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
- name: Run deletion on default graph with legacy data (Kuzu)
env:
ENV: 'dev'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
ENABLE_AUTO_MIGRATIONS: 'false'
run: uv run python ./cognee/tests/test_delete_default_graph_with_legacy_data_1.py
+169
View File
@@ -0,0 +1,169 @@
name: automation | Sync Mintlify Docs
on:
release:
types: [published]
workflow_dispatch:
permissions:
contents: read
jobs:
sync-mintlify-docs:
if: ${{ github.event_name != 'release' || github.event.release.prerelease == false }}
runs-on: ubuntu-22.04
timeout-minutes: 20
steps:
- name: Check out core repository
uses: actions/checkout@v6
with:
fetch-depth: 0
# Normalize release metadata so the sync script can run unchanged for
# published releases, manual dispatches, and branch-push preview runs.
# This step always produces a body file plus synthetic tag/url/date
# values when the event is not an actual GitHub release.
- name: Prepare release body file
id: release_meta
env:
EVENT_NAME: ${{ github.event_name }}
REF_NAME: ${{ github.ref_name }}
COMMIT_SHA: ${{ github.sha }}
RELEASE_BODY: ${{ github.event.release.body }}
RELEASE_TAG: ${{ github.event.release.tag_name }}
RELEASE_URL: ${{ github.event.release.html_url }}
RELEASE_PUBLISHED_AT: ${{ github.event.release.published_at }}
REPOSITORY: ${{ github.repository }}
SERVER_URL: ${{ github.server_url }}
run: |
BODY_FILE="$(mktemp)"
if [ "${EVENT_NAME}" = "release" ]; then
TAG="${RELEASE_TAG}"
RELEASE_LINK="${RELEASE_URL}"
PUBLISHED_AT="${RELEASE_PUBLISHED_AT}"
DOCS_BRANCH_NAME="automation/sync-mintlify-docs-${RELEASE_TAG}"
printf "%s" "${RELEASE_BODY}" > "${BODY_FILE}"
else
TAG="test-sync-${REF_NAME}-${COMMIT_SHA::7}"
RELEASE_LINK="${SERVER_URL}/${REPOSITORY}/commit/${COMMIT_SHA}"
PUBLISHED_AT="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
DOCS_BRANCH_NAME="${REF_NAME}"
printf "%s\n\n- Source commit: \`%s\`\n- Workflow event: \`%s\`\n- Commit URL: %s\n" \
"Automated docs sync test run from branch \`${REF_NAME}\`." \
"${COMMIT_SHA}" \
"${EVENT_NAME}" \
"${RELEASE_LINK}" > "${BODY_FILE}"
fi
SAFE_DOCS_BRANCH_NAME="${DOCS_BRANCH_NAME// /-}"
echo "body_file=${BODY_FILE}" >> "$GITHUB_OUTPUT"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "release_url=${RELEASE_LINK}" >> "$GITHUB_OUTPUT"
echo "published_at=${PUBLISHED_AT}" >> "$GITHUB_OUTPUT"
echo "docs_branch_name=${SAFE_DOCS_BRANCH_NAME}" >> "$GITHUB_OUTPUT"
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Install Python
run: uv python install
- name: Install dependencies
run: uv sync --locked --all-extras
- name: Check out docs repository
uses: actions/checkout@v6
with:
repository: topoteretes/cognee-docs
token: ${{ secrets.REPO_DISPATCH_PAT_TOKEN }}
ref: main
path: docs-repo
- name: Sync OpenAPI and changelog
run: |
uv run python tools/sync_release_docs.py \
--docs-repo "${GITHUB_WORKSPACE}/docs-repo" \
--tag "${{ steps.release_meta.outputs.tag }}" \
--release-url "${{ steps.release_meta.outputs.release_url }}" \
--published-at "${{ steps.release_meta.outputs.published_at }}" \
--release-body-file "${{ steps.release_meta.outputs.body_file }}"
- name: Commit docs changes
id: commit_docs
working-directory: docs-repo
run: |
BRANCH_NAME="${{ steps.release_meta.outputs.docs_branch_name }}"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git checkout -B "${BRANCH_NAME}"
git add cognee_openapi_spec.json changelog.mdx
if git diff --cached --quiet; then
echo "changes_made=false" >> "$GITHUB_OUTPUT"
echo "branch_name=${BRANCH_NAME}" >> "$GITHUB_OUTPUT"
exit 0
fi
git commit -m "docs: sync ${{ steps.release_meta.outputs.tag }}"
echo "changes_made=true" >> "$GITHUB_OUTPUT"
echo "branch_name=${BRANCH_NAME}" >> "$GITHUB_OUTPUT"
- name: Push docs branch
if: ${{ steps.commit_docs.outputs.changes_made == 'true' }}
working-directory: docs-repo
env:
GH_TOKEN: ${{ secrets.REPO_DISPATCH_PAT_TOKEN }}
run: |
git push --force-with-lease origin "${{ steps.commit_docs.outputs.branch_name }}"
- name: Create or update docs pull request
if: ${{ steps.commit_docs.outputs.changes_made == 'true' }}
env:
GH_TOKEN: ${{ secrets.REPO_DISPATCH_PAT_TOKEN }}
EVENT_NAME: ${{ github.event_name }}
RELEASE_TAG: ${{ steps.release_meta.outputs.tag }}
RELEASE_URL: ${{ steps.release_meta.outputs.release_url }}
TARGET_REPO: topoteretes/cognee-docs
HEAD_BRANCH: ${{ steps.commit_docs.outputs.branch_name }}
run: |
if [ "${EVENT_NAME}" = "release" ]; then
PR_TITLE="docs: sync release ${RELEASE_TAG}"
PR_BODY=$(cat <<EOF
Automated sync for release \`${RELEASE_TAG}\`.
Source release: ${RELEASE_URL}
EOF
)
else
PR_TITLE="test(docs): preview sync for ${HEAD_BRANCH}"
PR_BODY=$(cat <<EOF
Automated preview sync from branch \`${HEAD_BRANCH}\`.
Source commit/revision: ${RELEASE_URL}
EOF
)
fi
HEAD_REF="topoteretes:${HEAD_BRANCH}"
EXISTING_PR_NUMBER="$(gh pr list \
--repo "${TARGET_REPO}" \
--head "${HEAD_REF}" \
--base main \
--state open \
--json number \
--jq '.[0].number // empty')"
if [ -n "${EXISTING_PR_NUMBER}" ]; then
gh pr edit "${EXISTING_PR_NUMBER}" \
--repo "${TARGET_REPO}" \
--title "${PR_TITLE}" \
--body "${PR_BODY}"
else
gh pr create \
--repo "${TARGET_REPO}" \
--base main \
--head "${HEAD_REF}" \
--title "${PR_TITLE}" \
--body "${PR_BODY}"
fi
+230
View File
@@ -0,0 +1,230 @@
name: Temporal Graph Tests
permissions:
contents: read
packages: read
on:
workflow_call:
inputs:
databases:
required: false
type: string
default: "all"
description: "Which vector databases to test (comma-separated list or 'all')"
ci-image:
required: false
type: string
default: ''
description: "Optional container image for CI"
env:
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
run_temporal_graph_kuzu_lance_sqlite:
name: Temporal Graph test Kuzu (lancedb + sqlite)
runs-on: ubuntu-22.04
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'kuzu/lance/sqlite') }}
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
- name: Dependencies already installed
run: echo "Dependencies already installed in setup"
- name: Run Temporal Graph with Kuzu (lancedb + sqlite)
env:
ENV: 'dev'
LLM_MODEL: ${{ secrets.OPENAI_MODEL }}
LLM_ENDPOINT: ${{ secrets.OPENAI_ENDPOINT }}
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
GRAPH_DATABASE_PROVIDER: 'kuzu'
VECTOR_DB_PROVIDER: 'lancedb'
DB_PROVIDER: 'sqlite'
run: uv run python ./cognee/tests/test_temporal_graph.py
run_temporal_graph_neo4j_lance_sqlite:
name: Temporal Graph test Neo4j (lancedb + sqlite)
runs-on: ubuntu-22.04
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'neo4j/lance/sqlite') }}
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
- name: Setup Neo4j with GDS
uses: ./.github/actions/setup_neo4j
id: neo4j
- name: Dependencies already installed
run: echo "Dependencies already installed in setup"
- name: Run Temporal Graph with Neo4j (lancedb + sqlite)
env:
ENV: 'dev'
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
LLM_MODEL: ${{ secrets.OPENAI_MODEL }}
LLM_ENDPOINT: ${{ secrets.OPENAI_ENDPOINT }}
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
GRAPH_DATABASE_PROVIDER: 'neo4j'
VECTOR_DB_PROVIDER: 'lancedb'
DB_PROVIDER: 'sqlite'
GRAPH_DATABASE_URL: ${{ steps.neo4j.outputs.neo4j-url }}
GRAPH_DATABASE_USERNAME: ${{ steps.neo4j.outputs.neo4j-username }}
GRAPH_DATABASE_PASSWORD: ${{ steps.neo4j.outputs.neo4j-password }}
run: uv run python ./cognee/tests/test_temporal_graph.py
run_temporal_graph_kuzu_postgres_pgvector:
name: Temporal Graph test Kuzu (postgres + pgvector)
runs-on: ubuntu-22.04
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'kuzu/pgvector/postgres') }}
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
services:
postgres:
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: cognee
POSTGRES_DB: cognee_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
extra-dependencies: "postgres"
- name: Dependencies already installed
run: echo "Dependencies already installed in setup"
- name: Run Temporal Graph with Kuzu (postgres + pgvector)
env:
ENV: dev
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
LLM_MODEL: ${{ secrets.OPENAI_MODEL }}
LLM_ENDPOINT: ${{ secrets.OPENAI_ENDPOINT }}
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
GRAPH_DATABASE_PROVIDER: 'kuzu'
VECTOR_DB_PROVIDER: 'pgvector'
DB_PROVIDER: 'postgres'
DB_NAME: 'cognee_db'
DB_HOST: ${{ inputs.ci-image != '' && 'postgres' || '127.0.0.1' }}
DB_PORT: 5432
DB_USERNAME: cognee
DB_PASSWORD: cognee
run: uv run python ./cognee/tests/test_temporal_graph.py
run_temporal_graph_neo4j_postgres_pgvector:
name: Temporal Graph test Neo4j (postgres + pgvector)
runs-on: ubuntu-22.04
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'neo4j/pgvector/postgres') }}
services:
neo4j:
image: neo4j:5.11
env:
NEO4J_AUTH: neo4j/pleaseletmein
NEO4J_PLUGINS: '["apoc","graph-data-science"]'
ports:
- 7474:7474
- 7687:7687
options: >-
--health-cmd="cypher-shell -u neo4j -p pleaseletmein 'RETURN 1'"
--health-interval=10s
--health-timeout=5s
--health-retries=5
postgres:
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: cognee
POSTGRES_DB: cognee_db
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries=5
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
extra-dependencies: "postgres"
- name: Dependencies already installed
run: echo "Dependencies already installed in setup"
- name: Run Temporal Graph with Neo4j (postgres + pgvector)
env:
ENV: dev
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
LLM_MODEL: ${{ secrets.OPENAI_MODEL }}
LLM_ENDPOINT: ${{ secrets.OPENAI_ENDPOINT }}
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
GRAPH_DATABASE_PROVIDER: 'neo4j'
VECTOR_DB_PROVIDER: 'pgvector'
DB_PROVIDER: 'postgres'
GRAPH_DATABASE_URL: bolt://localhost:7687
GRAPH_DATABASE_USERNAME: neo4j
GRAPH_DATABASE_PASSWORD: pleaseletmein
DB_NAME: cognee_db
DB_HOST: 127.0.0.1
DB_PORT: 5432
DB_USERNAME: cognee
DB_PASSWORD: cognee
run: uv run python ./cognee/tests/test_temporal_graph.py
@@ -0,0 +1,220 @@
name: Tests to run on different Operating Systems
permissions:
contents: read
on:
workflow_call:
inputs:
python-versions:
required: false
type: string
default: '["3.10.x", "3.12.x", "3.13.x"]'
os:
required: false
type: string
default: '["ubuntu-22.04", "macos-15", "windows-latest"]'
extra-dependencies:
# Space-separated package extras for the unit-test job (e.g. "postgres").
# Driver-dependent tests importorskip when their extra is absent.
required: false
type: string
default: ''
secrets:
LLM_PROVIDER:
required: true
LLM_MODEL:
required: true
LLM_ENDPOINT:
required: true
LLM_API_KEY:
required: true
LLM_ARGS:
required: false
LLM_API_VERSION:
required: true
EMBEDDING_PROVIDER:
required: true
EMBEDDING_MODEL:
required: true
EMBEDDING_API_KEY:
required: true
env:
RUNTIME__LOG_LEVEL: ERROR
ENV: 'dev'
jobs:
run-unit-tests:
name: Unit tests ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
strategy:
matrix:
python-version: ${{ fromJSON(inputs.python-versions) }}
os: ${{ fromJSON(inputs.os) }}
fail-fast: false
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ matrix.python-version }}
extra-dependencies: ${{ inputs.extra-dependencies }}
- name: Run unit tests
shell: bash
run: uv run pytest cognee/tests/unit/ --timeout=300 --timeout-method=thread
env:
PYTHONUTF8: 1
LLM_PROVIDER: openai
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_PROVIDER: openai
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run-library-test:
name: Library test ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
strategy:
matrix:
python-version: ${{ fromJSON(inputs.python-versions) }}
os: ${{ fromJSON(inputs.os) }}
fail-fast: false
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ matrix.python-version }}
- name: Run default basic pipeline
shell: bash
env:
PYTHONUTF8: 1
LLM_PROVIDER: openai
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_PROVIDER: openai
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./cognee/tests/test_library.py
run-build-test:
name: Build test ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
strategy:
matrix:
python-version: ${{ fromJSON(inputs.python-versions) }}
os: ${{ fromJSON(inputs.os) }}
fail-fast: false
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ matrix.python-version }}
- name: Build with uv
shell: bash
run: uv build
- name: Install Package
if: ${{ !contains(matrix.os, 'windows-latest') }}
run: |
cd dist
pip install *.whl
run-soft-deletion-test:
name: Soft Delete test ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
strategy:
matrix:
python-version: ${{ fromJSON(inputs.python-versions) }}
os: ${{ fromJSON(inputs.os) }}
fail-fast: false
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ matrix.python-version }}
- name: Path setup
if: ${{ matrix.os == 'windows-latest' }}
shell: bash
run: |
PATH=$(printf '%s' "$PATH" | tr ':' $'\n' | grep -vi '/git/usr/bin' | paste -sd: -)
export PATH
- name: Run Soft Deletion Tests
env:
ENV: 'dev'
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }} # Test needs OpenAI endpoint to handle multimedia
LLM_ARGS: ${{ secrets.LLM_ARGS }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./cognee/tests/test_delete_default_graph.py
run-hard-deletion-test:
name: Custom Graph Delete test ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
strategy:
matrix:
python-version: ${{ fromJSON(inputs.python-versions) }}
os: ${{ fromJSON(inputs.os) }}
fail-fast: false
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ matrix.python-version }}
- name: Run Custom Graph Deletion Test
env:
ENV: 'dev'
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }} # Test needs OpenAI endpoint to handle multimedia
LLM_ARGS: ${{ secrets.LLM_ARGS }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./cognee/tests/test_delete_custom_graph.py
+61
View File
@@ -0,0 +1,61 @@
name: test | ollama
on:
workflow_call:
env:
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
run_llama-cpp_test:
# needs ~4 Gb RAM for the GGUF model in a container which the smallest runner has
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.13.x'
extra-dependencies: postgres llama-cpp
- name: Install torch dependency
run: |
uv add torch
- name: Download Phi-3.5 GGUF model from S3
# Mirrored from huggingface.co/bartowski/Phi-3.5-mini-instruct-GGUF (MIT)
# into our bucket to avoid HuggingFace 429 rate limits in CI.
# Phi-3.5-mini reliably emits the required per-node `description`;
# the previous Phi-3-mini-q4 dropped it, failing extraction.
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_S3_DEV_USER_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_S3_DEV_USER_SECRET_KEY }}
AWS_DEFAULT_REGION: eu-west-1
BUCKET: github-runner-cognee-tests
MODEL_KEY: nightly_ci_artifacts/huggingface_models/Phi-3.5-mini-instruct-Q4_K_M.gguf
MODEL_SHA256: e4165e3a71af97f1b4820da61079826d8752a2088e313af0c7d346796c38eff5
run: |
set -euo pipefail
aws s3 cp "s3://$BUCKET/$MODEL_KEY" ./Phi-3.5-mini-instruct-Q4_K_M.gguf
echo "$MODEL_SHA256 ./Phi-3.5-mini-instruct-Q4_K_M.gguf" | sha256sum -c -
- name: Run example test
env:
PYTHONFAULTHANDLER: 1
LLM_PROVIDER: "llama_cpp"
LLAMA_CPP_MODEL_PATH: "./Phi-3.5-mini-instruct-Q4_K_M.gguf"
LLM_ENDPOINT: ""
LLAMA_CPP_N_CTX: 4096
EMBEDDING_PROVIDER: "openai"
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
EMBEDDING_MODEL: "openai/text-embedding-3-large"
EMBEDDING_DIMENSIONS: "3072"
EMBEDDING_MAX_TOKENS: "8191"
STRUCTURED_OUTPUT_FRAMEWORK: "instructor"
LLM_INSTRUCTOR_MODE: ""
run: uv run python ./examples/demos/simple_cognee_example.py
+220
View File
@@ -0,0 +1,220 @@
name: LLM Test Suites
permissions:
contents: read
packages: read
on:
workflow_call:
inputs:
ci-image:
required: false
type: string
default: ''
env:
RUNTIME__LOG_LEVEL: ERROR
ENV: 'dev'
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
test-gemini:
name: Run Gemini Test
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
- name: Run Gemini Simple Example
env:
LLM_PROVIDER: "gemini"
LLM_API_KEY: ${{ secrets.GEMINI_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_MODEL: "gemini/gemini-3-flash-preview"
EMBEDDING_PROVIDER: "gemini"
EMBEDDING_API_KEY: ${{ secrets.GEMINI_API_KEY }}
EMBEDDING_MODEL: "gemini/gemini-embedding-001"
EMBEDDING_DIMENSIONS: "768"
EMBEDDING_MAX_TOKENS: "8076"
run: uv run python ./examples/demos/simple_cognee_example.py
test-fastembed:
name: Run Fastembed Test
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
- name: Run Fastembed Simple Example
env:
LLM_PROVIDER: "openai"
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_PROVIDER: "fastembed"
EMBEDDING_MODEL: "sentence-transformers/all-MiniLM-L6-v2"
EMBEDDING_DIMENSIONS: "384"
EMBEDDING_MAX_TOKENS: "256"
run: uv run python ./examples/demos/simple_cognee_example.py
test-openrouter:
name: Run OpenRouter Test
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
- name: Run OpenRouter Simple Example
env:
LLM_PROVIDER: "custom"
LLM_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_MODEL: "openrouter/x-ai/grok-4.3"
LLM_ENDPOINT: "https://openrouter.ai/api/v1"
EMBEDDING_PROVIDER: "openai"
EMBEDDING_API_KEY: ${{ secrets.OPENAI_API_KEY }}
EMBEDDING_MODEL: "openai/text-embedding-3-large"
EMBEDDING_DIMENSIONS: "3072"
EMBEDDING_MAX_TOKENS: "8191"
run: uv run python ./examples/demos/simple_cognee_example.py
test-bedrock-api-key:
name: Run Bedrock API Key Test
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
extra-dependencies: "aws"
- name: Run Bedrock API Key Simple Example
env:
LLM_PROVIDER: "bedrock"
LLM_API_KEY: ${{ secrets.BEDROCK_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_MODEL: "eu.anthropic.claude-sonnet-4-5-20250929-v1:0"
LLM_MAX_TOKENS: "16384"
AWS_REGION_NAME: "eu-west-1"
EMBEDDING_PROVIDER: "bedrock"
EMBEDDING_API_KEY: ${{ secrets.BEDROCK_API_KEY }}
EMBEDDING_MODEL: "amazon.titan-embed-text-v2:0"
EMBEDDING_DIMENSIONS: "1024"
EMBEDDING_MAX_TOKENS: "8191"
run: uv run python ./examples/demos/simple_cognee_example.py
test-bedrock-aws-credentials:
name: Run Bedrock AWS Credentials Test
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
extra-dependencies: "aws"
- name: Run Bedrock AWS Credentials Simple Example
env:
LLM_PROVIDER: "bedrock"
LLM_MODEL: "eu.anthropic.claude-sonnet-4-5-20250929-v1:0"
LLM_MAX_TOKENS: "16384"
AWS_REGION_NAME: "eu-west-1"
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
EMBEDDING_PROVIDER: "bedrock"
EMBEDDING_API_KEY: ${{ secrets.BEDROCK_API_KEY }}
EMBEDDING_MODEL: "amazon.titan-embed-text-v2:0"
EMBEDDING_DIMENSIONS: "1024"
EMBEDDING_MAX_TOKENS: "8191"
run: uv run python ./examples/demos/simple_cognee_example.py
test-bedrock-aws-profile:
name: Run Bedrock AWS Profile Test
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
extra-dependencies: "aws"
- name: Configure AWS Profile
run: |
mkdir -p ~/.aws
cat > ~/.aws/credentials << EOF
[bedrock-test]
aws_access_key_id = ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_access_key = ${{ secrets.AWS_SECRET_ACCESS_KEY }}
EOF
- name: Run Bedrock AWS Profile Simple Example
env:
LLM_PROVIDER: "bedrock"
LLM_MODEL: "eu.anthropic.claude-sonnet-4-5-20250929-v1:0"
LLM_MAX_TOKENS: "16384"
AWS_PROFILE_NAME: "bedrock-test"
AWS_REGION_NAME: "eu-west-1"
EMBEDDING_PROVIDER: "bedrock"
EMBEDDING_MODEL: "amazon.titan-embed-text-v2:0"
EMBEDDING_DIMENSIONS: "1024"
EMBEDDING_MAX_TOKENS: "8191"
run: uv run python ./examples/demos/simple_cognee_example.py
test-claude-anthropic:
name: Run Anthropic Claude LLM Test
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
- name: Run Claude Anthropic LLM Simple Example
env:
LLM_PROVIDER: "anthropic"
# Note: If model becomes outdated update docs with new model as well
LLM_MODEL: "anthropic/claude-sonnet-4-5-20250929"
LLM_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_MAX_TOKENS: "16384"
EMBEDDING_API_KEY: ${{ secrets.OPENAI_API_KEY }}
EMBEDDING_MODEL: "openai/text-embedding-3-large"
EMBEDDING_DIMENSIONS: "3072"
EMBEDDING_MAX_TOKENS: "8191"
run: uv run python ./examples/demos/simple_cognee_example.py
+64
View File
@@ -0,0 +1,64 @@
name: test | mcp
on:
workflow_call:
inputs:
cognee_version:
required: false
type: string
default: "local" # local - Installing Cognee from local source
description: "Pypi-compatible version of cognee to use. For example, 0.5.2.dev0. `local` (default) - Installing Cognee from local source"
env:
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
test-mcp:
name: Run MCP Test
runs-on: ubuntu-22.04
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: ${{ inputs.python-version }}
- name: Install UV
shell: bash
run: |
python -m pip install --upgrade pip
pip install uv
- name: Install dependencies
shell: bash
working-directory: cognee-mcp
run: uv sync
- name: Install Cognee
uses: ./.github/actions/install_cognee
with:
python-version: ${{ inputs.python-version }}
cognee_version: ${{ inputs.cognee_version }}
- name: Run MCP unit tests
working-directory: cognee-mcp
run: uv run --no-sync pytest tests/
- name: Run MCP test
env:
ENV: 'dev'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
working-directory: cognee-mcp
run: |
echo "Cognee Version:"
uv pip show cognee | grep Version
uv run --no-sync python ./src/test_client.py
+111
View File
@@ -0,0 +1,111 @@
name: test | ollama
on:
workflow_call:
env:
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
run_ollama_test:
# TODO: needs 32 Gb RAM for phi4 in a container — GitHub-hosted larger runner
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
- name: Install torch dependency
run: |
uv add torch
- name: Start Ollama container
run: |
docker run -d --name ollama -p 11434:11434 ollama/ollama
sleep 5
docker exec -d ollama bash -c "ollama serve --openai"
- name: Check Ollama logs
run: docker logs ollama
- name: Wait for Ollama to be ready
run: |
for i in {1..30}; do
if curl -s http://localhost:11434/v1/models > /dev/null; then
echo "Ollama is ready"
exit 0
fi
echo "Waiting for Ollama... attempt $i"
sleep 2
done
echo "Ollama failed to start"
exit 1
- name: Pull required Ollama models
run: |
curl -X POST http://localhost:11434/api/pull -d '{"name": "phi4"}'
curl -X POST http://localhost:11434/api/pull -d '{"name": "qwen3-embedding:latest"}'
- name: Call ollama API
run: |
curl -X POST http://localhost:11434/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "phi4",
"stream": false,
"messages": [
{ "role": "system", "content": "You are a helpful assistant." },
{ "role": "user", "content": "Whatever I say, answer with Yes." }
]
}'
curl -X POST http://127.0.0.1:11434/api/embed \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3-embedding:latest",
"input": "This is a test sentence to generate an embedding."
}'
- name: Dump Docker logs
run: |
docker ps
docker logs $(docker ps --filter "ancestor=ollama/ollama" --format "{{.ID}}")
- name: Download embedding tokenizer from S3
# Mirrored from huggingface.co/Qwen/Qwen3-Embedding-8B (Apache-2.0) so the
# embedding tokenizer loads offline and never hits HuggingFace 429s in CI.
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_S3_DEV_USER_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_S3_DEV_USER_SECRET_KEY }}
AWS_DEFAULT_REGION: eu-west-1
BUCKET: github-runner-cognee-tests
TOKENIZER_KEY: nightly_ci_artifacts/huggingface_models/qwen3-embedding-tokenizer.tar.gz
TOKENIZER_SHA256: 8f5834d8791c8da03220feaccc2fe9c443e23b1092dcd99c576ef613990bbd00
run: |
set -euo pipefail
aws s3 cp "s3://$BUCKET/$TOKENIZER_KEY" tokenizer.tar.gz
echo "$TOKENIZER_SHA256 tokenizer.tar.gz" | sha256sum -c -
tar -xzf tokenizer.tar.gz -C "$GITHUB_WORKSPACE"
- name: Run example test
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
PYTHONFAULTHANDLER: 1
LLM_PROVIDER: "ollama"
LLM_API_KEY: "ollama"
LLM_ENDPOINT: "http://localhost:11434/v1/"
LLM_MODEL: "phi4"
EMBEDDING_PROVIDER: "ollama"
EMBEDDING_MODEL: "qwen3-embedding:latest"
EMBEDDING_ENDPOINT: "http://localhost:11434/api/embed"
EMBEDDING_DIMENSIONS: "4096"
# Load the tokenizer from the S3-mirrored local dir, fully offline.
HUGGINGFACE_TOKENIZER: "${{ github.workspace }}/qwen3-embedding-tokenizer"
HF_HUB_OFFLINE: "1"
TRANSFORMERS_OFFLINE: "1"
run: uv run python ./examples/demos/simple_cognee_example.py
@@ -0,0 +1,52 @@
name: test | s3 file storage
on:
workflow_call:
inputs:
ci-image:
required: false
type: string
default: ''
permissions:
contents: read
packages: read
env:
RUNTIME__LOG_LEVEL: ERROR
ENV: 'dev'
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
test-s3-storage:
name: Run S3 File Storage Test
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out repository
uses: actions/checkout@v6
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11.x'
extra-dependencies: "aws"
- name: Run S3 File Storage Test
env:
STORAGE_BACKEND: s3
ENABLE_BACKEND_ACCESS_CONTROL: True
AWS_REGION: eu-west-1
AWS_ENDPOINT_URL: https://s3-eu-west-1.amazonaws.com
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_S3_DEV_USER_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_S3_DEV_USER_SECRET_KEY }}
STORAGE_BUCKET_NAME: github-runner-cognee-tests
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./cognee/tests/test_s3_file_storage.py
+413
View File
@@ -0,0 +1,413 @@
name: Test Suites
permissions:
contents: read
packages: write
on:
push:
branches: [ main, dev ]
pull_request:
branches: [ main, dev ]
types: [opened, synchronize, reopened, labeled]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
RUNTIME__LOG_LEVEL: ERROR
ENV: 'dev'
jobs:
# ── Build pre-baked CI container ──────────────────────────────────────
build-ci-env:
name: Build CI Environment
runs-on: ubuntu-latest
if: >-
github.event_name == 'push' || github.event_name == 'workflow_dispatch' ||
(github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name == github.repository)
outputs:
ci-image: ${{ steps.set-image.outputs.image }}
steps:
- name: Sparse checkout (deps only)
uses: actions/checkout@v6
with:
sparse-checkout: |
pyproject.toml
uv.lock
README.md
Dockerfile.ci
.dockerignore.ci
sparse-checkout-cone-mode: false
- name: Compute dep hash and image tag
id: set-image
run: |
DEP_HASH=$(sha256sum pyproject.toml uv.lock | sha256sum | head -c 16)
IMAGE="ghcr.io/${{ github.repository }}/ci-env:deps-${DEP_HASH}"
echo "image=${IMAGE}" >> "$GITHUB_OUTPUT"
echo "dep_hash=${DEP_HASH}" >> "$GITHUB_OUTPUT"
echo "Image tag: ${IMAGE}"
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Check if image already exists
id: check
run: |
if docker manifest inspect "${{ steps.set-image.outputs.image }}" > /dev/null 2>&1; then
echo "exists=true" >> "$GITHUB_OUTPUT"
echo "Image already exists, skipping build."
else
echo "exists=false" >> "$GITHUB_OUTPUT"
echo "Image not found, will build."
fi
- name: Set up Docker Buildx
if: steps.check.outputs.exists != 'true'
uses: docker/setup-buildx-action@v3
- name: Build and push CI image
if: steps.check.outputs.exists != 'true'
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile.ci
push: true
tags: ${{ steps.set-image.outputs.image }}
cache-from: type=registry,ref=ghcr.io/${{ github.repository }}/ci-env:buildcache
cache-to: type=registry,ref=ghcr.io/${{ github.repository }}/ci-env:buildcache,mode=max
pre-test:
name: basic checks
uses: ./.github/workflows/pre_test.yml
basic-tests:
name: Basic Tests
uses: ./.github/workflows/basic_tests.yml
needs: [ build-ci-env ]
if: ${{ !cancelled() }}
with:
ci-image: ${{ needs.build-ci-env.outputs.ci-image || '' }}
secrets: inherit
e2e-tests:
name: End-to-End Tests
uses: ./.github/workflows/e2e_tests.yml
needs: [ build-ci-env ]
if: ${{ !cancelled() }}
with:
ci-image: ${{ needs.build-ci-env.outputs.ci-image || '' }}
secrets: inherit
cli-tests:
name: CLI Tests
uses: ./.github/workflows/cli_tests.yml
needs: [ build-ci-env ]
if: ${{ !cancelled() }}
with:
ci-image: ${{ needs.build-ci-env.outputs.ci-image || '' }}
secrets: inherit
slow-e2e-tests:
name: Slow End-to-End Tests
uses: ./.github/workflows/slow_e2e_tests.yml
needs: [ build-ci-env ]
if: ${{ !cancelled() }}
with:
ci-image: ${{ needs.build-ci-env.outputs.ci-image || '' }}
secrets: inherit
graph-db-tests:
name: Graph Database Tests
needs: [ build-ci-env ]
if: ${{ !cancelled() }}
uses: ./.github/workflows/graph_db_tests.yml
with:
ci-image: ${{ needs.build-ci-env.outputs.ci-image || '' }}
secrets: inherit
vector-db-tests:
name: Vector DB Tests
needs: [ build-ci-env ]
if: ${{ !cancelled() }}
uses: ./.github/workflows/vector_db_tests.yml
with:
ci-image: ${{ needs.build-ci-env.outputs.ci-image || '' }}
secrets: inherit
example-tests:
name: Example Tests
needs: [ build-ci-env ]
if: ${{ !cancelled() }}
uses: ./.github/workflows/examples_tests.yml
with:
ci-image: ${{ needs.build-ci-env.outputs.ci-image || '' }}
secrets: inherit
notebook-tests:
name: Notebook Tests
needs: [ build-ci-env ]
if: ${{ !cancelled() }}
uses: ./.github/workflows/notebooks_tests.yml
with:
ci-image: ${{ needs.build-ci-env.outputs.ci-image || '' }}
secrets: inherit
different-os-tests-basic:
name: OS and Python Tests Ubuntu
uses: ./.github/workflows/test_different_operating_systems.yml
with:
python-versions: '["3.10.x", "3.11.x", "3.12.x", "3.13.x", "3.14.x"]'
os: '["ubuntu-22.04"]'
# postgres so the SQL cache adapter tests run instead of skipping; omitted
# on macos/windows (extended) where psycopg2 has no prebuilt wheels.
extra-dependencies: 'postgres'
secrets: inherit
different-os-tests-extended:
name: OS and Python Tests Extended
uses: ./.github/workflows/test_different_operating_systems.yml
with:
python-versions: '["3.13.x"]'
os: '["macos-15", "windows-latest"]'
secrets: inherit
llm-tests:
name: LLM Test Suite
needs: [ build-ci-env ]
if: ${{ !cancelled() }}
uses: ./.github/workflows/test_llms.yml
with:
ci-image: ${{ needs.build-ci-env.outputs.ci-image || '' }}
secrets: inherit
s3-file-storage-test:
name: S3 File Storage Test
needs: [ build-ci-env ]
if: ${{ !cancelled() }}
uses: ./.github/workflows/test_s3_file_storage.yml
with:
ci-image: ${{ needs.build-ci-env.outputs.ci-image || '' }}
secrets: inherit
integration-tests:
name: Run Integration Tests
needs: [ build-ci-env ]
if: ${{ !cancelled() }}
uses: ./.github/workflows/integration_tests.yml
with:
ci-image: ${{ needs.build-ci-env.outputs.ci-image || '' }}
secrets: inherit
mcp-test:
name: MCP Tests
uses: ./.github/workflows/test_mcp.yml
secrets: inherit
docker-compose-test:
name: Docker Compose Test
uses: ./.github/workflows/docker_compose.yml
secrets: inherit
docker-ci-test:
name: Docker CI test
uses: ./.github/workflows/backend_docker_build_test.yml
secrets: inherit
temporal-graph-tests:
name: Temporal Graph Test
needs: [ build-ci-env ]
if: ${{ !cancelled() }}
uses: ./.github/workflows/temporal_graph_tests.yml
with:
ci-image: ${{ needs.build-ci-env.outputs.ci-image || '' }}
secrets: inherit
search-db-tests:
name: Search Test on Different DBs
needs: [ build-ci-env ]
if: ${{ !cancelled() }}
uses: ./.github/workflows/search_db_tests.yml
with:
ci-image: ${{ needs.build-ci-env.outputs.ci-image || '' }}
secrets: inherit
relational-db-migration-tests:
name: Relational DB Migration Tests
needs: [ build-ci-env ]
if: ${{ !cancelled() }}
uses: ./.github/workflows/relational_db_migration_tests.yml
with:
ci-image: ${{ needs.build-ci-env.outputs.ci-image || '' }}
secrets: inherit
# NOTE: intentionally excluded from the `notify` aggregator below — this is
# external infra (Modal + Azure secrets), informational only; it must not gate
# merges. (`continue-on-error` is not allowed on a reusable-workflow job.)
distributed-tests:
name: Distributed Cognee Test
needs: [ build-ci-env ]
if: ${{ !cancelled() }}
uses: ./.github/workflows/distributed_test.yml
with:
ci-image: ${{ needs.build-ci-env.outputs.ci-image || '' }}
secrets: inherit
db-examples-tests:
name: DB Examples Tests
needs: [ build-ci-env ]
if: ${{ !cancelled() }}
uses: ./.github/workflows/db_examples_tests.yml
with:
ci-image: ${{ needs.build-ci-env.outputs.ci-image || '' }}
secrets: inherit
notify:
name: Test Completion Status
needs: [
pre-test,
basic-tests,
e2e-tests,
cli-tests,
slow-e2e-tests,
graph-db-tests,
vector-db-tests,
example-tests,
notebook-tests,
different-os-tests-basic,
different-os-tests-extended,
llm-tests,
s3-file-storage-test,
integration-tests,
mcp-test,
docker-compose-test,
docker-ci-test,
temporal-graph-tests,
search-db-tests,
relational-db-migration-tests,
db-examples-tests,
]
runs-on: ubuntu-latest
if: ${{ !cancelled() }}
steps:
- name: Check Status
run: |
if [[ "${{ needs.pre-test.result }}" == "success" &&
"${{ needs.basic-tests.result }}" == "success" &&
"${{ needs.e2e-tests.result }}" == "success" &&
"${{ needs.cli-tests.result }}" == "success" &&
"${{ needs.slow-e2e-tests.result }}" == "success" &&
"${{ needs.graph-db-tests.result }}" == "success" &&
"${{ needs.vector-db-tests.result }}" == "success" &&
"${{ needs.example-tests.result }}" == "success" &&
"${{ needs.notebook-tests.result }}" == "success" &&
"${{ needs.different-os-tests-basic.result }}" == "success" &&
"${{ needs.different-os-tests-extended.result }}" == "success" &&
"${{ needs.llm-tests.result }}" == "success" &&
"${{ needs.s3-file-storage-test.result }}" == "success" &&
"${{ needs.integration-tests.result }}" == "success" &&
"${{ needs.mcp-test.result }}" == "success" &&
"${{ needs.docker-compose-test.result }}" == "success" &&
"${{ needs.docker-ci-test.result }}" == "success" &&
"${{ needs.temporal-graph-tests.result }}" == "success" &&
"${{ needs.search-db-tests.result }}" == "success" &&
"${{ needs.relational-db-migration-tests.result }}" == "success" &&
"${{ needs.db-examples-tests.result }}" == "success" ]]; then
echo "All test suites completed successfully!"
else
echo "One or more test suites failed."
exit 1
fi
# ── Advisory Claude Code review — pulls the private skill from cognee-ci at runtime ──
# The rubric + Slack map live in the private cognee-ci repo; this job carries no review
# logic. Runs only after the suite is green (needs: notify), core-team PRs only, advisory.
claude-review:
name: Claude Code Review
needs: [ notify ]
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository }}
runs-on: ubuntu-latest
continue-on-error: true
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout PR
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Core-team gate
id: gate
env:
AUTHOR: ${{ github.event.pull_request.user.login }}
run: |
author_lc="$(printf '%s' "$AUTHOR" | tr '[:upper:]' '[:lower:]')"
if grep -vE '^[[:space:]]*#' .github/core-team.txt \
| sed 's/^@//' | tr '[:upper:]' '[:lower:]' | grep -qxF "$author_lc"; then
echo "run=true" >> "$GITHUB_OUTPUT"
else
echo "run=false" >> "$GITHUB_OUTPUT"
echo "PR author '$AUTHOR' not in core-team.txt — skipping."
fi
- name: Mint private-repo token
if: ${{ steps.gate.outputs.run == 'true' }}
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.CI_APP_ID }}
private-key: ${{ secrets.CI_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: cognee-ci
- name: Fetch private review skill + slack map
if: ${{ steps.gate.outputs.run == 'true' }}
uses: actions/checkout@v6
with:
repository: ${{ github.repository_owner }}/cognee-ci
token: ${{ steps.app-token.outputs.token }}
path: .ci-private
- name: Stage skill into the user skills dir
if: ${{ steps.gate.outputs.run == 'true' }}
run: |
# Stage into the USER skills dir ($HOME/.claude), NOT the repo's .claude/.
# claude-code-action sanitizes the repo .claude for untrusted PR heads
# (it moves the working-tree .claude to .claude-pr/ and restores a clean
# .claude from the base branch), which wipes the staged private skill and
# leaves /pr-review unresolved -> 0 turns, nothing posted. $HOME/.claude is
# untouched by that sanitization and is loaded via settingSources: [user,...].
mkdir -p "$HOME/.claude/skills"
cp -r .ci-private/.claude/skills/pr-review "$HOME/.claude/skills/"
- name: Claude Code review
if: ${{ steps.gate.outputs.run == 'true' }}
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ secrets.GITHUB_TOKEN }}
prompt: "/pr-review"
claude_args: >-
--allowed-tools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Read,Glob,Grep"
--max-turns 20
--model claude-sonnet-4-5-20250929
- name: DM review summary to PR author on Slack
if: ${{ steps.gate.outputs.run == 'true' }}
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AUTHOR: ${{ github.event.pull_request.user.login }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_URL: ${{ github.event.pull_request.html_url }}
PR_TITLE: ${{ github.event.pull_request.title }}
REPO: ${{ github.repository }}
run: python3 .ci-private/scripts/pr_review_slack_notify.py
+37
View File
@@ -0,0 +1,37 @@
name: community | contributors leaderboard
on:
schedule:
- cron: "0 0 * * 1" # Runs every Monday
workflow_dispatch: # Allows manual trigger
jobs:
update-contributors:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v6
- name: Generate Contributor List
run: |
echo "## 💫 Contributors" > CONTRIBUTORS.md
echo "" >> CONTRIBUTORS.md
echo "Thanks to our amazing contributors! 💖" >> CONTRIBUTORS.md
echo "" >> CONTRIBUTORS.md
echo '<a href="https://github.com/topoteretes/cognee/graphs/contributors">' >> CONTRIBUTORS.md
echo ' <img src="https://contrib.rocks/image?repo=topoteretes/cognee" />' >> CONTRIBUTORS.md
echo '</a>' >> CONTRIBUTORS.md
echo "" >> CONTRIBUTORS.md
echo "## 🏆 Top Contributors" >> CONTRIBUTORS.md
echo "" >> CONTRIBUTORS.md
echo "| Rank | Contributor | Contributions |" >> CONTRIBUTORS.md
echo "|------|------------|---------------|" >> CONTRIBUTORS.md
git shortlog -sne | sort -rn | head -10 | awk '{print "| "NR" | ["$2"](https://github.com/"$2") | "$1" Commits |"}' >> CONTRIBUTORS.md
- name: Commit and Push Changes
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions@users.noreply.github.com"
git add CONTRIBUTORS.md
git commit -m "Update contributors list"
git push
+153
View File
@@ -0,0 +1,153 @@
name: Reusable Vector DB Tests
on:
workflow_call:
inputs:
databases:
required: false
type: string
default: "all"
description: "Which vector databases to test (comma-separated list or 'all')"
ci-image:
required: false
type: string
default: ''
secrets:
POSTGRES_PASSWORD:
required: false
env:
COGNEE_SKIP_CONNECTION_TEST: 'true'
jobs:
run-postgres-tests:
name: PostgreSQL Tests
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'postgres') }}
services:
postgres:
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
POSTGRES_DB: cognee_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
extra-dependencies: "postgres"
- name: Run PGVector Tests
env:
ENV: 'dev'
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
DB_HOST: ${{ inputs.ci-image != '' && 'postgres' || '127.0.0.1' }}
run: uv run python ./cognee/tests/test_pgvector.py
run-pgvector-multi-user-tests:
name: PGVector Multi-User Tests
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
if: ${{ inputs.databases == 'all' || contains(inputs.databases, 'postgres') }}
services:
postgres:
image: ghcr.io/topoteretes/pgvector:pg17
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
env:
POSTGRES_USER: cognee
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
POSTGRES_DB: cognee_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
extra-dependencies: "postgres"
- name: Run PGVector Permissions Tests
env:
ENV: 'dev'
ENABLE_BACKEND_ACCESS_CONTROL: 'true'
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
VECTOR_DB_HOST: ${{ inputs.ci-image != '' && 'postgres' || '127.0.0.1' }}
VECTOR_DB_PORT: 5432
VECTOR_DB_USERNAME: cognee
VECTOR_DB_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
VECTOR_DATASET_DATABASE_HANDLER: pgvector
run: uv run python ./cognee/tests/test_permissions.py
run-lancedb-tests:
name: LanceDB Tests
runs-on: ubuntu-22.04
container: ${{ inputs.ci-image != '' && fromJSON(format('{{"image":"{0}","credentials":{{"username":"{1}","password":"{2}"}}}}', inputs.ci-image, github.actor, github.token)) || null }}
steps:
- name: Check out
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ inputs.python-version }}
- name: Run LanceDB Tests
env:
ENV: 'dev'
# Cap cached DB adapters
DATABASE_MAX_LRU_CACHE_SIZE: 1
LLM_MODEL: ${{ secrets.LLM_MODEL }}
LLM_ENDPOINT: ${{ secrets.LLM_ENDPOINT }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: ${{ secrets.LLM_API_VERSION }}
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
run: uv run python ./cognee/tests/test_lancedb.py
+169
View File
@@ -0,0 +1,169 @@
name: Weighted Edges Tests
on:
push:
branches: [ main, dev, weighted_edges]
paths:
- 'cognee/modules/graph/utils/get_graph_from_model.py'
- 'cognee/infrastructure/engine/models/Edge.py'
- 'cognee/tests/unit/interfaces/graph/test_weighted_edges.py'
- 'examples/demos/dynamic_multiple_weighted_edges_example.py'
- '.github/workflows/weighted_edges_tests.yml'
pull_request:
branches: [ main, dev ]
paths:
- 'cognee/modules/graph/utils/get_graph_from_model.py'
- 'cognee/infrastructure/engine/models/Edge.py'
- 'cognee/tests/unit/interfaces/graph/test_weighted_edges.py'
- 'examples/demos/dynamic_multiple_weighted_edges_example.py'
- '.github/workflows/weighted_edges_tests.yml'
env:
RUNTIME__LOG_LEVEL: ERROR
ENV: 'dev'
jobs:
test-weighted-edges-functionality:
name: Test Weighted Edges Core Functionality
runs-on: ubuntu-22.04
strategy:
matrix:
python-version: ['3.11', '3.12']
env:
LLM_PROVIDER: openai
LLM_MODEL: gpt-5-mini
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: ${{ matrix.python-version }}
- name: Run Weighted Edges Unit Tests
run: |
uv run pytest cognee/tests/unit/interfaces/graph/test_weighted_edges.py -v --tb=short
- name: Run Standard Graph Tests (Regression)
run: |
uv run pytest cognee/tests/unit/interfaces/graph/get_graph_from_model_unit_test.py -v --tb=short
test-with-different-databases:
name: Test Weighted Edges with Different Graph Databases
runs-on: ubuntu-22.04
strategy:
matrix:
database: ['kuzu', 'neo4j']
include:
- database: kuzu
graph_db_provider: "kuzu"
- database: neo4j
graph_db_provider: "neo4j"
env:
LLM_PROVIDER: openai
LLM_MODEL: gpt-5-mini
LLM_ENDPOINT: https://api.openai.com/v1
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: "2024-02-01"
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11'
- name: Setup Neo4j with GDS
uses: ./.github/actions/setup_neo4j
id: neo4j
- name: Dependencies already installed
run: echo "Dependencies already installed in setup"
- name: Run Weighted Edges Tests
env:
ENABLE_BACKEND_ACCESS_CONTROL: 'false'
GRAPH_DATABASE_PROVIDER: ${{ matrix.graph_db_provider }}
GRAPH_DATABASE_URL: ${{ matrix.graph_db_provider == 'neo4j' && steps.neo4j.outputs.neo4j-url || '' }}
GRAPH_DATABASE_USERNAME: ${{ matrix.graph_db_provider == 'neo4j' && steps.neo4j.outputs.neo4j-username || '' }}
GRAPH_DATABASE_PASSWORD: ${{ matrix.graph_db_provider == 'neo4j' && steps.neo4j.outputs.neo4j-password || '' }}
run: |
uv run pytest cognee/tests/unit/interfaces/graph/test_weighted_edges.py -v --tb=short
test-examples:
name: Test Weighted Edges Examples
runs-on: ubuntu-22.04
env:
LLM_PROVIDER: openai
LLM_MODEL: gpt-5-mini
LLM_ENDPOINT: https://api.openai.com/v1
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LLM_ARGS: ${{ secrets.LLM_ARGS }}
LLM_API_VERSION: "2024-02-01"
EMBEDDING_DIMENSIONS: 300
EMBEDDING_MODEL: ${{ secrets.EMBEDDING_MODEL }}
EMBEDDING_API_KEY: ${{ secrets.EMBEDDING_API_KEY }}
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11'
- name: Test Weighted Edges Example
run: |
uv run python examples/demos/dynamic_multiple_weighted_edges_example.py
- name: Verify Visualization File Created
run: |
if [ -f "examples/demos/.artifacts/dunder_mifflin_company_graph.html" ]; then
echo "✅ Visualization file created successfully"
ls -la examples/demos/.artifacts/dunder_mifflin_company_graph.html
else
echo "❌ Visualization file not found"
exit 1
fi
code-quality:
name: Code Quality for Weighted Edges
runs-on: ubuntu-22.04
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Cognee Setup
uses: ./.github/actions/cognee_setup
with:
python-version: '3.11'
- name: Run Linting on Weighted Edges Files
uses: astral-sh/ruff-action@v3
with:
args: "check cognee/modules/graph/utils/get_graph_from_model.py cognee/tests/unit/interfaces/graph/test_weighted_edges.py examples/demos/dynamic_multiple_weighted_edges_example.py"
- name: Run Formatting Check on Weighted Edges Files
uses: astral-sh/ruff-action@v3
with:
args: "format --check cognee/modules/graph/utils/get_graph_from_model.py cognee/tests/unit/interfaces/graph/test_weighted_edges.py examples/demos/dynamic_multiple_weighted_edges_example.py"
+213
View File
@@ -0,0 +1,213 @@
.data
.env
.local.env
.prod.env
cognee/.data/
code_pipeline_output*/
# Test output files
test_outputs/
*.lance/
.DS_Store
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
full_run.ipynb
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
.python-version
cognee-mcp/.python-version
MANIFEST
# cognee-mcp app bundle (built by `npm run build` under cognee-mcp/apps-src/).
# Generated artifact — see cognee-mcp/README.md for the build step.
cognee-mcp/src/app_bundles/
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Cognee logs directory - keep directory, ignore contents
logs/*
!logs/.gitkeep
!logs/README.md
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.env.local
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
mise.toml
deployment/helm/values-local.yml
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/
.vscode/
cognee/data/
cognee/cache/
# Default cognee system directory, used in development
.cognee_system/
.data_storage/
.cognee_cache/
.artifacts/
.anon_id
node_modules/
# Evals
SWE-bench_testsample/
# ChromaDB Data
.chromadb_data/
deployment/helm/values-local.yml
# Performance test results
cognee/tests/performance/results
+9
View File
@@ -0,0 +1,9 @@
pull_request_rules:
- name: Backport to main when backport_main label is set
conditions:
- label=backport_main
- base=dev
actions:
backport:
branches:
- main
+21
View File
@@ -0,0 +1,21 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
exclude: ^deployment/helm/templates/
- id: check-added-large-files
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.15.11
hooks:
# Run the linter.
- id: ruff
types_or: [python, pyi]
# Run the formatter.
- id: ruff-format
types_or: [python, pyi]
+130
View File
@@ -0,0 +1,130 @@
## Repository Guidelines
This document summarizes how to work with the cognee repository: how its organized, how to build, test, lint, and contribute. It mirrors our actual tooling and CI while providing quick commands for local development.
## Project Structure & Module Organization
- `cognee/`: Core Python library and API.
- `api/`: FastAPI application and versioned routers (add, cognify, memify, search, delete, users, datasets, responses, visualize, settings, sync, update, checks).
- `cli/`: CLI entry points and subcommands invoked via `cognee` / `cognee-cli`.
- `infrastructure/`: Databases, LLM providers, embeddings, loaders, and storage adapters.
- `modules/`: Domain logic (graph, retrieval, ontology, users, processing, observability, etc.).
- `tasks/`: Reusable tasks (e.g., code graph, web scraping, storage). Extend with new tasks here.
- `eval_framework/`: Evaluation utilities and adapters.
- `shared/`: Cross-cutting helpers (logging, settings, utils).
- `tests/`: Unit, integration, CLI, and end-to-end tests organized by feature.
- `__main__.py`: Entrypoint to route to CLI.
- `cognee-mcp/`: Model Context Protocol server exposing cognee as MCP tools (SSE/HTTP/stdio). Contains its own README and Dockerfile.
- `cognee-frontend/`: Next.js UI for local development and demos.
- `distributed/`: Utilities for distributed execution (Modal, workers, queues).
- `examples/`: Example scripts demonstrating the public APIs and features (graph, code graph, multimodal, permissions, etc.).
- `notebooks/`: Jupyter notebooks for demos and tutorials.
- `alembic/`: Database migrations for relational backends.
Notes:
- Co-locate feature-specific helpers under their respective package (`modules/`, `infrastructure/`, or `tasks/`).
- Extend the system by adding new tasks, loaders, or retrievers rather than modifying core pipeline mechanisms.
## Build, Test, and Development Commands
Python (root) requires Python >= 3.10 and < 3.14. We recommend `uv` for speed and reproducibility.
- Create/refresh env and install dev deps:
```bash
uv sync --dev --all-extras --reinstall
```
- Run the CLI (examples):
```bash
uv run cognee-cli add "Cognee turns documents into AI memory."
uv run cognee-cli cognify
uv run cognee-cli search "What does cognee do?"
uv run cognee-cli -ui # Launches UI, backend API, and MCP server together
```
- Start the FastAPI server directly:
```bash
uv run python -m cognee.api.client
```
- Run tests (CI mirrors these commands):
```bash
uv run pytest cognee/tests/unit/ -v
uv run pytest cognee/tests/integration/ -v
```
- Lint and format (ruff):
```bash
uv run ruff check .
uv run ruff format .
```
- Optional static type checks (ty):
```bash
uv run ty check .
```
MCP Server (`cognee-mcp/`):
- Install and run locally:
```bash
cd cognee-mcp
uv sync --dev --all-extras --reinstall
uv run python src/server.py # stdio (default)
uv run python src/server.py --transport sse
uv run python src/server.py --transport http --host 127.0.0.1 --port 8000 --path /mcp
```
- API Mode (connect to a running Cognee API):
```bash
uv run python src/server.py --transport sse --api-url http://localhost:8000 --api-token YOUR_TOKEN
```
- Docker quickstart (examples): see `cognee-mcp/README.md` for full details
```bash
docker run -e TRANSPORT_MODE=http --env-file ./.env -p 8000:8000 --rm -it cognee/cognee-mcp:main
```
Frontend (`cognee-frontend/`):
```bash
cd cognee-frontend
npm install
npm run dev # Next.js dev server
npm run lint # ESLint
npm run build && npm start
```
## Coding Style & Naming Conventions
Python:
- 4-space indentation, modules and functions in `snake_case`, classes in `PascalCase`.
- Public APIs should be type-annotated where practical. Make sure type defined in API signature will be properly displayed in Swagger UI docs. For example this definition: content_type: Optional[str] = Form(default=None) maps to "string" as the default in Swagger docs for content_type, but it should be None/null instead.
- Use `ruff format` before committing; `ruff check` enforces import hygiene and style (line-length 100 configured in `pyproject.toml`).
- Prefer explicit, structured error handling. Use shared logging utilities in `cognee.shared.logging_utils`.
MCP server and Frontend:
- Follow the local `README.md` and ESLint/TypeScript configuration in `cognee-frontend/`.
## Testing Guidelines
- Place Python tests under `cognee/tests/`.
- Unit tests: `cognee/tests/unit/`
- Integration tests: `cognee/tests/integration/`
- CLI tests: `cognee/tests/cli_tests/`
- Name test files `test_*.py`. Use `pytest.mark.asyncio` for async tests.
- Avoid external state; rely on test fixtures and the CI-provided env vars when LLM/embedding providers are required. See CI workflows under `.github/workflows/` for expected environment variables.
- When adding public APIs, provide/update targeted examples under `examples/python/`.
## Commit & Pull Request Guidelines
- Use clear, imperative subjects (≤ 72 chars) and conventional commit styling in PR titles. Our CI validates semantic PR titles (see `.github/workflows/pr_lint`). Examples:
- `feat(graph): add temporal edge weighting`
- `fix(api): handle missing auth cookie`
- `docs: update installation instructions`
- Reference related issues/discussions in the PR body and provide brief context.
- PRs should describe scope, list local test commands run, and mention any impacts on MCP server or UI if applicable.
- Sign commits and affirm the DCO (see `CONTRIBUTING.md`).
## CI Mirrors Local Commands
Our GitHub Actions run the same ruff checks and pytest suites shown above (`.github/workflows/basic_tests.yml` and related workflows). Use the commands in this document locally to minimize CI surprises.
+605
View File
@@ -0,0 +1,605 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Cognee is an open-source AI memory platform that transforms raw data into persistent knowledge graphs for AI agents. It replaces traditional RAG (Retrieval-Augmented Generation) with an ECL (Extract, Cognify, Load) pipeline combining vector search, graph databases, and LLM-powered entity extraction.
**Requirements**: Python 3.10 - 3.14
## Development Commands
### Setup
```bash
# Create virtual environment (recommended: uv)
uv venv && source .venv/bin/activate
# Install with pip, poetry, or uv
uv pip install -e .
# Install with dev dependencies
uv pip install -e ".[dev]"
# Install with specific extras
uv pip install -e ".[postgres,neo4j,docs,chromadb]"
# Set up pre-commit hooks
pre-commit install
```
### Available Installation Extras
- **postgres** / **postgres-binary** - PostgreSQL + PGVector support (also enables the Postgres session-cache backend, `CACHE_BACKEND=postgres`)
- **neo4j** - Neo4j graph database support
- **neptune** - AWS Neptune support
- **chromadb** - ChromaDB vector database
- **docs** - Document processing (unstructured library)
- **scraping** - Web scraping (Tavily, BeautifulSoup, Playwright)
- **langchain** - LangChain integration
- **llama-index** - LlamaIndex integration
- **anthropic** - Anthropic Claude models
- **gemini** - Google Gemini models
- **ollama** - Ollama local models
- **mistral** - Mistral AI models
- **groq** - Groq API support
- **llama-cpp** - Llama.cpp local inference
- **huggingface** - HuggingFace transformers
- **aws** - S3 storage backend
- **redis** - Redis caching
- **graphiti** - Graphiti-core integration
- **baml** - BAML structured output
- **dlt** - Data load tool (dlt) integration
- **docling** - Docling document processing
- **codegraph** - Code graph extraction
- **evals** - Evaluation tools
- **deepeval** - DeepEval testing framework
- **posthog** - PostHog analytics
- **tracing** - OpenTelemetry tracing
- **distributed** - Modal distributed execution
- **dev** - All development tools (pytest, ty, ruff, etc.)
- **debug** - Debugpy for debugging
### Testing
```bash
# Run all tests
pytest
# Run with coverage
pytest --cov=cognee --cov-report=html
# Run specific test file
pytest cognee/tests/test_custom_model.py
# Run specific test function
pytest cognee/tests/test_custom_model.py::test_function_name
# Run async tests
pytest -v cognee/tests/integration/
# Run unit tests only
pytest cognee/tests/unit/
# Run integration tests only
pytest cognee/tests/integration/
```
### Code Quality
```bash
# Run ruff linter
ruff check .
# Run ruff formatter
ruff format .
# Run both linting and formatting (pre-commit)
pre-commit run --all-files
# Type checking with ty
ty check .
```
### Running Cognee
```bash
# Using Python SDK
uv run python examples/demos/simple_cognee_example.py
# Using CLI
cognee-cli add "Your text here"
cognee-cli cognify
cognee-cli search "Your query"
cognee-cli delete --all
# Launch full stack with UI
cognee-cli -ui
```
## Architecture Overview
### Core Workflow: add → cognify → search/memify
1. **add()** - Ingest data (files, URLs, text) into datasets
2. **cognify()** - Extract entities/relationships and build knowledge graph
3. **search()** - Query knowledge using various retrieval strategies
4. **memify()** - Enrich graph with additional context and rules
### Key Architectural Patterns
#### 1. Pipeline-Based Processing
All data flows through task-based pipelines (`cognee/modules/pipelines/`). Tasks are composable units that can run sequentially or in parallel. Example pipeline tasks: `classify_documents`, `extract_graph_from_data`, `add_data_points`.
#### 2. Interface-Based Database Adapters
Multiple backends are supported through adapter interfaces:
- **Graph**: Ladybug (default), Neo4j, Neptune, Postgres via `GraphDBInterface`
- **Vector**: LanceDB (default), ChromaDB, PGVector via `VectorDBInterface`
- **Relational**: SQLite (default), PostgreSQL
Key files:
- `cognee/infrastructure/databases/graph/graph_db_interface.py`
- `cognee/infrastructure/databases/vector/vector_db_interface.py`
#### 3. Multi-Tenant Access Control
User → Dataset → Data hierarchy with permission-based filtering. Enable with `ENABLE_BACKEND_ACCESS_CONTROL=True`. Each user+dataset combination can have isolated graph/vector databases (when using supported backends: Ladybug, LanceDB, SQLite, Postgres).
### Layer Structure
```
API Layer (cognee/api/v1/)
Main Functions (add, cognify, search, memify)
Pipeline Orchestrator (cognee/modules/pipelines/)
Task Execution Layer (cognee/tasks/)
Domain Modules (graph, retrieval, ingestion, etc.)
Infrastructure Adapters (LLM, databases)
External Services (OpenAI, Ladybug, LanceDB, etc.)
```
### Critical Data Flow Paths
#### ADD: Data Ingestion
`add()``resolve_data_directories``ingest_data``save_data_item_to_storage` → Create Dataset + Data records in relational DB
Key files: `cognee/api/v1/add/add.py`, `cognee/tasks/ingestion/ingest_data.py`
#### COGNIFY: Knowledge Graph Construction
`cognify()``classify_documents``extract_chunks_from_documents``extract_graph_from_data` (LLM extracts entities/relationships using Instructor) → `summarize_text``add_data_points` (store in graph + vector DBs)
Key files:
- `cognee/api/v1/cognify/cognify.py`
- `cognee/tasks/graph/extract_graph_from_data.py`
- `cognee/tasks/storage/add_data_points.py`
#### SEARCH: Retrieval
`search(query_text, query_type)` → route to retriever type → filter by permissions → return results
Available search types (from `cognee/modules/search/types/SearchType.py`):
- **GRAPH_COMPLETION** (default) - Graph traversal + LLM completion
- **GRAPH_SUMMARY_COMPLETION** - Uses pre-computed summaries with graph context
- **GRAPH_COMPLETION_COT** - Chain-of-thought reasoning over graph
- **GRAPH_COMPLETION_CONTEXT_EXTENSION** - Extended context graph retrieval
- **TRIPLET_COMPLETION** - Triplet-based (subject-predicate-object) search
- **RAG_COMPLETION** - Traditional RAG with chunks
- **CHUNKS** - Vector similarity search over chunks
- **CHUNKS_LEXICAL** - Lexical (keyword) search over chunks
- **SUMMARIES** - Search pre-computed document summaries
- **CYPHER** - Direct Cypher query execution (requires `ALLOW_CYPHER_QUERY=True`)
- **NATURAL_LANGUAGE** - Natural language to structured query
- **TEMPORAL** - Time-aware graph search
- **FEELING_LUCKY** - Automatic search type selection
- **CODING_RULES** - Code-specific search rules
Key files:
- `cognee/api/v1/search/search.py`
- `cognee/modules/retrieval/context_providers/TripletSearchContextProvider.py`
- `cognee/modules/search/types/SearchType.py`
### Core Data Models
#### Engine Models (`cognee/infrastructure/engine/models/`)
- **DataPoint** - Base class for all graph nodes (versioned, with metadata)
- **Edge** - Graph relationships (source, target, relationship type)
- **Triplet** - (Subject, Predicate, Object) representation
#### Graph Models (`cognee/shared/data_models.py`)
- **KnowledgeGraph** - Container for nodes and edges
- **Node** - Entity (id, name, type, description)
- **Edge** - Relationship (source_node_id, target_node_id, relationship_name)
### Key Infrastructure Components
#### LLM Gateway (`cognee/infrastructure/llm/LLMGateway.py`)
Unified interface for multiple LLM providers: OpenAI, Anthropic, Gemini, Ollama, Mistral, Bedrock. Uses Instructor for structured output extraction.
#### Embedding Engines
Factory pattern for embeddings: `cognee/infrastructure/databases/vector/embeddings/get_embedding_engine.py`
#### Document Loaders
Support for PDF, DOCX, CSV, images, audio, code files in `cognee/infrastructure/files/`
## Important Configuration
### Environment Setup
Copy `.env.template` to `.env` and configure:
```bash
# Minimal setup (defaults to OpenAI + local file-based databases)
LLM_API_KEY="your_openai_api_key"
LLM_MODEL="openai/gpt-5-mini" # Default model
```
**Important**: If you configure only LLM or only embeddings, the other defaults to OpenAI. Ensure you have a working OpenAI API key, or configure both to avoid unexpected defaults.
Default databases (no extra setup needed):
- **Relational**: SQLite (metadata and state storage)
- **Vector**: LanceDB (embeddings for semantic search)
- **Graph**: Ladybug (knowledge graph and relationships)
All stored in `.venv` by default. Override with `DATA_ROOT_DIRECTORY` and `SYSTEM_ROOT_DIRECTORY`.
### Switching Databases
#### Relational Databases
```bash
# PostgreSQL (requires postgres extra: pip install cognee[postgres])
DB_PROVIDER=postgres
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=cognee
DB_PASSWORD=cognee
DB_NAME=cognee_db
```
#### Vector Databases
Supported: lancedb (default), pgvector, chromadb, qdrant, weaviate, milvus
```bash
# ChromaDB (requires chromadb extra)
VECTOR_DB_PROVIDER=chromadb
# PGVector (requires postgres extra)
VECTOR_DB_PROVIDER=pgvector
VECTOR_DB_URL=postgresql://cognee:cognee@localhost:5432/cognee_db
```
#### Graph Databases
Supported: ladybug (default), neo4j, neptune, ladybug-remote, postgres
```bash
# Neo4j (requires neo4j extra: pip install cognee[neo4j])
GRAPH_DATABASE_PROVIDER=neo4j
GRAPH_DATABASE_URL=bolt://localhost:7687
GRAPH_DATABASE_NAME=neo4j
GRAPH_DATABASE_USERNAME=neo4j
GRAPH_DATABASE_PASSWORD=yourpassword
# Remote Ladybug
GRAPH_DATABASE_PROVIDER=ladybug-remote
GRAPH_DATABASE_URL=http://localhost:8000
GRAPH_DATABASE_USERNAME=your_username
GRAPH_DATABASE_PASSWORD=your_password
# Postgres (requires postgres extra: pip install cognee[postgres])
# Does not support raw Cypher queries, natural language search, or Graphiti.
GRAPH_DATABASE_PROVIDER=postgres
GRAPH_DATABASE_URL=postgresql+asyncpg://cognee:cognee@localhost:5432/cognee_db
```
#### Session Cache
```bash
# Session/conversation cache backend: sqlite (default), postgres, redis, fs, tapes
CACHE_BACKEND=sqlite
# Optional explicit SQLAlchemy URL for sqlite/postgres cache backends (overrides defaults)
CACHE_DB_URL=postgresql+asyncpg://cognee:cognee@localhost:5432/cognee_db
```
### LLM Provider Configuration
Supported providers: OpenAI (default), Azure OpenAI, Google Gemini, Anthropic, AWS Bedrock, Ollama, LM Studio, Custom (OpenAI-compatible APIs)
#### OpenAI (Recommended - Minimal Setup)
```bash
LLM_API_KEY="your_openai_api_key"
LLM_MODEL="openai/gpt-5-mini" # default; or gpt-5, gpt-4o, gpt-4o-mini, etc.
LLM_PROVIDER="openai"
```
#### Azure OpenAI
```bash
LLM_PROVIDER="azure"
LLM_MODEL="azure/gpt-4o-mini"
LLM_ENDPOINT="https://YOUR-RESOURCE.openai.azure.com/openai/deployments/gpt-4o-mini"
LLM_API_KEY="your_azure_api_key"
LLM_API_VERSION="2024-12-01-preview"
```
#### Google Gemini (requires gemini extra)
```bash
LLM_PROVIDER="gemini"
LLM_MODEL="gemini/gemini-2.0-flash-exp"
LLM_API_KEY="your_gemini_api_key"
```
#### Anthropic Claude (requires anthropic extra)
```bash
LLM_PROVIDER="anthropic"
LLM_MODEL="claude-3-5-sonnet-20241022"
LLM_API_KEY="your_anthropic_api_key"
```
#### Ollama (Local - requires ollama extra)
```bash
LLM_PROVIDER="ollama"
LLM_MODEL="llama3.1:8b"
LLM_ENDPOINT="http://localhost:11434/v1"
LLM_API_KEY="ollama"
EMBEDDING_PROVIDER="ollama"
EMBEDDING_MODEL="nomic-embed-text:latest"
EMBEDDING_ENDPOINT="http://localhost:11434/api/embed"
HUGGINGFACE_TOKENIZER="nomic-ai/nomic-embed-text-v1.5"
```
#### Custom / OpenRouter / vLLM
```bash
LLM_PROVIDER="custom"
LLM_MODEL="openrouter/google/gemini-2.0-flash-lite-preview-02-05:free"
LLM_ENDPOINT="https://openrouter.ai/api/v1"
LLM_API_KEY="your_api_key"
```
#### AWS Bedrock (requires aws extra)
```bash
LLM_PROVIDER="bedrock"
LLM_MODEL="anthropic.claude-3-sonnet-20240229-v1:0"
AWS_REGION="us-east-1"
AWS_ACCESS_KEY_ID="your_access_key"
AWS_SECRET_ACCESS_KEY="your_secret_key"
# Optional for temporary credentials:
# AWS_SESSION_TOKEN="your_session_token"
```
#### LLM Rate Limiting
```bash
LLM_RATE_LIMIT_ENABLED=true
LLM_RATE_LIMIT_REQUESTS=60 # Requests per interval
LLM_RATE_LIMIT_INTERVAL=60 # Interval in seconds
```
#### Instructor Mode (Structured Output)
```bash
# LLM_INSTRUCTOR_MODE controls how structured data is extracted
# Each LLM has its own default (e.g., gpt-4o models use "json_schema_mode")
# Override if needed:
LLM_INSTRUCTOR_MODE="json_schema_mode" # or "tool_call", "md_json", etc.
```
### Structured Output Framework
```bash
# Use Instructor (default, via litellm)
STRUCTURED_OUTPUT_FRAMEWORK="instructor"
# Or use BAML (requires baml extra: pip install cognee[baml])
STRUCTURED_OUTPUT_FRAMEWORK="baml"
BAML_LLM_PROVIDER=openai
BAML_LLM_MODEL="gpt-4o-mini"
BAML_LLM_API_KEY="your_api_key"
```
### Storage Backend
```bash
# Local filesystem (default)
STORAGE_BACKEND="local"
# S3 (requires aws extra: pip install cognee[aws])
STORAGE_BACKEND="s3"
STORAGE_BUCKET_NAME="your-bucket-name"
AWS_REGION="us-east-1"
AWS_ACCESS_KEY_ID="your_access_key"
AWS_SECRET_ACCESS_KEY="your_secret_key"
DATA_ROOT_DIRECTORY="s3://your-bucket/cognee/data"
SYSTEM_ROOT_DIRECTORY="s3://your-bucket/cognee/system"
```
## Extension Points
### Adding New Functionality
1. **New Task Type**: Create task function in `cognee/tasks/`, return Task object, register in pipeline
2. **New Database Backend**: Implement `GraphDBInterface` or `VectorDBInterface` in `cognee/infrastructure/databases/`
3. **New LLM Provider**: Add configuration in LLM config (uses litellm)
4. **New Document Processor**: Extend loaders in `cognee/modules/data/processing/`
5. **New Search Type**: Add to `SearchType` enum and implement retriever in `cognee/modules/retrieval/`
6. **Custom Graph Models**: Define Pydantic models extending `DataPoint` in your code
### Working with Ontologies
Cognee supports ontology-based entity extraction to ground knowledge graphs in standardized semantic frameworks (e.g., OWL ontologies).
Configuration:
```bash
ONTOLOGY_RESOLVER=rdflib # Default: uses rdflib and OWL files
MATCHING_STRATEGY=fuzzy # Default: fuzzy matching with 80% similarity
ONTOLOGY_FILE_PATH=/path/to/your/ontology.owl # Full path to ontology file
```
Implementation: `cognee/modules/ontology/`
## Branching Strategy
**IMPORTANT**: Always branch from `dev`, not `main`. The `dev` branch is the active development branch.
```bash
git checkout dev
git pull origin dev
git checkout -b feature/your-feature-name
```
**Core-team PRs must reference a Linear issue.** Put the issue key (e.g. `COG-123`)
in the PR title or the branch name so Linear links the PR to its ticket. This is
enforced by the `Require Linear issue` workflow (`linear-issue-check`), a required
status check. Fork / external-contributor PRs are exempt (the check skips them), so
this rule applies only to internal PRs.
## Code Style
- **Formatter**: Ruff (configured in `pyproject.toml`)
- **Line length**: 100 characters
- **String quotes**: Use double quotes `"` not single quotes `'` (enforced by ruff-format)
- **Pre-commit hooks**: Run ruff linting and formatting automatically
- **Type hints**: Encouraged (ty checks enabled)
- **Important**: Always run `pre-commit run --all-files` before committing to catch formatting issues
## Testing Strategy
Tests are organized in `cognee/tests/`:
- `unit/` - Unit tests for individual modules
- `integration/` - Full pipeline integration tests
- `cli_tests/` - CLI command tests
- `tasks/` - Task-specific tests
When adding features, add corresponding tests. Integration tests should cover the full add → cognify → search flow.
## API Structure
FastAPI application with versioned routes under `cognee/api/v1/`:
- `/add` - Data ingestion
- `/cognify` - Knowledge graph processing
- `/search` - Query interface
- `/memify` - Graph enrichment
- `/datasets` - Dataset management
- `/users` - Authentication (when `REQUIRE_AUTHENTICATION` is effectively true; see auth posture below)
- `/visualize` - Graph visualization server
## Python SDK Entry Points
Main functions exported from `cognee/__init__.py`:
- `add(data, dataset_name)` - Ingest data
- `cognify(datasets)` - Build knowledge graph
- `search(query_text, query_type)` - Query knowledge
- `memify(extraction_tasks, enrichment_tasks)` - Enrich graph
- `delete(data_id)` - Remove data
- `config()` - Configuration management
- `datasets()` - Dataset operations
All functions are async - use `await` or `asyncio.run()`.
## Security Considerations
Several security environment variables in `.env`:
- `ACCEPT_LOCAL_FILE_PATH` - Allow local file paths (default: True)
- `ALLOW_HTTP_REQUESTS` - Allow HTTP requests from Cognee (default: True)
- `ALLOW_CYPHER_QUERY` - Allow raw Cypher queries (default: True)
- `ENABLE_BACKEND_ACCESS_CONTROL` - Multi-tenant isolation (default: True). When `true`, API auth is required and per-user/dataset DB isolation is enabled. When `false`, single-user mode: shared DBs and auth off unless overridden.
- `REQUIRE_AUTHENTICATION` - Explicit auth override. Unset (default): follows `ENABLE_BACKEND_ACCESS_CONTROL`. `false` is ignored when `ENABLE_BACKEND_ACCESS_CONTROL=true`. For a single-user deployment with auth off, set `ENABLE_BACKEND_ACCESS_CONTROL=false` (and optionally `REQUIRE_AUTHENTICATION=false`).
For production deployments, review and tighten these settings.
## Common Patterns
### Creating a Custom Pipeline Task
```python
from cognee.modules.pipelines.tasks.Task import Task
async def my_custom_task(data):
# Your logic here
processed_data = process(data)
return processed_data
# Use in pipeline
task = Task(my_custom_task)
```
### Accessing Databases Directly
```python
from cognee.infrastructure.databases.graph import get_graph_engine
from cognee.infrastructure.databases.vector import get_vector_engine_async
graph_engine = await get_graph_engine()
vector_engine = await get_vector_engine_async()
```
### Using LLM Gateway
```python
from cognee.infrastructure.llm.get_llm_client import get_llm_client
llm_client = get_llm_client()
response = await llm_client.acreate_structured_output(
text_input="Your prompt",
system_prompt="System instructions",
response_model=YourPydanticModel
)
```
## Key Concepts
### Datasets
Datasets are project-level containers that support organization, permissions, and isolated processing workflows. Each user can have multiple datasets with different access permissions.
```python
# Create/use a dataset
await cognee.add(data, dataset_name="my_project")
await cognee.cognify(datasets=["my_project"])
```
### DataPoints
Atomic knowledge units that form the foundation of graph structures. All graph nodes extend the `DataPoint` base class with versioning and metadata support.
### Permissions System
Multi-tenant architecture with users, roles, and Access Control Lists (ACLs):
- Read, write, delete, and share permissions per dataset
- Enable with `ENABLE_BACKEND_ACCESS_CONTROL=True`
- Supports isolated databases per user+dataset (Ladybug, LanceDB, SQLite, Postgres)
### Graph Visualization
Launch visualization server:
```bash
# Via CLI
cognee-cli -ui # Launches full stack with UI at http://localhost:3000
# Via Python
from cognee.api.v1.visualize import start_visualization_server
await start_visualization_server(port=8080)
```
## Debugging & Troubleshooting
### Debug Configuration
- Set `LITELLM_LOG="DEBUG"` for verbose LLM logs (default: "ERROR")
- Enable debug mode: `ENV="development"` or `ENV="debug"`
- Disable telemetry: `TELEMETRY_DISABLED=1`
- Check logs in structured format (uses structlog)
- Use `debugpy` optional dependency for debugging: `pip install cognee[debug]`
### Common Issues
**Ollama + OpenAI Embeddings NoDataError**
- Issue: Mixing Ollama with OpenAI embeddings can cause errors
- Solution: Configure both LLM and embeddings to use the same provider, or ensure `HUGGINGFACE_TOKENIZER` is set when using Ollama
**LM Studio Structured Output**
- Issue: LM Studio requires explicit instructor mode
- Solution: Set `LLM_INSTRUCTOR_MODE="json_schema_mode"` (or appropriate mode)
**Default Provider Fallback**
- Issue: Configuring only LLM or only embeddings defaults the other to OpenAI
- Solution: Always configure both LLM and embedding providers, or ensure valid OpenAI API key
**Permission Denied on Search**
- Behavior: Returns empty list rather than error (prevents information leakage)
- Solution: Check dataset permissions and user access rights
**Database Connection Issues**
- Check: Verify database URLs, credentials, and that services are running
- Docker users: Use `DB_HOST=host.docker.internal` for local databases
**Rate Limiting Errors**
- Enable client-side rate limiting: `LLM_RATE_LIMIT_ENABLED=true`
- Adjust limits: `LLM_RATE_LIMIT_REQUESTS` and `LLM_RATE_LIMIT_INTERVAL`
## Resources
- [Documentation](https://docs.cognee.ai/)
- [Discord Community](https://discord.gg/NQPKmU5CCg)
- [GitHub Issues](https://github.com/topoteretes/cognee/issues)
- [Example Notebooks](examples/python/)
- [Research Paper](https://arxiv.org/abs/2505.24478) - Optimizing knowledge graphs for LLM reasoning
+128
View File
@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or
advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email
address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement by emailing <NAME> at <EMAIL>.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
+163
View File
@@ -0,0 +1,163 @@
> [!IMPORTANT]
> **Note for contributors:** When branching out, create a new branch from the `dev` branch.
# 🎉 Welcome to **cognee**!
We're excited that you're interested in contributing to our project!
We want to ensure that every user and contributor feels welcome, included and supported to participate in cognee community.
This guide will help you get started and ensure your contributions can be efficiently integrated into the project.
## 🌟 Quick Links
- [Code of Conduct](CODE_OF_CONDUCT.md)
- [Discord Community](https://discord.gg/bcy8xFAtfd)
- [Issue Tracker](https://github.com/topoteretes/cognee/issues)
- [Cognee Docs](https://docs.cognee.ai)
## 1. 🚀 Ways to Contribute
You can contribute to **cognee** in many ways:
- 📝 Submitting bug reports or feature requests
- 💡 Improving documentation
- 🔍 Reviewing pull requests
- 🛠️ Contributing code or tests
- 🌐 Helping other users
## 📫 Get in Touch
There are several ways to connect with the **cognee** team and community:
### GitHub Collaboration
- [Open an issue](https://github.com/topoteretes/cognee/issues) for bug reports, feature requests, or discussions
- Submit pull requests to contribute code or documentation
- Join ongoing discussions in existing issues and PRs
### Community Channels
- Join our [Discord community](https://discord.gg/bcy8xFAtfd) for real-time discussions
- Participate in community events and discussions
- Get help from other community members
### Direct Contact
- Email: vasilije@cognee.ai
- For business inquiries or sensitive matters, please reach out via email
- For general questions, prefer public channels like GitHub issues or Discord
We aim to respond to all communications within 2 business days. For faster responses, consider using our Discord channel where the whole community can help!
## Issue Labels
To help you find the most appropriate issues to work on, we use the following labels:
- `good first issue` - Perfect for newcomers to the project
- `bug` - Something isn't working as expected
- `documentation` - Improvements or additions to documentation
- `enhancement` - New features or improvements
- `help wanted` - Extra attention or assistance needed
- `question` - Further information is requested
- `wontfix` - This will not be worked on
Looking for a place to start? Try filtering for [good first issues](https://github.com/topoteretes/cognee/labels/good%20first%20issue)!
## 2. 🛠️ Development Setup
### Required tools
* [Python](https://www.python.org/downloads/)
* [uv](https://docs.astral.sh/uv/getting-started/installation/)
* pre-commit: `uv run pip install pre-commit && pre-commit install`
### Fork and Clone
1. Fork the [**cognee**](https://github.com/topoteretes/cognee) repository
2. Clone your fork:
```shell
git clone https://github.com/<your-github-username>/cognee.git
cd cognee
```
In case you are working on Vector and Graph Adapters
1. Fork the [**cognee-community**](https://github.com/topoteretes/cognee-community) repository
2. Clone your fork:
```shell
git clone https://github.com/<your-github-username>/cognee-community.git
cd cognee-community
```
### Create a Branch
Create a new branch for your work:
```shell
git checkout -b feature/your-feature-name
```
## 3. 🎯 Making Changes
1. **Code Style**: Follow the project's coding standards
2. **Documentation**: Update relevant documentation
3. **Tests**: Add tests for new features
4. **Commits**: Write clear commit messages
### Running Tests
Copy `.env.template` to `.env` and provide your OPENAI_API_KEY as LLM_API_KEY
```shell
uv run python cognee/tests/test_library.py
```
### Running Simple Example
Copy `.env.template` to `.env` and provide your OPENAI_API_KEY as LLM_API_KEY
Make sure to run ```shell uv sync ``` in the root cloned folder or set up a virtual environment to run cognee
```shell
uv run python examples/demos/simple_cognee_example.py
```
## 4. 📤 Submitting Changes
1. Make sure that `pre-commit` and hooks are installed. See `Required tools` section for more information. Try executing `pre-commit run` if you are not sure.
3. Push your changes:
```shell
git add .
git commit -s -m "Description of your changes"
git push origin feature/your-feature-name
```
2. Create a Pull Request:
- Go to the [**cognee** repository](https://github.com/topoteretes/cognee) or [cognee community repository](https://github.com/topoteretes/cognee-community)
- Click "Compare & Pull Request" and open a PR against dev branch
- Fill in the PR template with details about your changes
- You MUST provide screenshots of unit and integration tests passing on your machine. We can't merge PRs otherwise
> **Reviewers are auto-routed.** Cognee uses a [`CODEOWNERS`](.github/CODEOWNERS)
> file to request reviews automatically based on the directories your PR touches.
> No manual ping required — the right person will get notified when you open the PR.
## 5. 📜 Developer Certificate of Origin (DCO)
All contributions must be signed-off to indicate agreement with our DCO:
```shell
git config alias.cos "commit -s" # Create alias for signed commits
```
When your PR is ready, please include:
> "I affirm that all code in every commit of this pull request conforms to the terms of the Topoteretes Developer Certificate of Origin"
## 6. 🤝 Community Guidelines
- Be respectful and inclusive
- Help others learn and grow
- Follow our [Code of Conduct](CODE_OF_CONDUCT.md)
- Provide constructive feedback
- Ask questions when unsure
## 7. 📫 Getting Help
- Open an [issue](https://github.com/topoteretes/cognee/issues)
- Join our Discord community
- Check existing documentation
Thank you for contributing to **cognee**! 🌟
+12
View File
@@ -0,0 +1,12 @@
## 💫 Contributors
Thanks to our amazing contributors! 💖
<a href="https://github.com/topoteretes/cognee/graphs/contributors">
<img src="https://contrib.rocks/image?repo=topoteretes/cognee" />
</a>
## 🏆 Top Contributors
| Rank | Contributor | Contributions |
|------|------------|---------------|
+17
View File
@@ -0,0 +1,17 @@
Developer Certificate of Origin Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or
(b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or
(c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it.
(d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved.
+74
View File
@@ -0,0 +1,74 @@
# Use a Python image with uv pre-installed
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS uv
# Install the project into `/app`
WORKDIR /app
# Enable bytecode compilation: without it the venv ships no .pyc files, so
# every container cold start recompiles the entire dependency tree from
# source (measured on cognee-saas-pod: ~8s of a ~13s import, halving startup).
ENV UV_COMPILE_BYTECODE=1
# Copy from the cache instead of linking since it's a mounted volume
ENV UV_LINK_MODE=copy
# Set build argument
ARG DEBUG
# Set environment variable based on the build argument
ENV DEBUG=${DEBUG}
# Install system dependencies
RUN apt-get update && apt-get install -y \
gcc \
libpq-dev \
git \
curl \
cmake \
clang \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# Copy pyproject.toml and lockfile first for better caching
COPY README.md pyproject.toml uv.lock entrypoint.sh ./
# Install the project's dependencies using the lockfile and settings
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --extra debug --extra api --extra postgres --extra neo4j --extra llama-index --extra ollama --extra mistral --extra groq --extra anthropic --frozen --no-install-project --no-dev --no-editable
# Then, add the rest of the project source code and install it
# Installing separately from its dependencies allows optimal layer caching
COPY ./cognee /app/cognee
COPY ./distributed /app/distributed
COPY ./cognee_db_workers /app/cognee_db_workers
# Compatibility shim that re-exports ladybug under the legacy `kuzu`
# module name. Listed in [tool.hatch.build.targets.wheel] packages, and
# imported at module load by alembic/versions/b9274c27a25a_kuzu_11_migration.py.
COPY ./kuzu /app/kuzu
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --extra debug --extra api --extra postgres --extra neo4j --extra llama-index --extra ollama --extra mistral --extra groq --extra anthropic --frozen --no-dev --no-editable
FROM python:3.12-slim-bookworm
RUN apt-get update && apt-get install -y \
libpq5 \
curl \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=uv /app /app
# COPY --from=uv /app/.venv /app/.venv
# COPY --from=uv /root/.local /root/.local
# Strip Windows carriage returns (fixes "no such file" on Windows Docker)
RUN sed -i 's/\r$//' /app/entrypoint.sh && chmod +x /app/entrypoint.sh
# Place executables in the environment at the front of the path
ENV PATH="/app/.venv/bin:$PATH"
ENV PYTHONPATH=/app
# ENV LOG_LEVEL=ERROR
ENV PYTHONUNBUFFERED=1
ENTRYPOINT ["/app/entrypoint.sh"]
+26
View File
@@ -0,0 +1,26 @@
FROM ghcr.io/astral-sh/uv:python3.11-bookworm-slim
WORKDIR /app
ENV UV_LINK_MODE=copy
# System deps (superset of all CI needs)
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc g++ libpq-dev git curl cmake clang build-essential \
postgresql-client libgl1 libglib2.0-0 \
&& rm -rf /var/lib/apt/lists/*
COPY pyproject.toml uv.lock README.md ./
# ALL extras used across CI - no-install-project so project code isn't baked in
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-install-project \
--extra api --extra docs --extra evals --extra codegraph --extra ollama \
--extra dev --extra neo4j --extra redis --extra postgres --extra aws \
--extra baml --extra distributed --extra deepeval --extra scraping \
--extra notebook --extra docling
# Marker file for container detection in cognee_setup
RUN echo "test-machine" > /app/.anon_id
ENV PATH="/app/.venv/bin:$PATH"
ENV PYTHONPATH=/app
ENV PYTHONUNBUFFERED=1
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2024 Topoteretes UG
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+10
View File
@@ -0,0 +1,10 @@
topoteretes - cognee
Copyright © 2024 Topoteretes UG. (haftungsbeschränkt), Schonehauser Allee 163, Berlin.
This project includes software developed at Topoteretes UG. (https://www.cognee.ai/).
<!-- Add software from external sources that you used here. e.g.
This project redistributes code originally from <website>.
-->
+437
View File
@@ -0,0 +1,437 @@
<div align="center">
<a href="https://github.com/topoteretes/cognee">
<img src="https://raw.githubusercontent.com/topoteretes/cognee/refs/heads/dev/assets/cognee-logo-transparent.png" alt="Cognee Logo" height="60">
</a>
<br />
Cognee - The Open-Source AI Memory Platform for Agents
<p align="center">
<a href="https://www.youtube.com/watch?v=8hmqS2Y5RVQ&t=13s">Demo</a>
.
<a href="https://docs.cognee.ai/">Docs</a>
.
<a href="https://cognee.ai">Learn More</a>
·
<a href="https://discord.gg/NQPKmU5CCg">Join Discord</a>
·
<a href="https://www.reddit.com/r/AIMemory/">Join r/AIMemory</a>
.
<a href="https://github.com/topoteretes/cognee-community">Community Plugins & Add-ons</a>
</p>
[![GitHub forks](https://img.shields.io/github/forks/topoteretes/cognee.svg?style=social&label=Fork&maxAge=2592000)](https://GitHub.com/topoteretes/cognee/network/)
[![GitHub stars](https://img.shields.io/github/stars/topoteretes/cognee.svg?style=social&label=Star&maxAge=2592000)](https://GitHub.com/topoteretes/cognee/stargazers/)
[![GitHub commits](https://badgen.net/github/commits/topoteretes/cognee)](https://GitHub.com/topoteretes/cognee/commit/)
[![GitHub tag](https://badgen.net/github/tag/topoteretes/cognee)](https://github.com/topoteretes/cognee/tags/)
[![Downloads](https://static.pepy.tech/badge/cognee)](https://pepy.tech/project/cognee)
[![License](https://img.shields.io/github/license/topoteretes/cognee?colorA=00C586&colorB=000000)](https://github.com/topoteretes/cognee/blob/main/LICENSE)
[![Contributors](https://img.shields.io/github/contributors/topoteretes/cognee?colorA=00C586&colorB=000000)](https://github.com/topoteretes/cognee/graphs/contributors)
<a href="https://github.com/sponsors/topoteretes"><img src="https://img.shields.io/badge/Sponsor-❤️-ff69b4.svg" alt="Sponsor"></a>
<p>
<a href="https://trendshift.io/repositories/13955" target="_blank" style="display:inline-block;">
<img src="https://trendshift.io/api/badge/repositories/13955" alt="topoteretes%2Fcognee | Trendshift" width="250" height="55" />
</a>
</p>
Cognee is the open-source AI memory platform that gives AI agents persistent long-term memory across sessions. Ingest data in any format, build a self-hosted knowledge graph, and let every agent recall, connect, and act with full context
<p align="center">
🌐 This README is also available in:
:
<!-- Keep these links. Translations will automatically update with the README. -->
<a href="https://www.readme-i18n.com/topoteretes/cognee?lang=de">Deutsch</a> |
<a href="https://www.readme-i18n.com/topoteretes/cognee?lang=es">Español</a> |
<a href="https://www.readme-i18n.com/topoteretes/cognee?lang=fr">Français</a> |
<a href="https://www.readme-i18n.com/topoteretes/cognee?lang=ja">日本語</a> |
<a href="README_ko.md">한국어</a> |
<a href="https://www.readme-i18n.com/topoteretes/cognee?lang=pt">Português</a> |
<a href="https://www.readme-i18n.com/topoteretes/cognee?lang=ru">Русский</a> |
<a href="https://www.readme-i18n.com/topoteretes/cognee?lang=zh">中文</a>
</p>
<p align="center">
<img src="assets/cognee-demo.gif" alt="Cognee Demo" width="80%" />
</p>
</div>
📄 Read the research paper: [Optimizing the Interface Between Knowledge Graphs and LLMs for Complex Reasoning](https://arxiv.org/abs/2505.24478) — Markovic et al., 2025
## About Cognee
Cognee is an open-source AI memory platform for AI Agents. Ingest data in any format, and Cognee continuously builds a self-hosted knowledge graph that gives your agents persistent long-term memory across sessions. Cognee combines vector embeddings, graph reasoning, and cognitive-science-grounded ontology generation to make documents both searchable by meaning and connected by relationships that evolve as your knowledge does.
:star: _Help us reach more developers and grow the cognee community. Star this repo!_
:books: _Check our detailed [documentation](https://docs.cognee.ai/getting-started/installation#environment-configuration) for setup and configuration._
:crab: _Available as a plugin for your OpenClaw — [cognee-openclaw](https://www.npmjs.com/package/@cognee/cognee-openclaw)_
✴️ _Available as a plugin for your Claude Code — [claude-code-plugin](https://github.com/topoteretes/cognee-integrations/tree/main/integrations/claude-code)_
🦀 _Available as a Rust client — [cognee-rs](https://github.com/topoteretes/cognee-rs)_
🟦 _Available as a TypeScript client — [@cognee/cognee-ts](https://www.npmjs.com/package/@cognee/cognee-ts)_
### Why use Cognee:
- Easily Build Company Brain - unify data from various sources in one place and enable Agents with your domain knowledge
- Knowledge infrastructure — unified ingestion, graph/vector search, runs locally, ontology grounding, multimodal
- Persistent and Learning Agents - learn from feedback, context management, cross-agent knowledge sharing
- Reliable and Trustworthy Agents - agentic user/tenant isolation, traceability, OTEL collector, audit traits
### How it Works
<p align="center">
<img src="assets/remember.svg" alt="Cognee Products" width="80%" />
</p>
<p align="center">
<img src="assets/recall.svg" alt="Cognee Recall" width="80%" />
</p>
## Basic Usage & Feature Guide
To learn more, [check out this short, end-to-end Colab walkthrough](https://colab.research.google.com/drive/1HRrzIvzcbwrESVfX76wJLKmtIg00SUga?usp=sharing) of Cognee's core features.
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/1HRrzIvzcbwrESVfX76wJLKmtIg00SUga?usp=sharing)
## Quickstart
Lets try Cognee in just a few lines of code.
### Prerequisites
- Python 3.10 to 3.14
### Step 1: Install Cognee
You can install Cognee with **pip**, **poetry**, **uv**, or your preferred Python package manager.
```bash
uv pip install cognee
```
### Step 2: Configure the LLM
```python
import os
os.environ["LLM_API_KEY"] = "YOUR OPENAI_API_KEY"
```
Alternatively, create a `.env` file using our [template](https://github.com/topoteretes/cognee/blob/main/.env.template).
To integrate other LLM providers, see our [LLM Provider Documentation](https://docs.cognee.ai/setup-configuration/llm-providers).
### Step 3: Run the Pipeline
Cognee's API gives you four operations — `remember`, `recall`, `forget`, and `improve`:
```python
import cognee
import asyncio
async def main():
# Store permanently in the knowledge graph (runs add + cognify + improve)
await cognee.remember("Cognee turns documents into AI memory.")
# Store in session memory (fast cache, syncs to graph in background)
await cognee.remember("User prefers detailed explanations.", session_id="chat_1")
# Query with auto-routing (picks best search strategy automatically)
results = await cognee.recall("What does Cognee do?")
for result in results:
print(result)
# Query session memory first, fall through to graph if needed
results = await cognee.recall("What does the user prefer?", session_id="chat_1")
for result in results:
print(result)
# Delete when done
await cognee.forget(dataset="main_dataset")
if __name__ == '__main__':
asyncio.run(main())
```
### Use the Cognee CLI
```bash
cognee-cli remember "Cognee turns documents into AI memory."
cognee-cli recall "What does Cognee do?"
cognee-cli forget --all
```
To open the local UI, run:
```bash
cognee-cli -ui
```
> **Note:** The MCP server launched by `cognee-cli -ui` runs inside a Docker container.
> Docker Desktop, Colima, or any OCI-compatible runtime with a working `docker` CLI is
> required. See [Docker & Colima Setup](docs/docker-colima-setup.md) for details.
## Run with Docker
Prefer containers? Cognee publishes prebuilt images to Docker Hub on every push to `main`:
[`cognee/cognee`](https://hub.docker.com/r/cognee/cognee) (the API server) and
[`cognee/cognee-mcp`](https://hub.docker.com/r/cognee/cognee-mcp) (the MCP server).
### Option A — Docker Compose (build from source)
Clone the repo, create a `.env` with at least `LLM_API_KEY`, then:
```bash
cp .env.template .env # then edit .env and set LLM_API_KEY
# Start the API server (http://localhost:8000)
docker compose up
# Optional profiles (combine as needed):
docker compose --profile ui up # + frontend on http://localhost:3000
docker compose --profile mcp up # + MCP server on http://localhost:8001
docker compose --profile postgres up # + Postgres/PGVector
docker compose --profile neo4j up # + Neo4j
```
> The `cognee` and `cognee-mcp` services publish different host ports (`8000` vs `8001`),
> so you can run both at once.
### Option B — Pull the prebuilt image (no clone required)
```bash
# Create a minimal .env in the current directory
echo 'LLM_API_KEY="YOUR_OPENAI_API_KEY"' > .env
# API server
docker run --env-file ./.env -p 8000:8000 --rm -it cognee/cognee:main
# MCP server (HTTP transport)
docker pull cognee/cognee-mcp:main
docker run -e TRANSPORT_MODE=http --env-file ./.env -p 8000:8000 --rm -it cognee/cognee-mcp:main
```
See the [MCP server README](cognee-mcp/README.md) for SSE/stdio transports, optional
extras, and MCP client configuration.
## Use with AI Agents
### Claude Code
Install the [Cognee memory plugin](https://github.com/topoteretes/cognee-integrations/tree/main/integrations/claude-code) to give Claude Code persistent memory across sessions. The plugin captures prompts, tool traces, and assistant responses into session memory, injects relevant context on every prompt, and syncs session memory into the permanent knowledge graph at session end.
**Install** from the Claude Code marketplace. The recommended way is from your shell, *before* launching Claude Code, so the first `claude` launch is a clean session that bootstraps memory automatically:
```bash
# Add the marketplace and install the plugin (one-time, user-scoped)
claude plugin marketplace add topoteretes/cognee-integrations
claude plugin install cognee-memory@cognee
# Set env vars for your mode (see below), then launch
export LLM_API_KEY="sk-..." # local mode; or COGNEE_BASE_URL + COGNEE_API_KEY for cloud
claude
```
**Local mode** (default) — the plugin bootstraps a local Cognee API at `http://localhost:8011`. Only `LLM_API_KEY` is required; the Cognee API key is auto-minted if absent:
```bash
export LLM_API_KEY="sk-..."
```
**Cognee Cloud or a remote server** — set both:
```bash
export COGNEE_BASE_URL="https://your-instance.cognee.ai"
export COGNEE_API_KEY="ck_..."
```
On startup you should see a "Cognee Memory Connected" system message.
The plugin hooks into Claude Code's lifecycle — `SessionStart` selects mode and sets up identity, `UserPromptSubmit` injects dataset-scoped context, `PostToolUse` captures tool traces, `Stop` writes the assistant's answer, `PreCompact` preserves memory across context resets, and `SessionEnd` triggers the final sync into the permanent graph.
See the [plugin README](https://github.com/topoteretes/cognee-integrations/tree/main/integrations/claude-code) for sessions, datasets, and full configuration.
### Connect to Cognee Cloud
Point any Python agent at a managed Cognee instance — all SDK calls route to the cloud:
```python
import cognee
await cognee.serve(url="https://your-instance.cognee.ai", api_key="ck_...")
await cognee.remember("important context")
results = await cognee.recall("what happened?")
await cognee.disconnect()
```
## Examples
Browse more examples in the [`examples/`](examples/) folder — demos, guides, custom pipelines, and database configurations.
**Use Case 1 — Customer Support Agent**
```python
Goal: Resolve customer issues using their personal data across finance, support, and product history.
User: "My invoice looks wrong and the issue is still not resolved."
Cognee tracks: past interactions, failed actions, resolved cases, product history
# Agent response:
Agent: "I found 2 similar billing cases resolved last month.
The issue was caused by a sync delay between payment
and invoice systems a fix was applied on your account."
# What happens under the hood:
- Unifies data sources from various company channels
- Reconstructs the interaction timeline and tracks outcomes
- Retrieves similar resolved cases
- Maps to the best resolution strategy
- Updates memory after execution so the agent never repeats the same mistake
```
**Use Case 2 — Expert Knowledge Distillation (SQL Copilot)**
```python
Goal: Help junior analysts solve tasks by reusing expert-level queries, patterns, and reasoning.
User: "How do I calculate customer retention for this dataset?"
Cognee tracks: expert SQL queries, workflow patterns, schema structures, successful implementations
# Agent response:
Agent: "Here's how senior analysts solved a similar retention query.
Cognee matched your schema to a known structure and adapted
the expert's logic to fit your dataset."
# What happens under the hood:
- Extracts and stores patterns from expert SQL queries and workflows
- Maps the current schema to previously seen structures
- Retrieves similar tasks and their successful implementations
- Adapts expert reasoning to the current context
- Updates memory with new successful patterns so junior analysts perform at near-expert level
```
## Run the Whole Memory Layer on Postgres
Graph memory traditionally means operating a stack — a graph database for relationships, a vector database for embeddings, Redis for sessions, and a relational database for metadata — all deployed, secured, and paid for before an agent remembers anything. In cognee 1.0 you can run the entire memory layer on a single Postgres instance.
| Memory layer | Traditional stack | cognee on Postgres |
| --- | --- | --- |
| Relationships | Neo4j or another graph database | cognee's Postgres graph backend |
| Embeddings | Dedicated vector database | pgvector |
| Sessions | Redis | SQL session-cache backend |
| Metadata | Relational database | same Postgres |
The graph still exists — it just lives inside the same Postgres-backed memory layer as the text, metadata, and embeddings, so retrieval moves between similarity and structure without crossing service boundaries. In our CI benchmarks, Postgres search ran ~10% faster than the separate graph-plus-vector setup.
Postgres is the default we recommend for most deployments, but you can still swap in dedicated backends when a workload needs them (Neo4j and Neptune for graphs, Redis for sessions, pgvector and LanceDB for vectors, plus Qdrant, ChromaDB, Weaviate, and Milvus via community adapters). Local development stays fully embedded — SQLite, LanceDB, and Kuzudb — with no extra services to stand up.
```bash
pip install "cognee[postgres]"
```
```bash
DB_PROVIDER=postgres
VECTOR_DB_PROVIDER=pgvector
GRAPH_DATABASE_PROVIDER=postgres
CACHE_BACKEND=postgres
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=cognee
DB_PASSWORD=cognee
DB_NAME=cognee_db
```
## Deploy Cognee
Use [Cognee Cloud](https://www.cognee.ai) for a fully managed experience, or self-host with one of the 1-click deployment configurations below.
| Platform | Best For | Command |
|----------|----------|---------|
| **Cognee Cloud** | Managed service, no infrastructure to maintain | [Sign up](https://www.cognee.ai) or `await cognee.serve()` |
| **Modal** | Serverless, auto-scaling, GPU workloads | `bash distributed/deploy/modal-deploy.sh` |
| **Railway** | Simplest PaaS, native Postgres | `railway init && railway up` |
| **Fly.io** | Edge deployment, persistent volumes | `bash distributed/deploy/fly-deploy.sh` |
| **Render** | Simple PaaS with managed Postgres | Deploy to Render button |
| **Daytona** | Cloud sandboxes (SDK or CLI) | See `distributed/deploy/daytona_sandbox.py` |
See the [`distributed/`](distributed/) folder for deploy scripts, worker configurations, and additional details.
## Use Cognee in Other Languages
Prefer something other than Python? Cognee also ships official clients for Rust and TypeScript.
### Getting Started with Rust
Use the [cognee-rs](https://github.com/topoteretes/cognee-rs) crate to add, cognify, and search from Rust.
```bash
cargo add cognee
```
See the [cognee-rs repository](https://github.com/topoteretes/cognee-rs) for full setup and examples.
### Getting Started with TypeScript
Use the [@cognee/cognee-ts](https://www.npmjs.com/package/@cognee/cognee-ts) package to add, cognify, and search from Node.js or the browser.
```bash
npm install @cognee/cognee-ts
```
See the [@cognee/cognee-ts package](https://www.npmjs.com/package/@cognee/cognee-ts) for full setup and examples.
## Benchmarks
We ran cognee against [BEAM](https://github.com/topoteretes/cognee), a long-context benchmark that tests whether a system can keep track of a long conversation as it changes — a more useful test for agent memory than typical needle-in-a-haystack benchmarks. Using only cognee's default settings and standard open-source features (no custom models, no BEAM-specific pipelines), we beat the previous state of the art at the 100K-token setting and matched it at 10M tokens.
| Benchmark | Setting | cognee | Previous SOTA | Obsidian / RAG baseline |
|-----------|---------|--------|---------------|--------------------------|
| BEAM | 100K tokens | **0.79** (>0.8 with per-question routing) | 0.735 | ~0.33 |
| BEAM | 10M tokens | **0.67** | 0.641 | ~0.33 |
These numbers are a directional signal rather than a definitive measure — see the write-up for the full methodology, caveats, and what the results actually mean.
## Latest News
[![Watch Demo](https://img.youtube.com/vi/8hmqS2Y5RVQ/maxresdefault.jpg)](https://www.youtube.com/watch?v=8hmqS2Y5RVQ&t=13s)
## Community & Support
### Contributing
We welcome contributions from the community! Your input helps make Cognee better for everyone. See [`CONTRIBUTING.md`](CONTRIBUTING.md) to get started.
### Code of Conduct
We're committed to fostering an inclusive and respectful community. Read our [Code of Conduct](https://github.com/topoteretes/cognee/blob/main/CODE_OF_CONDUCT.md) for guidelines.
## Research & Citation
We recently published a research paper on optimizing knowledge graphs for LLM reasoning:
```bibtex
@misc{markovic2025optimizinginterfaceknowledgegraphs,
title={Optimizing the Interface Between Knowledge Graphs and LLMs for Complex Reasoning},
author={Vasilije Markovic and Lazar Obradovic and Laszlo Hajdu and Jovan Pavlovic},
year={2025},
eprint={2505.24478},
archivePrefix={arXiv},
primaryClass={cs.AI},
url={https://arxiv.org/abs/2505.24478},
}
```
+7
View File
@@ -0,0 +1,7 @@
# WeHub 来源说明
- 原始项目:`topoteretes/cognee`
- 原始仓库:https://github.com/topoteretes/cognee
- 导入方式:上游默认分支的最新快照
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
+220
View File
@@ -0,0 +1,220 @@
<div align="center">
<a href="https://github.com/topoteretes/cognee">
<img src="https://raw.githubusercontent.com/topoteretes/cognee/refs/heads/dev/assets/cognee-logo-transparent.png" alt="Cognee Logo" height="60">
</a>
<br />
Cognee - 정확하고 지속적인 AI 메모리
<p align="center">
<a href="https://www.youtube.com/watch?v=1bezuvLwJmw&t=2s">데모</a>
.
<a href="https://docs.cognee.ai/">문서</a>
.
<a href="https://cognee.ai">더 알아보기</a>
·
<a href="https://discord.gg/NQPKmU5CCg">Discord 참여</a>
·
<a href="https://www.reddit.com/r/AIMemory/">r/AIMemory 참여</a>
.
<a href="https://github.com/topoteretes/cognee-community">커뮤니티 플러그인 & 애드온</a>
</p>
[![GitHub forks](https://img.shields.io/github/forks/topoteretes/cognee.svg?style=social&label=Fork&maxAge=2592000)](https://GitHub.com/topoteretes/cognee/network/)
[![GitHub stars](https://img.shields.io/github/stars/topoteretes/cognee.svg?style=social&label=Star&maxAge=2592000)](https://GitHub.com/topoteretes/cognee/stargazers/)
[![GitHub commits](https://badgen.net/github/commits/topoteretes/cognee)](https://GitHub.com/topoteretes/cognee/commit/)
[![GitHub tag](https://badgen.net/github/tag/topoteretes/cognee)](https://github.com/topoteretes/cognee/tags/)
[![Downloads](https://static.pepy.tech/badge/cognee)](https://pepy.tech/project/cognee)
[![License](https://img.shields.io/github/license/topoteretes/cognee?colorA=00C586&colorB=000000)](https://github.com/topoteretes/cognee/blob/main/LICENSE)
[![Contributors](https://img.shields.io/github/contributors/topoteretes/cognee?colorA=00C586&colorB=000000)](https://github.com/topoteretes/cognee/graphs/contributors)
<a href="https://github.com/sponsors/topoteretes"><img src="https://img.shields.io/badge/Sponsor-❤️-ff69b4.svg" alt="Sponsor"></a>
<p>
<a href="https://www.producthunt.com/posts/cognee?embed=true&utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-cognee" target="_blank" style="display:inline-block; margin-right:10px;">
<img src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=946346&theme=light&period=daily&t=1744472480704" alt="cognee - Memory&#0032;for&#0032;AI&#0032;Agents&#0032;&#0032;in&#0032;5&#0032;lines&#0032;of&#0032;code | Product Hunt" width="250" height="54" />
</a>
<a href="https://trendshift.io/repositories/13955" target="_blank" style="display:inline-block;">
<img src="https://trendshift.io/api/badge/repositories/13955" alt="topoteretes%2Fcognee | Trendshift" width="250" height="55" />
</a>
</p>
데이터를 사용하여 AI 에이전트를 위한 개인화되고 동적인 메모리를 구축하세요. Cognee를 사용하면 RAG를 확장 가능하고 모듈화된 ECL(추출[Extract], 인지화[Cognify], 로드[Load]) 파이프라인으로 대체할 수 있습니다.
<p align="center">
🌐 사용 가능한 언어
:
<!-- Keep these links. Translations will automatically update with the README. -->
<a href="https://www.readme-i18n.com/topoteretes/cognee?lang=de">Deutsch</a> |
<a href="https://www.readme-i18n.com/topoteretes/cognee?lang=es">Español</a> |
<a href="https://www.readme-i18n.com/topoteretes/cognee?lang=fr">Français</a> |
<a href="https://www.readme-i18n.com/topoteretes/cognee?lang=ja">日本語</a> |
<a href="README_ko.md">한국어</a> |
<a href="https://www.readme-i18n.com/topoteretes/cognee?lang=pt">Português</a> |
<a href="https://www.readme-i18n.com/topoteretes/cognee?lang=ru">Русский</a> |
<a href="https://www.readme-i18n.com/topoteretes/cognee?lang=zh">中文</a>
</p>
<div style="text-align: center">
<img src="https://raw.githubusercontent.com/topoteretes/cognee/refs/heads/main/assets/cognee_benefits.png" alt="Why cognee?" width="50%" />
</div>
</div>
## Cognee 소개
Cognee는 원시 데이터를 에이전트를 위한 지속적이고 동적인 AI 메모리로 변환하는 오픈 소스 도구이자 플랫폼입니다. 벡터 검색과 그래프 데이터베이스를 결합하여 문서를 의미적으로 검색 가능하게 하고 관계별로 연결합니다.
Cognee는 두 가지 방식으로 사용할 수 있습니다.
1. [Cognee 오픈 소스 (셀프 호스팅)](https://docs.cognee.ai/getting-started/installation): 기본적으로 모든 데이터를 로컬에 저장합니다.
2. [Cognee Cloud (관리형)](https://platform.cognee.ai/): 관리형 인프라에서 동일한 OSS 스택을 사용하여 더 쉽게 개발하고 프로덕션화할 수 있습니다.
### Cognee 오픈 소스 (셀프 호스팅):
- 과거 대화, 파일, 이미지, 오디오 스크립트 등 모든 유형의 데이터를 상호 연결
- 기존 RAG 시스템을 그래프와 벡터 기반의 통합 메모리 계층으로 대체
- 품질과 정밀도를 향상시키면서 개발자 노력과 인프라 비용 절감
- 30개 이상의 데이터 소스에서 데이터를 수집할 수 있는 Pythonic 데이터 파이프라인 제공
- 사용자 정의 작업, 모듈식 파이프라인, 내장 검색 엔드포인트를 통한 높은 사용자 정의 가능성 제공
### Cognee Cloud (관리형):
- 호스팅된 웹 UI 대시보드
- 자동 버전 업데이트
- 리소스 사용량 분석
- GDPR 준수, 엔터프라이즈급 보안
## 기본 사용법 & 기능 가이드
자세한 내용은 [Colab 튜토리얼](https://colab.research.google.com/drive/12Vi9zID-M3fpKpKiaqDBvkk98ElkRPWy?usp=sharing)을 확인하세요.
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/12Vi9zID-M3fpKpKiaqDBvkk98ElkRPWy?usp=sharing)
## 빠른 시작
단 몇 줄의 코드로 Cognee를 사용해 보세요. 자세한 설정 및 구성은 [Cognee 문서](https://docs.cognee.ai/getting-started/installation#environment-configuration)를 참조하세요.
### 필수 조건
- Python 3.10 ~ 3.14
### 1단계: Cognee 설치
**pip**, **poetry**, **uv** 또는 선호하는 Python 패키지 관리자를 사용하여 Cognee를 설치할 수 있습니다.
```bash
uv pip install cognee
```
### 2단계: LLM 구성
```python
import os
os.environ["LLM_API_KEY"] = "YOUR OPENAI_API_KEY"
```
또는 [템플릿](https://github.com/topoteretes/cognee/blob/main/.env.template)을 사용하여 `.env` 파일을 생성하세요.
다른 LLM 공급자를 통합하려면 [LLM 공급자 문서](https://docs.cognee.ai/setup-configuration/llm-providers)를 참조하세요.
### 3단계: 파이프라인 실행
Cognee는 문서를 가져와 지식 그래프를 생성한 다음 결합된 관계를 기반으로 그래프를 쿼리합니다.
이제 최소한의 파이프라인을 실행해 보겠습니다.
```python
import cognee
import asyncio
from pprint import pprint
async def main():
# Cognee에 텍스트 추가
await cognee.add("Cognee turns documents into AI memory.")
# 지식 그래프 생성
await cognee.cognify()
# 그래프에 메모리 알고리즘 추가
await cognee.memify()
# 지식 그래프 쿼리
results = await cognee.search("What does Cognee do?")
# 결과 표시
for result in results:
pprint(result)
if __name__ == '__main__':
asyncio.run(main())
```
보시다시피, 출력은 이전에 Cognee에 저장한 문서에서 생성됩니다.
```bash
Cognee turns documents into AI memory.
```
### Cognee CLI 사용
대안으로 다음 필수 명령으로 시작할 수 있습니다.
```bash
cognee-cli add "Cognee turns documents into AI memory."
cognee-cli cognify
cognee-cli search "What does Cognee do?"
cognee-cli delete --all
```
로컬 UI를 열려면 다음을 실행하세요.
```bash
cognee-cli -ui
```
## 데모 및 예제
Cognee 작동 모습 확인:
### 지속적인 에이전트 메모리
[LangGraph 에이전트를 위한 Cognee 메모리](https://github.com/user-attachments/assets/e113b628-7212-4a2b-b288-0be39a93a1c3)
### 간단한 GraphRAG
[데모 보기](https://github.com/user-attachments/assets/f2186b2e-305a-42b0-9c2d-9f4473f15df8)
### Cognee와 Ollama
[데모 보기](https://github.com/user-attachments/assets/39672858-f774-4136-b957-1e2de67b8981)
## 커뮤니티 및 지원
### 기여하기
여러분들의 기여를 환영합니다! 여러분의 의견은 Cognee를 더 좋게 만드는 데 큰 도움이 됩니다. 시작하려면 [`CONTRIBUTING.md`](CONTRIBUTING.md)를 참조하세요.
### 규칙
우리는 포용적이고 존중하는 커뮤니티를 만들기 위해 노력하고 있습니다. 규칙은 [규칙 문서](https://github.com/topoteretes/cognee/blob/main/CODE_OF_CONDUCT.md)를 확인해주세요.
## 연구 및 인용
최근 LLM 추론을 위한 지식 그래프 최적화에 관한 연구 논문을 발표했습니다.
```bibtex
@misc{markovic2025optimizinginterfaceknowledgegraphs,
title={Optimizing the Interface Between Knowledge Graphs and LLMs for Complex Reasoning},
author={Vasilije Markovic and Lazar Obradovic and Laszlo Hajdu and Jovan Pavlovic},
year={2025},
eprint={2505.24478},
archivePrefix={arXiv},
primaryClass={cs.AI},
url={https://arxiv.org/abs/2505.24478},
}
```
+6
View File
@@ -0,0 +1,6 @@
# Reporting Security Issues
The Cognee team takes security issues seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
To report a security issue, email [info@topoteretes.com](mailto:info@topoteretes.com) and include the word "SECURITY" in the subject line.
We'll endeavor to respond quickly, and will keep you updated throughout the process.
+336
View File
@@ -0,0 +1,336 @@
# Implementation Plan: Postgres-backed Session Store (CacheDBInterface adapter)
**Goal:** store cognee session data (QA entries, agent traces, usage logs, and small string KV values) in Postgres via a new `CacheDBInterface` adapter, removing the Redis requirement for session memory. Default backend stays `fs`; Redis and Tapes keep working unchanged. The design keeps a clean seam for a future Turbopuffer backend.
**Design stance:** minimal-surface adapter that slots into the existing backend plug point (like `FSCacheAdapter`), follows the graph Postgres adapter's engine/schema patterns, and adds **zero new dependencies** (SQLAlchemy is core; asyncpg/psycopg2 ship in the existing `postgres` extra). Where the minimal approach was naive (TTL purging, multi-worker RMW, lock semantics, prune scope), the robust alternatives are grafted in below — each divergence from the minimal design is justified inline.
---
## 1. Overview & goals
- Add `CACHE_BACKEND=postgres` as a fourth cache backend alongside `redis`, `fs`, `tapes`.
- Implement `PostgresCacheAdapter(CacheDBInterface)` with full behavioral parity to `RedisAdapter`/`FSCacheAdapter` (TTL semantics, merge semantics, error contracts), improving on known Redis races where doing so is observably identical (atomic deletes, `FOR UPDATE` updates).
- Support the formal string KV methods on `CacheDBInterface` (`get_value`/`set_value`/`delete_value`) for small cache values. The old graph-to-session sync contract is removed; new backends should not add an `async_redis` shim for it.
- Non-goals (v1): data migration tooling (cache is 7-day-TTL ephemeral), per-dataset DB isolation (sessions are per-user), distributed `SHARED_LADYBUG_LOCK` support on Postgres (Phase 6), multi-worker `improve()` mutex.
---
## 2. Current state
**Cache interface**`cognee/infrastructure/databases/cache/cache_db_interface.py`: ABC with sync lock methods (`acquire_lock`/`release_lock`, concrete `hold_lock()` contextmanager), async QA CRUD (`create_qa_entry`, `get_latest_qa_entries`, `get_all_qa_entries`, `update_qa_entry`, `delete_feedback`, `delete_qa_entry`, `delete_session`), agent traces (`append_agent_trace_step`, `get_agent_trace_session`, `get_agent_trace_feedback`, `get_agent_trace_count`), `prune`, `close`, `log_usage`/`get_usage_logs`, plus concrete back-compat shims `add_qa`/`get_latest_qa`/`get_all_qas` (do not reimplement). Base `__init__(host, port, lock_key="default_lock", log_key="usage_logs")`. Payload models: `SessionQAEntry`/`SessionAgentTraceEntry` in `cognee/infrastructure/databases/cache/models.py` (validators: feedback_score 15, `used_graph_element_ids` only `node_ids`/`edge_ids`, `memify_metadata` str→bool, trace sanitization/truncation).
**Backends**`cache/redis/RedisAdapter.py` (sync `redis.Redis` for locks + async `redis.asyncio.Redis` for data; one Redis LIST per key `agent_sessions:{user_id}:{session_id}` / `agent_traces:{user_id}:{session_id}` / `{log_key}:{user_id}`; JSON-string elements; `EXPIRE`-on-write sliding TTL; `FLUSHDB` prune); `cache/fscache/FsCacheAdapter.py` (diskcache, whole list as one JSON value under `self.cache`, `cache.transact()`, lock methods raise `SharedLadybugLockRequiresRedisError`); `cache/tapes/TapesCacheAdapter.py` (FS subclass mirroring QA creates over HTTP).
**Factory**`cache/get_cache_engine.py`: `@lru_cache`'d `create_cache_engine(...)` branches on `CacheConfig.cache_backend` (`Literal["redis","fs","tapes"]`, default `"fs"`, in `cache/config.py`); returns `None` when `caching` and `usage_logging` are both off; `close_cache_engine()` closes + `cache_clear()`s. **Verified gotcha:** `from ...RedisAdapter import RedisAdapter` executes unconditionally inside the caching-on block, *before* the backend dispatch — it only works because the unused core dep `fakeredis[lua]` transitively installs `redis`.
**Session manager**`cognee/infrastructure/session/session_manager.py` (built by `get_session_manager.py`): wraps every interface method, no-ops when `cache_engine is None`. It no longer stores graph snapshots in session prompts. For one release, `delete_session` still deletes the legacy `graph_knowledge:{user_id}:{session_id}` key via `delete_value` so old cache rows do not linger.
**Locks** — two unrelated systems: (1) `cognee/infrastructure/locks/session_lock.py`: pure in-process asyncio locks (per-`(session_id, op)` dict + improve-lock set), explicitly single-worker scope, **no Redis dependency, no change required**; (2) `CacheDBInterface.acquire_lock`/`release_lock`: **sync** methods used only by the Ladybug graph adapter (`graph/ladybug/adapter.py` ~line 187, via `asyncio.to_thread`) when `SHARED_LADYBUG_LOCK=true` — Redis-only today.
**Relational sibling**`cognee/modules/session_lifecycle/models.py` (`session_records`, `session_model_usage`): alembic-managed lifecycle/metrics rows, already Postgres-compatible, untouched by this plan. No FK between cache rows and `session_records` (cache rows TTL-expire; lifecycle rows persist — by design).
**Template**`cognee/infrastructure/databases/graph/postgres/adapter.py` + `tables.py`: own `create_async_engine(uri, json_serializer=lambda obj: json.dumps(obj, cls=JSONEncoder), **pool_args)` (verified, lines 4058), `async_sessionmaker(expire_on_commit=False)`, private `MetaData()` with `create_all(checkfirst=True)` in `initialize()` — not alembic.
---
## 3. Target architecture
```
SessionManager / usage_logger / forget / prune_system / memify tasks
│ (unchanged call sites)
get_cache_engine() ──reads── CacheConfig (.env: CACHE_BACKEND, CACHE_DB_URL, ...)
│ @lru_cache create_cache_engine()
├── "redis" → RedisAdapter (unchanged)
├── "fs" → FSCacheAdapter (unchanged)
├── "tapes" → TapesCacheAdapter (unchanged)
└── "postgres" → PostgresCacheAdapter (NEW, lazy import)
├── own async engine (postgresql+asyncpg://...)
│ json_serializer=JSONEncoder (UUID/datetime-safe JSONB)
├── tables (private MetaData, create-on-init):
│ cache_qa_entries ← agent_sessions:{u}:{s} lists
│ cache_trace_entries← agent_traces:{u}:{s} lists
│ cache_usage_logs ← {log_key}:{u} lists
│ cache_kv ← generic small string KV values
└── get_value/set_value/delete_value over cache_kv
```
---
## 4. Postgres adapter design
### 4.1 Module layout
Mirror the existing backend layout:
```
cognee/infrastructure/databases/cache/postgres/
├── __init__.py # re-export PostgresCacheAdapter
├── tables.py # private MetaData + SQLAlchemy Core tables
└── PostgresCacheAdapter.py # class PostgresCacheAdapter(CacheDBInterface)
```
### 4.2 Class skeleton
```python
class PostgresCacheAdapter(CacheDBInterface):
def __init__(
self,
connection_string: str, # any SQLAlchemy async URL (asyncpg in prod, aiosqlite in tests)
lock_key: str = "default_lock",
log_key: str = "usage_logs",
session_ttl_seconds: int | None = 604800,
agentic_lock_expire: int = 240, # stored now, used by Phase 6 advisory locks
agentic_lock_timeout: int = 300,
purge_interval_seconds: int = 900,
):
super().__init__(host="", port=0, lock_key=lock_key, log_key=log_key)
self.db_uri = connection_string
self.session_ttl_seconds = session_ttl_seconds
pool_args = dict(get_relational_config().pool_args or {})
self.engine = create_async_engine(
connection_string,
json_serializer=lambda obj: json.dumps(obj, cls=JSONEncoder),
**pool_args,
)
self.sessionmaker = async_sessionmaker(bind=self.engine, expire_on_commit=False)
self._initialized = False
self._init_lock = asyncio.Lock()
self._last_purge = 0.0
```
Notes:
- Call `super().__init__` (Redis does; FS doesn't — calling it gives `lock_key`/`log_key`/`lock` attributes).
- Single hashable `connection_string` arg keeps the `@lru_cache`'d factory happy.
- Owning the engine (rather than borrowing `get_relational_engine()`'s) keeps `close()` safe: `close_cache_engine()``adapter.close()``engine.dispose()` must not kill the shared relational pool.
- Engine-level `json_serializer` with `cognee.modules.storage.utils.JSONEncoder` is load-bearing: without it, asyncpg JSONB inserts containing UUIDs/datetimes fail (graph-adapter gotcha, replicated).
- Connection validation is **lazy** (in `_ensure_initialized`), not eager like Redis's `ping()` — the constructor must stay sync and lru_cache-friendly; the contract only requires `CacheConnectionError` to surface, which it does on first use. Also raise a clear `CacheConnectionError("CACHE_BACKEND=postgres requires cognee[postgres]")` if the asyncpg import fails.
### 4.3 Table DDL (`cache/postgres/tables.py`)
Private `MetaData()`**not** the relational declarative `Base`, **not** alembic-managed (graph-adapter precedent: `graph_node`/`graph_edge` are create-on-init while `session_records` is alembic-managed; private MetaData keeps alembic autogenerate from seeing these). Payload columns use `JSONB().with_variant(JSON(), "sqlite")` so unit tests run on aiosqlite. `cache_`-prefixed names avoid collision with `session_records`/`session_model_usage`.
```sql
-- QA entries: one row per entry; qa_id promoted to a column for direct UPDATE
-- (Redis buries it in JSON and does linear scan + LSET)
CREATE TABLE cache_qa_entries (
seq BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, -- insertion order
user_id TEXT NOT NULL,
session_id TEXT NOT NULL,
qa_id TEXT NOT NULL,
payload JSONB NOT NULL, -- full SessionQAEntry.model_dump() (incl. qa_id, time)
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
expires_at TIMESTAMPTZ NULL, -- NULL = no expiry
UNIQUE (user_id, session_id, qa_id)
);
CREATE INDEX idx_cache_qa_session ON cache_qa_entries (user_id, session_id, seq);
CREATE INDEX idx_cache_qa_expires ON cache_qa_entries (expires_at) WHERE expires_at IS NOT NULL;
-- Agent traces: append-only
CREATE TABLE cache_trace_entries (
seq BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
user_id TEXT NOT NULL,
session_id TEXT NOT NULL,
payload JSONB NOT NULL, -- SessionAgentTraceEntry.model_dump()
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
expires_at TIMESTAMPTZ NULL
);
CREATE INDEX idx_cache_trace_session ON cache_trace_entries (user_id, session_id, seq);
CREATE INDEX idx_cache_trace_expires ON cache_trace_entries (expires_at) WHERE expires_at IS NOT NULL;
-- Usage logs (Redis key {log_key}:{user_id})
CREATE TABLE cache_usage_logs (
seq BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
log_key TEXT NOT NULL, -- adapter's self.log_key
user_id TEXT NOT NULL,
payload JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
expires_at TIMESTAMPTZ NULL
);
CREATE INDEX idx_cache_usage ON cache_usage_logs (log_key, user_id, seq);
-- String KV for small cache values; legacy graph_knowledge:{u}:{s} keys may be deleted by SessionManager
CREATE TABLE cache_kv (
key TEXT PRIMARY KEY,
value TEXT NOT NULL,
expires_at TIMESTAMPTZ NULL
);
```
Notes:
- `session_id` stays a **plain string, no FK** to `session_records` (same `session_id` exists under multiple users; cache rows expire while lifecycle rows persist). Keying is always `(user_id, session_id)` — the exact relational analogue of the Redis key prefixes, which also preserves cross-user reads (recall / sessions router resolve the *owner's* `user_id` from `SessionRecord`).
- JSONB, not bytea/pickle: parity with `graph_node.properties` and the Redis JSON-string encoding; queryable for debugging.
- Hot-path: `get_latest_qa_entries` runs on every completion (last 10); `idx_cache_qa_session` makes the tail read an index scan. Rows can be tens of KB (payload embeds `context`) — a later `payload - 'context'` projection optimization is possible, but the contract returns full entries today; don't change behavior.
### 4.4 Method-by-method implementation
Every public async method: `await self._ensure_initialized()` first (once-flag under `self._init_lock`; runs `conn.run_sync(cache_metadata.create_all, checkfirst=True)`, wraps first-connect failure in `CacheConnectionError`), then `async with self.sessionmaker() as session, session.begin():`. Error contract (pinned by `test_redis_adapter_crud.py`/`test_fs_adapter_crud.py`): backend/SQLAlchemy errors → wrap in `CacheConnectionError`; create-path *validation* failures → also `CacheConnectionError` (odd but tested); update-path validation → `SessionQAEntryValidationError` **propagated unwrapped**.
| Method | Implementation |
|---|---|
| `create_qa_entry(user_id, session_id, question, context, answer, qa_id=None, ...)` | `qa_id: str \| None = None` with `str(uuid4())` fallback — match the adapters, not the ABC's `qa_id: str`. Build `SessionQAEntry` (stamps `time=datetime.utcnow().isoformat()`, runs validators; failure → `CacheConnectionError`). `INSERT` `payload=entry.model_dump()`; session-wide TTL refresh (§4.5); scoped lazy purge. One transaction. |
| `get_latest_qa_entries(u, s, last_n=5)` | `SELECT payload WHERE u/s AND not-expired ORDER BY seq DESC LIMIT :n`, reverse in Python → chronological; `SessionQAEntry.model_validate` each. **Return `[]` always on empty, including `last_n==1`** — the Redis `None`-on-`last_n==1` quirk is not replicated; all callers go through `SessionManager` and treat falsy uniformly (FS already returns `[]`). Pin in the unit test. |
| `get_all_qa_entries(u, s)` | Same, `ORDER BY seq ASC`, no LIMIT; `[]` if none. |
| `update_qa_entry(u, s, qa_id, ...)` | One transaction: `SELECT payload ... WHERE user_id/session_id/qa_id ... FOR UPDATE` (`with_for_update()`; no-op on the sqlite test variant, fine). No row → `False`. Merge in Python with exact existing semantics: `None` preserves every field; `memify_metadata = {**existing, **new}` (MERGE not replace — `apply_feedback_weights`/`apply_frequency_weights` idempotency flags depend on it); re-validate via `SessionQAEntry.model_validate`, letting `SessionQAEntryValidationError` propagate; `UPDATE payload`; TTL refresh; `True`. `FOR UPDATE` makes this RMW multi-worker-safe — strictly better than Redis's load/LSET race, observably identical. |
| `delete_feedback(u, s, qa_id)` | Same `FOR UPDATE` pattern; set `feedback_text`/`feedback_score` to `None` in payload; TTL refresh; bool. (This is the only way to clear feedback — `update_qa_entry(feedback_score=None)` preserves.) |
| `delete_qa_entry(u, s, qa_id)` | Single atomic `DELETE ... WHERE user_id/session_id/qa_id` (replaces Redis's non-atomic DEL+RPUSH-loop rewrite — crash-safe improvement); TTL refresh on remaining rows (Redis re-applies TTL after rewrite); return `rowcount > 0`. No "drop key when empty" step — empty session ≡ zero rows. |
| `delete_session(u, s)` | One transaction: `DELETE FROM cache_qa_entries` + `DELETE FROM cache_trace_entries` for `(u, s)`; `True` if either rowcount > 0. (`SessionManager.delete_session` separately deletes the legacy `graph_knowledge:` key via `delete_value` — keep that division for one release.) |
| `append_agent_trace_step(u, s, trace_id, origin_function, status, ...)` | Build `SessionAgentTraceEntry` (`method_params or {}`; model validators do sanitization/truncation for free; blank `trace_id`/`origin_function``CacheConnectionError`); INSERT; trace-session TTL refresh. |
| `get_agent_trace_session(u, s, last_n=None)` | `ORDER BY seq ASC`; when `last_n is not None`, `DESC LIMIT` + reverse. Reads do NOT refresh TTL. |
| `get_agent_trace_feedback(u, s, last_n=None)` | `[e.session_feedback for e in await self.get_agent_trace_session(...)]` — exactly the delegation both adapters use. |
| `get_agent_trace_count(u, s)` | `SELECT count(*)` with expiry filter; 0 for missing session. |
| `prune()` | `DELETE FROM` / `TRUNCATE` the **four cache tables only**. Deliberate, documented divergence from Redis `FLUSHDB` (which nukes co-tenant keys and other users' data) — strictly safer; both proposals agree. |
| `close()` | `await self.engine.dispose(close=True)`; dispose the sync lock engine if created (Phase 6); idempotent, swallow + debug-log errors (called by `close_cache_engine` and `prune_data.py`). Reset `self._initialized = False` so a reused instance re-inits. |
| `log_usage(user_id, log_entry, ttl=604800)` | INSERT into `cache_usage_logs` with `log_key=self.log_key`, `expires_at = now()+ttl` if ttl else NULL; **also refresh `expires_at` on the user's existing rows** under the same `(log_key, user_id)` — Redis `EXPIRE`s the whole list, so per-row-only TTL would diverge. |
| `get_usage_logs(user_id, limit=100)` | `SELECT payload WHERE log_key/user_id AND not-expired ORDER BY seq DESC LIMIT :limit` — already most-recent-first (Redis does lrange + reverse). |
| `acquire_lock()` / `release_lock(lock=None)` | **SYNC — do not make async** (Ladybug calls them via `asyncio.to_thread`). **v1: raise `SharedLadybugLockRequiresRedisError`**, imported from `cognee.infrastructure.databases.exceptions.exceptions` directly (it is NOT re-exported in the package `__init__`) — exactly like `FsCacheAdapter`. Inherited `hold_lock()` then raises too — correct. Phase 6 upgrade in §7. |
| Inherited (do not reimplement) | `hold_lock()`, `add_qa`, `get_latest_qa`, `get_all_qas`. |
**Concurrency posture:** unlike the graph adapter, **no global `asyncio.Lock` serializing writes** — row-level `FOR UPDATE` + single-statement deletes give correct multi-worker behavior with better throughput; the graph adapter's lock exists for bulk upsert batches that don't occur here. Add the graph adapter's tenacity retry on asyncpg `DeadlockDetectedError` as belt-and-braces.
### 4.5 TTL strategy: `expires_at` + read-time filter + lazy purge + throttled sweep
Replicates Redis sliding whole-key TTL exactly:
- **Write refresh:** every mutating op runs, inside its transaction, `UPDATE <table> SET expires_at = now() + :ttl WHERE user_id=:u AND session_id=:s` (skipped when `session_ttl_seconds` is `None`/`<= 0``expires_at` stays NULL, expiry disabled). Whole-session refresh matches `EXPIRE session_key`. Sessions are small (tenshundreds of rows); cheap.
- **Read filter:** every SELECT adds `AND (expires_at IS NULL OR expires_at > now())`. Reads never refresh TTL (tested Redis behavior). Correctness never depends on purging.
- **Purge** ("purge on init only" would leak rows in long-lived processes): (a) scoped `DELETE ... WHERE user_id=:u AND session_id=:s AND expires_at <= now()` opportunistically on writes to that session; (b) a throttled global sweep `DELETE FROM <each table> WHERE expires_at <= now()` at most once per `purge_interval_seconds` (default 900) per process, guarded by `pg_try_advisory_lock` on Postgres (skip the guard on the sqlite test variant) so concurrent workers don't stampede. No external cron. Precedents: `FSCacheAdapter.cache.expire()` on init; `session_lifecycle` computing "abandoned" at read time.
- **KV behavior:** string KV values are exact-key values with optional TTL support where the adapter exposes it. No graph-to-session checkpoint keys are written anymore.
### 4.6 String KV methods
The old hidden `async_redis` duck-type contract is gone with graph-to-session sync. Implement the formal `CacheDBInterface` string KV methods directly:
```python
async def get_value(self, key: str) -> str | None: ...
async def set_value(self, key: str, value: str, ttl: int | None = None) -> None: ...
async def delete_value(self, key: str) -> None: ...
```
`get_value` returns `str | None`. `set_value` should upsert by key and set `expires_at` when a TTL is supplied. `delete_value` should be idempotent.
---
## 5. Config & provider selection changes
**`cognee/infrastructure/databases/cache/config.py`:**
- `cache_backend: Literal["redis", "fs", "tapes", "postgres"] = "fs"` (default **unchanged**).
- New fields: `cache_db_url: Optional[str] = None` (env `CACHE_DB_URL`, e.g. `postgresql+asyncpg://cognee:cognee@localhost:5432/cognee_db`) and `cache_purge_interval_seconds: int = 900`. **Single-URL chosen over five discrete `CACHE_DB_*` fields**: one hashable kwarg through the lru_cache'd factory, one config field instead of five, and it matches the adapter's `connection_string` constructor. Do **not** reuse `cache_host`/`cache_port` — they default to Redis's `localhost:6379` (silent misdirection risk).
- Fallback resolution (helper `_resolve_cache_db_url` in `get_cache_engine.py`, mirroring `get_graph_engine.py`'s GRAPH_DATABASE_* → DB_* fallback): `CACHE_DB_URL` if set; else, when `get_relational_config().db_provider == "postgres"`, build `postgresql+asyncpg://DB_USERNAME:DB_PASSWORD@DB_HOST:DB_PORT/DB_NAME` with a warning-level log; else raise `CacheConnectionError("CACHE_BACKEND=postgres requires CACHE_DB_URL or DB_PROVIDER=postgres")`.
- Extend `to_dict()` and the class docstring (both pinned by `cognee/tests/unit/infrastructure/databases/cache/test_cache_config.py::test_cache_config_defaults/test_cache_config_to_dict`, which assert the exact full dict — update them).
**`cognee/infrastructure/databases/cache/get_cache_engine.py`:**
- Thread two new hashable params through both signatures (same pattern as the `tapes_*` params): `create_cache_engine(..., cache_db_url: str | None = None, cache_purge_interval_seconds: int = 900)`; pass from `get_cache_engine()`.
- New branch with **lazy import** (verified pattern: `TapesCacheAdapter` is imported inside its branch):
```python
elif config.cache_backend == "postgres":
from cognee.infrastructure.databases.cache.postgres.PostgresCacheAdapter import (
PostgresCacheAdapter,
)
return PostgresCacheAdapter(
connection_string=_resolve_cache_db_url(cache_db_url),
lock_key=lock_key,
log_key=log_key,
session_ttl_seconds=session_ttl_seconds,
agentic_lock_expire=agentic_lock_expire,
agentic_lock_timeout=agentic_lock_timeout,
purge_interval_seconds=cache_purge_interval_seconds,
)
```
- Update the `ValueError` message to `"'redis', 'fs', 'tapes', 'postgres'"`.
- Move the currently-unconditional `from ...RedisAdapter import RedisAdapter` (verified: executes for ALL backends once caching is on) inside the `== "redis"` branch — 2-line cleanup that removes the accidental reliance on `fakeredis` pulling in `redis`. Low-risk, do it in this PR.
- lru_cache caveats respected: `cache_db_url` is a hashable string; constructor params frozen after first call until `cache_clear()` (existing behavior); note the existing pool-per-`lock_key` instantiation pattern (Ladybug per-db lock_key) in the adapter docstring.
**`pyproject.toml`:** no changes — SQLAlchemy is core; asyncpg/psycopg2 are in the existing `postgres` extra. Document "`CACHE_BACKEND=postgres` requires `cognee[postgres]`".
---
## 6. Schema creation / migration approach
Graph-adapter style, **not alembic**:
- Tables on a private `MetaData()` in `cache/postgres/tables.py`; alembic's `env.py` (`target_metadata = Base.metadata`) never sees them; no migration files.
- Idempotent `create_all(checkfirst=True)` inside `_ensure_initialized()` (once-flag + `asyncio.Lock`), re-run lazily after `close_cache_engine()`/`prune_system`'s `cache_clear()` recreates the adapter — necessary because the cache factory has no `_GraphEngineHandle` equivalent.
- Rationale: cache content is ephemeral/TTL'd, schema is additive, and the repo precedent is explicit (`graph_node`/`graph_edge` create-on-init vs alembic-managed `session_records`).
- **No per-dataset database handler** — do not register anything in `supported_dataset_database_handlers.py` or copy `PostgresGraphDatasetDatabaseHandler`. Sessions are per-user, not per-dataset; isolation parity comes from `(user_id, session_id)` columns. Deployments wanting physical separation point `CACHE_DB_URL` at a dedicated database.
---
## 7. Session lock handling
- **`cognee/infrastructure/locks/session_lock.py`: no change.** It is pure in-process asyncio with no Redis dependency; its documented single-worker scope is unchanged. Note in the PR description that the adapter's `FOR UPDATE` in `update_qa_entry`/`delete_feedback` makes those RMW paths multi-worker-safe at the storage layer anyway (closes the gap session_lock.py's own docstring flags).
- **`CacheDBInterface.acquire_lock`/`release_lock` (shared Ladybug lock):**
- **v1 (core PR):** raise `SharedLadybugLockRequiresRedisError` — established FS precedent; `SHARED_LADYBUG_LOCK=true + CACHE_BACKEND=postgres` stays unsupported with a clear error.
- **Phase 6 (separate PR):** lazy-create a small **sync** engine (`postgresql+psycopg2`, `pool_size=2`; psycopg2 is already in the `postgres` extra) used only for locks. `lock_id = int.from_bytes(sha256(self.lock_key.encode()).digest()[:8], "big", signed=True)`. `acquire_lock()`: check out a dedicated connection, loop `SELECT pg_try_advisory_lock(:id)` with 0.1 s sleeps until the `agentic_lock_timeout` deadline; on success return a handle object owning the connection; on timeout raise `RuntimeError` (mirrors Redis). `release_lock(lock=None)`: `pg_advisory_unlock` on the **passed** handle, not `self.lock` (explicitly tested Redis behavior); close/return the connection; swallow errors if not held. Handle-bound connections give `thread_local=False` parity (releasable from worker threads). Semantics note to document: advisory locks release on connection death (safer than, but different from, Redis's 240 s `agentic_lock_expire` auto-expiry, which has no direct equivalent).
- Multi-worker `improve()` mutex via `pg_try_advisory_lock` behind `try_acquire_improve_lock`: explicit non-goal / future work.
---
## 8. Test plan
**Unit CRUD** — new `cognee/tests/unit/infrastructure/databases/cache/test_postgres_adapter_crud.py`, mirroring `test_redis_adapter_crud.py`'s ~25 cases. No real Postgres in pytest (repo convention — Redis suites use a hand-rolled `_InMemoryRedisList` fake; here we get a real-engine equivalent for free): construct `PostgresCacheAdapter("sqlite+aiosqlite:///<tmp>/cache.db")` — the `with_variant(JSON(), "sqlite")` columns and identity-PK→autoincrement degradation make the same code paths run without a server. Cover:
- QA create/get-latest/get-all ordering; uuid4 `qa_id` fallback; `[]` on empty **including `last_n=1`** (pins the FS-style choice)
- update: None-preserves every field; `memify_metadata` MERGE; `SessionQAEntryValidationError` propagates unwrapped; `False` on missing qa_id
- `delete_feedback` nulls both fields; `delete_qa_entry` rowcount semantics + TTL survival; `delete_session` clears both tables
- traces: append/get/count/feedback delegation; sanitization via model validators; blank `trace_id``CacheConnectionError`
- TTL: `expires_at` set/refreshed on create/update/delete_feedback/after-delete; NOT refreshed on reads; disabled when `session_ttl_seconds in (0, None)`; expired rows invisible to reads (assert via direct SQL with backdated `expires_at`)
- `prune()` clears only the four cache tables; `close()` idempotent; legacy `add_qa`/`get_latest_qa`/`get_all_qas` shims
- `acquire_lock`/`release_lock` raise `SharedLadybugLockRequiresRedisError`
- KV `get_value`/`set_value`/`delete_value` round-trips, including one legacy `graph_knowledge:{u}:{s}` deletion path through `SessionManager.delete_session`
**Integration** — add `"postgres"` to the `params=["fs", "redis"]` fixtures in `cognee/tests/integration/infrastructure/session/test_session_sdk_integration.py`, `test_session_persistence_memify_integration.py`, `test_feedback_weights_memify_integration.py` (aiosqlite URL, no server); new `test_session_manager_postgres.py` mirroring `test_session_manager_redis.py` (LLM mocked via `AsyncMock` on `LLMGateway.acreate_structured_output`).
**Config/factory** — update `test_cache_config.py` exact-dict assertions; new factory tests: `CACHE_BACKEND=postgres` returns `PostgresCacheAdapter`, unknown backend `ValueError` lists all four, URL fallback resolution (CACHE_DB_URL → DB_* → error).
**CI e2e (real Postgres)** — third twin job `run_conversation_sessions_test_postgres` in `.github/workflows/e2e_tests.yml`, copying `run_conversation_sessions_test_redis` minus the redis service (the pgvector/pg17 service is already provisioned there): env `CACHING=true AUTO_FEEDBACK=true CACHE_BACKEND=postgres DB_PROVIDER=postgres` (relying on the DB_* fallback, which also exercises it) or explicit `CACHE_DB_URL`; extras `"postgres"` only; runs `cognee/tests/test_conversation_history.py` unmodified. Phase 6 adds a `SHARED_LADYBUG_LOCK=true CACHE_BACKEND=postgres` variant of the concurrent-subprocess job running `test_concurrent_subprocess_access.py`, plus real-Postgres-gated advisory-lock unit tests (acquire/release of the *passed* handle, contention timeout → `RuntimeError`, cross-connection mutual exclusion).
**Regression coverage** — FS/Redis/Postgres tests proving generic string KV round-trips and the legacy `graph_knowledge:` cleanup path work consistently.
---
## 9. Rollout & backward compatibility
- **No behavior change by default:** `cache_backend` default stays `"fs"`; redis/tapes branches untouched; `get_cache_engine()` still returns `None` when caching + usage_logging are off (every consumer already handles `None`).
- **No data migration tooling:** session cache is 7-day-TTL ephemeral; switching backends starts fresh — same story as redis↔fs today. One-liner in docs. `SessionRecord` rows in the relational DB are unaffected.
- **`forget(everything=True)` / `prune_system` / `prune_data`** paths work unchanged (`prune()`, `close_cache_engine()`, `cache_clear()`); document that Postgres `prune()` is scoped to cognee cache tables (an improvement over `FLUSHDB`).
- **Failure modes:** misconfigured backend raises `CacheConnectionError` (503) at first use; `SHARED_LADYBUG_LOCK=true` + postgres raises `SharedLadybugLockRequiresRedisError` with a clear message until Phase 6.
- **Docs:** `.env.template` "Session cache settings" block (~line 375): add `# CACHE_BACKEND=postgres` + `# CACHE_DB_URL=postgresql+asyncpg://...`; `config.py` docstring backend list; factory `ValueError` message; `CLAUDE.md` extras note ("postgres — also enables the Postgres session-cache backend"); file a task for the external docs.cognee.ai "sessions-and-caching" page. `docker-compose.yml` needs nothing (postgres service exists; redis stays behind its profile).
---
## 10. Phased work breakdown
| Phase | Scope | Size |
|---|---|---|
| **P1 — Adapter core** | `cache/postgres/tables.py` + `PostgresCacheAdapter.py`: engine, `_ensure_initialized`, QA CRUD (`FOR UPDATE` updates, atomic deletes), TTL refresh + read filter + scoped/throttled purge, prune, close | **L** (~1.52 days, ~450 LOC) |
| **P2 — Traces, usage logs, locks-raise, string KV** | `append_agent_trace_step`/trace reads, `log_usage`/`get_usage_logs` (whole-list TTL refresh), lock methods raising `SharedLadybugLockRequiresRedisError`, `get_value`/`set_value`/`delete_value` | **M** (~0.51 day, ~150 LOC) |
| **P3 — Wiring** | `config.py` Literal + `cache_db_url` + `cache_purge_interval_seconds` + `to_dict` + docstring; `get_cache_engine.py` branch + `_resolve_cache_db_url` fallback + error msg + RedisAdapter import moved into its branch; config-test fixes | **S** (~0.5 day) |
| **P4 — Tests** | Unit CRUD suite (aiosqlite), `test_session_manager_postgres.py`, `"postgres"` params in 3 integration files, factory/config tests | **M** (~1 day, ~500 LOC tests) |
| **P5 — CI + docs** | `run_conversation_sessions_test_postgres` e2e twin job, `.env.template`, `CLAUDE.md`, docs.cognee.ai task | **S** (~0.5 day) |
| **P6 — Follow-up PR: advisory locks** | psycopg2 `pg_try_advisory_lock` sync lock impl lifting the `SHARED_LADYBUG_LOCK` restriction + concurrent-subprocess CI variant | **M** (~1 day) |
Core (P1P5): **~4 days**, one reviewable PR (or two: adapter+tests, then wiring+CI). P6 ships separately.
---
## 11. Future: Turbopuffer adapter sketch (do not build now — verify the seam)
Turbopuffer is a namespaced object/vector store with upsert-by-id, delete-by-id, and attribute-filtered queries. The same `CacheDBInterface` maps because every cognee cache access is by exact composite key, append-or-point-update, with no cross-key scans:
- **Namespaces:** today's key strings verbatim (`agent_sessions:{user_id}:{session_id}`, `agent_traces:{...}`, `usage_logs:{user_id}`) — key-prefix tenancy carries over unchanged.
- **Rows:** id = `qa_id` / trace uuid; attributes = entry fields plus a client-stamped monotonic `seq`/`created_at` for ordering (no serial column); vector optional (zero/1-dim placeholder if mandatory — or embed `question+answer` for free semantic recall later, a genuine upside).
- **Operations:** create/append → upsert; `get_latest/get_all` → seq-ordered query (tail = desc + limit + reverse); `update_qa_entry`/`delete_feedback` → read-merge-upsert by id (back to Redis-grade RMW races — no `FOR UPDATE`; acceptable for a cache tier, flag in docs); `delete_session` → namespace delete; `prune()` → enumerate + delete `cognee-*` namespaces by prefix; KV → a `cache_kv` namespace with key-as-id rows; TTL → `expires_at` attribute + query filter + periodic GC (no native TTL — the Postgres TTL design transfers directly); locks → raise `SharedLadybugLockRequiresRedisError` (precedent).
- **Seam requirements this plan satisfies:** (1) all storage details stay behind `CacheDBInterface`; no caller touches adapter internals; (2) entries cross the boundary only as pydantic `model_dump()` payloads; (3) ordering is adapter-internal (`seq` column vs `seq` attribute) — nothing leaks; do not let SQL row ids escape into return values during P2; (4) wiring is mechanical: `cache_backend` Literal += `"turbopuffer"`, lazy-import elif, `TURBOPUFFER_API_KEY`/`TURBOPUFFER_REGION` threaded through the lru_cache'd factory.
---
## 12. Open questions
1. **Default fallback to the relational DB:** when `CACHE_DB_URL` is unset and `DB_PROVIDER=postgres`, the cache silently shares the relational database (distinct `cache_*` tables, warning logged). Is co-tenancy acceptable as the default, or should `CACHE_DB_URL` be mandatory?
2. **Normalize the Redis `None`-on-`last_n==1` quirk in `RedisAdapter` itself** (return `[]` like FS/Postgres), or leave Redis as-is and only document Postgres's `[]` choice? (Some tests pin the Redis behavior.)
3. **Hot-path payload size:** should `get_latest_qa_entries` eventually project `payload - 'context'` for history reads (formatted history uses `include_context=False` but still fetches full entries)? Behavior-preserving today; revisit with real latency data.
4. **Throttled global purge tuning:** is 900 s / per-process advisory-lock-guarded sweep enough for high-volume deployments, or is a documented external cron (`DELETE ... WHERE expires_at <= now()`) preferable at scale?
5. **`fakeredis[lua]` core dependency:** verified unused in-repo and only load-bearing because it transitively installs `redis` for the unconditional import this plan removes — candidate for deletion in a separate cleanup PR (needs a check that no downstream consumers rely on it).
6. **Lock auto-expiry parity (Phase 6):** Redis locks auto-expire after `agentic_lock_expire=240` s; pg advisory locks hold until connection death. Is connection-scoped release acceptable, or do we need a watchdog that closes the lock connection after 240 s?
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 936 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 569 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

Some files were not shown because too many files have changed in this diff Show More