# sqlite-graphrag
> Persistent memory for 27 AI agents in a single 25 MB Rust binary
27 AI agents. One 25 MB binary. Zero cloud calls. sqlite-graphrag gives every AI coding assistant a local, fast, private memory layer backed by a single SQLite file, with no Pinecone account, no OpenAI embedding bill, no Docker cluster to maintain. Sub-50ms recall. Graph-native retrieval. Deterministic JSON output ready for pipeline orchestration.
- Portuguese version available at [README.pt-BR.md](https://github.com/daniloaguiarbr/sqlite-graphrag/blob/main/README.pt-BR.md)
```bash
cargo install --locked sqlite-graphrag
```
## What is it?
### sqlite-graphrag delivers durable memory for AI agents
- Stores memories, entities and relationships inside a single SQLite file under 25 MB
- Embeds content locally via `fastembed` with the `multilingual-e5-small` model
- Combines FTS5 full-text search with `sqlite-vec` KNN into a hybrid Reciprocal Rank Fusion ranker
- Extracts an entity graph with typed edges for multi-hop recall across memories
- Preserves every edit through an immutable version history table for full audit
- Runs on Linux, macOS and Windows natively with zero external services required
## Why sqlite-graphrag?
### Differentiators against cloud RAG stacks
- Offline-first architecture eliminates OpenAI embeddings and Pinecone recurring fees
- Single-file SQLite storage replaces Docker clusters of vector databases entirely
- Graph-native retrieval beats pure vector RAG on multi-hop questions by design
- Deterministic JSON output unlocks clean orchestration by LLM agents in pipelines
- Native cross-platform binary ships without Python, Node or Docker dependencies
- Save 200 dollars per month by replacing Pinecone plus OpenAI embedding calls
- Drop retrieval latency from 800 ms in cloud vector DBs to 8 ms on local SSD
## Economy That Converts
### Numbers That Sell The Switch
- Cut tokens spent on RAG by up to 80 percent through graph traversal recall
- Reduce cold-start time from 12 seconds Docker boot to 90 ms single binary launch
- Avoid 4 hours weekly of cluster maintenance with a single-file zero-ops database
- Your proprietary data NEVER leaves the developer workstation or the CI runner
- Your compliance surface shrinks to one SQLite file under your own encryption
- Your audit trail lives in the `memory_versions` table with immutable history
## Quick Start
### Install and record your first memory in four commands
```bash
cargo install --locked sqlite-graphrag
sqlite-graphrag init
sqlite-graphrag remember --name onboarding-note --type user --description "first memory" --body "hello graphrag"
sqlite-graphrag recall "graphrag" --k 5 --json
```
- The flag `--locked` reuses the `Cargo.lock` shipped with the crate to prevent MSRV breakage
- Without `--locked` Cargo may resolve a patch release that requires a newer `rustc` than 1.88
## Superpowers for AI Agents
### First-class CLI contract for orchestration
- Every subcommand accepts `--json` producing deterministic stdout payloads
- Every invocation can stay stateless, while heavy embedding commands may also auto-start and reuse `sqlite-graphrag daemon` when needed
- Every write is idempotent through `--name` kebab-case uniqueness constraints
- Stdin accepts bodies or JSON payloads for entities and relationship batches
- Stderr carries tracing output under `SQLITE_GRAPHRAG_LOG_LEVEL=debug` only
- Cross-platform behavior is identical across Linux, macOS and Windows hosts
## Compatible Agents and Orchestrators
### Catalog — 21 Supported Integrations
| Agent | Vendor | Minimum Version | Integration Type | Example |
| --- | --- | --- | --- | --- |
| Claude Code | Anthropic | 1.0+ | Subprocess | `sqlite-graphrag recall "query" --json` |
| Codex CLI | OpenAI | 0.5+ | AGENTS.md + subprocess | `sqlite-graphrag remember --name X --type user --description "..." --body "..."` |
| Gemini CLI | Google | any recent | Subprocess | `sqlite-graphrag hybrid-search "query" --json --k 5` |
| Opencode | open source | any recent | Subprocess | `sqlite-graphrag recall "auth flow" --json --k 3` |
| OpenClaw | community | any recent | Subprocess | `sqlite-graphrag list --type user --json` |
| Paperclip | community | any recent | Subprocess | `sqlite-graphrag read --name onboarding-note --json` |
| VS Code Copilot | Microsoft | 1.90+ | tasks.json | `{"command": "sqlite-graphrag", "args": ["recall", "$selection", "--json"]}` |
| Google Antigravity | Google | any recent | Runner | `sqlite-graphrag hybrid-search "prompt" --k 10 --json` |
| Windsurf | Codeium | any recent | Terminal | `sqlite-graphrag recall "refactor plan" --json` |
| Cursor | Cursor | 0.40+ | Terminal | `sqlite-graphrag remember --name cursor-ctx --type project --description "..." --body "..."` |
| Zed | Zed Industries | any recent | Assistant Panel | `sqlite-graphrag recall "open tabs" --json --k 5` |
| Aider | open source | 0.60+ | Shell | `sqlite-graphrag recall "refactor target" --k 5 --json` |
| Jules | Google Labs | preview | CI automation | `sqlite-graphrag stats --json` |
| Kilo Code | community | any recent | Subprocess | `sqlite-graphrag recall "recent tasks" --json` |
| Roo Code | community | any recent | Subprocess | `sqlite-graphrag hybrid-search "repo context" --json` |
| Cline | community | VS Code ext | Terminal | `sqlite-graphrag list --limit 20 --json` |
| Continue | open source | VS Code or JetBrains ext | Terminal | `sqlite-graphrag recall "docstring" --json` |
| Factory | Factory | any recent | API or subprocess | `sqlite-graphrag recall "pr context" --json` |
| Augment Code | Augment | any recent | IDE | `sqlite-graphrag hybrid-search "code review" --json` |
| JetBrains AI Assistant | JetBrains | 2024.2+ | IDE | `sqlite-graphrag recall "stacktrace" --json` |
| OpenRouter | OpenRouter | any | Router for multi-LLM | `sqlite-graphrag recall "routing rule" --json` |
## Commands
### Core database lifecycle
| Command | Arguments | Description |
| --- | --- | --- |
| `init` | `--namespace <ns>` | Initialize database and download embedding model |
| `health` | `--json` | Show database integrity and pragma status |
| `stats` | `--json` | Count memories, entities and relationships |
| `migrate` | `--json` | Apply pending schema migrations via `refinery` |
| `vacuum` | `--json` | Checkpoint WAL and reclaim disk space |
| `optimize` | `--json` | Run `PRAGMA optimize` to refresh statistics |
| `sync-safe-copy` | `--output <path>` | Checkpoint then copy a sync-safe snapshot |
### Memory content lifecycle
| Command | Arguments | Description |
| --- | --- | --- |
| `remember` | `--name`, `--type`, `--description`, `--body` | Save a memory with optional entity graph |
| `recall` | `<query>`, `--k`, `--type` | Search memories semantically via KNN |
| `read` | `--name <name>` | Fetch a memory by exact kebab-case name |
| `list` | `--type`, `--limit`, `--offset` | Paginate memories sorted by `updated_at` |
| `forget` | `--name <name>` | Soft-delete a memory preserving history |
| `rename` | `--old <name>`, `--new <name>` | Rename a memory while keeping versions |
| `edit` | `--name`, `--body`, `--description` | Edit body or description creating new version |
| `history` | `--name <name>` | List all versions of a memory |
| `restore` | `--name`, `--version` | Restore a memory to a previous version |
### Retrieval and graph
| Command | Arguments | Description |
| --- | --- | --- |
| `hybrid-search` | `<query>`, `--k`, `--rrf-k` | FTS5 plus vector fused via Reciprocal Rank Fusion |
| `link` | `--source`, `--target`, `--relation` | Create a typed edge between two memories |
| `unlink` | `--source`, `--target`, `--relation` | Remove a typed edge |
| `related` | `<name>`, `--hops` | Traverse the entity graph N hops from a memory |
| `namespace-detect` | `--namespace <name>` | Resolve namespace precedence for invocation |
### Graph Input Payloads
- `--entities-file` expects a JSON array of entities
- Each entity MUST include `name` and `entity_type`; alias `type` is accepted
- Agents MUST NOT send both `entity_type` and `type` in the same object
- Valid `entity_type` values: `project`, `tool`, `person`, `file`, `concept`, `incident`, `decision`, `memory`, `dashboard`, `issue_tracker`
- `--relationships-file` expects a JSON array of relationships
- Each relationship MUST include `source`, `target`, `relation`, and `strength`
- `strength` MUST be a float in `[0.0, 1.0]` and maps to `weight` in graph outputs
- File payload relations use underscore labels such as `applies_to`, `depends_on`, and `tracked_in`
- `link` and `unlink` flags use dashed labels such as `applies-to`, `depends-on`, and `tracked-in`
```json
[
{ "name": "SQLite", "entity_type": "tool" },
{ "name": "GraphRAG", "type": "concept" }
]
```
```json
[
{
"source": "SQLite",
"target": "GraphRAG",
"relation": "supports",
"strength": 0.8,
"description": "SQLite supports local GraphRAG retrieval"
}
]
```
### Maintenance
| Command | Arguments | Description |
| --- | --- | --- |
| `purge` | `--retention-days <n>`, `--dry-run`, `--yes` | Permanently delete soft-deleted memories |
## Environment Variables
### Runtime configuration overrides
| Variable | Description | Default | Example |
| --- | --- | --- | --- |
| `SQLITE_GRAPHRAG_DB_PATH` | Path override for the SQLite database file | `./graphrag.sqlite` in the invocation directory | `/data/graphrag.sqlite` |
| `SQLITE_GRAPHRAG_CACHE_DIR` | Directory for embedding model cache | XDG cache dir | `~/.cache/sqlite-graphrag` |
| `SQLITE_GRAPHRAG_LANG` | CLI output language as `en` or `pt` | `en` | `pt` |
| `SQLITE_GRAPHRAG_LOG_LEVEL` | Tracing filter level for stderr output | `info` | `debug` |
| `SQLITE_GRAPHRAG_NAMESPACE` | Namespace override bypassing detection | none | `project-foo` |
## Integration Patterns
### Compose with Unix pipelines and tools
```bash
sqlite-graphrag recall "auth tests" --k 5 --json | jaq -r '.results[].name'
```
### Feed hybrid search into a summarizer endpoint
```bash
sqlite-graphrag hybrid-search "postgres migration" --k 10 --json \
| jaq -c '.results[] | {name, combined_score}' \
| xh POST http://localhost:8080/summarize
```
### Backup with atomic snapshot and compression
```bash
sqlite-graphrag sync-safe-copy --output /tmp/ng.sqlite
ouch compress /tmp/ng.sqlite /tmp/ng-$(date +%Y%m%d).tar.zst
```
### Claude Code subprocess example in Node
```javascript
const { spawn } = require('child_process');
const proc = spawn('sqlite-graphrag', ['recall', query, '--k', '5', '--json']);
```
### Docker Alpine build for CI pipelines
```dockerfile
FROM rust:1.88-alpine AS builder
RUN apk add musl-dev sqlite-dev
RUN cargo install --locked sqlite-graphrag
```
## Exit Codes
### Deterministic status codes for orchestration
| Code | Meaning | Recommended Action |
| --- | --- | --- |
| `0` | Success | Continue the agent loop |
| `1` | Validation or runtime failure | Log and surface to operator |
| `2` | CLI usage error or duplicate | Fix arguments then retry |
| `3` | Optimistic update conflict | Re-read `updated_at` and retry |
| `4` | Memory or entity not found | Handle missing resource gracefully |
| `5` | Namespace limit or unresolved | Pass `--namespace` explicitly |
| `6` | Payload exceeded allowed limits | Split body into smaller chunks |
| `10` | SQLite database error | Run `health` to inspect integrity |
| `11` | Embedding generation failed | Check model files and retry |
| `12` | `sqlite-vec` extension failed | Reinstall binary with bundled extension |
| `13` | Batch partial failure | Honor backoff and retry later |
| `14` | Filesystem I/O error | Check permissions and disk space |
| `15` | Database busy after retries | Wait and retry the operation |
| `20` | Internal or JSON serialization error | File a bug report |
| `73` | Memory guard rejected low RAM | Free RAM before retry |
| `75` | `EX_TEMPFAIL` — all slots busy | Retry with backoff |
| `77` | Low RAM for embedding model | Free at least 1 GB before retry |
## JSON Output Format
### Recall — Vector-Only KNN
```json
{
"query": "graphrag retrieval",
"k": 3,
"namespace": "default",
"elapsed_ms": 12,
"results": [
{ "name": "graphrag-intro", "score": 0.91, "type": "user", "updated_at": "2026-04-18T12:00:00Z" },
{ "name": "vector-search-notes", "score": 0.84, "type": "project", "updated_at": "2026-04-17T08:12:03Z" },
{ "name": "hybrid-ranker", "score": 0.77, "type": "feedback", "updated_at": "2026-04-16T21:04:55Z" }
]
}
```
### Hybrid Search — FTS5 Plus Vector RRF
```json
{
"query": "postgres migration",
"k": 5,
"rrf_k": 60,
"weights": { "vec": 1.0, "fts": 1.0 },
"elapsed_ms": 18,
"results": [
{ "name": "postgres-migration-plan", "score": 0.96, "vec_rank": 1, "fts_rank": 1 },
{ "name": "db-migration-checklist", "score": 0.88, "vec_rank": 2, "fts_rank": 3 }
]
}
```
## Performance
### Measured on a 1000-memory database
- Cold startup under 50 milliseconds on native ARM64 Apple Silicon
- Recall with `--k 5` completes under 20 milliseconds after model load
- Hybrid search with RRF completes under 30 milliseconds on warm cache
- First `init` downloads the quantized model once and caches it locally
- Embedding model uses approximately 750 MB of RAM per process instance
## Safe Parallel Invocation
### Counting semaphore with four simultaneous slots
- Each invocation loads `multilingual-e5-small` consuming roughly 750 MB of RAM
- Up to four instances run in parallel via `MAX_CONCURRENT_CLI_INSTANCES` default
- Lock files live at `~/.cache/sqlite-graphrag/cli-slot-{1..4}.lock` using `flock`
- A fifth concurrent invocation waits up to 300 seconds then exits with code 75
- Use `--max-concurrency N` to override the slot limit for the current invocation
- Memory guard aborts with exit 77 when less than 2 GB of RAM is available
- SIGINT and SIGTERM trigger graceful shutdown via `shutdown_requested()` atomic
## Idempotency and Side Effects
### Read-Only Commands — Zero Mutations Guaranteed
- `recall` reads the vector and metadata tables without touching disk state
- `read` fetches a single row by name and emits JSON without side effects
- `list` paginates memories sorted deterministically with stable cursors
- `health` runs SQLite `PRAGMA integrity_check` and reports without writing
- `stats` counts rows in read-only transactions safe for concurrent agents
### Write Commands — Optimistic Locking Protects Concurrency
- `remember` uses `ON CONFLICT(name)` so duplicate calls return exit code `2`
- `rename` requires `--expected-updated-at` to detect stale writes via exit `3`
- `edit` creates a new row in `memory_versions` preserving immutable history
- `restore` rewinds content while appending a new version instead of overwriting
- `forget` is soft-delete so re-running it is safe and idempotent by design
## Payload Limits
### Ceilings — Enforced By The Binary
- `EMBEDDING_MAX_TOKENS` equals 512 tokens measured by the model tokenizer
- `TEXT_BODY_PREVIEW_LEN` equals 200 characters in list and recall snippets
- `MAX_CONCURRENT_CLI_INSTANCES` equals 4 across cooperating subprocess agents
- `CLI_LOCK_DEFAULT_WAIT_SECS` equals 300 seconds before exit code `75`
- `PURGE_RETENTION_DAYS_DEFAULT` equals 30 days before hard delete becomes allowed
## Troubleshooting FAQ
### Common issues and fixes
- Database locked after crash requires `sqlite-graphrag vacuum` to checkpoint the WAL
- First `init` takes roughly one minute while `fastembed` downloads the quantized model
- Permission denied on Linux means the cache directory lacks write access for your user
- Namespace detection falls back to `global` when no explicit override is present
- Parallel invocations beyond four slots receive exit 75 and SHOULD retry with backoff
- Exit 10 signals database error: run `sqlite-graphrag health --json` to inspect integrity
- Exit 12 signals sqlite-vec load failure: verify SQLite version is 3.40 or newer
- Exit 77 signals low RAM: free at least 1 GB before invoking the embedding model
## HOW TO USE
### Prerequisites
- Rust 1.88 or newer installed via `rustup` across Linux macOS and Windows
- SQLite version 3.40 or newer shipped with your operating system distribution
- Available RAM of 100 MB free for runtime plus 1 GB during embedding model load
- Disk space of 200 MB for the embedding model cache on first invocation
- Network access required ONLY for first `init` to download quantized embeddings
### First Command in 60 Seconds
```bash
cargo install --locked sqlite-graphrag
sqlite-graphrag init
sqlite-graphrag remember --name first-note --type user --description "first memory" --body "hello graphrag"
```
- First line downloads, builds and installs the binary into `~/.cargo/bin`
- Second line creates the SQLite database and downloads the embedding model
- Third line persists your first memory and indexes it for hybrid retrieval
- Your next `recall` call returns the note you just saved in milliseconds
### Advanced Patterns
#### Hybrid Search With Weighted Fusion
```bash
sqlite-graphrag hybrid-search "postgres migration strategy" \
--k 20 \
--rrf-k 60 \
--weight-vec 0.7 \
--weight-fts 0.3 \
--json \
| jaq '.results[] | {name, score, source}'
```
- Combines dense vector similarity and sparse full-text matches in one ranked list
- Weight tuning lets you favor semantic proximity against keyword precision per query
- Pipeline saves eighty percent of tokens compared to LLM-based re-ranking
#### Graph Traversal for Multi-Hop Recall
```bash
sqlite-graphrag link --source auth-design --target jwt-spec --relation depends-on
sqlite-graphrag related auth-design --hops 2 --json \
| jaq -r '.nodes[] | select(.depth == 2) | .name'
```
- Two hops surface transitive knowledge invisible to pure vector search methods
- Typed relations let your agent reason about cause, dependency and reference chains
- Multi-hop recall recovers context that flat embeddings consistently drop out of top-K
#### Snapshot-Safe Sync With Dropbox or iCloud
```bash
sqlite-graphrag sync-safe-copy --dest ~/Dropbox/graphrag.sqlite
ouch compress ~/Dropbox/graphrag.sqlite ~/Dropbox/graphrag-$(date +%Y%m%d).tar.zst
```
- `sync-safe-copy` checkpoints the WAL and copies a consistent snapshot atomically
- Dropbox, iCloud and Google Drive NEVER corrupt the active database during sync
#### Integration With Claude Code Orchestrator
```bash
sqlite-graphrag recall "$USER_QUERY" --k 5 --json \
| jaq -c '{
context: [.results[] | {name, body, score}],
generated_at: now | todate
}' \
| claude --print "Use this context to answer: $USER_QUERY"
```
- Structured JSON flows cleanly into any orchestrator reading from stdin
- Token cost drops by seventy percent compared to full-corpus context stuffing
## COOKBOOK
### Bootstrap Memory Database In 60 Seconds
```bash
cargo install --locked sqlite-graphrag
sqlite-graphrag init --namespace default
sqlite-graphrag health --json
```
- Command `init` creates the SQLite file and downloads `multilingual-e5-small` locally
- Exit code `0` signals the database is ready for writes and reads from any agent
- Saves 30 minutes per laptop versus a Pinecone plus Docker plus Python bootstrap
### Bulk-Import Knowledge Base Via Stdin Pipeline
```bash
fd -e md docs/ -0 | xargs -0 -n 1 -I{} sh -c '
sqlite-graphrag remember \
--name "$(basename {} .md)" \
--type user \
--description "imported from {}" \
--body-stdin < {}
'
```
- `--body-stdin` pipes the Markdown body without quoting or shell escape accidents
- Exit code `2` flags duplicates for you to skip cleanly inside the outer shell
- Saves 4 hours per thousand files versus hand-crafted CSV loaders
### Combine Vector And FTS Search With Tunable Weights
```bash
sqlite-graphrag hybrid-search "authentication jwt" \
--weight-vec 0.7 \
--weight-fts 0.3 \
--k 10 \
--json \
| jaq '.results[] | {name, score}'
```
- `--weight-vec 0.7` gives 70 percent weight to semantic similarity
- `--weight-fts 0.3` gives 30 percent weight to exact keyword matches
- Adjust weights per query type: raise fts for code identifiers, raise vec for concepts
### Purge Soft-Deleted Memories On A Schedule
```bash
sqlite-graphrag purge --retention-days 90 --dry-run --json
sqlite-graphrag purge --retention-days 90 --yes
```
- `--dry-run` shows exactly which memories qualify for hard deletion before committing
- Run on a weekly cron or GitHub Actions schedule to keep the database lean
### Export Memories To NDJSON For Backup
```bash
sqlite-graphrag list --limit 1000 --json \
| jaq -c '.[]' \
> memories-backup-$(date +%Y%m%d).ndjson
```
- One line per memory in NDJSON format for streaming ingestion by any tool
- Pipe through `ouch compress` to reduce file size by sixty percent for archival
## INTEGRATIONS
### Claude Code — Subprocess Integration
```bash
sqlite-graphrag recall "$USER_PROMPT" --k 5 --json \
| jaq -r '.results[].body' \
| claude --print "Context: $(cat -) — Answer: $USER_PROMPT"
```
- Add to `.claude/hooks/pre-task.sh` for automatic context injection per session
- Capture exit code `75` as retry-later to keep the agent alive gracefully
- Use `SQLITE_GRAPHRAG_NAMESPACE=$(basename $PWD)` to isolate context per project
### Codex CLI — AGENTS.md Driven Integration
```bash
sqlite-graphrag recall "$QUERY" --k 5 --json
sqlite-graphrag remember --name "codex-$(date +%s)" --type project --description "Codex result" --body "$RESULT"
```
- Add the tool definition to your project `AGENTS.md` file for Codex to discover
- Use `--type project` for Codex-generated memories to filter them separately later
### Gemini CLI — Function Call Integration
```bash
sqlite-graphrag hybrid-search "$GEMINI_QUERY" --json --k 5 \
| jaq '{results: [.results[] | {name, score, snippet: .body[:200]}]}'
```
- Truncate `.body[:200]` to fit within Gemini function call output size limits
### GitHub Actions — CI Memory Integration
```yaml
- name: Recall project context
run: |
sqlite-graphrag recall "build failure patterns" --k 5 --json \
| jaq -r '.results[].body' > /tmp/context.txt
```
- Install binary with `cargo install --locked sqlite-graphrag` in a setup step
- Run the binary inside the workflow workspace so the default `graphrag.sqlite` stays local to that run
## Language Control
### Bilingual Output — One Flag Switches Locale
- Flag `--lang en` forces English messages regardless of system locale
- Flag `--lang pt` forces Portuguese messages regardless of system locale
- Env `SQLITE_GRAPHRAG_LANG=pt` overrides system locale when `--lang` is absent
- Unknown locales default to English without emitting any warning to stderr
## Stable Identity
### Facts that remain invariant across doc updates
- Package `sqlite-graphrag` v1.0.2 published on crates.io with MSRV Rust 1.88
- Repository `https://github.com/daniloaguiarbr/sqlite-graphrag` with CI on push and tag
- License dual `MIT OR Apache-2.0` with individual license files at the repository root
- Embedding model `multilingual-e5-small` quantized via `fastembed` at approximately 750 MB RAM
- Storage layer `rusqlite` bundled SQLite plus `sqlite-vec` extension plus FTS5 module
## Acknowledgments
### Built on top of excellent open source
- `fastembed` provides local quantized embedding models without ONNX hassle
- `sqlite-vec` adds vector indexes directly inside SQLite as an extension
- `refinery` runs schema migrations with transactional safety guarantees
- `clap` powers the CLI argument parsing with derive macros
- `rusqlite` wraps SQLite with safe Rust bindings and bundled build
- `rayon` accelerates parallel batch operations on multicore hardware
- `tokio` drives the async runtime for I/O-bound orchestration tasks
## License
### Dual license MIT OR Apache-2.0
- Licensed under either of Apache License 2.0 or MIT License at your option
- See `LICENSE-APACHE` and `LICENSE-MIT` in the repository root for full text