Cortexdb Memory Hermes
liliang-cn/cortexdb
Give a Python agent (such as Hermes Agent by Nous Research) durable, local-first memory plus a queryable SPARQL knowledge graph, backed by CortexDB through its gRPC sidecar and the cortexdb-client…
Explains how to load text, files, folders, URLs, repositories and databases into cognee memory with remember(), including datasets, extractors and tags.
$ npx skills add topoteretes/cognee --skill cognee-ingestion -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install topoteretes/cognee cognee-ingestion --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/topoteretes/cognee.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/cognee-ingestion .claude/skills/cognee-ingestion && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "cognee-ingestion" agent skill from https://github.com/topoteretes/cognee/tree/main/.agents/skills/cognee-ingestion into .claude/skills/cognee-ingestion/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "cognee-ingestion", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/topoteretes/cognee/tree/main/.agents/skills/cognee-ingestionType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add topoteretes/cognee --skill cognee-ingestion -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install topoteretes/cognee cognee-ingestion --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/topoteretes/cognee.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/cognee-ingestion .agents/skills/cognee-ingestion && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "cognee-ingestion" agent skill from https://github.com/topoteretes/cognee/tree/main/.agents/skills/cognee-ingestion into .agents/skills/cognee-ingestion/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "cognee-ingestion", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add topoteretes/cognee --skill cognee-ingestion -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install topoteretes/cognee cognee-ingestion --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/topoteretes/cognee.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/cognee-ingestion .cursor/skills/cognee-ingestion && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "cognee-ingestion" agent skill from https://github.com/topoteretes/cognee/tree/main/.agents/skills/cognee-ingestion into .cursor/skills/cognee-ingestion/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "cognee-ingestion", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/topoteretes/cognee.git --path .agents/skills/cognee-ingestion--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add topoteretes/cognee --skill cognee-ingestion -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install topoteretes/cognee cognee-ingestion --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/topoteretes/cognee.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/cognee-ingestion .gemini/skills/cognee-ingestion && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "cognee-ingestion" agent skill from https://github.com/topoteretes/cognee/tree/main/.agents/skills/cognee-ingestion into .gemini/skills/cognee-ingestion/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "cognee-ingestion", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install topoteretes/cognee cognee-ingestionInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add topoteretes/cognee --skill cognee-ingestion -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/topoteretes/cognee.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/cognee-ingestion .github/skills/cognee-ingestion && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "cognee-ingestion" agent skill from https://github.com/topoteretes/cognee/tree/main/.agents/skills/cognee-ingestion into .github/skills/cognee-ingestion/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "cognee-ingestion", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add topoteretes/cognee --skill cognee-ingestion -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install topoteretes/cognee cognee-ingestion --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/topoteretes/cognee.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/cognee-ingestion .opencode/skills/cognee-ingestion && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "cognee-ingestion" agent skill from https://github.com/topoteretes/cognee/tree/main/.agents/skills/cognee-ingestion into .opencode/skills/cognee-ingestion/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "cognee-ingestion", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
cognee-ingestionExplains how to load text, files, folders, URLs, repositories and databases into cognee memory with remember(), including datasets, extractors and tags.
This skill covers cognee's remember() call, the single ingestion entry point that stores data, builds a knowledge graph from it and enriches the graph. It explains what remember() accepts: strings, lists of strings, file paths (absolute, file:// or s3://), http and https URLs, binary streams, folders, code repositories and GitHub or GitLab URLs, SQL connection strings, dlt sources, CSV files and SKILL.md playbooks.
It then explains the options that shape the result: dataset_name or dataset_id for the target dataset and its permissions, node_set tags that recall can filter on later, session_id for writing to the fast session cache, and an extractor choice between an LLM and GLiNER, picked automatically from whether an API key is configured. Code files take a separate deterministic route with no LLM calls, searchable with SearchType.CODE. The skill is meant for questions about loaders, ontologies, chunking, dry-run cost estimates and temporal graphs, and for diagnosing a remember() call that rejects a keyword argument.
Read from SKILL.md and the folder at commit 0ec7a9f. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
pipFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use pip, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
LLM_API_KEYFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Cognee Data Ingestion loads about 2.6k tokens when it runs. Until then it costs about 76 tokens; SKILL.md has 1,087 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check noted patterns worth knowing about, such as sudo or a known installer.
`.env`. `annotate` (default) only enriches; `strict` drops entities thatAutomated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from topoteretes/cognee at commit 0ec7a9f, republished under its Apache-2.0 licence (© topoteretes). 1,087 words, ~2,625 tokens.
.claude/skills/cognee-ingestion/SKILL.md (or your agent's skills folder).remember() is cognee's ingestion API. One call stores the data, builds the
knowledge graph, and enriches it. Use it for all ingestion; every option in
this skill is a remember() argument unless it says otherwise.
import cognee
result = await cognee.remember("Einstein was born in Ulm.") # text
result = await cognee.remember(
["./notes.md", "./report.pdf"], # files
dataset_name="research",
)
print(result.status, result.dataset_id) # "completed", UUIDAll cognee functions are async. Without dataset_name data goes to
main_dataset. Needs LLM_API_KEY unless you use the GLiNER extractor
(below).
data accepts a string, a list of strings, file paths (absolute, file://,
s3://), http(s) URLs, binary streams, or a list mixing them.
ALLOW_HTTP_REQUESTS=true, the
default).git
on PATH)..py, .ts, .go, …) go down the code-graph route: a
deterministic graph, no LLM calls, searchable only with
SearchType.CODE. To index a whole repository explicitly, pass
content_type="code".DltResource / DltSource, or a CSV. dlt is a core dependency, so no
extra is needed (cognee[dlt] is an empty compatibility extra). Options: primary_key (default "id"),
write_disposition ("replace" default, or "append"), query,
max_rows_per_table.SKILL.md files): content_type="skills"; ingests
into the target dataset (default main_dataset), so pass dataset_name
to keep skills in their own dataset.| Argument | What it does |
|---|---|
dataset_name / dataset_id | Target dataset. dataset_id wins. A dataset is the unit of permissions and isolation. |
node_set=["AI", "FinTech"] | Tags the data so recall can filter to it later with recall(..., node_name=["AI"]). |
session_id="chat_1" | Writes to the fast session cache instead of the graph; improve() bridges it into the graph in the background. See the cognee-improve-sessions skill. Requires CACHING=true. |
| Argument | What it does |
|---|---|
extractor | "llm" or "gliner_demo" (alias "gliner"). Default is GRAPH_EXTRACTOR=auto: the LLM when an API key is configured, otherwise GLiNER. |
graph_model=MyModel | Extract into your own DataPoint model instead of the generic KnowledgeGraph. See the cognee-custom-graph-models skill. |
custom_prompt | Replaces the entity-extraction prompt (ignored by GLiNER). |
config={"ontology_config": {...}} | Ground entities in an OWL ontology (below). |
chunk_size, chunker | Max tokens per chunk (default: derived from the embedding and LLM limits) and the chunker class (default TextChunker). |
preferred_loaders | Choose a loader per file type (below). |
self_improvement | Default True: runs improve() after the graph is built. Its outcome is on result.improve / result.improve_error; a failed improve never fails the remember. |
run_in_background=True | Returns immediately with status="running"; await result to wait. |
from cognee.modules.ontology.rdf_xml.RDFLibOntologyResolver import RDFLibOntologyResolver
config = {
"ontology_config": {
"ontology_resolver": RDFLibOntologyResolver(ontology_file="./my.owl"),
# "ontology_mode": "strict", # drop entities with no ontology match
}
}
await cognee.remember(texts, config=config)Or set ONTOLOGY_FILE_PATH (plus ONTOLOGY_MODE, MATCHING_STRATEGY) in
.env. annotate (default) only enriches; strict drops entities that
match no ontology class or individual. It prunes only the graph, chunk text
is still stored. Strict mode with an empty or missing ontology file is a hard
error. Over HTTP, upload the ontology to /api/v1/ontologies and pass its
ontology_key to POST /api/v1/remember. Example:
examples/guides/ontology_quickstart.py.
Each file is claimed by the first loader that accepts it. Default order:
code, text, pypdf, image, audio, video, dlt_csv, csv, unstructured,
advanced_pdf, docling. Names: text_loader, code_loader, csv_loader,
dlt_csv_loader, pypdf_loader, image_loader, audio_loader,
video_loader, unstructured_loader, advanced_pdf_loader,
docling_loader, beautiful_soup_loader.
# Treat a code file as a plain document (chunking + LLM extraction):
await cognee.remember("./script.py", preferred_loaders={"text_loader": {}})Office formats (DOCX, PPTX, …) need the docs (unstructured) or docling
extra. A preferred loader that is not installed is skipped with only an info
log, so check the extra is installed when a file comes out wrong.
dry_run=True returns a token and cost estimate without ingesting anything
or calling the LLM. It excludes the calls improve() makes. Not supported
with GLiNER, sessions, or a remote instance.
dry_run="presort" on a folder returns a PresortReport (junk, duplicates,
version candidates, possible personal data, proposed dataset groups). Apply
it with await cognee.remember(report), or pass auto_apply=True.
extractor="gliner" builds the graph and summaries with a local GLiNER2
model, with no LLM call (embeddings still run). Install
pip install "cognee[gliner]"; the model (about 750 MB) downloads on first use.
It cannot be combined with a custom graph_model, dry_run,
session_id, or a remote instance.
For production: the open-source GLiNER extractor is a demo. cognee's enterprise GLiNER extraction is more accurate and covers more labels. The same goes for the Postgres graph adapter (
postgres_demo). Contact social@cognee.ai.
Unknown keyword arguments raise. remember() forwards kwargs through
a fixed allow-list and raises TypeError: Unexpected keyword arguments
for anything else. These real options are not on it yet:
| Option | Workaround through remember() |
|---|---|
ontology_file_path | config={"ontology_config": ...} or ONTOLOGY_FILE_PATH (above) |
functional_relationships, chunk_attachment | None yet. Only cognee.cognify() accepts them. |
extraction_rules | Pass it through the loader: preferred_loaders={"beautiful_soup_loader": {"extraction_rules": {...}}} (works in remember() and add()). Needs the scraping extra: without it the loader is not registered and the rules are silently ignored |
tavily_config, soup_crawler_config | Not honoured by add() or remember(); only the cognee/tasks/web_scraper tasks use them |
column_value_columns (dlt) | None yet. Only cognee.add() accepts it. |
If a user needs one with no workaround, say so plainly: the option exists
on the lower-level add() / cognify() but not on remember() yet.
Changed files raise DocumentUpdateRequiredError. Re-remembering the
same path (or the same filename for an upload) with different content is
an update, not a new document. Use
cognee.update(data_id=..., data=..., dataset_id=...), which re-extracts
only the changed chunks and keeps the document's id. Identical content is
a no-op.
content_type is strict. Only None, "skills", or "code".
"code" rejects session_id and needs repository paths or git URLs;
"skills" ingests into the target dataset like any other call (default
main_dataset); pass dataset_name to keep skills in their own dataset.
Session mode needs CACHING=true, and extractor cannot be combined
with session_id.
Remote mode. After cognee.serve(url), calls go to the server:
extractor and session_ids raise, and other options the client does not
forward (including graph_model, node_set, and ontology config) are
dropped without an error.
Every remember runs improve() unless self_improvement=False or
IMPROVE_AUTO_ENABLED=false. In scripts, call
await cognee.wait_for_background_tasks() before exiting.
remember(data) runs add() (store raw data and create Data rows), then
cognify() (classify documents, chunk, extract the graph and summaries,
store in graph and vector DBs), then improve(). remember(data, session_id=...) writes to the session cache instead.
cognee/api/v1/remember/remember.py
(RememberKwargs, _ADD_ONLY / _COGNIFY_ONLY / _SHARED)cognee/api/v1/add/add.py, cognee/tasks/ingestion/ingest_data.pycognee/api/v1/cognify/cognify.py,
cognee/tasks/graph/extract_graph_from_data.py,
cognee/tasks/storage/add_data_points.pycognee/modules/cognify/config.py:resolve_extractor;
GLiNER package: cognee/tasks/graph/gliner_demo/cognee/modules/ontology/cognee/infrastructure/loaders/ (supported_loaders.py,
LoaderEngine.py)cognee/tasks/ingestion/resolve_dlt_sources.pyExamples in examples/guides/: simple_cognee_example.py,
nodeset_grouping_example.py, ontology_quickstart.py,
gliner_demo_llm_free_cognify.py, no_llm_remember_recall.py,
temporal_recall.py, presort_downloads.py,
web_url_content_ingestion_example.py, code_graph_example.py.
RememberKwargs and to the matching
routing set in remember.py. An option on add()/cognify() that is not
in a routing set raises TypeError from remember().LoaderInterface
(cognee/infrastructure/loaders/LoaderInterface.py), register it in
supported_loaders.py (extras-gated loaders go under external/), and
add it to the priority list in LoaderEngine.py if it should run by
default.cognee-custom-pipelines skill and
cognee/tasks/README.md.© topoteretes, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .agents/skills/cognee-ingestion of topoteretes/cognee.
Open the folder on GitHubat commit 0ec7a9f
Cognee Data Ingestion next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Cognee Data Ingestion this skilltopoteretes/cognee | 32k | — | ~2.6k | Automated safety check: Notes | Apache-2.0 | |
| Cortexdb Memory Hermesliliang-cn/cortexdb | 274 | — | ~1.7k | Automated safety check: Pass | MIT | |
| Neo4j Graphrag Skillneo4j-contrib/neo4j-skills | 114 | — | ~4.2k | Automated safety check: Notes | MIT | |
| Hermes Memory Providersmnemosyne-oss/mnemosyne | 3.4k | — | ~1.8k | Automated safety check: Pass | MIT | |
| Neo4j Genai Plugin Skillneo4j-contrib/neo4j-skills | 114 | — | ~3k | Automated safety check: Notes | MIT | |
| Cortexdb Memory Openclawliliang-cn/cortexdb | 274 | — | ~1.6k | Automated safety check: Pass | MIT |
liliang-cn/cortexdb
Give a Python agent (such as Hermes Agent by Nous Research) durable, local-first memory plus a queryable SPARQL knowledge graph, backed by CortexDB through its gRPC sidecar and the cortexdb-client…
neo4j-contrib/neo4j-skills
Build GraphRAG retrieval pipelines on Neo4j using the neo4j-graphrag Python package (v1.22.0+).
mnemosyne-oss/mnemosyne
Install and configure Mnemosyne as a Hermes Agent memory provider — local SQLite with vector search, episodic consolidation, and temporal knowledge graphs.
neo4j-contrib/neo4j-skills
Use Neo4j GenAI Plugin ai.text. An agent skill from neo4j-contrib/neo4j-skills.
liliang-cn/cortexdb
Give a Node.js agent (such as OpenClaw) durable, local-first memory plus a queryable SPARQL knowledge graph, backed by CortexDB through its gRPC sidecar and the cortexdb-client npm package.
simbajigege/book2skills
A developer guide to adding compact memory to an agent: when to trigger compaction, how to fork a compactor sub-agent, what the summary holds, and how to restore it.
topoteretes/cognee
Drives cognee from the terminal with remember, recall, forget and improve memory commands, dataset and config management and database migrations.
topoteretes/cognee
Guide to using and contributing cognee community packages: database adapters, data-source connectors, custom tasks and retrievers, and Keywords AI observability.
topoteretes/cognee
Defines the shape of cognee's knowledge graph with graph_model: DataPoint node classes, identity and index fields, typed edges and fixes for duplicated nodes.
topoteretes/cognee
Shows how to write custom cognee tasks, chain them into pipelines, store custom DataPoints and run enrichment over the existing graph.
topoteretes/cognee
Runs the Cognee AI memory platform in Docker, from a one-file prebuilt image to a full compose stack with UI, MCP server, Postgres and Neo4j.
topoteretes/cognee
Removes data from cognee memory with forget(), finding the right dataset and document first and choosing between one document, a dataset or only the graph and vector memory.
Works with
Categories
Explains how to load text, files, folders, URLs, repositories and databases into cognee memory with remember(), including datasets, extractors and tags. This skill covers cognee's remember() call, the single ingestion entry point that stores data, builds a knowledge graph from it and enriches the graph.md playbooks.
Cognee Data Ingestion fits situations like: loading documents, folders or URLs into cognee memory; indexing a code repository or a SQL database through remember(); choosing between the LLM and GLiNER graph extractors; tagging data with node sets or splitting it across datasets.
Run `npx skills add topoteretes/cognee --skill cognee-ingestion -a claude-code`. Or copy the skill folder (.agents/skills/cognee-ingestion in topoteretes/cognee) into .claude/skills/cognee-ingestion in your project. Claude Code loads it when a task matches its description.
Run `npx skills add topoteretes/cognee --skill cognee-ingestion -a codex`. Or copy the skill folder (.agents/skills/cognee-ingestion in topoteretes/cognee) into .agents/skills/cognee-ingestion in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add topoteretes/cognee --skill cognee-ingestion -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/cognee-ingestion, .gemini/skills/cognee-ingestion, .github/skills/cognee-ingestion and .opencode/skills/cognee-ingestion in your project.
Going by SKILL.md and its folder, Cognee Data Ingestion needs the command-line tools its instructions call (pip) and credentials named LLM_API_KEY. Our summary lists: Python with the cognee package; An LLM_API_KEY unless using the GLiNER extractor; git on PATH when ingesting code repositories.
SKILL.md contains no URLs. Its commands use pip, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.
Cognee Data Ingestion is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 2.6k tokens (SKILL.md is roughly 11k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Cognee Data Ingestion: Cortexdb Memory Hermes (liliang-cn/cortexdb, 274 stars), Neo4j Graphrag Skill (neo4j-contrib/neo4j-skills, 114 stars), Hermes Memory Providers (mnemosyne-oss/mnemosyne, 3.4k stars) and Neo4j Genai Plugin Skill (neo4j-contrib/neo4j-skills, 114 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
topoteretes (a GitHub organization) maintains it in topoteretes/cognee, which has 31,919 GitHub stars. The repository holds 19 skills in this directory. The repository was last updated on October 9, 2026.
Source: topoteretes/cognee on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.