Backfill years of coding-assistant history into durable, local-first memory.
Keep the projects, tasks, investigations, decisions, fixes, workflows, and gotchas. Leave the junk behind.
Quick start · How it works · Technical wiki · Connector roadmap
Agent-memory systems are built to remember what happens next. Mainstream tools capture new conversations after installation, but do not ship a practical end-to-end mechanism for backfilling years of existing coding-assistant history. Your new memory layer starts empty while the decisions and fixes that matter remain trapped in old session databases.
cognee-backfill fills that gap. It converts existing assistant history into
a compact Cognee knowledge graph,
without blindly embedding every message.
Coding sessions routinely contain source code, filesystem paths, internal URLs, shell output, credentials, customer context, and unfinished ideas. Shipping a multi-gigabyte history through hosted AI APIs sends all of that into big-tech infrastructure with retention, logging, and downstream data practices you may not control.
This pipeline keeps the source database, distillation model, embedding model, graph, vectors, and metadata on your machine by default. Your history does not leave the machine unless you deliberately point the configuration at a remote endpoint.
Each session is distilled locally; only durable knowledge is passed to Cognee for graph extraction, embeddings, and recall.
Current connector: OpenCode SQLite history. The pipeline is designed for additional connectors, including Claude Code, Cursor, Cline, and generic JSONL exports.
flowchart TB
subgraph prepare[1. Private source preparation]
direction LR
source[(Assistant<br/>history)]
extract[Read-only<br/>connector]
scrub[Normalize, bound<br/>and scrub secrets]
source --> extract --> scrub
end
subgraph distill[2. Distill and checkpoint]
direction LR
llm[Local LLM<br/>distillation]
gate{Worth<br/>keeping?}
notes[(Persisted<br/>Markdown notes)]
junk[Junk skipped]
llm --> gate
gate -->|Yes| notes
gate -->|No| junk
end
subgraph remember[3. Build durable local memory]
direction LR
ingest[Idempotent<br/>batched add]
cognify[One bounded<br/>Cognify run]
entities[Entities and<br/>relationships]
vectors[Local<br/>embeddings]
stores[(Kuzu + LanceDB<br/>+ SQLite)]
ingest --> cognify --> entities --> vectors --> stores
end
recall[Graph and<br/>hybrid recall]
scrub --> llm
notes --> ingest
stores --> recall
Cognee preserves chunks and extracts a graph, but extraction is chunk-local. A coding session often spreads its outcome across user prompts, tool calls, failures, retries, and a final response. Distillation creates one coherent session-level document before graph extraction.
An end-to-end comparison on four representative sessions found that direct
conversation ingestion was 3.2x slower and answered only 3 of 8 factual checks
fully correctly; distilled notes answered all 8. Preserving tool activity made
direct ingestion roughly 38x slower. The normalized model input is therefore
retained in var/transcripts/ for audit, while the compact note is indexed.
| Naive transcript indexing | cognee-backfill |
|---|---|
| Embeds greetings, false starts, and log dumps | Keeps decisions, fixes, patterns, and project context |
| Lets tool output dominate retrieval | Bounds every field and samples long sessions intelligently |
| Stores raw reasoning traces | Produces concise, structured knowledge notes |
| Reprocesses everything after interruption | Persists model inputs and notes for lossless resume |
| Launches one graph job per document | Adds in idempotent batches, then runs one bounded Cognify job |
| Risks sending secrets downstream | Scrubs common credentials before the LLM boundary |
- Python 3.10+
- Docker with Compose
- A local OpenAI-compatible inference server
- One chat model and one embedding model loaded
Tested with oMLX. Ollama, LM Studio, and vLLM work when their OpenAI-compatible endpoints accept the configured model IDs and request extensions.
git clone https://github.com/thomasmaerz/cognee-backfill.git
cd cognee-backfill
cp .env.example .env
# Edit .env: set LLM_API_KEY and confirm model IDs/endpoints.
docker compose up -d
curl -f http://localhost:8010/health| Service | URL |
|---|---|
| Cognee UI | http://localhost:3010 |
| Cognee API | http://localhost:8010 |
| Swagger API docs | http://localhost:8010/docs |
The bundled UI uses the local-development credentials
default_user@example.com / default_password. Keep this stack bound to
localhost unless you replace that development posture.
export LLM_BASE_URL=http://127.0.0.1:8000
export LLM_API_KEY='your-local-server-key'
python3 backfill.py --stats
# Test only three sessions in an isolated dataset.
python3 backfill.py \
--limit 3 \
--dataset kb_smoke \
--recall "What durable decisions appear in these sessions?"Review var/transcripts/ and var/distilled/, then delete the smoke dataset
before starting the complete run. Cognee content hashes make later re-adds
idempotent; local distillation state is not tied to one dataset.
On macOS, install it as a launchd user service. The service starts Cognee, resumes from persisted artifacts, restarts after failures, and exits permanently after a successful backfill:
chmod +x service/*.sh
./service/install-launchd.sh
launchctl print gui/$(id -u)/com.thomasmaerz.cognee-backfill
tail -f var/log/backfill.out.logManual and non-macOS execution remains available:
python3 backfill.py --dataset knowledge_base --improveStop and restart the service or manual command at any time. Normalized model
inputs are persisted to var/transcripts/<session-id>.md; accepted notes are
persisted to var/distilled/<session-id>.md; progress.json records only
distillation state. Cognee owns content deduplication and processing status.
Every skipped source ID remains in progress.json and in the review-friendly
var/skipped.json manifest. Re-evaluate them later with:
python3 backfill.py --dataset knowledge_base --reparse-skippedAfter Cognee reports that all documents completed processing:
python3 backfill.py \
--dataset knowledge_base \
--improve \
--recall \
"Which authentication decisions were made?" \
"Which recurring failures have known fixes?"See the Operations guide for monitoring, backups, cleanup, and verification criteria.
| Guarantee | Implementation |
|---|---|
| Source isolation | SQLite is opened with mode=ro; connectors never mutate history |
| Resume safety | Model inputs and notes reach disk before their state becomes distilled |
| Deterministic chronology | Sessions are prepared oldest-first with stable ID tie-breaking |
| Bounded backend load | Batched add is followed by one Cognify run with explicit concurrency |
| Backend idempotency | Cognee content hashes and per-item pipeline status make reruns safe |
| Conservative junk filtering | Work history is retained even without a decision; only empty handshakes, pings, and sessions with no meaningful activity are discarded |
| Retryable failures | Distillation and submission errors remain eligible for retry |
| Secret defense-in-depth | Common keys, tokens, passwords, and private-key markers are redacted |
| Local-first execution | LLM, embeddings, graph, vectors, and metadata can stay on one machine |
The connector and Cognee use the same local OpenAI-compatible server by default, but route their requests independently:
flowchart TB
connector[Python connector] -->|LLM_BASE_URL| distillModel[Distillation model]
cognee[Cognee container] -->|LLM_DOCKER_ENDPOINT| graphModel[Structured extraction model]
cognee -->|LLM_DOCKER_ENDPOINT| embedModel[Embedding model]
distillModel --> server[Local inference server]
graphModel --> server
embedModel --> server
Reasoning-capable Qwen models require a hard thinking-mode switch for reliable
schema output. The connector sends
chat_template_kwargs.enable_thinking=false, while Cognee forwards the same
setting through LLM_ARGS. Read the
thinking-preamble guide
before changing model families.
| Variable / flag | Default | Purpose |
|---|---|---|
LLM_BASE_URL |
http://127.0.0.1:8000 |
Inference server as seen by the connector |
LLM_DOCKER_ENDPOINT |
http://host.docker.internal:8000/v1 |
Same server as seen by Cognee |
LLM_API_KEY |
none | Local server bearer token |
DISTILL_MODEL / --model |
Qwen3.6-35B-A3B MLX alias | Session distillation model |
DISABLE_THINKING |
true |
Send the Qwen-compatible hard switch |
COGNEE_API_URL |
http://localhost:8010 |
Cognee API endpoint |
OPENCODE_DB |
~/.local/share/opencode/opencode.db |
Read-only OpenCode source |
--concurrency |
4 |
Parallel distillation workers |
--add-batch-size |
100 |
Documents per idempotent Add request |
--data-per-batch |
4 |
Documents Cognee processes concurrently |
--chunks-per-batch |
12 |
Chunks per Cognee task batch |
--limit, --offset |
unset | Smoke testing and manual sharding |
--reparse-skipped |
off | Re-evaluate every session currently classified as junk |
--reparse-all |
off | Re-distill every retained session |
--reparse-all changes document hashes. Use a new empty dataset, or delete the
existing target dataset first, so old and replacement notes cannot coexist.
The complete model, embedding, and structured-output matrix lives in Configuration.
| Connector | Status | Source format |
|---|---|---|
| OpenCode | ✅ Available | session / message / part SQLite tables |
| Claude Code | 🛠 Planned | ~/.claude/projects/ JSONL |
| Cursor / Windsurf | 🛠 Planned | Agent transcript exports |
| Cline / Continue | 🛠 Planned | Extension storage / exports |
| Generic JSONL | 🛠 Planned | Normalized external ETL format |
Every connector follows the same contract:
extract oldest-first -> normalize, scrub, and persist -> distill -> batched add -> one cognify
See Adding a connector for the interface, fixtures, invariants, and acceptance criteria.
Historical ingestion and ongoing memory are separate concerns. After the backfill, Cognee's OpenCode plugin can capture new sessions and bridge them into the same dataset:
{
"plugin": [
[
"file:/path/to/cognee-opencode",
{
"baseUrl": "http://localhost:8010",
"datasetName": "knowledge_base"
}
]
]
}Build the plugin from
topoteretes/cognee-integrations,
then restart OpenCode.
| Guide | Covers |
|---|---|
| Architecture | Data flow, state machine, storage, and failure boundaries |
| Configuration | Models, embeddings, ports, concurrency, and persistence |
| Operations | Smoke tests, launch, monitoring, pause/resume, backup, cleanup |
| OpenCode connector | Source schema, transcript reconstruction, and known limits |
| Adding a connector | Adapter contract and quality gates for future sources |
| Thinking preamble | Safe structured extraction with reasoning-capable models |
| Security and privacy | Source isolation, scrubbing, network boundaries, retention |
Session history is sensitive. Keep the inference server, Cognee API, and UI local unless you add authentication, TLS, explicit CORS origins, and firewall controls. Regex scrubbing is defense-in-depth, not a complete DLP system.
Read Security and privacy before processing regulated or organization-confidential data.
MIT. See LICENSE. Cognee is licensed separately under Apache-2.0.