NewRelease 0.12.3 is out: Engine v0.12.3, Dashboard 0.5.2, Helm 0.12.3, the four SDKs, CLI 0.8.2 and MCP 0.12.3Release 0.12.3 is outSee what's new →

Patterns and recipes

This page collects short, copyable curl recipes for the most common Dakera tasks: prompt context, conversations, expiring task memory, the knowledge graph, consolidation, feedback, migration, multi-tenant keys, event streams and auditing, plus a checklist before going to production. It is for developers wiring Dakera into an agent; the full architecture write-ups live in the Patterns Library.

Browse all patterns

Patterns Library →

The Patterns Library covers user preference recall, cross-session context, multi-agent memory, knowledge graphs, session handoff, semantic deduplication, RAG augmentation and batch ingestion, each with an explanation and working code. The examples below assume a server on localhost:3000 and an API key in $DAKERA_API_KEY.

Quick reference: common recipes

Ground an LLM's answers in what the agent remembers: store facts as they come up, and recall the relevant ones before each generation.

# 1. Store a memory from conversation
curl -X POST http://localhost:3000/v1/memory/store \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "assistant",
    "content": "User prefers dark mode and concise responses",
    "importance": 0.8,
    "tags": ["preference"]
  }'

# 2. Before generating a response, recall relevant context
curl -X POST http://localhost:3000/v1/memory/recall \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "assistant",
    "query": "What does the user prefer?",
    "top_k": 5
  }'

# 3. Inject recalled memories into your system prompt
# system_prompt = f"Context from memory:\n{memories}\n\nRespond to the user."

Conversation memory

Store and recall multi-turn conversation context. Use sessions to group memories by conversation thread:

# Start a session
curl -X POST http://localhost:3000/v1/sessions/start \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "chat-agent", "metadata": {"user": "u_123", "channel": "web"}}'

# Store each turn with the session
curl -X POST http://localhost:3000/v1/memory/store \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "chat-agent",
    "session_id": "sess_abc123",
    "content": "User asked about billing. Explained monthly vs annual pricing.",
    "importance": 0.7,
    "memory_type": "episodic"
  }'

# End session with summary
curl -X POST http://localhost:3000/v1/sessions/sess_abc123/end \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"summary": "Discussed billing options. User chose annual plan."}'

Task memory with TTL

Short-lived memories that auto-expire. Use expires_at (Unix timestamp) for task-scoped context that shouldn't persist after completion:

curl -X POST http://localhost:3000/v1/memory/store \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "task-agent",
    "content": "Working on PR #123 — fixing auth middleware",
    "importance": 0.3,
    "expires_at": 1778800000,
    "tags": ["ephemeral", "task"],
    "metadata": {"pr": 123, "repo": "backend"}
  }'
Decay vs TTL — Decay gradually reduces importance over time (configurable strategy). TTL hard-deletes the memory at the timestamp. Use TTL for task context; use decay for long-term memories that should fade naturally.

Knowledge base construction

Build a structured knowledge base using entities and the knowledge graph. Store facts, extract entities, then link related knowledge:

# Store a fact (tagged with entities when the agent's namespace has extract_entities on)
curl -X POST http://localhost:3000/v1/memory/store \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "kb-builder",
    "content": "React 19 introduces use() hook for async data fetching. Released January 2025.",
    "importance": 0.9,
    "memory_type": "semantic",
    "tags": ["react", "frontend"]
  }'

# Extract entities from a piece of text (nothing is stored)
curl -X POST http://localhost:3000/v1/memories/extract \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content": "React 19 introduces use() hook for async data fetching.", "entity_types": ["technology"]}'

# Traverse the knowledge graph outward from a memory
curl -X POST http://localhost:3000/v1/knowledge/graph \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "kb-builder", "memory_id": "<memory-id>", "depth": 2}'

Agent wake-up context

Load an agent's working context at startup with filter-based batch recall (no query, no embedding). Useful for scheduled agents and agents resuming after idle time; GET /v1/agents/{id}/wake-up is the built-in alternative.

# Recall high-importance recent memories
curl -X POST http://localhost:3000/v1/memories/recall/batch \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "my-agent",
    "filter": {
      "min_importance": 0.7,
      "created_after": 1778000000,
      "tags": ["critical", "decision"]
    },
    "limit": 50
  }'

# Also recall blockers and pending handoffs
curl -X POST http://localhost:3000/v1/memories/recall/batch \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "my-agent",
    "filter": {"tags": ["blocker", "handoff"], "min_importance": 0.5}
  }'

# Get agent stats to assess memory health
curl http://localhost:3000/v1/agents/my-agent/stats \
  -H "Authorization: Bearer $DAKERA_API_KEY"

Memory consolidation pipeline

Merge redundant memories on demand, for example after a bulk import or a long session. AutoPilot already deduplicates and consolidates in the background; these calls are for when you want it now or want to choose the memories:

# Consolidate chosen memories into one (a memory with an attachment, a TTL or user metadata is refused)
curl -X POST http://localhost:3000/v1/memory/consolidate \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "my-agent", "memory_ids": ["<memory-id-1>", "<memory-id-2>"]}'

# Deduplicate: merge true duplicates (preview with dry_run; refused past 5,000 memories to compare)
curl -X POST http://localhost:3000/v1/knowledge/deduplicate \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "my-agent", "threshold": 0.95, "dry_run": true}'

# Summarize chosen memories into one compressed memory
curl -X POST http://localhost:3000/v1/knowledge/summarize \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "my-agent", "memory_ids": ["<memory-id-1>", "<memory-id-2>"]}'

Hybrid search patterns

Recall searches by meaning (vector), by keyword (BM25) or both. By default the server picks per query; set routing to force one:

PatternModeWhen to use
Semantic recallrouting: "vector"Meaning-based — "what does the user prefer?"
Keyword lookuprouting: "bm25"Exact terms — error codes, IDs, names
Hybridrouting: "hybrid"Vector and BM25 results fused into one ranking
Automatic (default)routing: "auto" (or omitted)The server classifies the query and picks the backend
# Force hybrid routing
curl -X POST http://localhost:3000/v1/memory/recall \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "my-agent",
    "query": "authentication error ERR_AUTH_401",
    "routing": "hybrid",
    "top_k": 10
  }'

# Exact terms: force BM25 full-text routing (no query embedding)
curl -X POST http://localhost:3000/v1/memory/recall \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "my-agent", "query": "ERR_AUTH_401", "routing": "bm25", "top_k": 5}'

Cross-agent knowledge network

Agents are isolated. To see what several agents have in common, map the shared entities and related memories across them:

# Map shared entities and related memories across agents
curl -X POST http://localhost:3000/v1/knowledge/network/cross-agent \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_ids": ["agent-a", "agent-b", "supervisor"],
    "min_similarity": 0.8,
    "max_nodes_per_agent": 50
  }'

# Link two memories of the same agent (404 unless both are live memories of that agent)
curl -X POST http://localhost:3000/v1/memories/mem_abc/links \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "my-agent", "target_id": "mem_xyz", "label": "related"}'

Memory feedback loop

Feedback is how importance moves after a memory is stored; a recall itself does not change it. An upvote raises importance by 0.05 plus 5% of its current value (at most 1.0), a downvote lowers it by 0.15, and flag marks the memory as irrelevant without changing its importance:

# Upvote a memory that was useful
curl -X POST http://localhost:3000/v1/memories/mem_abc/feedback \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "my-agent", "signal": "upvote"}'

# Downvote an irrelevant result
curl -X POST http://localhost:3000/v1/memories/mem_xyz/feedback \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "my-agent", "signal": "downvote"}'

# Get feedback summary for an agent
curl http://localhost:3000/v1/agents/my-agent/feedback/summary \
  -H "Authorization: Bearer $DAKERA_API_KEY"

Migration from Mem0 / Zep

Bring memories over from another memory system, or move them between Dakera servers. Import and export support Mem0, Zep, JSONL and CSV:

# Import an export file (multipart upload; format is auto-detected or explicit)
curl -X POST "http://localhost:3000/v1/import?agent_id=my-agent&format=mem0" \
  -H "Authorization: Bearer $DAKERA_API_KEY" \
  -F file=@mem0-export.json

# Check the import job
curl http://localhost:3000/v1/import/<job_id>/status \
  -H "Authorization: Bearer $DAKERA_API_KEY"

# Export from Dakera (for backup or migration)
curl "http://localhost:3000/v1/export?agent_id=my-agent&format=jsonl" \
  -H "Authorization: Bearer $DAKERA_API_KEY" -o my-agent.jsonl
Supported formats — jsonl (default), csv, mem0, zep. Export carries plaintext content and TTLs; each imported item is limited to 100,000 bytes of content, and an import into another agent's namespace is rewritten to the importing agent. A key needs read (export) or write (import) access to the agent's namespace.

Namespace isolation for multi-tenant apps

An agent's memories live in the namespace _dakera_agent_<agent_id>. To isolate a tenant, give it an agent id and an API key pinned to that agent's namespace. The namespace must exist, which it does after the agent's first store:

# The tenant's first memory creates its namespace (_dakera_agent_acme-bot)
curl -X POST http://localhost:3000/v1/memory/store \
  -H "Authorization: Bearer $DAKERA_ROOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "acme-bot", "content": "Acme user prefers metric units"}'

# Create a key pinned to that namespace (scope: read, write or admin)
curl -X POST http://localhost:3000/v1/namespaces/_dakera_agent_acme-bot/keys \
  -H "Authorization: Bearer $DAKERA_ROOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "acme-prod-key", "scope": "write"}'

# The pinned key reaches only that agent's memories
curl -X POST http://localhost:3000/v1/memory/recall \
  -H "Authorization: Bearer $ACME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "acme-bot", "query": "units", "top_k": 5}'
v0.12.0 — A key pinned to a namespace no longer reaches node-wide routes (/admin/* apart from four per-namespace routes, /ops/*, /v1/analytics/*, /v1/audit*, /v1/events/stream, ...): those answer 403. Backup download, upload and restore need a global super_admin key. Per-namespace limits are enforced as quotas (413 QUOTA_EXCEEDED). See Security.

Real-time event streaming

Follow memory lifecycle events as Server-Sent Events, for dashboards, audit trails or agents that react to changes. The stream carries every agent's events and needs a global admin key (no namespace restriction):

# Stream memory events (all agents)
curl -N http://localhost:3000/v1/events/stream \
  -H "Authorization: Bearer $DAKERA_ROOT_API_KEY"

# Each event is an SSE event named after its type, with a JSON body, for example:
# event: stored
# data: {"event_type":"stored","agent_id":"my-agent","memory_id":"mem_abc","importance":0.8,"timestamp":1778800000000}

Event types: stored, recalled, decayed, forgotten, consolidated, session_started, session_ended, importance_updated. The stream opens with a connected event, sends a keep-alive every 15 s, and emits stream_lagged when a slow client dropped events (reconnect to resume). Timestamps are Unix milliseconds.

Audit logging & compliance

The audit API is a queryable log of the memory lifecycle events (stored, recalled, decayed, forgotten, consolidated, importance_updated, session_started, session_ended); it needs a global admin key:

# Query the audit log for a specific agent (from / to are Unix milliseconds)
curl "http://localhost:3000/v1/audit?agent_id=my-agent&event_type=forgotten&from=1778000000000&to=1778800000000&limit=100" \
  -H "Authorization: Bearer $DAKERA_ROOT_API_KEY"

# Export it, or follow it live
curl "http://localhost:3000/v1/audit/export?agent_id=my-agent" -H "Authorization: Bearer $DAKERA_ROOT_API_KEY"
curl -N http://localhost:3000/v1/audit/stream -H "Authorization: Bearer $DAKERA_ROOT_API_KEY"

Production deployment checklist

Before going live, check each of these:

CheckCommand / verification
Health endpointsReadiness probe on GET /health/ready, liveness on GET /health/live; GET /health reports "status": "healthy" with empty degraded and config_warnings
Configuration checkeddakera --check-config against the production environment and data volume exits 0
API key setDAKERA_ROOT_API_KEY is a strong, unique value
Persistent storageData volume mounted: -v dakera_data:/data
Backup configuredPOST /admin/backups (global super_admin key; optional encrypt and compression), and a restore tested; a stored backup schedule runs in v0.12
AutoPilot runningOn by default (deduplication every 6 h, consolidation every 12 h); GET /admin/autopilot/status shows the last runs. Decay runs separately every hour
Entity extractionThe GLiNER model (about 782 MB) downloads on the first store into a namespace that extracts entities; pre-fetch with dakera models pull gliner
Tenant isolationOne agent per tenant, with a key pinned to its namespace; never share the root key
MonitoringScrape GET /metrics (Prometheus) and watch degraded in GET /health
Resource limitsSet DAKERA_HNSW_CACHE_MAX, Docker memory limits
TLS terminationUse a reverse proxy (nginx, Caddy) for HTTPS in production

Related: Deployment guide · Security hardening · Configuration reference · Memory Patterns Library · Multi-Agent Memory Systems

Ship memory-enabled agents

Start with the free binary or Docker image; every recipe on this page runs against it.

Get Started Free → Memory Patterns Library →
Stay sharp on agent memory
Benchmark results, SDK releases, and production patterns. Under 500 words per issue.
✓ You're in. First issue lands soon — watch for Dakera in your inbox.