Why Use This Integration
- Zero code: Install, run
hermes memory setup cognee, and memory works automatically - Two memory tiers: Turns land in a session cache, then
improve()promotes them into the permanent graph - Three connection modes: Remote/cloud (setup’s default), a local server run from a private Cognee runtime, or in-process embedded
- Resilient: Built-in circuit breaker prevents cascading failures when Cognee is unreachable
Installation
Install the plugin from the Hermes plugin catalog (recommended), then run the setup in a terminal:memory.provider, and hermes memory setup cognee is what selects it. hermes plugins enable cognee and the plugin toggle in Hermes Desktop enable the plugin but do not select it, so after either one hermes memory status still shows Provider: (none).
Update a catalog install with hermes plugins update cognee. cognee-hermes-install refuses to overwrite a catalog-managed copy, and hermes cognee status and hermes cognee version point you at the catalog command instead of checking PyPI, even with --check-updates.
Or install from PyPI:
hermes_agent.memory_providers entry point; cognee-hermes-install adds the directory copy that carries the hermes cognee subcommands and the dashboard config panel. Update with pip install -U cognee-integration-hermes-agent followed by cognee-hermes-install — hermes cognee status tells you when the package and the copy have drifted.
For development, copy a checkout into a Hermes home that has no Cognee plugin installed:
Requires Python 3.10+ — note that macOS’s Xcode Command Line Tools ship Python 3.9, so use a Homebrew, python.org or uv-managed interpreter. The plugin declares no dependencies, so it installs on any Hermes: remote mode is plain HTTP and needs no
cognee package. Local mode runs its server from a private Cognee runtime (cognee==1.6.6) that the plugin installs only when you ask for it — see Local runtime.Quick Start
Run setup once, then run Hermes as usual — memory is captured and recalled automatically:hermes session) after setup. Check with hermes memory status (Provider: cognee) and hermes cognee status (mode, dataset, service URL, the recall mode in effect, and a Local runtime line).
During a session, just talk to the agent:
COGNEE_IMPROVE_ON_END=true (the default), cognee.improve(...) runs to promote the session cache into the permanent graph.
Connection Modes
The plugin connects to Cognee in one of three modes. There are no silent fallbacks — if the configured mode fails, the failure surfaces.hermes memory setup cognee offers remote first and as the default; an install that chose local sees Current mode: local above the prompt, and must type local when re-running setup, since accepting the default switches it to remote. Choosing local clears COGNEE_BASE_URL and COGNEE_API_KEY, so a Cognee Cloud key is not sent to the local server.
The provider reports itself available with a service URL (remote), or once the local runtime is ready (local); it does not need LLM_API_KEY. When it is unavailable, Hermes starts the chat with its built-in memory only and its warning names the fix (hermes cognee install-runtime, or, in embedded mode, the embedded-mode wording when cognee is not in Hermes’s environment and, when it is older than the pin, the version it found and the command that upgrades it, <python> -m pip install cognee==1.6.6, or turning embedded mode off; the runtime venv never counts for embedded mode, so install-runtime does not help it).
Local runtime
Local mode never puts cognee into Hermes’s environment, where its pins conflict with Hermes extras. Instead the plugin installscognee==1.6.6 into a venv of its own, ~/.cognee-plugin/hermes/runtime/venv (about 1 GB from PyPI), built from the interpreter running Hermes — with uv when it is on your PATH, otherwise with stdlib venv and pip. Nothing is downloaded when a session starts: hermes memory setup cognee offers the install when you choose local, and you can manage it on its own:
hermes cognee install-runtime: the plugin never starts a server on a cognee it was not written against, and never downloads one behind your back. Hermes reports Cognee as unavailable with that command, and hermes cognee status shows the runtime as outdated. install-runtime upgrades the venv in place; a failed or interrupted install leaves local mode off rather than half-upgraded, and the next install-runtime repairs it. Once it has finished, start a new Hermes session.
install-runtime stops the local server this plugin started before it installs, so the venv is never upgraded under a running process. It finds that server by the pidfile the plugin writes when it starts one (~/.cognee-plugin/hermes/runtime/servers/<port>.pid, checked to still run cognee.api.client:app, so a reused pid is left alone), says which server it will stop, and asks Continue? (y/n) (default yes); without a terminal it goes ahead only with --yes. The setup wizard’s install question names the pid too. The server gets SIGTERM only, never SIGKILL, and up to 60 seconds to finish; one still running after that is left running and the install stops without changing anything. The server is shared, so other Cognee plugins using it (Claude Code, Codex, OpenClaw) start a new one on their next request. While install-runtime runs, a Hermes session that would start a server reports Cognee as unavailable instead.
If a cognee server the plugin cannot stop still answers on the local port and reports a cognee older than the pin, or no version at all (for example one started by plugin 1.4.2 or earlier, or by another plugin on an older cognee; on Windows the plugin stops nothing), install-runtime changes nothing and names the port, the version and, when lsof is installed, the pid to stop before you re-run it. A server on the pinned cognee or newer does not block the install.
At session start the plugin also reads the version the server on the local port reports on /health. If it is older than the pinned cognee (for example a 1.6.5 server another plugin started), Hermes reports Cognee as unavailable and names the port until that server is replaced. A server that reports no version is used.
Session start waits up to 90 seconds for the local server. If the server it started is alive but not answering yet — typically a first start migrating an existing ~/.cognee — the session starts anyway, Cognee’s tools answer that the server is still starting (pointing at ~/.cognee-plugin/hermes/server.log), and Cognee turns on in that session once the server is ready.
cognee 1.6.0 creates its default user only when the server starts with
DEFAULT_USER_PASSWORD set. The local server the plugin spawns sets it for you. If you run your own local server, start it with DEFAULT_USER_PASSWORD matching COGNEE_USER_PASSWORD, or set COGNEE_API_KEY; otherwise the login fails with This user does not have a password.Authentication
Cognee authenticates with its own credentials — Hermes’ model credentials are not reused. Everything Cognee does on its own — entity and relationship extraction, summarization, embeddings, and search-time completions — runs against the provider Cognee itself is configured with, billed by that provider. Cognee’s LLM layer authenticates by API key only: a host agent’s subscription or OAuth sign-in (for example a Codex-style ChatGPT login) cannot be handed to it, and Cognee’s own OAuth flows sign you in to Cognee Cloud or to data-source integrations such as Slack, never to an LLM provider. So in local or embedded mode Cognee uses your ownLLM_API_KEY even when your agent’s model is already signed in.
Which credentials you need depends on the connection mode:
Credentials come through Hermes only.
hermes memory setup cognee stores LLM_API_KEY, COGNEE_API_KEY and COGNEE_BASE_URL in the profile’s .env through Hermes’ own writer, and the plugin reads them back with Hermes’ get_secret, so a gateway serving several profiles hands each one its own keys. get_secret returns the active profile’s value and falls back to the environment unless a multi-profile gateway is routing the turn, so exported variables still work in a single-profile setup (on a Hermes without get_secret, the plugin reads the environment). The same goes for every other API key the local server uses (EMBEDDING_API_KEY, LLM_EXTRACTION_API_KEY, LLM_QUERY_API_KEY, LLM_SUMMARIZATION_API_KEY) and for COGNEE_USER_EMAIL / COGNEE_USER_PASSWORD, so put those in Hermes’ .env too. Non-secret settings such as LLM_PROVIDER, LLM_MODEL and LLM_ENDPOINT still come from the environment.
The local server the plugin spawns starts in ~/.cognee-plugin/hermes, so a .env in the directory you start Hermes from doesn’t reach it. It also starts with COGNEE_ENV_FILE pointing at an empty file of its own (~/.cognee-plugin/hermes/cognee-server.env), which stops Cognee’s upward .env search — so a .env above the plugin’s state directory, such as ~/.cognee-plugin/.env, does not override the keys and settings Hermes hands over. A COGNEE_ENV_FILE you set yourself still wins.
In local mode the plugin keeps no API key file: at each process’s first connect it logs in to the local server and reuses the key the server already has (creating one only when none exists), so it still lands on the same key as the other Cognee plugins. A configured COGNEE_API_KEY that the local server rejects with 401/403 (for example one left by an earlier remote setup) is replaced by the local server’s own key. If it starts the server without an LLM key, it logs a warning that Cognee will use local models, naming hermes memory setup cognee for adding a key.
Without an LLM key, cognee builds memory with local models — the GLiNER extractor for the graph and the fastembed BAAI/bge-small-en-v1.5 embedder — installed into the runtime and downloaded on the first graph build (about 1.5 GB). Recall then returns the stored text that matches rather than a generated answer. The embedder sticks to the store: adding an LLM key later switches the default embedder to OpenAI, which a keyless store refuses with EmbeddingDimensionMismatchError, so also set EMBEDDING_PROVIDER=fastembed and EMBEDDING_MODEL=BAAI/bge-small-en-v1.5, or start a new store (COGNEE_DATA_ROOT, COGNEE_SYSTEM_ROOT). A server shared by several profiles keeps the LLM key of the profile that started it, so profiles that must not share an LLM bill need their own COGNEE_LOCAL_PORT.
In local and embedded mode one LLM_API_KEY covers everything: Cognee defaults to openai/gpt-5.6-luna for the LLM and openai/text-embedding-3-large for embeddings, and embeddings reuse LLM_API_KEY when EMBEDDING_API_KEY is unset. For another provider, set LLM_PROVIDER, LLM_MODEL, and — for Azure, Ollama, or OpenAI-compatible endpoints — LLM_ENDPOINT, plus the matching EMBEDDING_* variables, with any API key among them in Hermes’ .env. See LLM providers and embedding providers.
Configuration
Set these as environment variables, or answer the prompts ofhermes memory setup cognee, which saves non-secret settings to $HERMES_HOME/cognee.json and secrets to $HERMES_HOME/.env. Values saved in $HERMES_HOME/cognee.json take precedence over environment variables, and hermes memory setup cognee always writes the mode and dataset there — so after running setup, change those by running setup again, not by exporting a variable. The one exception is the recall mode: an exported COGNEE_PLUGIN_RECALL_MODE overrides recall_mode in cognee.json, which setup always writes.
By default the plugin shares one brain with Cognee’s other agent plugins (Claude Code, Codex, OpenClaw): the same agent_sessions dataset, the same store under ~/.cognee, and the same local server on port 8011. Memory written in any of them is recalled in all of them. Set COGNEE_PLUGIN_DATASET to keep Hermes’s saves in a dataset of its own; recall stays on that dataset while no recall mode is set (see Recall mode).
Recall mode
On the default dataset, recall is auto: the per-prompt memory recall andcognee_recall name no dataset, and the server picks the best-matching one among those you can read. Routing needs a cognee 1.6.6 server; an older one searches every dataset you can read. Saves still go to the conversation’s dataset, and the guidance lane, cognee_code_search and recaps keep their datasets.
recall_mode / COGNEE_PLUGIN_RECALL_MODE sets it: auto lets the server pick, pinned keeps recall on the active dataset, and any other value means auto. Set it with the variable, recall_mode in cognee.json, or the recall-mode question hermes memory setup cognee asks. With no mode set, the default dataset is auto and a configured non-default dataset stays pinned, so a dataset chosen to keep agents or projects apart keeps recall apart too; setup offers pinned for such a dataset. A user in that last case gets a one-time line appended to the first reply of a session (once per machine and dataset) saying that Cognee can also pick the dataset, and how to turn that on; it is never stored with the answer. A conversation can override the configured mode with cognee_switch_dataset.
COGNEE_PLUGIN_DATASET=auto (any case) means the default dataset and says nothing about the recall mode.
Manage the plugin with
hermes cognee status, hermes cognee setup, hermes cognee config, hermes cognee install, hermes cognee install-runtime [--yes] / hermes cognee remove-runtime (the local-mode runtime), and hermes cognee version (plugin version and update availability). hermes cognee standup, hermes cognee digest and hermes cognee timeline <topic> print a recap of the sessions recorded into the configured dataset (--since, --projects, --all-sessions, --dataset, --json). hermes cognee index-repo <path-or-git-url> indexes a repository into a deterministic code graph (add --index-vectors to also embed code entities for semantic search, --dataset <name> to name the code dataset instead of the default codebase-<repo>-<digest> (dots in the repo name become -), and --wait <seconds> to wait for indexing to finish) and needs a Cognee server >= 1.5.4.hermes cognee keys list and hermes cognee keys revoke <key_id> --plugin <plugin> manage the API keys of your other Cognee plugin agents (Claude Code, Codex, …). Every machine a plugin runs on holds its own key for that plugin’s agent, and the server caps them, so an agent that is full refuses a new machine a key until an old machine’s key is revoked. keys list shows every plugin agent’s keys, most recently used first (never-used keys last), with their ids; narrow it with --plugin <plugin> (for example claude-code) or add --json. keys revoke needs the --plugin that holds the key. On a server without these key routes, such as cognee 1.6.5 and earlier, keys list reports no keys.Tools
The plugin exposes six tools to the agent:
In local server and remote mode,
cognee_remember asks the server to build the graph in the background, so it returns right away with status: "running" and the write finishes server-side. A slow or rate-limited LLM endpoint therefore no longer causes a timeout error for a write that actually lands. The flip side is that the new content isn’t recallable until that build finishes, and a build that fails server-side no longer shows up as an error in the tool result. In embedded mode the write runs in-process, as before.
cognee_forget never deletes on a single call. The agent first runs action="find" with terms describing what to forget, which returns candidate documents with previews to show you; only then does action="forget" with the confirmed data_ids and confirm=true delete exactly those documents. Clearing a whole dataset takes everything_in_dataset alongside confirm=true, and both deletions are irreversible.
cognee_switch_dataset refuses a switch to a name containing a space or a dot rather than rewriting it, and its error suggests the sanitized name (for example my_data for my.data). It also refuses the name auto.
The conversation’s own recall choice wins over the configured recall mode. action="pin" pins recall to the active dataset without starting a new session; a switch pins recall to its target, and a switch to the dataset already in use behaves as pin. action="auto" lets the server pick for that conversation, lifting a configured pin too (the result names it in lifted). reset returns to the configured dataset and recall mode. current reports the mode in effect and, when pinned, a reason: dataset_picked for the conversation’s own pin, configured_pin for the configured mode or a configured non-default dataset with no mode set. The results of current, pin, auto, switch and reset carry a message line for the agent to relay. A pin without a switch is stored as the mode only, so if the configured dataset later changes, the conversation is pinned to the new one.
cognee_recap and the matching hermes cognee commands build a standup (what was worked on and left open), a digest (sessions plus the lessons distilled into memory) or a dated timeline of one topic from the sessions Cognee recorded, grouped by the repository their edited files live in. A recap only covers sessions recorded into the active dataset, so on a shared server it never shows other users’ conversations; all_sessions adds other clients’ sessions in that dataset. It reads up to 2,500 of the newest sessions and says so when the server had more, and it lists the newest 25 of them (--max-sessions on the commands raises that). Recaps need the HTTP transport (local server or remote mode); in embedded mode they fail.
Set COGNEE_DATASET_SWITCH_TOOL=false, COGNEE_CODE_SEARCH_TOOL=false or COGNEE_RECAP_TOOL=false to withhold any of the last three tools; all are exposed by default.
How It Works
- Prefetch: Before each turn, a background recall requests the knowledge graph and the session’s guidance, plus a code-graph lookup when the query names indexed symbols
- Capture: Each completed turn is synced to the session cache automatically, and its tool calls are stored as traces under the capture policy (see the
COGNEE_CAPTURE_*settings in Configuration). After redaction, each side of a turn is capped at 8,000 characters, tool arguments at 4,000 and tool results at 8,000. Tool traces need the HTTP transport (local server or remote mode); embedded mode stores the turns only - Promote: At session end (with
COGNEE_IMPROVE_ON_END=true),cognee.improve(session_ids=[...])promotes the session cache into the permanent graph. Hermes also compresses long conversations, and before each compression the plugin starts the same improve on a background thread. That way, turns that get compressed away still reach the graph even if the session never closes cleanly. Compression never waits for this improve. A failure is only logged as a warning, and no second improve starts while the previous one is still running. It follows the same conditions as the session-end improve (COGNEE_IMPROVE_ON_END, writes enabled, circuit breaker closed), and the session-end improve still runs. Either improve is skipped when nothing was stored for the session since the last one, so a session that ends right after a compaction, with nothing new stored, pays for one improve, not two. An improve the server refuses with 402 (its LLM budget is spent, cognee 1.6.3 and later) is logged and not retried, and doesn’t count toward the circuit breaker - Resilience: After repeated failures the provider trips a circuit breaker, pausing briefly before retrying so errors don’t cascade
COGNEE_RECALL_BUDGET, default 20 seconds), and none of them runs an LLM on the server:
- Memory: a graph-scope
HYBRID_COMPLETIONrecall withonly_context=true, sent without the session id so the answer doesn’t carry the conversation Hermes already has, and with no dataset while recall is auto (the active dataset when pinned). The plugin keeps only the retrieved context — the question template goes, passages recorded in this session go, each passage is capped atCOGNEE_RECALL_PASSAGE_CHARS, and entity lines that say nothing are pruned — and injects it as a<cognee_memory>block. Text it cannot parse (an older server’s bare context) is injected whole. - Guidance: a
session_contextrequest with the session id, against the active dataset, injected as<cognee_guidance>— the lessons the server distilled from this session. - Code: the code-graph lookup, when armed.
COGNEE_RECALL_CONTEXT_CHARS then caps the whole injection (guidance first, then memory, then code facts). A lane that fails or misses the deadline is dropped without costing the others. After three prompts in a row whose recall only timed out, each prompt first spends a 3-second /health probe and skips recall while the server doesn’t answer. Recall never searches the server’s raw session-cache scopes; turns are still written there for improve() to promote.
A turn or tool trace that never reached the server — the connection could not be opened (it was booting or down) or it answered 503 — is queued in ~/.cognee-plugin/hermes/pending-entries.json (newest 500, kept a week) and replayed after the next successful write, when a session starts, and before the pre-compress and session-end improves. While the circuit breaker is open, writes go straight to the queue. A write that timed out or was cut off mid-request is not replayed, since the server may already have stored it. The queue needs the HTTP transport (local server or remote mode); in embedded mode a failed write is dropped.
Memory credit
When an answer uses recalled memory, the agent ends it with one credit line, and the credit is stripped before the turn is stored in Cognee. Every recalled item the agent is given — the per-prompt memory block andcognee_recall results — is tagged m1, m2… with where it came from, numbered across the conversation; an instruction asks the agent to add the credit only when the answer used a tagged item. When the recall was auto, each item’s tag carries the dataset the server reports for it ([m1 · Cognee memory · dataset shop_support]), and the credit names the datasets of the items the answer used (“based on dataset shop_support and dataset returns”); when the server reports no dataset (an older server), the credit says “based on Cognee memory”. When recall is pinned, the credit names the dataset. How the line looks depends on where you chat:
- Hermes Desktop: the agent writes
> Cognee: <what it remembered>, based on dataset <name>., and the plugin replacesCognee:with the Cognee logo in brand purple and sets each credited dataset name in inline code. The rewritten answer is what Hermes keeps in its chat history. - Terminal chats (
hermes --tuiandhermes): the agent writes the line without theCognee:label, and the Cognee logo in braille is printed under it, readingCOGNEE based on <name> dataset(“a and b datasets” for several); a line crediting only “Cognee memory” keeps the logo alone. In the classic chat the logo follows the answer’s closing line with no blank lines in between. Withdisplay.streamingoff in the classic chat, the logo replaces the quote marker instead, with the sentence beside it. - Messaging apps: the plain
> Cognee: …line.
COGNEE_PLUGIN_CITE_MEMORY=off to turn it off.
GitHub Repository
View source code and examples
Hermes Agent
Learn about Hermes Agent