Dakera Documentation
The memory engine for AI agents. A single Rust binary that replaces five separate services — vector search, full-text search, embeddings, agent memory, and knowledge graphs.
What Dakera replaces
| Instead of running | Dakera provides |
|---|---|
| Qdrant · Pinecone · Weaviate | HNSW, IVF, and SPFresh vector indexes |
| Elasticsearch · OpenSearch | BM25 full-text search engine |
| OpenAI / Cohere embeddings API | On-device ONNX inference — zero API calls |
| Redis / Postgres memory layer | Decay-weighted agent memory with sessions |
| Neo4j knowledge graph | Built-in entity graph with cross-agent network |
Start here
| I want to… | Go to |
|---|---|
| Get Dakera running in 5 minutes | Quick Start → |
| Add memory to Claude Desktop, Code, or Cursor | MCP Server → |
| Integrate from Python | Python SDK → |
| Integrate from TypeScript / Node | TypeScript SDK → |
| Integrate from Go or Rust | Go SDK → · Rust SDK → |
| Use from the command line | CLI Reference → |
| See all configuration options | Configuration → |
| Deploy to production | Deployment → |
| Understand the retrieval pipeline | Architecture → |
| Security hardening for production | Security → |
| Use with LangChain, CrewAI, LlamaIndex, or AutoGen | Integrations → |
Key capabilities
Hybrid Retrieval
Vector + BM25 full-text combined in one call. Reciprocal Rank Fusion merges results. Sub-10ms for millions of vectors.
On-device Embeddings
MiniLM, BGE, and E5 models run via ONNX at startup. No external embedding API required.
Memory Decay
Access-weighted importance scoring. Memories fade naturally when not recalled. Configurable half-life.
Knowledge Graphs
Entity extraction, relationship storage, and cross-agent network visualization — no schema design required.
Session Management
Group memories by agent session. Auto-generate session summaries. Per-session deduplication.
MCP Native
83 tools for Claude Desktop, Claude Code, Cursor, and Windsurf. No code changes required.
Packages
| Package | Version | Language | Install | Registry |
|---|---|---|---|---|
dakera-py | 0.11.54 | Python 3.10+ | pip install dakera | PyPI |
dakera-js | 0.11.54 | Node 20+ / Bun / Deno | npm install dakera | npm |
dakera-rs | 0.11.54 | Rust 1.70+ | cargo add dakera-client | crates.io |
dakera-go | 0.11.54 | Go 1.21+ | go get github.com/dakera-ai/dakera-go | pkg.go.dev |
dakera-cli | 0.5.5 | Rust 1.70+ | cargo install dakera-cli | crates.io |
dakera-mcp | 0.9.8 | Rust binary | download binary or docker pull | GitHub Releases |
dakera | 0.11.55 | Rust server | docker pull ghcr.io/dakera-ai/dakera:latest | Docker Hub |
Release artifacts
Every release publishes pre-built binaries, Docker images, and source archives. All artifacts are signed and checksummed.
| Artifact | Where to find it |
|---|---|
| Server binary + Docker image | hub.docker.com/r/dakera/dakera |
| MCP binary (Linux x64/arm64, macOS, Windows) | github.com/dakera-ai/dakera-mcp/releases |
| Helm chart OCI package | oci://ghcr.io/dakera-ai/dakera-helm/dakera |
| Helm chart repo (dakera-helm) | ArtifactHub · GitHub Pages index |
| Python SDK | pypi.org/project/dakera/#history |
| TypeScript SDK | npmjs.com/package/dakera |
| Rust SDK | crates.io/crates/dakera-client/versions |
| Go SDK | pkg.go.dev/github.com/dakera-ai/dakera-go |
| Deploy repo (Docker Compose, Kubernetes) | github.com/dakera-ai/dakera-deploy |
Quick Start
Store your first memory in under 10 minutes.
Run the server
Pull and start the official Docker image from GitHub Container Registry:
docker run -d \
--name dakera \
--restart unless-stopped \
-p 3300:3300 \
-e DAKERA_PORT=3300 \
-e DAKERA_ROOT_API_KEY=my-dev-key \
-e DAKERA_STORAGE=filesystem \
-e DAKERA_STORAGE_PATH=/data \
-v dakera-data:/data \
ghcr.io/dakera-ai/dakera:latest
Verify it's healthy (replace localhost with your server's IP if running remotely):
curl http://localhost:3300/health
# {"service":"dakera","status":"healthy","version":"0.11.55"}
# Remote server:
curl http://<YOUR_SERVER_IP>:3300/health
http://<SERVER_IP>:3300) in all SDK and MCP configs below. See Deployment for Docker Compose, Kubernetes, and Helm options.Install a SDK
pip install dakeranpm install dakera
# yarn add dakera | pnpm add dakerago get github.com/dakera-ai/dakera-go# Cargo.toml
[dependencies]
dakera-client = "0.11"cargo install dakera-cli
dk init # interactive setup wizardStore a memory
Use env vars to configure the server URL — works for local and remote servers:
import os
from dakera import DakeraClient
# Configure via env vars (recommended) or pass directly:
# export DAKERA_URL=http://<YOUR_SERVER_IP>:3300
# export DAKERA_API_KEY=my-dev-key
client = DakeraClient(
base_url=os.getenv("DAKERA_URL", "http://localhost:3300"),
api_key=os.getenv("DAKERA_API_KEY")
)
client.memories.store(
agent_id="my-agent",
content="User prefers dark mode",
importance=0.8,
tags=["preference", "ui"]
)import { DakeraClient } from 'dakera';
// Configure via env vars (recommended):
// DAKERA_URL=http://<YOUR_SERVER_IP>:3300
// DAKERA_API_KEY=my-dev-key
const client = new DakeraClient({
baseUrl: process.env.DAKERA_URL ?? 'http://localhost:3300',
apiKey: process.env.DAKERA_API_KEY,
});
await client.memories.store({
agentId: 'my-agent',
content: 'User prefers dark mode',
importance: 0.8,
tags: ['preference', 'ui'],
});import (
dakera "github.com/dakera-ai/dakera-go"
"os"
)
serverURL := os.Getenv("DAKERA_URL")
if serverURL == "" { serverURL = "http://localhost:3300" }
client := dakera.NewClientWithOptions(dakera.ClientOptions{
BaseURL: serverURL,
APIKey: os.Getenv("DAKERA_API_KEY"),
})
client.Memories.Store(ctx, &dakera.StoreRequest{
AgentID: "my-agent",
Content: "User prefers dark mode",
Importance: 0.8,
Tags: []string{"preference", "ui"},
})use dakera_client::{DakeraClient, Config, memory::StoreRequest};
let client = DakeraClient::new(Config {
base_url: std::env::var("DAKERA_URL")
.unwrap_or_else(|_| "http://localhost:3300".into()),
api_key: std::env::var("DAKERA_API_KEY").ok(),
..Default::default()
})?;
client.memories().store(StoreRequest {
agent_id: "my-agent".into(),
content: "User prefers dark mode".into(),
importance: Some(0.8),
tags: vec!["preference".into()],
..Default::default()
}).await?;Recall memories
response = client.memories.recall(
agent_id="my-agent",
query="what UI preferences does the user have?"
)
for m in response.memories:
print(m.content, m.importance, m.score)const response = await client.memories.recall({
agentId: 'my-agent',
query: 'what UI preferences does the user have?',
});
response.memories.forEach(m => console.log(m.content, m.importance, m.score));MCP Server
Dakera ships as a native MCP server — 83 tools for Claude Desktop, Claude Code, Cursor, Windsurf, and any MCP-compatible client. No code changes required.
Install the MCP binary
Download a pre-built binary in one command — no Rust or build tools required:
# Linux x64 (also works in WSL)
curl -fsSL https://github.com/dakera-ai/dakera-mcp/releases/latest/download/dakera-mcp-linux-x64.tar.gz \
| tar -xz -C /usr/local/bin
chmod +x /usr/local/bin/dakera-mcp
# Linux arm64
curl -fsSL https://github.com/dakera-ai/dakera-mcp/releases/latest/download/dakera-mcp-linux-arm64.tar.gz \
| tar -xz -C /usr/local/bin
# Verify
dakera-mcp --version# macOS Apple Silicon (M1/M2/M3)
curl -fsSL https://github.com/dakera-ai/dakera-mcp/releases/latest/download/dakera-mcp-macos-arm64.tar.gz \
| tar -xz -C /usr/local/bin
# macOS Intel
curl -fsSL https://github.com/dakera-ai/dakera-mcp/releases/latest/download/dakera-mcp-macos-x64.tar.gz \
| tar -xz -C /usr/local/bin
# Verify
dakera-mcp --version# PowerShell — Windows x64
Invoke-WebRequest `
-Uri "https://github.com/dakera-ai/dakera-mcp/releases/latest/download/dakera-mcp-windows-x64.zip" `
-OutFile "$env:TEMP\dakera-mcp.zip"
Expand-Archive "$env:TEMP\dakera-mcp.zip" -DestinationPath "C:\tools\dakera-mcp" -Force
# Add C:\tools\dakera-mcp to your PATH, then verify:
dakera-mcp --version# Requires Rust 1.70+
git clone https://github.com/dakera-ai/dakera-mcp
cd dakera-mcp
cargo build --release
# binary: ./target/release/dakera-mcpOr browse all releases and checksums on the GitHub Releases page.
Point the MCP server at your Dakera instance
Set two environment variables — DAKERA_API_URL is the address of your running Dakera server (the IP or hostname where you deployed it), and DAKERA_API_KEY is the root key you set when starting the server.
docker run -p 3300:3300 ... on a remote host, use http://<SERVER_IP>:3300. For a local dev machine use http://localhost:3300. For Kubernetes with an ingress, use your ingress hostname.# Quick test — verify connectivity before wiring up any client:
export DAKERA_API_URL=http://<YOUR_SERVER_IP>:3300
export DAKERA_API_KEY=<your-api-key>
dakera-mcp --test-connection
# Connected to Dakera v0.11.55 — 83 tools available
Environment variables
| Variable | Description | Default |
|---|---|---|
DAKERA_API_URL | Dakera server base URL — set to your server address | http://localhost:3300 |
DAKERA_API_KEY | API key for authentication | none |
RUST_LOG | Log level (e.g. dakera_mcp=debug) | dakera_mcp=info |
Connect your AI client
In all configs below, replace <YOUR_SERVER_IP> with your Dakera server address and <your-api-key> with your root API key. Use /usr/local/bin/dakera-mcp (Linux/macOS) or the full path where you extracted the binary.
// ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
// %APPDATA%\Claude\claude_desktop_config.json (Windows)
{
"mcpServers": {
"dakera": {
"command": "/usr/local/bin/dakera-mcp",
"env": {
"DAKERA_API_URL": "http://<YOUR_SERVER_IP>:3300",
"DAKERA_API_KEY": "<your-api-key>"
}
}
}
}
Restart Claude Desktop after editing. Use Settings → Developer → MCP Servers to verify "dakera" shows as connected.
// .mcp.json in your project root (or ~/.claude/settings.json for global)
{
"mcpServers": {
"dakera": {
"command": "/usr/local/bin/dakera-mcp",
"env": {
"DAKERA_API_URL": "http://<YOUR_SERVER_IP>:3300",
"DAKERA_API_KEY": "<your-api-key>"
}
}
}
}
Run claude mcp list to confirm dakera is loaded. Run claude mcp get dakera to see connection status.
// ~/.cursor/mcp.json
{
"mcpServers": {
"dakera": {
"command": "/usr/local/bin/dakera-mcp",
"env": {
"DAKERA_API_URL": "http://<YOUR_SERVER_IP>:3300",
"DAKERA_API_KEY": "<your-api-key>"
}
}
}
}
// ~/.codeium/windsurf/mcp_config.json
{
"mcpServers": {
"dakera": {
"command": "/usr/local/bin/dakera-mcp",
"env": {
"DAKERA_API_URL": "http://<YOUR_SERVER_IP>:3300",
"DAKERA_API_KEY": "<your-api-key>"
}
}
}
}
// ~/.config/zed/settings.json
{
"context_servers": {
"dakera": {
"command": {
"path": "/usr/local/bin/dakera-mcp",
"env": {
"DAKERA_API_URL": "http://<YOUR_SERVER_IP>:3300",
"DAKERA_API_KEY": "<your-api-key>"
}
}
}
}
}
# Open WebUI — add as an external tool server
# Admin Panel → Settings → Tools → Add Tool Server
Server URL: http://<YOUR_SERVER_IP>:3300
# Or run the MCP binary as a sidecar and point at its HTTP bridge:
DAKERA_API_URL=http://<YOUR_SERVER_IP>:3300 \
DAKERA_API_KEY=<your-api-key> \
dakera-mcp --http-bridge --port 8811
# Then add http://localhost:8811 as tool server in Open WebUI
Verify the connection
# In Claude Code — ask Claude to use the dakera MCP server:
List the Dakera MCP tools available.
# Expected: Claude responds with 83 tool names across 8 categories
# Or test the underlying server directly:
curl -s -H "Authorization: Bearer <your-api-key>" \
http://<YOUR_SERVER_IP>:3300/health
# {"service":"dakera","status":"healthy","version":"0.11.55"}
Tool categories (83 tools)
| Category | Key tools | Count |
|---|---|---|
| Memory | store, recall, batch_recall, search, memory_get, memory_update, memory_importance, forget, consolidate, batch_forget | 10 |
| Memory Feedback | memory_feedback, memory_feedback_get, agent_feedback_summary | 3 |
| Sessions | session_start, session_end, session_list, session_get, session_memories | 5 |
| Agents | agent_stats, agent_memories, agent_sessions | 3 |
| Knowledge | knowledge_graph, knowledge_summarize, knowledge_deduplicate, knowledge_network_cross_agent | 4 |
| Knowledge Graph | graph_link_memory, graph_traverse, graph_path, graph_export, kg_query, kg_traverse, kg_export | 7 |
| Entity Extraction | extract_entities, auto_tag, memory_entities, extract, extractor_get, extractor_set, entity_types_get, entity_types_set | 8 |
| Namespaces | namespace_list, namespace_get, namespace_create, namespace_delete, namespace_configure, namespace_key_create, namespace_key_list, namespace_key_delete, namespace_key_usage | 9 |
| Vectors | vector_upsert, vector_upsert_columns, vector_query, vector_batch_query, vector_multi_search, vector_unified_query, vector_delete, vector_bulk_update, vector_bulk_delete, vector_count, vector_export, vector_aggregate, vector_explain, vector_warm | 14 |
| Full-text & Inference | fulltext_index, fulltext_search, fulltext_stats, fulltext_delete, upsert_text, text_query, batch_query_text, hybrid_search | 8 |
| Decay & AutoPilot | decay_config_get, decay_config_set, decay_stats, autopilot_trigger, autopilot_status | 5 |
| Admin & Other | audit_query, memory_export, memory_import, encryption_rotate_key, agent_feedback_summary, memory_policy_get, memory_policy_set | 7 |
Tool reference
Memory tools (10)
| Tool | Description |
|---|---|
dakera_store | Store a memory — content, type, importance score, tags, optional session link and hard-expiry timestamp |
dakera_recall | Semantic similarity search — returns ranked memories with scores |
dakera_batch_recall | Filter-based bulk recall without embedding — returns memories matching all predicates |
dakera_search | Advanced search — tag and type filters applied before ranking |
dakera_memory_get | Retrieve a specific memory by ID |
dakera_memory_update | Update content, importance, or tags — re-embeds on content change |
dakera_memory_importance | Batch-update importance scores for multiple memories |
dakera_forget | Delete memories by ID list or tag filter |
dakera_consolidate | Merge a list of memories into a single summary memory |
dakera_batch_forget | Filter-based bulk delete — requires Admin scope |
dakera_store parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
agent_id | string | Yes | — | Agent namespace to store the memory in |
content | string | Yes | — | Memory content text |
memory_type | string | No | episodic | Type: episodic, semantic, procedural, or working |
importance | number | No | 0.5 | Importance score 0.0–1.0. Higher values survive decay longer |
tags | string[] | No | [] | Tags for categorisation and filter-based recall |
session_id | string | No | — | Session ID to associate this memory with |
expires_at | integer | No | — | Hard-delete at this Unix timestamp (seconds). Bypasses decay math |
// Example
{
"agent_id": "my-agent",
"content": "User prefers concise bullet-point summaries.",
"memory_type": "semantic",
"importance": 0.8,
"tags": ["preference", "style"]
}
dakera_recall parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
agent_id | string | — | Required. Agent namespace to recall from |
query | string | — | Required. Natural-language query to match against |
top_k | integer | 5 | Maximum primary results to return |
memory_type | string | null | Filter by type |
tags | string[] | null | Return only memories carrying all listed tags |
min_importance | number | null | Exclude memories below this importance score |
include_associated | boolean | false | Traverse the knowledge graph from each result and include neighbouring memories |
since | string (ISO-8601) | null | Only return memories created at or after this timestamp |
until | string (ISO-8601) | null | Only return memories created at or before this timestamp |
dakera_batch_recall parameters
Filter-based bulk recall — no embedding required. All fields are optional and ANDed together; at least one must be set.
| Parameter | Type | Description |
|---|---|---|
agent_id | string | Required. Agent namespace to recall from |
tags | string[] | Return only memories with all listed tags |
min_importance | number | Minimum importance score (0.0–1.0) |
max_importance | number | Maximum importance score (0.0–1.0) |
created_after | integer | Unix timestamp lower bound (inclusive) |
created_before | integer | Unix timestamp upper bound (inclusive) |
memory_type | string | Filter by type: episodic, semantic, procedural, or working |
session_id | string | Filter to memories from a specific session |
dakera_search parameters
Tag and type filters are applied before ranking (not as a soft signal), and defaults to top_k=10.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
agent_id | string | Yes | — | Agent namespace to search |
query | string | Yes | — | Semantic search query |
top_k | integer | No | 10 | Number of results to return |
tags | string[] | No | [] | Pre-filter: only search memories with all these tags |
memory_type | string | No | null | Pre-filter by memory type |
dakera_memory_get / dakera_memory_update / dakera_forget
| Tool | Parameters |
|---|---|
dakera_memory_get | memory_id (required), agent_id (required) — returns full memory object |
dakera_memory_update | memory_id, agent_id (both required) + optional content, importance, tags — re-embeds on content change |
dakera_forget | agent_id (required) + memory_ids (string[]) or tags (string[]) — at least one filter required |
dakera_consolidate | agent_id, memory_ids (both required, min 2 IDs) — returns new summary memory; source memories are kept |
dakera_memory_importance | agent_id (required), updates (required) — array of { memory_id, importance } pairs |
Session tools (5)
| Tool | Description |
|---|---|
dakera_session_start | Start a new session — returns session object with id |
dakera_session_end | End a session with optional summary — auto-consolidates near-duplicate memories |
dakera_session_list | List sessions for an agent, optionally active-only |
dakera_session_get | Get session details including metadata and summary |
dakera_session_memories | List all memories associated with a session |
| Tool | Required params | Optional params |
|---|---|---|
dakera_session_start | agent_id | metadata (object) |
dakera_session_end | session_id | summary (string) |
dakera_session_list | agent_id | active_only (boolean, default false) |
dakera_session_get | session_id | — |
dakera_session_memories | session_id | — |
// Start → store → end pattern
{ "agent_id": "my-agent", "metadata": { "task": "customer-support" } } // session_start
{ "session_id": "sess_01abc", "summary": "Resolved billing question" } // session_end
Agent tools (3)
| Tool | Required params | Returns |
|---|---|---|
dakera_agent_stats | agent_id | memory_count, session_count, storage_bytes, top_tags |
dakera_agent_memories | agent_id | Paginated list of memories (limit, offset optional) |
dakera_agent_sessions | agent_id | All sessions for the agent |
Knowledge tools (4)
| Tool | Description |
|---|---|
dakera_knowledge_graph | Build a graph from a seed memory via embedding similarity — returns nodes and similarity edges |
dakera_knowledge_summarize | Merge a list of memories into one summary memory (source memories kept) |
dakera_knowledge_deduplicate | Find and optionally merge duplicate memories by cosine similarity threshold |
dakera_knowledge_network_cross_agent | Cross-agent memory similarity network — requires Admin scope |
| Tool | Key parameters |
|---|---|
dakera_knowledge_graph | agent_id, memory_id (required); depth (default 2), min_similarity (default 0.7) |
dakera_knowledge_summarize | agent_id, memory_ids (required, min 2); target_type (default semantic) |
dakera_knowledge_deduplicate | agent_id (required); threshold (default 0.9), dry_run (default true) — always run dry_run first |
dakera_knowledge_network_cross_agent | agent_ids, min_similarity (default 0.3), max_nodes_per_agent (default 50) |
Namespace tools (9)
| Tool | Description |
|---|---|
dakera_namespace_list | List all namespaces — no parameters required |
dakera_namespace_get | Get namespace details: dimensions, distance, vector count, index stats |
dakera_namespace_create | Create a new namespace — fails if it already exists |
dakera_namespace_configure | Create-or-update (idempotent) — use for application boot and CI pipelines |
dakera_namespace_delete | Delete namespace and all its vectors — irreversible, requires Admin scope |
dakera_namespace_key_create | Create an API key scoped to a namespace (read/write/admin) |
dakera_namespace_key_list | List namespace-scoped keys (metadata only — not raw key values) |
dakera_namespace_key_delete | Revoke a namespace key by ID |
dakera_namespace_key_usage | Get request counts and last-used timestamp for a key |
| Tool | Required | Optional |
|---|---|---|
dakera_namespace_create | name, dimension | distance (cosine/euclidean/dot, default cosine) |
dakera_namespace_configure | namespace, dimension | distance — same as create but idempotent |
dakera_namespace_key_create | namespace, name, scope | extra_namespaces, expires_in_days |
Vector tools (14)
| Tool | Description |
|---|---|
dakera_vector_upsert | Upsert vectors: { id, values, metadata? }[] |
dakera_vector_upsert_columns | Column-format bulk upsert — more efficient for large batches |
dakera_vector_query | ANN similarity search by vector |
dakera_vector_batch_query | Run multiple similarity searches in one request |
dakera_vector_multi_search | Positive/negative vector search with optional MMR diversity |
dakera_vector_unified_query | Flexible hybrid ranking: ANN, BM25, attribute, composite |
dakera_vector_delete | Delete vectors by ID list |
dakera_vector_bulk_update | Update metadata on all vectors matching a filter |
dakera_vector_bulk_delete | Delete all vectors matching a filter — requires Admin scope |
dakera_vector_count | Count vectors in a namespace with optional filter |
dakera_vector_export | Paginated export of vectors |
dakera_vector_aggregate | Compute Count/Sum/Avg/Min/Max with optional grouping |
dakera_vector_explain | Explain a query execution plan with cost estimates |
dakera_vector_warm | Pre-load vectors into cache for faster queries |
| Tool | Required params | Key optional params |
|---|---|---|
dakera_vector_upsert | namespace, vectors (array of {id, values, metadata?}) | — |
dakera_vector_query | namespace, vector | top_k (default 10), filter |
dakera_vector_batch_query | namespace, queries (array of {vector, top_k?, filter?}) | — |
dakera_vector_multi_search | namespace, positive_vectors | negative_vectors, enable_mmr (default false), mmr_lambda (default 0.5), score_threshold |
dakera_vector_unified_query | namespace, rank_by | top_k, filter — rank_by forms: ["vector","ANN",[...]], ["text","BM25","query"], ["Sum",[...]] |
dakera_vector_bulk_update | namespace, filter, update | — |
dakera_vector_bulk_delete | namespace, filter | — (Admin scope required) |
dakera_vector_upsert_columns | namespace, ids, vectors | attributes (column metadata object) |
Full-text & Inference tools (8)
| Tool | Description |
|---|---|
dakera_fulltext_index | Index a document for full-text search |
dakera_fulltext_search | BM25 full-text search across indexed documents |
dakera_fulltext_stats | Full-text index statistics (document count, token count) |
dakera_fulltext_delete | Remove a document from the full-text index |
dakera_upsert_text | Embed text server-side and upsert into a namespace |
dakera_text_query | Embed a query server-side and search — no client-side embedding required |
dakera_batch_query_text | Batch text queries with server-side embedding |
dakera_hybrid_search | Hybrid vector + BM25 search — semantic + keyword in one call |
The Inference tools (dakera_upsert_text, dakera_text_query, dakera_batch_query_text, dakera_hybrid_search) embed on the server — you never need to compute vectors client-side. Use these for text-first workflows.
Entity Extraction tools (8)
| Tool | Description | Added |
|---|---|---|
dakera_extract_entities | Extract named entities from text using GLiNER (local, no external API) | CE-4 |
dakera_auto_tag | Auto-tag a memory with extracted entity labels | CE-4 |
dakera_memory_entities | Get entities extracted from a specific memory | CE-4 |
dakera_entity_types_get | Get configured entity type labels for a namespace | — |
dakera_entity_types_set | Set entity type labels for a namespace | — |
dakera_extract | Extract entities/topics/keyphrases/summary via pluggable provider (OpenAI, Anthropic, Ollama, GLiNER) | EXT-1 |
dakera_extractor_get | Read the extraction provider config for a namespace | EXT-1 |
dakera_extractor_set | Set the extraction provider for a namespace | EXT-1 |
dakera_extract vs dakera_auto_tag: auto_tag uses GLiNER locally and returns entity labels only. dakera_extract supports pluggable backends (OpenAI, Anthropic, Ollama) and returns richer output: entities, topics, key phrases, and a summary.
Decay & AutoPilot tools (5)
| Tool | Required params | Description |
|---|---|---|
dakera_decay_config_get | agent_id | Read decay policy for an agent (half-life, floor importance, access boost) |
dakera_decay_config_set | agent_id + policy fields | Update decay policy — half-life controls how fast unaccessed memories fade |
dakera_decay_stats | agent_id | Decay engine statistics: memories decayed, average importance drift |
dakera_autopilot_trigger | agent_id | Manually trigger an AutoPilot run (consolidation + deduplication) |
dakera_autopilot_status | agent_id | Get AutoPilot run status: last run time, memories consolidated, duplicates removed |
Memory Feedback tools (3)
| Tool | Required params | Description |
|---|---|---|
dakera_memory_feedback | memory_id, signal | Submit a feedback signal (positive/negative/neutral) — adjusts importance score |
dakera_memory_feedback_get | memory_id | Get feedback history for a memory |
dakera_agent_feedback_summary | agent_id | Feedback health summary for all of an agent's memories |
Knowledge Graph tools (7)
| Tool | Required params | Description |
|---|---|---|
dakera_graph_link_memory | source_id, target_id, weight | Create a directed edge between two memories |
dakera_graph_traverse | memory_id, agent_id | Traverse the KG from a start node |
dakera_graph_path | source_id, target_id, agent_id | Find shortest path between two memory nodes |
dakera_graph_export | agent_id | Export the full KG for an agent as nodes + edges |
dakera_kg_query | agent_id, query | Semantic search over KG nodes |
dakera_kg_traverse | agent_id, start_id | BFS/DFS traversal of the KG |
dakera_kg_export | agent_id | Export KG in JSON or DOT graph format |
Admin & Audit tools (7)
| Tool | Required params | Description |
|---|---|---|
dakera_audit_query | agent_id | Query the audit log — who accessed what, when. Requires Admin scope |
dakera_memory_export | agent_id | Export all memories for an agent as JSON |
dakera_memory_import | agent_id, memories | Bulk-import memories from a JSON export |
dakera_encryption_rotate_key | namespace | Rotate the encryption key for a namespace. Requires Admin scope |
dakera_memory_policy_get | agent_id | Get retention and access policy for an agent |
dakera_memory_policy_set | agent_id + policy fields | Set retention policy: max_memories, max_age_days, auto_purge |
dakera_namespace_configure | See Namespaces section | Idempotent namespace creation/configuration |
CLI Reference
v0.5.5The dk binary lets you manage agent memory, vector operations, namespaces, and sessions from the terminal.
Installation
cargo install dakera-cli
Or download pre-built binaries from GitHub Releases.
Setup wizard
dk init
Prompts for server URL, tests connectivity, sets default namespace, and writes ~/.config/dakera/config.toml.
Global flags
| Flag | Short | Default | Description |
|---|---|---|---|
--url | -u | http://localhost:3300 | Server URL (overrides config and DAKERA_URL) |
--format | -f | table | Output format: table, json, compact |
--verbose | -v | — | Enable verbose output |
--api-key | — | env DAKERA_API_KEY | API key (overrides config) |
Memory commands
# Store a memory
dk memory store --agent my-agent --content "User prefers dark mode" --importance 0.8
# Recall memories (semantic search)
dk memory recall --agent my-agent --query "UI preferences"
# Batch recall (filter-based)
dk memory recall --agent my-agent --tags preference --min-importance 0.7
# Forget a memory
dk memory forget mem-abc123
# List all memories for an agent
dk memory list --agent my-agent
Session commands
# Start a session
dk session start my-agent
# End a session
dk session end sess-abc123 --summary "Completed code review"
# List sessions for an agent
dk session list my-agent
Namespace commands
# Create a namespace
dk namespace create my-namespace --embedding-model MiniLML6V2
# List all namespaces
dk namespace list
# Delete a namespace
dk namespace delete my-namespace
Vector commands
# Upsert vectors from a JSON file
dk vector upsert my-namespace --file vectors.json
# Query nearest neighbors
dk vector query my-namespace --vector "[0.1,0.2,0.3]" --top-k 10
# Hybrid search
dk vector hybrid my-namespace --query "agent task completion" --top-k 5
Exit codes
| Code | Meaning |
|---|---|
0 | Success |
2 | Connection error (server unreachable) |
3 | Not found (namespace, vector, memory) |
4 | Permission denied / authentication failure |
5 | Invalid input / validation error |
6 | Server-side error (5xx) |
Python SDK
v0.11.54 · Python 3.10+pip install dakera # core (sync client)
pip install dakera[async] # include async client
pip show dakera # verify installed version
Client setup
Point the client at your Dakera server. Use env vars to keep the URL and key out of source code:
import os
from dakera import DakeraClient
# Recommended: configure via env vars
# export DAKERA_URL=http://<YOUR_SERVER_IP>:3300
# export DAKERA_API_KEY=your-api-key
client = DakeraClient(
base_url=os.getenv("DAKERA_URL", "http://localhost:3300"),
api_key=os.getenv("DAKERA_API_KEY")
)
Memory operations
# Store
client.memories.store(
agent_id="my-agent",
content="User is learning Rust",
importance=0.8,
tags=["learning", "programming"]
)
# Recall — semantic search over stored memories
memories = client.memories.recall(
agent_id="my-agent",
query="programming languages the user knows",
top_k=10
)
# Batch recall — filter-based, no semantic search
memories = client.memories.batch_recall(
agent_id="my-agent",
tags=["learning"],
min_importance=0.6
)
# Forget a specific memory
client.memories.forget(memory_id="mem-abc123")
# Update importance
client.memories.set_importance(memory_id="mem-abc123", importance=0.9)
# Get a memory by ID
memory = client.memories.get(memory_id="mem-abc123")
Sessions
# Start a session
session = client.sessions.start(
agent_id="my-agent",
metadata={"task": "code review", "user": "alice"}
)
# Store memory linked to the session
client.memories.store(
agent_id="my-agent",
content="Reviewed auth module — found 2 security issues",
session_id=session.id
)
# End session — auto-generates a summary
result = client.sessions.end(
session_id=session.id,
summary="Code review complete. 2 issues logged."
)
# List sessions for an agent
sessions = client.sessions.list(agent_id="my-agent")
# Get memories from a session
session_mems = client.sessions.memories(session_id=session.id)
Vector operations
# Upsert raw vectors
client.vectors.upsert(
namespace="my-ns",
vectors=[
{"id": "v1", "values": [0.1, 0.2, 0.3], "metadata": {"label": "a"}},
]
)
# Query nearest neighbors
results = client.vectors.query(
namespace="my-ns",
vector=[0.1, 0.2, 0.3],
top_k=10,
include_metadata=True
)
# Hybrid search (vector + BM25)
results = client.vectors.hybrid_search(
namespace="my-ns",
query="agent task completion",
top_k=10
)
# Full-text search
results = client.fulltext.search(
namespace="my-ns",
query="authentication issues",
top_k=5
)
Namespaces
# Create an isolated namespace for your project
client.namespaces.create(namespace="project-alpha", embedding_model="MiniLML6V2")
# Upsert vectors into a namespace
client.vectors.upsert(
namespace="project-alpha",
vectors=[{"id": "doc-1", "values": [0.1, 0.2, 0.3], "metadata": {"title": "intro"}}]
)
# Hybrid search across that namespace
results = client.vectors.hybrid_search(
namespace="project-alpha",
query="project goals and milestones",
top_k=10
)
# List all namespaces
ns_list = client.namespaces.list()
# Delete a namespace (irreversible)
client.namespaces.delete(namespace="project-alpha")
Error handling
from dakera import DakeraClient, DakeraError, AuthorizationError, NotFoundError
try:
client.memories.get(memory_id="mem-does-not-exist")
except NotFoundError:
print("Memory not found")
except AuthorizationError:
print("Invalid API key — check DAKERA_API_KEY")
except DakeraError as e:
print(f"Dakera error: {e.error_code} — {e.message}")
Async client
import os, asyncio
from dakera import AsyncDakeraClient
async def main():
async with AsyncDakeraClient(
base_url=os.getenv("DAKERA_URL", "http://localhost:3300"),
api_key=os.getenv("DAKERA_API_KEY")
) as client:
await client.memories.store(agent_id="agent", content="async example")
memories = await client.memories.recall(agent_id="agent", query="async")
print(memories)
asyncio.run(main())
TypeScript SDK
v0.11.54 · Node 20+ · TypeScript 5.0+npm install dakera
# yarn add dakera | pnpm add dakera | bun add dakera
Client setup
import { DakeraClient } from 'dakera';
// Recommended: set via env vars
// DAKERA_URL=http://<YOUR_SERVER_IP>:3300
// DAKERA_API_KEY=your-api-key
const client = new DakeraClient({
baseUrl: process.env.DAKERA_URL ?? 'http://localhost:3300',
apiKey: process.env.DAKERA_API_KEY,
});
Memory operations
// Store
await client.memories.store({
agentId: 'my-agent',
content: 'User is learning Rust',
importance: 0.8,
tags: ['learning', 'programming'],
});
// Recall — semantic search
const memories = await client.memories.recall({
agentId: 'my-agent',
query: 'programming languages the user knows',
topK: 10,
});
// Batch recall — filter-based
const filtered = await client.memories.batchRecall({
agentId: 'my-agent',
tags: ['learning'],
minImportance: 0.6,
});
// Forget
await client.memories.forget({ memoryId: 'mem-abc123' });
// Update importance
await client.memories.setImportance({ memoryId: 'mem-abc123', importance: 0.9 });
Sessions
// Start session
const session = await client.sessions.start({
agentId: 'my-agent',
metadata: { task: 'code review' },
});
// Store memory linked to session
await client.memories.store({
agentId: 'my-agent',
content: 'Reviewed auth module',
sessionId: session.id,
});
// End session
const result = await client.sessions.end({
sessionId: session.id,
summary: 'Code review complete',
});
// List sessions
const sessions = await client.sessions.list({ agentId: 'my-agent' });
TypeScript types
import type {
MemoryRecord, // { id, agentId, content, importance, tags, createdAt, sessionId? }
RecallResult, // extends MemoryRecord with score: number
StoreMemoryRequest, // { agentId, content, importance?, tags?, sessionId? }
RecallRequest, // { agentId, query, topK? }
Session, // { id, agentId, startedAt, endedAt?, memoryCount, summary? }
DakeraClient,
} from 'dakera';
Namespaces & vector operations
// Create a namespace
await client.namespaces.create({ namespace: 'project-alpha' });
// Upsert vectors
await client.vectors.upsert({
namespace: 'project-alpha',
vectors: [{ id: 'doc-1', values: [0.1, 0.2, 0.3], metadata: { title: 'intro' } }],
});
// Hybrid search (vector + BM25)
const results = await client.vectors.hybridSearch({
namespace: 'project-alpha',
query: 'project goals',
topK: 10,
});
Error handling
import { DakeraError, AuthorizationError, NotFoundError } from 'dakera';
try {
await client.memories.get({ memoryId: 'mem-does-not-exist' });
} catch (err) {
if (err instanceof NotFoundError) {
console.error('Memory not found');
} else if (err instanceof AuthorizationError) {
console.error('Invalid API key — check DAKERA_API_KEY');
} else if (err instanceof DakeraError) {
console.error(`${err.errorCode}: ${err.message}`);
}
}
Go SDK
v0.11.54 · Go 1.21+go get github.com/dakera-ai/dakera-go@latest
Client setup
import (
dakera "github.com/dakera-ai/dakera-go"
"os"
"time"
)
// Recommended: configure via env vars
// DAKERA_URL=http://<YOUR_SERVER_IP>:3300
// DAKERA_API_KEY=your-api-key
serverURL := os.Getenv("DAKERA_URL")
if serverURL == "" { serverURL = "http://localhost:3300" }
client := dakera.NewClientWithOptions(dakera.ClientOptions{
BaseURL: serverURL,
APIKey: os.Getenv("DAKERA_API_KEY"),
Timeout: 30 * time.Second,
})
Memory operations
// Store
_, err := client.Memories.Store(ctx, &dakera.StoreRequest{
AgentID: "my-agent",
Content: "User is learning Rust",
Importance: 0.8,
Tags: []string{"learning"},
})
// Recall
memories, err := client.Memories.Recall(ctx, &dakera.RecallRequest{
AgentID: "my-agent",
Query: "programming languages",
TopK: 10,
})
// Batch recall
memories, err := client.Memories.BatchRecall(ctx, &dakera.BatchRecallRequest{
AgentID: "my-agent",
Tags: []string{"learning"},
MinImportance: 0.6,
})
// Forget
err = client.Memories.Forget(ctx, "mem-abc123")
Sessions
session, err := client.Sessions.Start(ctx, &dakera.StartSessionRequest{
AgentID: "my-agent",
Metadata: map[string]interface{}{"task": "review"},
})
result, err := client.Sessions.End(ctx, &dakera.EndSessionRequest{
SessionID: session.ID,
Summary: "Review complete",
})
Vector operations
// Upsert
_, err = client.Upsert(ctx, "my-ns", []dakera.VectorInput{
{ID: "v1", Values: []float32{0.1, 0.2, 0.3}, Metadata: map[string]interface{}{"label": "a"}},
})
// Hybrid search (vector + BM25)
results, err := client.HybridSearch(ctx, "my-ns", &dakera.HybridSearchRequest{
Query: "agent task completion",
TopK: 10,
})
// ANN vector query
results, err := client.Query(ctx, "my-ns", []float32{0.1, 0.2, 0.3}, &dakera.QueryOptions{
TopK: 10, IncludeMetadata: true,
})
Error handling
import (
dakera "github.com/dakera-ai/dakera-go"
"errors"
"log"
)
memories, err := client.Memories.Recall(ctx, &dakera.RecallRequest{
AgentID: "my-agent",
Query: "important decisions",
TopK: 10,
})
if err != nil {
var authErr *dakera.AuthorizationError
var notFoundErr *dakera.NotFoundError
var dakeraErr *dakera.DakeraError
switch {
case errors.As(err, &authErr):
log.Fatalf("authentication failed — check DAKERA_API_KEY: %v", authErr)
case errors.As(err, ¬FoundErr):
log.Printf("agent or memory not found: %v", notFoundErr)
case errors.As(err, &dakeraErr):
log.Printf("dakera error %d: %s", dakeraErr.ErrorCode, dakeraErr.Message)
default:
log.Printf("network or serialisation error: %v", err)
}
}
Rust SDK
v0.11.54 · Rust 1.70+ · Tokio# Cargo.toml
[dependencies]
dakera-client = "0.11"
tokio = { version = "1", features = ["full"] }
Client setup
use dakera_client::{DakeraClient, Config};
// Recommended: configure via env vars
// DAKERA_URL=http://<YOUR_SERVER_IP>:3300
// DAKERA_API_KEY=your-api-key
let client = DakeraClient::new(Config {
base_url: std::env::var("DAKERA_URL")
.unwrap_or_else(|_| "http://localhost:3300".into()),
api_key: std::env::var("DAKERA_API_KEY").ok(),
..Default::default()
})?;
Memory operations
use dakera_client::memory::{StoreRequest, RecallRequest};
// Store
client.memories().store(StoreRequest {
agent_id: "my-agent".into(),
content: "User is learning Rust".into(),
importance: Some(0.8),
tags: vec!["learning".into()],
..Default::default()
}).await?;
// Recall
let memories = client.memories().recall(RecallRequest {
agent_id: "my-agent".into(),
query: "programming languages".into(),
top_k: Some(10),
..Default::default()
}).await?;
// Sessions
let session = client.sessions().start(StartRequest {
agent_id: "my-agent".into(),
..Default::default()
}).await?;
gRPC transport
# Enable in Cargo.toml
dakera-client = { version = "0.11", features = ["grpc"] }
let client = DakeraClient::grpc(GrpcConfig {
endpoint: "http://localhost:50051".into(),
..Default::default()
})?;
Error handling
use dakera_client::error::{DakeraError, ErrorKind};
match client.memories().recall(RecallRequest {
agent_id: "my-agent".into(),
query: "important decisions".into(),
..Default::default()
}).await {
Ok(memories) => {
for m in &memories { println!("{}: {}", m.id, m.content); }
}
Err(DakeraError { kind: ErrorKind::Unauthorized, .. }) => {
eprintln!("Invalid API key — check DAKERA_API_KEY");
}
Err(DakeraError { kind: ErrorKind::NotFound, message, .. }) => {
eprintln!("Not found: {message}");
}
Err(DakeraError { kind: ErrorKind::RateLimited, .. }) => {
eprintln!("Rate limit hit — back off and retry");
}
Err(e) => {
eprintln!("Dakera error [{:?}]: {}", e.kind, e.message);
}
}
REST API Reference
All endpoints require Authorization: Bearer <key> when authentication is enabled.
localhost:3300 with your server's address (e.g. http://<YOUR_SERVER_IP>:3300). All routes versioned under /v1/.Health
| Method | Path | Auth | Description |
|---|---|---|---|
GET | /health | No | Returns server status and version |
GET | /metrics | No | Prometheus metrics |
Memory
| Method | Path | Description |
|---|---|---|
POST | /v1/memory/store | Store a memory |
POST | /v1/memory/recall | Semantic recall |
POST | /v1/memories/recall/batch | Filter-based batch recall |
GET | /v1/memory/get/{id} | Get memory by ID |
PUT | /v1/memory/update/{id} | Update memory content, importance, or tags |
POST | /v1/memory/forget | Delete (forget) a memory |
Store memory — request body
{
"agent_id": "my-agent", // required
"content": "User prefers dark mode", // required
"importance": 0.8, // optional, 0.0–1.0, default 0.5
"tags": ["preference", "ui"], // optional
"session_id": "sess-abc123", // optional
"memory_type": "episodic" // episodic | semantic | procedural | working
}
Recall — request body
{
"agent_id": "my-agent", // required
"query": "UI preferences", // required
"top_k": 10, // optional, default 10
"min_importance": 0.5, // optional filter
"tags": ["preference"], // optional filter
"session_id": "sess-abc123" // optional: scope to session
}
Sessions
| Method | Path | Description |
|---|---|---|
POST | /v1/sessions/start | Start a session |
GET | /v1/sessions/:id | Get session by ID |
POST | /v1/sessions/{id}/end | End a session |
GET | /v1/sessions/:id/memories | Get all memories from a session |
GET | /v1/agents/:id/sessions | List all sessions for an agent |
Vectors (namespaces)
| Method | Path | Description |
|---|---|---|
POST | /v1/namespaces/:ns/vectors | Upsert vectors |
POST | /v1/namespaces/:ns/query | ANN vector search |
POST | /v1/namespaces/:ns/hybrid-search | Vector + BM25 hybrid |
POST | /v1/namespaces/:ns/fulltext/index | Index documents for BM25 |
POST | /v1/namespaces/:ns/fulltext/search | Full-text search |
DELETE | /v1/namespaces/:ns/vectors/:id | Delete a vector |
GET | /v1/namespaces | List all namespaces |
POST | /v1/namespaces | Create a namespace |
PUT | /v1/namespaces/:ns | Configure a namespace |
DELETE | /v1/namespaces/:ns | Delete a namespace |
Configuration
All configuration via environment variables. No config file required.
Server
| Variable | Type | Default | Description |
|---|---|---|---|
DAKERA_ROOT_API_KEY | string | — | Bootstrap root API key (super_admin scope). If unset, auth is disabled. |
DAKERA_HOST | string | 0.0.0.0 | Bind address |
DAKERA_PORT | u16 | 3300 | REST API port |
DAKERA_GRPC_PORT | u16 | 50051 | gRPC port |
RUST_LOG | string | info | Log level: trace/debug/info/warn/error |
Storage
| Variable | Default | Description |
|---|---|---|
DAKERA_STORAGE | memory | Backend: memory, filesystem, s3, minio |
DAKERA_STORAGE_PATH | ./data | Data directory for filesystem storage |
DAKERA_S3_BUCKET | — | S3 bucket name (3–63 chars) |
DAKERA_S3_REGION | — | S3 region (e.g. us-east-1) |
DAKERA_S3_ENDPOINT | — | S3-compatible endpoint URL (MinIO) |
DAKERA_S3_MAX_RETRIES | 3 | Max retry attempts on transient S3 errors |
AWS_ACCESS_KEY_ID | — | AWS / MinIO access key |
AWS_SECRET_ACCESS_KEY | — | AWS / MinIO secret key |
Embeddings
| Variable | Default | Description |
|---|---|---|
DAKERA_EMBEDDING_MODEL | MiniLML6V2 | ONNX model: MiniLML6V2, BGESmallENV15, E5SmallV2 |
DAKERA_INFERENCE_DEVICE | cpu | cpu or cuda |
Memory & decay
| Variable | Default | Description |
|---|---|---|
DAKERA_DECAY_ENABLED | true | Enable memory importance decay over time |
DAKERA_DECAY_HALF_LIFE_SECS | 604800 | Half-life for decay (default: 7 days) |
DAKERA_AUTOPILOT_ENABLED | false | Enable AutoPilot memory lifecycle management |
Retrieval tuning
| Variable | Default | Description |
|---|---|---|
DAKERA_RRF_K | 60 | Reciprocal Rank Fusion k-parameter. Lower = boosts top ranks more aggressively. |
DAKERA_NAME_BOOST | 0.3 | Score boost for memories matching proper nouns in the query. Range [0.0, 1.0]. |
DAKERA_ML_CLASSIFIER | false | Enable ML-based query classifier (embedding centroid cosine similarity). |
DAKERA_TEMPORAL_INFERENCE | true | Enable per-query temporal boost for Cat3 inference queries (requires ML_CLASSIFIER). |
DAKERA_INFERENCE_TEMPORAL_MULT_BETA | 0.65 | Multiplicative temporal scaling β. Formula: score *= (1 + β × (proximity − 0.5)). Raised from 0.5 to 0.65 in v0.11.54 (CE-115) for stronger temporal tilt. (v0.11.52+) Supersedes DAKERA_ML_TEMPORAL_BOOST. |
DAKERA_ML_TEMPORAL_BOOST | 0.3 | Deprecated (v0.11.45–v0.11.54). ML-driven additive temporal boost weight. Superseded by DAKERA_INFERENCE_TEMPORAL_MULT_BETA in v0.11.54 — recalibrate custom values against the new multiplicative formula. |
DAKERA_ENTITY_VECTOR_SEARCH | true | Enable entity-filtered second HNSW pass merged via RRF. (v0.11.47+) |
DAKERA_HNSW_CACHE_MAX | 50 | Max HNSW indexes in LRU cache. Increase for many-namespace deployments. |
Rate limiting & auth
| Variable | Default | Description |
|---|---|---|
RATE_LIMIT_RPS | 100 | Requests per second |
RATE_LIMIT_BURST | 50 | Burst capacity |
DAKERA_AUTH_ENABLED | true | Enable/disable API key authentication |
DAKERA_CORS_ORIGINS | * | Allowed CORS origins (comma-separated) |
Observability
| Variable | Default | Description |
|---|---|---|
DAKERA_TRACING_ENABLED | false | Enable OpenTelemetry tracing |
OTEL_EXPORTER_OTLP_ENDPOINT | http://localhost:4317 | OTLP collector endpoint |
OTEL_SERVICE_NAME | dakera | Service name in traces |
SLOW_QUERY_THRESHOLD_MS | 100 | Log queries slower than this (ms) |
Audit logging
| Variable | Default | Description |
|---|---|---|
DAKERA_AUDIT_LOG | false | Enable audit logging — records every API request with agent ID, operation, and timestamp |
DAKERA_AUDIT_LOG_PATH | ./audit.log | Path for audit log output (JSON format, one record per line) |
Example production .env
# Server
DAKERA_ROOT_API_KEY=your-strong-secret-here # openssl rand -hex 32
DAKERA_PORT=3300
RUST_LOG=info
# Storage (filesystem — single node)
DAKERA_STORAGE=filesystem
DAKERA_STORAGE_PATH=/var/dakera/data
# Embeddings
DAKERA_EMBEDDING_MODEL=MiniLML6V2
# Decay
DAKERA_DECAY_ENABLED=true
DAKERA_DECAY_HALF_LIFE_SECS=604800 # 7 days
# Retrieval — enables ML classifier + temporal scoring (87.6% LoCoMo)
DAKERA_ML_CLASSIFIER=true
DAKERA_TEMPORAL_INFERENCE=true
DAKERA_INFERENCE_TEMPORAL_MULT_BETA=0.65
# Observability
DAKERA_AUDIT_LOG=true
DAKERA_AUDIT_LOG_PATH=/var/dakera/audit.log
Deployment
Docker images
All images are published to GitHub Container Registry (ghcr.io/dakera-ai/). No Docker Hub account required — public pull, no authentication needed.
| Image | Architectures | Description |
|---|---|---|
ghcr.io/dakera-ai/dakera:latest | linux/amd64, linux/arm64 | Dakera memory server — latest stable release |
ghcr.io/dakera-ai/dakera:v0.11.55 | linux/amd64, linux/arm64 | Pinned version (recommended for production) |
ghcr.io/dakera-ai/dakera-dashboard:latest | linux/amd64, linux/arm64 | Web UI dashboard |
ghcr.io/dakera-ai/dakera-mcp:latest | linux/amd64, linux/arm64 | MCP server (for containerised deployments) |
# Pull all images
docker pull ghcr.io/dakera-ai/dakera:latest
docker pull ghcr.io/dakera-ai/dakera-dashboard:latest
docker pull ghcr.io/dakera-ai/dakera-mcp:latest
# Inspect available tags
docker run --rm ghcr.io/dakera-ai/dakera:latest --version
Docker (single node)
docker run -d \
--name dakera \
--restart unless-stopped \
-p 3300:3300 \
-e DAKERA_PORT=3300 \
-e DAKERA_ROOT_API_KEY=your-secret \
-e DAKERA_STORAGE=filesystem \
-e DAKERA_STORAGE_PATH=/data \
-v dakera-data:/data \
ghcr.io/dakera-ai/dakera:latest
After starting, point your SDK clients and MCP binary at http://<SERVER_IP>:3300.
Docker Compose (recommended)
Copy the two files below into a working directory (e.g. ~/dakera/) and run docker compose up -d. The minio-setup service creates the storage bucket automatically — Dakera will not start until the bucket exists.
docker-compose.yml
# docker-compose.yml — production-grade single-node stack
# Usage:
# docker compose up -d # server + MinIO
# docker compose --profile dashboard up -d # + Dashboard UI
# docker compose --profile monitoring up -d # + Prometheus + Grafana
# docker compose --profile full up -d # all services
name: dakera
services:
dakera:
image: ${DAKERA_IMAGE:-ghcr.io/dakera-ai/dakera:latest}
container_name: dakera
restart: unless-stopped
ports:
- "${DAKERA_PORT:-3300}:3300"
- "${DAKERA_GRPC_PORT:-50051}:50051"
environment:
RUST_LOG: ${RUST_LOG:-info}
DAKERA_HOST: 0.0.0.0
DAKERA_PORT: 3300
DAKERA_GRPC_PORT: 50051
DAKERA_AUTH_ENABLED: ${DAKERA_AUTH_ENABLED:-true}
DAKERA_ROOT_API_KEY: ${DAKERA_ROOT_API_KEY:?Set DAKERA_ROOT_API_KEY in .env}
DAKERA_STORAGE: s3
DAKERA_S3_ENDPOINT: http://minio:9000
DAKERA_S3_BUCKET: dakera
DAKERA_S3_REGION: us-east-1
DAKERA_S3_MAX_RETRIES: 3
AWS_ACCESS_KEY_ID: ${MINIO_ROOT_USER:-minioadmin}
AWS_SECRET_ACCESS_KEY: ${MINIO_ROOT_PASSWORD:?Set MINIO_ROOT_PASSWORD in .env}
DAKERA_L1_CACHE_SIZE: 536870912
DAKERA_L2_CACHE_PATH: /data/rocksdb
DAKERA_TIERED_STORAGE: true
DAKERA_HOT_TO_WARM_SECS: 3600
DAKERA_WARM_TO_COLD_SECS: 86400
DAKERA_ML_CLASSIFIER: true
DAKERA_TEMPORAL_INFERENCE: true
volumes:
- dakera-cache:/data/cache
- dakera-rocksdb:/data/rocksdb
depends_on:
minio-setup:
condition: service_completed_successfully
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:3300/health"]
interval: 10s
timeout: 5s
retries: 5
start_period: 15s
deploy:
resources:
limits:
memory: 4G
cpus: "2.0"
reservations:
memory: 512M
networks:
- dakera-net
minio:
image: minio/minio:latest
container_name: dakera-minio
restart: unless-stopped
command: server /data --console-address ":9001"
ports:
- "${MINIO_API_PORT:-9000}:9000"
- "${MINIO_CONSOLE_PORT:-9001}:9001"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minioadmin}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?Set MINIO_ROOT_PASSWORD in .env}
MINIO_API_REQUESTS_MAX: 6000
volumes:
- minio-data:/data
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 10s
timeout: 5s
retries: 10
networks:
- dakera-net
# IMPORTANT: creates the MinIO bucket before Dakera starts.
# Without this, Dakera will start but all writes will fail.
minio-setup:
image: minio/mc:latest
container_name: dakera-minio-setup
depends_on:
minio:
condition: service_healthy
entrypoint: >
/bin/sh -c "
mc alias set local http://minio:9000 $${MINIO_ROOT_USER:-minioadmin} $${MINIO_ROOT_PASSWORD};
mc mb local/dakera --ignore-existing;
echo 'Bucket ready.';
"
networks:
- dakera-net
# Dashboard UI (optional — enable with --profile dashboard)
dashboard:
image: ${DASHBOARD_IMAGE:-ghcr.io/dakera-ai/dakera-dashboard:latest}
container_name: dakera-dashboard
profiles: ["dashboard", "full"]
restart: unless-stopped
ports:
- "${DASHBOARD_PORT:-3002}:3000"
environment:
DAKERA_API_UPSTREAM: http://dakera:3300
DAKERA_API_KEY: ${DAKERA_ROOT_API_KEY}
depends_on:
dakera:
condition: service_healthy
networks:
- dakera-net
# Prometheus + Grafana (optional — enable with --profile monitoring)
prometheus:
image: prom/prometheus:v3.2.0
container_name: dakera-prometheus
profiles: ["monitoring", "full"]
ports:
- "${PROMETHEUS_PORT:-9090}:9090"
volumes:
- prometheus-data:/prometheus
command:
- "--storage.tsdb.path=/prometheus"
- "--storage.tsdb.retention.time=15d"
- "--web.enable-lifecycle"
restart: unless-stopped
networks:
- dakera-net
grafana:
image: grafana/grafana:11.4.0
container_name: dakera-grafana
profiles: ["monitoring", "full"]
ports:
- "${GRAFANA_PORT:-3003}:3000"
environment:
GF_SECURITY_ADMIN_USER: ${GRAFANA_USER:-admin}
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-dakera}
volumes:
- grafana-data:/var/lib/grafana
depends_on: [prometheus]
restart: unless-stopped
networks:
- dakera-net
volumes:
dakera-cache:
dakera-rocksdb:
minio-data:
prometheus-data:
grafana-data:
networks:
dakera-net:
driver: bridge
.env template
Place alongside docker-compose.yml. Never commit .env to version control.
# .env — fill in REQUIRED values before first start
# REQUIRED — root API key (grants full access)
DAKERA_ROOT_API_KEY=
# REQUIRED — MinIO credentials
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=
# Optional port overrides (defaults shown)
# DAKERA_PORT=3300
# DAKERA_GRPC_PORT=50051
# MINIO_API_PORT=9000
# MINIO_CONSOLE_PORT=9001
# DASHBOARD_PORT=3002
# Optional image pins
# DAKERA_IMAGE=ghcr.io/dakera-ai/dakera:v0.11.55
# DASHBOARD_IMAGE=ghcr.io/dakera-ai/dakera-dashboard:latest
Generate fresh secrets in one command:
printf "DAKERA_ROOT_API_KEY=%s
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=%s
" "$(openssl rand -hex 32)" "$(openssl rand -hex 16)" > .env
Startup sequence
# Start core stack (Dakera + MinIO + bucket init)
docker compose up -d
# Wait ~30s, then verify all services are healthy
docker compose ps
# Confirm the API is accepting requests
curl -s http://localhost:3300/health
# → {"service":"dakera","status":"healthy","version":"0.11.x"}
# Optional: launch Dashboard UI at http://localhost:3002
docker compose --profile dashboard up -d
# Optional: launch Prometheus (port 9090) + Grafana (port 3003)
docker compose --profile monitoring up -d
Kubernetes — Kustomize
The dakera-deploy repo ships a production-ready kustomize stack. Zero extra tools required — just kubectl ≥ 1.21.
# Clone the deploy repo
git clone https://github.com/dakera-ai/dakera-deploy
cd dakera-deploy
# 1. Create secrets (gitignored — never commit)
cp k8s/secret.example.yaml k8s/secret.yaml
# Edit k8s/secret.yaml — set base64-encoded values:
# DAKERA_ROOT_API_KEY: $(echo -n "$(openssl rand -hex 32)" | base64)
# 2. Apply the full stack (namespace, MinIO, server, dashboard, MCP, ingress)
kubectl apply -f k8s/secret.yaml
kubectl apply -k k8s/
# 3. Verify pods are running
kubectl get pods -n dakera
Kubernetes — Helm
The official Helm chart lives in the dedicated dakera-helm repository and deploys all components: server, dashboard, MCP, MinIO, and optional monitoring. Requires Helm ≥ 3.8.
Install from OCI registry (recommended)
# No extra repo config needed — pulls directly from GHCR
helm install dakera oci://ghcr.io/dakera-ai/dakera-helm/dakera \
--namespace dakera --create-namespace \
--set dakera.rootApiKey="$(openssl rand -hex 32)" \
--set minio.rootPassword="$(openssl rand -hex 16)"
# Pin a specific version
helm install dakera oci://ghcr.io/dakera-ai/dakera-helm/dakera \
--version 0.11.55 \
--namespace dakera --create-namespace \
--set dakera.rootApiKey="$(openssl rand -hex 32)" \
--set minio.rootPassword="$(openssl rand -hex 16)"
# Upgrade an existing release
helm upgrade dakera oci://ghcr.io/dakera-ai/dakera-helm/dakera \
--namespace dakera \
--set dakera.rootApiKey="<existing-key>" \
--set minio.rootPassword="<existing-password>"
# Check release status
helm status dakera -n dakera
Install from Helm repository (ArtifactHub)
helm repo add dakera https://dakera-ai.github.io/dakera-helm
helm repo update
helm install dakera dakera/dakera \
--namespace dakera --create-namespace \
--set dakera.rootApiKey="$(openssl rand -hex 32)" \
--set minio.rootPassword="$(openssl rand -hex 16)"
Install from chart source
git clone https://github.com/dakera-ai/dakera-helm
cd dakera-helm
# Dry-run to preview rendered manifests
helm install dakera ./charts/dakera --dry-run --debug
# Install
helm install dakera ./charts/dakera \
--namespace dakera --create-namespace \
--set dakera.rootApiKey="$(openssl rand -hex 32)" \
--set minio.rootPassword="$(openssl rand -hex 16)"
Complete values.yaml reference
Override any value with --set key=value or a custom values file (-f my-values.yaml). Full defaults in charts/dakera/values.yaml.
Dakera server
| Key | Default | Description |
|---|---|---|
dakera.image.repository | ghcr.io/dakera-ai/dakera | Server container image repository |
dakera.image.tag | chart appVersion | Image tag — pin this in production |
dakera.image.pullPolicy | IfNotPresent | Pull policy: Always / IfNotPresent / Never |
dakera.replicaCount | 1 | Server replicas (use HPA for auto-scaling) |
dakera.rootApiKey | required | Root API key — set via --set or external secret |
dakera.config.port | 3000 | REST API port inside the pod |
dakera.config.grpcPort | 50051 | gRPC port inside the pod |
dakera.config.storage | s3 | Storage backend: memory, filesystem, s3 |
dakera.config.s3Bucket | dakera | MinIO / S3 bucket name |
dakera.config.s3Region | us-east-1 | Region (any string for self-hosted MinIO) |
dakera.config.l1CacheSize | 1073741824 | In-memory L1 cache in bytes (default 1 GB) |
dakera.config.tieredStorage | true | Enable hot → RocksDB → S3 tiering |
dakera.config.hotToWarmSecs | 3600 | Seconds before L1 moves to RocksDB |
dakera.config.warmToColdSecs | 86400 | Seconds before RocksDB moves to S3 |
dakera.config.authEnabled | true | Enforce API key auth on all requests |
dakera.persistence.enabled | true | Mount a PVC for the RocksDB L2 cache |
dakera.persistence.size | 20Gi | RocksDB PVC size |
dakera.persistence.storageClass | cluster default | StorageClass (empty = cluster default) |
dakera.resources.requests.cpu | 500m | CPU request |
dakera.resources.requests.memory | 512Mi | Memory request |
dakera.resources.limits.cpu | 2 | CPU limit |
dakera.resources.limits.memory | 4Gi | Memory limit — increase for >1M memories |
dakera.service.type | ClusterIP | Service type (ClusterIP / NodePort / LoadBalancer) |
Autoscaling (HPA)
| Key | Default | Description |
|---|---|---|
dakera.autoscaling.enabled | true | Enable Horizontal Pod Autoscaler |
dakera.autoscaling.minReplicas | 1 | Minimum replicas |
dakera.autoscaling.maxReplicas | 5 | Maximum replicas |
dakera.autoscaling.targetCPUUtilizationPercentage | 70 | Scale-up CPU threshold (%) |
dakera.autoscaling.targetMemoryUtilizationPercentage | 80 | Scale-up memory threshold (%) |
Dashboard, MCP, MinIO
| Key | Default | Description |
|---|---|---|
dashboard.enabled | true | Deploy the Dashboard UI |
dashboard.replicaCount | 1 | Dashboard replicas |
dashboard.resources.limits.cpu | 500m | Dashboard CPU limit |
dashboard.resources.limits.memory | 256Mi | Dashboard memory limit |
mcp.enabled | true | Deploy the MCP server sidecar |
mcp.config.port | 3001 | MCP server listen port |
mcp.resources.limits.memory | 256Mi | MCP memory limit |
minio.enabled | true | Deploy built-in MinIO — set false for external S3 |
minio.rootUser | minioadmin | MinIO root username — change in production |
minio.rootPassword | required | MinIO root password — set via --set |
minio.persistence.size | 50Gi | MinIO data PVC size |
minio.persistence.storageClass | cluster default | StorageClass for MinIO PVC |
minio.resources.limits.memory | 2Gi | MinIO memory limit |
Ingress
| Key | Default | Description |
|---|---|---|
ingress.enabled | false | Enable nginx Ingress |
ingress.className | nginx | Ingress class (nginx / traefik) |
ingress.apiHost | — | Hostname for the Dakera REST API |
ingress.dashboardHost | — | Hostname for the Dashboard UI |
ingress.mcpHost | — | Hostname for the MCP server |
ingress.annotations | {} | Ingress annotations (e.g. cert-manager issuer) |
Monitoring
| Key | Default | Description |
|---|---|---|
monitoring.enabled | false | Deploy Prometheus + Grafana (auto-scrapes /metrics) |
monitoring.prometheus.retention | 15d | Prometheus data retention |
monitoring.prometheus.persistence.size | 10Gi | Prometheus PVC size |
monitoring.grafana.adminUser | admin | Grafana admin username |
monitoring.grafana.adminPassword | auto-generated | Grafana admin password (random if empty) |
monitoring.grafana.persistence.size | 5Gi | Grafana PVC size |
Enable ingress with TLS
# production-values.yaml
ingress:
enabled: true
className: nginx
apiHost: api.dakera.example.com
dashboardHost: dashboard.dakera.example.com
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
tls:
- secretName: dakera-tls
hosts:
- api.dakera.example.com
- dashboard.dakera.example.com
helm upgrade dakera oci://ghcr.io/dakera-ai/dakera-helm/dakera -f production-values.yaml
Use external S3 instead of MinIO
# external-s3-values.yaml
minio:
enabled: false
dakera:
config:
s3Endpoint: https://s3.amazonaws.com
s3Bucket: my-dakera-bucket
s3Region: us-east-1
Verify your deployment
# All pods should reach Running
kubectl get pods -n dakera
# Port-forward and smoke-test
kubectl port-forward svc/dakera 3300:3300 -n dakera &
curl -s http://localhost:3300/health
# {"status":"ok"}
# View recent logs
kubectl logs -l app.kubernetes.io/name=dakera -n dakera --tail=50
# Describe a pod for events
kubectl describe pod -l app.kubernetes.io/name=dakera -n dakera
Cloud deployment
AWS ECS / EKS
Use ECR for the container image. For EKS, add the AWS Load Balancer Controller for Ingress and IRSA for S3 access without static credentials.
GCP GKE
Build via gcloud builds submit, push to GCR/Artifact Registry, and apply kustomize. Use Workload Identity for GCS bucket access.
Azure AKS
Build via Azure Container Registry. Use AKS with Azure Blob Storage backend, enabling minio.enabled=false in the Helm values.
Bare metal / VM
Single binary, no runtime deps. Run under systemd with Restart=always. See the Docker Compose files for a production-hardened stack.
Self-host on a VPS
Five steps to run Dakera on a fresh Ubuntu/Debian VPS or bare metal server. Requires Docker ≥ 24 and Docker Compose ≥ 2.20.
Install Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
newgrp docker
Create a working directory
mkdir -p ~/dakera && cd ~/dakera
Generate secrets
# Creates .env with fresh random credentials
cat > .env << EOF
DAKERA_API_KEY=$(openssl rand -hex 32)
MINIO_USER=minioadmin
MINIO_PASSWORD=$(openssl rand -hex 16)
EOF
.env private. It holds your root API key — the only credential that can create namespaces and rotate keys. Never commit it to git.Copy the docker-compose.yml
Save the Docker Compose (recommended) snippet from above as ~/dakera/docker-compose.yml. The compose file reads credentials from .env automatically.
Start the stack
docker compose up -d
The first start pulls images and initialises MinIO storage. Allow 20–30 seconds for all health checks to pass.
Startup verification
Run these checks after docker compose up -d to confirm the stack is healthy before routing traffic.
# All services should show "Up (healthy)"
docker compose ps
# REST API health — expects {"status":"ok","version":"0.11.x"}
curl -s http://localhost:3300/health
# Confirm authentication is enforced — expects 401
curl -s -o /dev/null -w "%{http_code}" http://localhost:3300/v1/memories
# Smoke-test write path with your API key
curl -s -X POST http://localhost:3300/v1/memories \
-H "Authorization: Bearer $DAKERA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"agent_id":"smoke-test","content":"startup check","importance":0.5}'
# Expected: {"id":"mem_...","agent_id":"smoke-test",...}
# Tail logs for any startup errors
docker compose logs -f dakera --tail=50
http://<SERVER_IP>:3300 with your DAKERA_API_KEY.Upgrading Dakera
Minor and patch upgrades are data-safe — RocksDB and S3 data survive image replacements. No migration scripts are needed unless the release notes say otherwise.
# Pull the latest image (or pin a specific tag in docker-compose.yml first)
docker compose pull dakera
# Restart only the Dakera container — MinIO keeps running
docker compose up -d --no-deps dakera
# Confirm the new version is live
curl -s http://localhost:3300/health | grep version
# Watch logs for any startup errors
docker compose logs -f dakera --tail=100
Environment variable reference
Pass variables via an .env file (co-located with docker-compose.yml) or set them directly in the environment: block. Variables marked required must be set before starting.
Core
| Variable | Default | Description |
|---|---|---|
DAKERA_ROOT_API_KEY | required | Root API key — grants full admin access. Generate: openssl rand -hex 32. |
DAKERA_AUTH_ENABLED | true | Enforce API key authentication on all requests. Set false only for local dev. |
DAKERA_HOST | 0.0.0.0 | Bind address for the REST API. |
DAKERA_PORT | 3300 | REST API listen port. |
DAKERA_GRPC_PORT | 50051 | gRPC listen port. |
RUST_LOG | info | Log verbosity: error | warn | info | debug. Avoid debug in production. |
DAKERA_ML_CLASSIFIER | false | Enable ML-based query classification for improved recall across diverse query types. Recommended in production. |
Storage
| Variable | Default | Description |
|---|---|---|
DAKERA_STORAGE | memory | Storage backend: memory (non-persistent), filesystem, or s3. Use s3 with MinIO for production. |
DAKERA_STORAGE_PATH | /data | Root path for filesystem storage and cache. Mount a persistent volume here. |
DAKERA_L2_CACHE_PATH | /data/rocksdb | RocksDB L2 cache path. SSD-backed storage improves recall latency. |
DAKERA_L1_CACHE_SIZE | 536870912 | In-memory L1 cache size in bytes (default 512 MB). Increase for high-throughput deployments. |
DAKERA_TIERED_STORAGE | true | Enable automatic hot → RocksDB → S3 tiering. |
DAKERA_HOT_TO_WARM_SECS | 3600 | Seconds before L1 memories are promoted to RocksDB (L2). |
DAKERA_WARM_TO_COLD_SECS | 86400 | Seconds before RocksDB memories are promoted to S3 cold storage. |
S3 / MinIO
Required when DAKERA_STORAGE=s3.
| Variable | Default | Description |
|---|---|---|
DAKERA_S3_ENDPOINT | — | S3-compatible endpoint URL. For self-hosted MinIO: http://minio:9000. Omit for AWS S3. |
DAKERA_S3_BUCKET | — | Target bucket name. The bucket must exist before Dakera starts. |
DAKERA_S3_REGION | us-east-1 | S3 region. For self-hosted MinIO this can be any non-empty string. |
DAKERA_S3_MAX_RETRIES | 3 | Retry count on transient S3 errors. |
AWS_ACCESS_KEY_ID | — | S3 / MinIO access key ID. |
AWS_SECRET_ACCESS_KEY | — | S3 / MinIO secret access key. |
Request handling
| Variable | Default | Description |
|---|---|---|
DAKERA_MAX_BODY_SIZE | 524288000 | Max HTTP request body in bytes (default 500 MB). Reduce if not using bulk import. |
DAKERA_REQUEST_TIMEOUT | 120 | HTTP request timeout in seconds. |
Cluster (HA mode only)
| Variable | Default | Description |
|---|---|---|
DAKERA_CLUSTER_MODE | false | Enable multi-node cluster. See the High Availability section for the full setup guide. |
DAKERA_NODE_ID | — | Unique node identifier within the cluster (e.g. node-1). |
DAKERA_CLUSTER_SEEDS | — | Comma-separated gossip bootstrap addresses: dakera-2:7946,dakera-3:7946. |
DAKERA_GOSSIP_PORT | 7946 | SWIM-style cluster gossip port. Must be open between nodes. |
DAKERA_REDIS_URL | — | Redis connection URL for distributed L2 cache in cluster mode (e.g. redis://redis:6379). |
Production checklist
| Item | Notes |
|---|---|
✓ Set DAKERA_ROOT_API_KEY | Use a cryptographically random 32+ char secret |
✓ Mount persistent volume for DAKERA_STORAGE_PATH | Use SSD for best performance |
| ✓ Enable S3 storage for critical data | MinIO works well for self-hosted |
✓ Scrape /metrics with Prometheus | 13 built-in metrics including per-operation counters |
| ✓ Set resource limits | 1–2 CPU, 2–4 GB RAM for ≤1M memories |
✓ Enable DAKERA_ML_CLASSIFIER=true | Improves recall quality for diverse query types |
✓ Set RUST_LOG=info | Avoid debug in production (too verbose) |
Deployment resources
Architecture
Five Rust crates compiled into one binary. No runtime dependencies, no sidecars.
System overview
Design principles
Single binary
All five crates compile to one statically-linked binary. No Node.js, no Python runtime, no sidecar containers required.
Async-first
Every I/O path is async via Tokio. REST, gRPC, storage reads/writes, and embedding inference never block threads.
SIMD-accelerated distances
Cosine similarity, Euclidean distance, and dot product use vectorized instructions. Nearest-neighbor search stays fast at millions of vectors.
Pluggable storage
The VectorStorage trait abstracts over in-memory, RocksDB, and S3 backends. Swap storage tiers without changing application code.
Crate structure
| Crate | Responsibility |
|---|---|
crates/api/ | Axum HTTP server — all routes, middleware, rate limiting, authentication |
crates/engine/ | Recall pipeline — hybrid retrieval, reranking, temporal scoring, decay |
crates/storage/ | RocksDB + OpenDAL tiered storage; Moka LRU cache; HNSW/IVF/SPFresh indexes |
crates/inference/ | ONNX embedding inference — MiniLM, BGE, E5 loaded eagerly at startup |
crates/common/ | Shared types — MemoryRecord, ImportanceFilter, SessionId, FilterExpression |
Storage tiers
| Tier | Technology | Characteristics |
|---|---|---|
| Hot | Moka in-memory LRU | Sub-millisecond access, bounded by RAM, auto-eviction |
| Warm | RocksDB (WAL-backed) | Persistent, low-latency, survives restarts |
| Cold | S3 / MinIO (OpenDAL) | Durable, scalable, archival snapshots |
Vector indexes
| Algorithm | Best for | Trade-offs |
|---|---|---|
| HNSW | General-purpose ANN, <10M vectors | Best recall/speed; higher memory |
| IVF | Large collections, 10M+ vectors | Lower memory overhead; slightly lower recall |
| SPFresh | High-frequency streaming inserts | Updates without full rebuild; good for append-heavy workloads |
| Flat (exact) | Ground-truth benchmarking, small datasets | 100% recall; O(n) query time |
Recall pipeline
Every POST /v1/memory/recall passes through 6 stages:
Embed
Input query encoded to a dense vector using the configured ONNX model (on-device, zero API calls).
Hybrid retrieve
Vector ANN search + BM25 full-text search run in parallel. Results fused via Reciprocal Rank Fusion (RRF, k=60 default).
ML classify
Optional ML classifier (embedding centroid cosine similarity) assigns query category: Cat1 (factual), Cat2 (multi-hop), Cat3 (temporal inference), Cat4 (comparison).
Temporal scoring
For Cat3 queries: multiplicative tilt toward temporally-relevant memories. Formula: score *= (1 + β × (proximity − 0.5)).
Rerank
Cross-encoder or score-based rerank on top-K candidates. Entity name boost applied post-fusion.
Decay & return
Importance decay applied. Recalled memories get access-count boost. Top-N returned with scores, metadata, and session context.
Memory store flow
Filter expressions
Metadata filters can be applied to any recall, vector query, or batch operation. Filters compose with $and / $or operators.
# Find memories tagged as important, created after a timestamp
{
"filter": {
"$and": [
{ "importance": { "$gt": 0.7 } },
{ "tags": { "$in": ["decision", "blocker"] } }
]
}
}
| Operator | Type | Example |
|---|---|---|
$eq | Equality | {"agent_id": {"$eq": "my-agent"}} |
$gt / $lt | Numeric range | {"importance": {"$gt": 0.5}} |
$gte / $lte | Inclusive range | {"score": {"$gte": 0.8}} |
$in | Array membership | {"tags": {"$in": ["prod","alert"]}} |
$and | Logical AND | Combine multiple conditions |
$or | Logical OR | Match any condition |
Security Guide
Comprehensive security documentation for deploying and operating Dakera securely in production.
Security Layers
| Layer | Protection | Configuration |
|---|---|---|
| API Authentication | API key validation with scopes | DAKERA_ROOT_API_KEY |
| Rate Limiting | DoS protection | RATE_LIMIT_RPS, RATE_LIMIT_BURST |
| Security Headers | XSS, clickjacking, MIME sniffing | Enabled by default |
| Audit Logging | Request tracking and forensics | DAKERA_AUDIT_* |
| Input Validation | Injection prevention | Built-in validation layer |
API Key Scopes
| Scope | Permissions | Use Case |
|---|---|---|
read | Query vectors, get namespace info | Read-only clients |
write | Upsert/delete vectors (includes read) | Applications writing data |
admin | Namespace management (includes write) | Administrative tools |
super_admin | Key management, cluster ops | Operators only |
Bootstrap Root Key
# Generate a secure random key (256-bit entropy)
export DAKERA_ROOT_API_KEY=$(openssl rand -hex 32)
./dakera
Creating Application Keys
# Create a read-only key
curl -X POST http://localhost:3300/admin/keys \
-H "Authorization: Bearer $DAKERA_ROOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"query-service","scope":"read","expires_in_days":90}'
Network Security
- Bind to
127.0.0.1or a private network interface — never expose port 3300 publicly without a reverse proxy - Use TLS termination at your load balancer (nginx, Caddy, Traefik)
- Rate limiting is enabled by default — tune
RATE_LIMIT_RPSfor your workload - Security headers (HSTS, CSP, X-Frame-Options) are sent on all responses
Audit Logging
Every API request is logged with agent ID, operation, and timestamp when DAKERA_AUDIT_LOG=true. Audit logs are written to DAKERA_AUDIT_LOG_PATH (default: ./audit.log) in JSON format.
Production Security Checklist
| Item | Status |
|---|---|
| Root API key generated with ≥256-bit entropy | Required |
| Application keys use minimum required scope | Required |
| TLS enabled on all external-facing endpoints | Required |
| Server not directly accessible from the internet (reverse proxy) | Required |
| Rate limiting configured for expected traffic | Recommended |
| Audit logging enabled | Recommended |
| API key rotation schedule (90 days) | Recommended |
Kubernetes secrets
Store the root API key in a Kubernetes Secret rather than in a ConfigMap or environment literal.
# Create the secret from a generated key
kubectl create secret generic dakera-secret \
--namespace dakera \
--from-literal=api-key="$(openssl rand -hex 32)"
# Reference in your Pod spec
env:
- name: DAKERA_ROOT_API_KEY
valueFrom:
secretKeyRef:
name: dakera-secret
key: api-key
TLS configuration
Terminate TLS at your reverse proxy or ingress controller. Dakera does not natively terminate TLS — this is by design (separation of concerns, simpler rotation).
# nginx reverse proxy — TLS termination
server {
listen 443 ssl;
ssl_certificate /etc/ssl/dakera.crt;
ssl_certificate_key /etc/ssl/dakera.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
location / {
proxy_pass http://127.0.0.1:3300;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
High Availability
Dakera ships a 3-node HA cluster via docker-compose.ha.yml in the dakera-deploy repo. Traffic is load-balanced by Traefik; shared state is stored on MinIO. Nodes discover each other via a SWIM-style gossip protocol.
Cluster topology
Quick start
# Start the full HA stack
cd dakera-deploy
docker-compose -f docker-compose.ha.yml up -d
# Verify all services are healthy
docker-compose -f docker-compose.ha.yml ps
Expected: dakera-lb, dakera-1, dakera-2, dakera-3, dakera-ha-minio all in running (healthy) state.
Key ports
| Service | Default port | Override env var |
|---|---|---|
| Dakera REST API (via LB) | 3100 | HA_LB_HTTP_PORT |
| Dakera gRPC (via LB) | 50151 | HA_LB_GRPC_PORT |
| Gossip / cluster membership | 7946 | HA_GOSSIP_PORT |
| MinIO S3 API | 9100 | HA_MINIO_PORT |
| MinIO console | 9101 | HA_MINIO_CONSOLE_PORT |
Smoke-test the cluster
# Health check (via load balancer)
curl http://localhost:3100/health
# Cluster node status
curl -H "Authorization: Bearer $DAKERA_ROOT_API_KEY" \
http://localhost:3100/admin/cluster/status
# List all nodes
curl -H "Authorization: Bearer $DAKERA_ROOT_API_KEY" \
http://localhost:3100/admin/cluster/nodes
Failover behaviour
Traefik health-checks each node via /health every 10 s. If a node fails its checks, Traefik stops routing traffic to it within one check interval. The gossip protocol detects the departure and removes the node from cluster membership. When the node recovers it rejoins automatically.
# Simulate node failure (test failover)
docker stop dakera-2
# Verify the cluster still responds
curl http://localhost:3100/health # should still return {"status":"ok"}
# Restore the node
docker start dakera-2
Scaling
To add nodes, extend docker-compose.ha.yml with additional service blocks using the same gossip seed address (DAKERA_GOSSIP_SEED=dakera-1:7946). For Kubernetes, increase dakera.replicaCount in the Helm values — the HPA handles autoscaling up to 5 replicas at 70% CPU utilisation by default.
HA key environment variables
| Variable | Description |
|---|---|
DAKERA_CLUSTER_MODE=ha | Enable HA mode (gossip + shared state) |
DAKERA_GOSSIP_SEED | Bootstrap peer address (host:port) |
DAKERA_NODE_ID | Unique identifier for this node |
DAKERA_STORAGE=s3 | All nodes must share an S3-compatible backend |
DAKERA_S3_BUCKET | Shared bucket for indexes and metadata |
Production considerations
- Use a dedicated MinIO cluster (or managed S3) for the shared storage tier — avoid single-point-of-failure on the storage node.
- Place the load balancer (Traefik / nginx / AWS ALB) outside the Dakera node pool to ensure it survives individual node failures.
- Enable Prometheus scraping on all nodes — the cluster health dashboard aggregates per-node metrics automatically.
- Run odd replica counts (3, 5) to maintain quorum during leader election.
How Memory Works
Before writing your first memory, it helps to understand Dakera's core primitives. Once you understand agents, importance, and retrieval, the API will make intuitive sense.
Core primitives
Agents
An agent is a named memory namespace identified by a string you choose. All memories belong to an agent. Agents are isolated by default — a recall call on agent-A never returns memories from agent-B.
You can have as many agents as you need — one per user, one per pipeline stage, one per AI persona. There's no registration step; Dakera creates the namespace automatically the first time you store a memory for it.
/v1/knowledge/network/cross-agent). See Patterns & Recipes →Memory types
Every memory has a memory_type that controls how it is used and how quickly it decays:
| Type | Use for | Decay rate |
|---|---|---|
episodic | Specific events, user actions, conversation history | Normal (default) |
semantic | Facts, knowledge, learned patterns — more durable | Slow |
procedural | Instructions, skills, how-to knowledge | Slow |
working | Short-term scratchpad, current task context | Fast |
If you omit memory_type, it defaults to episodic.
Importance scoring
Every memory has an importance score from 0.0 to 1.0. Importance affects:
- Recall ranking — higher-importance memories score better in retrieval, all else equal
- Decay resistance — memories with high importance fade more slowly over time
- Batch filtering — use
min_importanceto exclude low-signal memories
Rough guide: 0.9+ for critical facts, 0.7–0.8 for important context, 0.5 for routine observations (the default), 0.3 for ephemeral state. When a recalled memory is accessed, Dakera automatically boosts its importance slightly — frequently-retrieved memories stay relevant longer.
Memory decay
Memories decay over time when not accessed. Rarely-recalled information fades; frequently-retrieved knowledge stays sharp. Decay rate is governed by memory_type and importance. Configure the global decay rate via DAKERA_DECAY_RATE — see Configuration →
To expire a memory after a known deadline, set expires_at to a Unix timestamp at store time. The decay engine hard-deletes expired memories automatically.
Sessions
A session groups related memories under a single ID. Sessions are optional but useful for:
- Scoping recall to a single conversation or task
- Retrieving all memories from a specific interaction via
/v1/sessions/{id}/memories - Per-session deduplication and auto-generated summaries
Start a session with POST /v1/sessions/start, pass the returned session_id to /v1/memory/store, then close it with POST /v1/sessions/{id}/end.
Namespaces
Namespaces are the low-level isolation unit for vector data. Each namespace has its own HNSW index, BM25 index, and embedding configuration. The memory API routes to namespaces automatically via agent IDs — you only interact with namespaces directly when using the low-level vector search API (/v1/namespaces/) for RAG or custom search use cases.
The retrieval pipeline
When you call recall, Dakera runs a three-stage pipeline:
Embed
Your query is embedded using the configured ONNX model (default: MiniLM-L6-v2). Embedding runs on-device — no external API call, no latency added by network hops.
Retrieve
Vector ANN search (HNSW) and BM25 full-text search run in parallel. Results are merged using Reciprocal Rank Fusion (RRF). The ML routing classifier selects the optimal retrieval mode based on query characteristics.
Rank
Results are re-ranked combining semantic relevance score with importance and recency. Memories above the min_importance threshold are returned in ranked order.
What's next?
Patterns & Recipes
Common patterns for building production-grade agent memory systems.
Multi-agent memory sharing
By default, agents are isolated. To share knowledge across agents, use the cross-agent knowledge network endpoint. Useful for supervisor/worker pipelines where a parent agent needs context from sub-agents:
# Query memory across multiple agents
curl -X POST http://localhost:3300/v1/knowledge/network/cross-agent \
-H "Authorization: Bearer $DAKERA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent_ids": ["agent-a", "agent-b", "supervisor"],
"query": "user preferences",
"top_k": 5
}'
Importance scoring guidelines
| Score | Use for | Examples |
|---|---|---|
0.9 – 1.0 | Critical, must-not-forget facts | User name, critical config, key decisions |
0.7 – 0.8 | Important context and decisions | User preferences, completed tasks, key findings |
0.5 | Routine observations (default) | Conversational notes, intermediate results |
0.3 | Ephemeral / will decay fast | Temporary state, telemetry markers |
Memory decay & TTL
If memories are disappearing too quickly, raise their importance at store time (importance ≥ 0.8). To hard-expire a memory after a task, set expires_at to a Unix timestamp:
{
"agent_id": "task-agent",
"content": "Working on PR #123",
"importance": 0.3,
"expires_at": 1778800000 // Unix timestamp — memory hard-deleted after this
}
Session-scoped memory
For conversational agents, wrap each conversation in a session to isolate context and enable session-level retrieval:
# Start session
session = client.sessions.start(agent_id="my-agent")
# Store memories scoped to this session
client.memories.store(
agent_id="my-agent",
content="User asked about pricing",
session_id=session.id
)
# End session
client.sessions.end(session_id=session.id)const session = await client.sessions.start({ agentId: 'my-agent' });
await client.memories.store({
agentId: 'my-agent',
content: 'User asked about pricing',
sessionId: session.id,
});
await client.sessions.end({ sessionId: session.id });Batch recall with filters
Use batch_recall for filter-based lookups without a semantic query — useful for fetching all memories with specific tags, above an importance threshold, or within a time range:
POST /v1/memories/recall/batch
{
"agent_id": "my-agent",
"tags": ["preference", "critical"],
"min_importance": 0.7,
"created_after": 1778000000
}
Related docs
Troubleshooting
Common issues and how to fix them. Always start with the health endpoint:
curl http://localhost:3300/health
# {"service":"dakera","status":"healthy","version":"0.11.55"}
Server not starting
Check container logs first: docker logs dakera --tail 50. Common causes:
- Port conflict — Change
DAKERA_PORTand the-pmapping in your Docker command - Volume permission error — Ensure the data directory is writable by the container user
- Missing API key — Set
DAKERA_ROOT_API_KEYin your environment
Authentication errors (401)
All authenticated requests need: Authorization: Bearer <your-api-key>
In SDKs, pass via environment variable (DAKERA_API_KEY=your-key) or the api_key / apiKey constructor parameter. Verify the key matches DAKERA_ROOT_API_KEY on the server.
No memories returned from recall
- Wrong
agent_id— Recall is scoped to a single agent. Verify it exactly matches what you stored with. - Nothing stored yet — Confirm with
GET /v1/agents/{id}/sessions. min_importancefilter too high — Lower or remove the filter.- Query too different from stored content — Try a query closer to the stored text to verify retrieval is working, then refine.
Slow queries
- First request after startup — Dakera loads ONNX models on first use; expect 1–2 s cold start. Subsequent calls are fast.
- Large HNSW index — Above 1M vectors, consider lowering
DAKERA_HNSW_EF(lower = faster, slightly less accurate). - Slow storage backend — Use SSD-backed volumes. S3 storage adds latency — use filesystem mode for low-latency workloads.
Connection refused
- Verify the server is running:
docker ps | grep dakera - Use the server's public IP, not
localhost, when the server is on a remote VM - Check firewall rules allow inbound traffic on port 3300 (or your configured port)
MCP server not connecting to Claude
- Use an absolute path to the MCP binary in
.mcp.jsonand ensure the file is executable - Verify
DAKERA_URLin the MCP env config points to your running server - After editing
.mcp.json, fully restart Claude Desktop / Claude Code - Run the MCP binary directly in a terminal to see startup errors
Changelog
Recent Dakera releases. Full history at GitHub Releases and Docker Hub tags.
| Version | Date | Highlights |
|---|---|---|
v0.11.55 LATEST |
May 2026 | CE-118 temporal hybrid retrieval. Cat2 gate achieved (86.3%). 87.6% LoCoMo overall. |
v0.11.54 |
May 2026 | MCP: 83 tools. DAKERA_ENTITY_VECTOR_SEARCH enabled by default. Cross-encoder pipeline. |
v0.11.45 |
Apr 2026 | CE-71: ML routing classifier on by default. TEMPORAL_INFERENCE enabled. 87.1% LoCoMo. |
v0.11.27 |
Apr 2026 | HA cluster gossip stability improvements. MinIO throttle tuning. |
v0.10.2 |
Apr 2026 | Full stack release: server + py + js + rs + go SDKs simultaneously. |
v0.11.54, server at v0.11.55. See the Introduction → for the full packages table.Release cadence
Dakera releases frequently — typically multiple versions per week during active development. All releases follow semantic versioning. Patch versions (0.x.y → 0.x.(y+1)) are always safe to upgrade to in-place.
Release artifacts