Skip to main content
We welcome contributions from the community! Your input helps make Cognee better for everyone. This page outlines instructions and best practices for contributing to Cognee, ensuring your contributions are integrated into the project efficiently.

How To Contribute

There are many ways in which you can contribute to this project include: submitting bug reports and feature requests via GitHub issues, opening PRs with features, fixes, or tests, reviewing others’ PRs, and collaborating by commenting or answering questions in the Discord community.

Development Setup

Firstly, you will need to set up your local copy of the cognee code repository. Keep in mind that we have two different repositories: our core repo, which contains core cognee functionalities, and our community repo, which contains community-maintained add-ons and custom packages. Once you have chosen the repo you are going to work on, you have to fork it, and clone it to your machine:
After this, just create a branch for your work, and add your code there:

Development Guidelines

While working on new features and fixes, make sure to keep these guidelines in mind:
  • Code Style - Make sure to follow the PEP8 style guide, and also the style of the project codebase. Reuse as much of the code as possible, and follow the existing package and file hierarchy.
  • Tests - Make sure to add tests for new features, and that the tests pass before opening a PR — see Running Tests below for where they live and how to run them
  • Commits - Write clear and concise commit messages, following the commit and PR title style below

Commit & PR Title Style

The same style applies to commit messages and PR titles. If you use a coding agent (e.g. Claude Code) in the repository, it picks up these rules from CLAUDE.md automatically. Subject line (required):
  • Use the format (type): (short summary)
  • Write the summary as if it is giving an instruction — “Fix bug”, not “Fixed bug”
  • Keep it to 50 characters or less
  • Capitalize the first character of the summary
  • Do not end it with a period
The PR title is checked automatically by the lint | PR workflow (.github/workflows/pr_lint.yml), which runs amannn/action-semantic-pull-request every time a PR is opened, reopened, edited, or pushed to. A title that does not parse as type: Summary (or type(scope): Summary) fails the check, so edit the title to fix it — no new commit is needed. The accepted types are a closed list:
It is close to, but not the same as, the conventional-commits set: build and style are not accepted, and break is. The same workflow also runs release-drafter, which keeps a draft release listing PR titles; the published release notes are generated separately by the release workflow. Body (optional):
  • Explain the motivation behind the change, what problem it solves, and any relevant background — the what and why, not the how; the code itself should make the “how” clear
  • Separate the subject line from the body with a blank line. Generally, all commits should have separate subject and body.

Linting, Formatting, and Type Checking

Before creating a Pull Request, you need to make sure that your code is linted and formatted correctly. To do this, you first have to install ruff on your system. Ruff is part of the project’s dev dependencies, so you can install it with uv in the root of the core repo, or on its own through pip.
Then run the linter and the formatter from the root of the project:
If you only want to verify formatting without rewriting any files — which is what CI does — use the --check variant instead:
Both checks also run as pre-commit hooks (ruff and ruff-format) and again directly in CI’s Code Quality job. Install the hooks once so they run automatically on every commit:
The hooks are pinned to a specific ruff version in .pre-commit-config.yaml, while the ruff dependency in pyproject.toml allows a range of versions. If a locally installed ruff disagrees with CI, run the pinned version through the hooks instead:
Ruff’s configuration lives in pyproject.toml under [tool.ruff] — most notably a line length of 100 and a list of excluded paths — and the rules the project deliberately switches off live under [tool.ruff.lint] in the ignore list, most with a comment explaining why. The ASYNC220, ASYNC221, ASYNC230, and ASYNC251 rules (blocking file, subprocess, and sleep calls inside async functions) are in that list: the document loaders and the local storage layer do their file IO synchronously today, and the parser holding the handle — not the open() call — is the blocking work, so the fix is moving each loader’s parse off the event loop rather than wrapping the open() calls. That work is tracked separately, and the rules are meant to be re-enabled when it lands. Don’t add new blocking IO to async code on the strength of those rules being off. Ruff is not the last gate, though. The Code Quality job runs these steps, in this order:
If uv lock --check fails, run uv lock and commit the updated uv.lock. The second ruff pass re-runs the exception-handling rules with --ignore-noqa, so a # noqa comment on any of them counts as a finding rather than a waiver. A blind except Exception, a try/except that only passes or continues, or a bare re-raise has to be fixed — log with the traceback, re-raise, or narrow the exception type — not suppressed. The last step is ty, the type checker. It ships in the project’s dev extra, which is also how CI installs its environment, so run it the same way:
Two things worth knowing about how the type check is scoped:
  • It does not cover the whole repository yet. [tool.ty.src] in pyproject.toml lists the directories that are checked — currently around fifteen paths under cognee/, such as cognee/infrastructure/llm, cognee/infrastructure/loaders, cognee/memory, and cognee/shared — and the generated BAML client is explicitly excluded. The list is meant to grow, so a clean ty check . means the checked directories are clean, not that every module in your PR was inspected. If you touch a directory that is not on the list yet, adding it is welcome but is a change of its own.
  • Optional dependencies are suppressed inline. Imports that only resolve when an extra is installed — Pillow and rapidocr_onnxruntime in the image loader, for example — carry a # ty: ignore[unresolved-import] comment, because CI type-checks with only the dev extra installed. Use that marker for the same situation, and keep it narrow: prefer fixing the underlying problem where a public API exists (for instance Image.Resampling.LANCZOS rather than suppressing Image.LANCZOS) instead of silencing the diagnostic.

Running Tests

Tests live in cognee/tests/. Its folders include unit/ (fast and mocked), integration/ (full pipelines), e2e/ (full-stack suites per backend), cli_tests/, and journeys/ (high-level product contract tests), plus top-level test_*.py scenario tests. Always pass a path: a bare uv run pytest currently aborts at collection. Most suites outside unit/ need an LLM_API_KEY; cognee/tests/README.md has the full layout and lists what each folder requires. The journey tests check what a user experiences rather than what a module does — quickstart, memory correctness, session memory, data lifecycle, idempotency and recovery, and the HTTP API — and assert on retrieved content, not just on getting a non-empty result. They run in two modes, selected by COGNEE_JOURNEY_MODE:
  • mock (default) swaps the LLM and the embedding calls for deterministic stand-ins. No network, no credentials, so it runs on forks and is the mode to use locally.
  • llm runs the same journeys against the real providers configured in your environment. It uses threshold assertions instead of exact ones, and it spends API credits.
cognee/tests/journeys/README.md is the reference for extending the suite: what the mock AI tier does, the golden corpus format and how to add documents and questions to it, how answers are scored, and how to regenerate the HTTP route snapshot.

Submitting a Pull Request

After successfully linting and formatting your code, you can push your changes:
And now, create a Pull Request so your contribution can be reviewed, and eventually merged to the project repository:
  • Go to the repository you made changes for (i.e. the core repo or the community repo)
  • Click Compare & Pull Request and open a PR, being careful against which branch you open it (dev for core repo, main for community)
  • Fill in the PR template with details about your changes
After opening the PR, the right reviewers will be notified automatically — Cognee uses a CODEOWNERS file to request reviews based on the directories your PR touches. No manual ping required. We will make sure to review it, and eventually your contribution will be a part of the Cognee project!

Changelog Entries

The repository has no CHANGELOG.md — it was removed in the v1.6.1 release cut. When a release is tagged, the release workflow has an LLM write the notes from the commit subjects since the last release and the diff; if no LLM is available, it lists the commit subjects as they are, grouped by type. A squash-merged PR’s title becomes its commit subject, so write your PR title as a changelog entry. Write it in the conventional type: Summary form described above, and make it understandable on its own by someone who has not read the diff:
Published release notes live in the changelog and on GitHub Releases.

Contributing Guide Details

More details about the contributing process.

Community Guidelines

Be respectful and follow our code of conduct. Help others learn and grow, and provide constructive feedback.

Join our Discord Community

Join the community for real-time discussions with us and other users!