Cognee Memory for SillyTavern


DOWNLOAD v1.2

Friendly reminder to always check unknown extensions for keygrabbers and other nasties.

but don't worry, it's vibeslopped with fable, so it's s a f e

v1.1 - bugfixes and qol, improved default .env
v1.2 - fixed Graph Reasoning synthesis


Long-term memory for your chats, backed by cognee. The extension pushes your chat history into a self-hosted cognee knowledge graph and pulls relevant memories back into the prompt before every generation. Memories persist across chats: start a new chat with the same character and it still knows what happened.

How it works:

  • Every N messages (default 10), the new chat messages get sent to cognee (add + cognify), which extracts entities and relationships into a knowledge graph
  • Before every generation, the last few messages are used as a query against that graph, and the results are injected into the prompt
  • One dataset per character by default, so all chats with a character share one memory

Braindead setup with OpenRouter

You need: Docker, an OpenRouter API key, SillyTavern (recent release).

1. Start the cognee server

Make a folder anywhere, put a file named .env in it:

LLM_PROVIDER=custom
LLM_MODEL=openrouter/google/gemini-3.5-flash
LLM_ENDPOINT=https://openrouter.ai/api/v1
LLM_API_KEY=sk-or-v1-YOUR-KEY-HERE

EMBEDDING_PROVIDER=fastembed
EMBEDDING_MODEL=BAAI/bge-small-en-v1.5
EMBEDDING_DIMENSIONS=384
EMBEDDING_MAX_TOKENS=512

REQUIRE_AUTHENTICATION=false
ENABLE_BACKEND_ACCESS_CONTROL=false

Three rules baked into that file:

  • No quotes anywhere. Docker's --env-file does not strip quotes like a shell does; quoted values are passed through literally ("384" including the quote characters) and cognee's config validation will reject them.
  • The openrouter/ prefix on the model is mandatory. LiteLLM routes by the first path segment: anthropic/claude-... goes to the native Anthropic API (and 404s against OpenRouter with a cryptic AnthropicException), openrouter/anthropic/claude-... goes where you want. Whatever the model is called on OpenRouter, prepend openrouter/.
  • The two auth lines are required. Without them the API demands a login token and every add fails with 401. Fine for a localhost-only server; do not expose this port to the internet in this mode.

Why fastembed: OpenRouter only serves chat completions, not embeddings. fastembed runs a small embedding model locally inside the container, so the whole stack needs exactly one API key.

There are alternatives to the default embedding model:
Within fastembed (change two env lines, done):

  • nomic-ai/nomic-embed-text-v1.5, 768 dim, 0.52GB, with a quantized -Q variant at 0.13GB. Long-context (8k), noticeably stronger, chunks of chat log fit whole. Needs EMBEDDING_DIMENSIONS=768.
  • mixedbread-ai/mxbai-embed-large-v1, 1024 dim, 0.64GB is the quality ceiling of the catalog if you don't mind the size.

Model choice: cognee makes a lot of structured-output extraction calls during cognify. Cheap and reliable picks on OpenRouter: google/gemini-2.5-flash, openai/gpt-4.1-mini, deepseek/deepseek-chat. Claude-class models work great but the cognify meter runs noticeably hotter. Avoid tiny models, they choke on the JSON extraction.

The prebuilt cognee/cognee:main image needs two patches: it ships without the fastembed extra, and it doesn't send CORS headers, which blocks a browser extension from talking to it. Put a file named Dockerfile next to the .env:

1
2
3
4
FROM cognee/cognee:main
USER root
RUN /app/.venv/bin/python -m ensurepip && /app/.venv/bin/python -m pip install fastembed
RUN printf 'from cognee.api.client import app\nfrom starlette.middleware.cors import CORSMiddleware\napp.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])\n' > /app/cors_app.py    && sed -i 's/cognee\.api\.client:app/cors_app:app/g' /app/entrypoint.sh

Then, from that folder:

docker build -t cognee-fastembed .
docker run --env-file ./.env -p 9876:8000 --name cognee --restart unless-stopped -d cognee-fastembed

Port 9876 on purpose: SillyTavern already sits on 8000. Don't map cognee to 8000. --restart unless-stopped makes it come back on its own after reboots. To update cognee later: docker pull cognee/cognee:main, rebuild the image, recreate the container.

Check it's alive: open http://localhost:9876/health in a browser. First boot takes a while (it downloads the embedding model); wait for "status":"ready" before judging it.

Changing anything in .env later? docker rm -f cognee and rerun the docker run line. The env is baked in at container creation; docker restart does not reload it.

2. Install the extension

Download the zip, extract it, drop the cognee-memory folder into

SillyTavern/data/default-user/extensions/cognee-memory/

(older installs: SillyTavern/public/scripts/extensions/third-party/cognee-memory/) so that manifest.json sits directly in that folder, then reload the ST page.

3. Configure

Extensions panel → Cognee Memory:

  1. Endpoint URL: http://localhost:9876
  2. Authentication: None
  3. Hit Test connection. Green = done.

That's it. Chat normally. Every 10 messages the extension ships the log to cognee and rebuilds the graph in the background. Use Memorize now to force a flush (do this before closing a chat you care about).

Keeping memory from hijacking your scenes

Retrieved memory that reads like transcript gets treated like transcript: the model will happily continue an old scene instead of the current one. The defaults are tuned against this, but know the knobs:

  • Search type is the big one. SUMMARIES (default) returns distilled prose from the graph. INSIGHTS returns terse graph facts ("X trusts Y", "Z located in the old mill"), the least suggestive format. CHUNKS returns verbatim transcript slices and is the mode that causes scene hijacking; use it only for non-RP retrieval.
  • Keep the template's framing. The default wraps memories in an explicit "these are PAST events, never continue them" instruction. If you customize it, keep something to that effect.
  • Top K 2-3 if memory still feels pushy; five blocks of the past is a lot of gravitational pull.
  • Depth 4-6, or position "Before main prompt" to file memories with the character card as lore instead of near the recent conversation.
  • GRAPH_COMPLETION synthesized is the nuclear option: cognee's own LLM writes a fresh summary of relevant memory for every generation. Cleanest output, but adds one LLM call of latency and cost before each reply.

Part of the effect is self-recall: the current chat's own memorized past scores highest against a query built from the current chat. SUMMARIES/INSIGHTS blunt it; "Separate dataset per chat" removes it entirely at the price of no cross-chat memory.

Settings worth knowing

Setting What it does
Flush every N messages Batch size before auto-memorize triggers. Bigger = fewer cognify runs = cheaper, but memory lags behind
Separate dataset per chat Isolates memory per chat instead of per character
Search type See section above. SUMMARIES default; completion types are queried with only_context so cognee never generates text itself, except the explicit synthesized mode
Top K How many memory snippets get injected
Position / Depth / Role Where the memory block lands in the prompt. Default: in-chat at depth 2 as system
Template Wrapper around the injected memories, {{memories}} is the placeholder

Slash commands

  • /cognee-sync - force-flush pending messages into memory
  • /cognee-recall your question here - query the memory directly, returns raw results

Troubleshooting

"Connection failed: Failed to fetch" / CORS errors in the browser console: you're running the stock cognee/cognee:main image instead of the patched one. Build the Dockerfile from step 1; the CORS patch in it is what lets a browser extension talk to the server. Do not try to route around this with SillyTavern's CORS proxy (enableCorsProxy): it forwards JSON fine but mangles multipart/form-data, so /health and search will work while every memorize fails with 400 There was an error parsing the body. The patched image is the only path that works end to end.

"add failed: 401 Unauthorized": the REQUIRE_AUTHENTICATION=false and ENABLE_BACKEND_ACCESS_CONTROL=false lines are missing from your .env (or you edited .env and only restarted instead of recreating the container). Alternatively, run with auth on purpose: log in via POST /api/v1/auth/login, paste the access_token with auth mode Bearer, and set a long JWT_LIFETIME_SECONDS in .env so the token doesn't expire hourly.

500 with AnthropicException and an OpenRouter 404 page in the error: your LLM_MODEL is missing the openrouter/ prefix, so LiteLLM called the wrong API. See the model rule in step 1.

ValidationError ... unable to parse string as an integer, input_value='"384"': you have quotes in the .env. Remove all of them and recreate the container.

Memorize hangs on "Building knowledge graph": cognify is genuinely slow, it's making multiple LLM calls per chunk. A 10-message batch typically takes 15-60 s depending on the model. It runs async and doesn't block chatting.

429 / rate limits: OpenRouter free-tier models rate limit hard. Use a paid model or raise the batch size so cognify runs less often.

Wrong/stale memories after editing messages: the extension tracks a committed-message cursor per chat. If you rewrite history, hit Purge dataset and then Memorize now to rebuild from scratch.

Cost note

Every cognify run burns LLM tokens (entity extraction per chunk). With gemini-2.5-flash that's fractions of a cent per batch. Recall with SUMMARIES, INSIGHTS, and CHUNKS is free; the context-only completion modes are retrieval only; GRAPH_COMPLETION synthesized costs one LLM call per generation.

Edit

Pub: 18 Jul 2026 03:54 UTC

Edit: 19 Jul 2026 23:14 UTC

Views: 375