OpenClaw Cortex

Persistent, semantically searchable memory for AI agents — across sessions, projects, and context windows.
OpenClaw Cortex gives Claude and other AI agents long-term memory. It captures important information from conversations, classifies it by type and scope, and retrieves the most relevant context for each new turn — all within your token budget.
Why OpenClaw Cortex?
The problem: AI agents lose context between sessions. Passing full conversation history
burns tokens and hits context window limits.
The solution: A self-hosted memory layer — captures decisions and rules from
conversations, classifies them, deduplicates near-identical facts, and retrieves only the
most relevant context within your token budget.
| Outcome |
How |
| Never lose rules, decisions, or preferences across sessions |
Semantic recall + permanent scope |
| Recall stays relevant as memory grows |
Multi-factor ranking + conflict resolution |
| Zero vendor lock-in |
Self-hosted Qdrant + Ollama |
| Drop-in for Claude Code |
Pre/post-turn hooks — no code changes needed |
| Intelligent ranking |
Threshold-gated LLM re-ranking when scores are ambiguous |
Status: v0.6.0 — production-ready for single-user / small-team use.
Install
curl -fsSL https://raw.githubusercontent.com/ajitpratap0/openclaw-cortex/main/scripts/install.sh | bash
Or build from source (requires Go 1.25+):
git clone https://github.com/ajitpratap0/openclaw-cortex
cd openclaw-cortex
go build -o bin/openclaw-cortex ./cmd/openclaw-cortex
3-Command Quickstart
docker compose up -d # start Qdrant vector store
ollama pull nomic-embed-text # pull the embedding model
openclaw-cortex store "Always run tests before merging" \
--type rule --scope permanent # store your first memory
Then recall relevant context in your next session:
openclaw-cortex recall "What are the testing requirements?" --budget 2000
Why OpenClaw Cortex?
| Feature |
Naive conversation history |
OpenClaw Cortex |
| Token limit |
Hits context window, truncates |
Token-budgeted recall: always fits |
| Search |
Sequential scan / none |
Semantic vector search |
| Ranking |
Chronological only |
8-factor scoring + supersession/conflict penalties |
| Memory expiry |
Manual |
TTL, session decay, lifecycle consolidation |
| Entity tracking |
None |
Automatic from conversation capture |
| Cross-session |
Context window only |
Persists in Qdrant across all sessions |
| API access |
None |
REST API + MCP server |
| Project isolation |
None |
Per-project scoping and boosting |
| Conflict detection |
None |
Automatic: contradicting facts tagged and resolved |
| LLM re-ranking |
None |
Threshold-gated: Claude re-ranks ambiguous results |
| Confidence reinforcement |
None |
Repeated observations boost memory confidence |
Architecture
┌──────────────────────────────────────────────────────────┐
│ Claude / AI Agent │
│ │
│ Pre-Turn Hook ──> Recall ──> Inject context │
│ Post-Turn Hook ──> Capture ──> Store memories │
└──────────┬───────────────────────────────┬───────────────┘
│ │
▼ ▼
CLI / HTTP API / MCP Hook Integration
(index search recall (Pre/Post Turn,
capture store consolidate) graceful degradation)
│ │
└──────────────┬───────────────┘
│
┌───────────▼────────────┐
│ Core Engine │
│ Indexer Capturer │
│ Recaller Classifier │
│ Lifecycle Manager │
└────────┬────────────────┘
│
┌───────────▼──────────────┐
│ Embedder Store │
│ (Ollama) (Qdrant gRPC)│
│ 768-dim vectors │
└───────────────────────────┘
Features
- Semantic recall: Vector similarity search (Qdrant gRPC, 768-dim
nomic-embed-text)
- Smart capture: Claude Haiku extracts structured memories from conversation turns
- Multi-factor ranking: 8-factor scoring (similarity + recency + frequency + type + scope + confidence + reinforcement + tag affinity) with supersession and conflict penalties
- Token-aware output: Recalled memories trimmed to fit your token budget
- Deduplication: Cosine similarity dedup (threshold: 0.92) prevents redundant storage
- Memory types:
rule (1.5x) / procedure (1.3x) / fact (1.0x) / episode (0.8x) / preference (0.7x)
- Lifecycle management: TTL expiry, session decay, consolidation
- Claude Code hooks: Pre/post-turn hooks with graceful degradation
- HTTP API: REST endpoints for any LLM pipeline
- MCP server: Native Model Context Protocol support for Claude Desktop
- Conflict engine: Detects contradicting facts, surfaces them inline, resolves on consolidate
- Confidence reinforcement: Repeated captures strengthen existing memory confidence
- Session pre-warm cache: Zero-latency context injection on session resume
- Multi-turn capture: Extracts memories spanning multiple conversation turns
Documentation
Full documentation: https://ajitpratap0.github.io/openclaw-cortex/
Configuration
Configuration is loaded from (in order of precedence):
- Environment variables (prefixed
OPENCLAW_CORTEX_)
~/.openclaw-cortex/config.yaml
- Built-in defaults
qdrant:
host: localhost
grpc_port: 6334
ollama:
base_url: http://localhost:11434
model: nomic-embed-text
memory:
dedup_threshold: 0.92
default_ttl_hours: 720
recall:
weights:
similarity: 0.35
recency: 0.15
frequency: 0.10
type_boost: 0.10
scope_boost: 0.08
confidence: 0.10
reinforcement: 0.07
tag_affinity: 0.05
| Variable |
Default |
Description |
ANTHROPIC_API_KEY |
— |
Required for capture (Claude Haiku extraction) |
OPENCLAW_CORTEX_QDRANT_HOST |
localhost |
Qdrant hostname |
OPENCLAW_CORTEX_QDRANT_GRPC_PORT |
6334 |
Qdrant gRPC port |
OPENCLAW_CORTEX_OLLAMA_BASE_URL |
http://localhost:11434 |
Ollama endpoint |
Claude Code Integration
Add to .claude/settings.json in your project:
{
"hooks": {
"PreTurn": [{
"hooks": [{
"type": "command",
"command": "echo '{\"message\": \"{{HUMAN_TURN}}\", \"project\": \"my-project\", \"token_budget\": 2000}' | openclaw-cortex hook pre"
}]
}],
"PostTurn": [{
"hooks": [{
"type": "command",
"command": "echo '{\"user_message\": \"{{HUMAN_TURN}}\", \"assistant_message\": \"{{ASSISTANT_TURN}}\", \"session_id\": \"{{SESSION_ID}}\", \"project\": \"my-project\"}' | openclaw-cortex hook post"
}]
}]
}
}
Both hooks exit with code 0 even if services are unavailable — Claude is never blocked.
CLI Reference
# Store a memory
openclaw-cortex store "Always run tests before merging" --type rule --scope permanent
# Batch store (JSON array via stdin)
echo '[{"content":"rule one","type":"rule"},{"content":"fact two"}]' | openclaw-cortex store-batch
# Recall with token budget and filters
openclaw-cortex recall "deployment process" --budget 2000 --project myapp
openclaw-cortex recall "testing rules" --type rule --scope permanent --tags go,testing
# Update a memory (creates new version with lineage)
openclaw-cortex update <memory-id> --content "Updated rule text" --type rule
# Capture memories from a conversation turn
openclaw-cortex capture \
--user "How do I handle errors?" \
--assistant "Always wrap errors with fmt.Errorf and %w..."
# Index markdown memory files
openclaw-cortex index --path ~/.openclaw/workspace/memory/
# Search (raw similarity, no re-ranking)
openclaw-cortex search "error handling" --type rule --limit 5
# View stats (with health metrics)
openclaw-cortex stats
openclaw-cortex stats --json
# Run lifecycle management (TTL expiry, decay, consolidation, conflict resolution)
openclaw-cortex lifecycle --dry-run --json
openclaw-cortex consolidate
# Start HTTP API server (default :8080, configure via OPENCLAW_CORTEX_API_LISTEN_ADDR)
openclaw-cortex serve
# Start MCP server (for Claude Desktop)
openclaw-cortex mcp
Development
# Run all tests (race detector enabled)
go test -v -race -count=1 ./...
# Short tests only (no external services needed)
go test -short -count=1 ./...
# Lint
golangci-lint run ./...
# Build
go build -o bin/openclaw-cortex ./cmd/openclaw-cortex
# Using Taskfile
task test
task lint
task build
Project Structure
openclaw-cortex/
├── cmd/openclaw-cortex/ # CLI entrypoint (Cobra); all wiring of interfaces
├── internal/
│ ├── api/ # HTTP API server (REST endpoints)
│ ├── capture/ # Claude Haiku memory extraction + conflict detection
│ ├── classifier/ # Heuristic keyword scoring -> MemoryType
│ ├── config/ # Viper-based configuration
│ ├── embedder/ # Embedder interface + Ollama HTTP implementation
│ ├── hooks/ # Pre/post-turn hook handlers
│ ├── indexer/ # Markdown tree walker + section summarizer
│ ├── lifecycle/ # TTL expiry, session decay, consolidation
│ ├── mcp/ # MCP server (remember/recall/forget/search/stats)
│ ├── metrics/ # In-process counters
│ ├── models/ # Memory struct and type definitions
│ ├── recall/ # Multi-factor ranker + optional Claude re-ranker
│ └── store/ # Store interface, Qdrant gRPC, MockStore
├── pkg/tokenizer/ # Token estimation and budget-aware formatting
├── tests/ # Black-box test suite (no live services needed)
├── docs/ # MkDocs documentation source
├── scripts/install.sh # Binary installer
├── k8s/qdrant.yaml # Kubernetes StatefulSet
├── docker-compose.yml # Local Qdrant
└── Dockerfile # Multi-stage build
Tech Stack
- Go 1.23+ with structured logging (
slog)
- Qdrant vector database (gRPC via
github.com/qdrant/go-client)
- Ollama for local embeddings (
nomic-embed-text, 768 dimensions)
- Claude Haiku for memory extraction (
github.com/anthropics/anthropic-sdk-go)
- Cobra + Viper for CLI and configuration
- mcp-go for Model Context Protocol server
Contributing
Contributions are welcome. Please read CONTRIBUTING.md first.
# Start a feature branch
git checkout -b feat/short-description
# Make changes, then verify
go test -short -race -count=1 ./...
golangci-lint run ./...
# Push and open a PR
git push -u origin feat/short-description
gh pr create --title "feat: ..." --body "..."
Branch naming: feat/<topic>, fix/<topic>, refactor/<topic>, test/<topic>.
main is protected — direct pushes are blocked. All changes go through a PR with CI checks.
License
MIT — see LICENSE.