Skip to content

MemoryStore CRD

The MemoryStore custom resource provisions a central, long-term memory service that agents share. It runs the KAOS memory engine (Mem0) behind a stable in-cluster endpoint, backing it with either pod-local storage for development or an external pgvector database for production. Agents bind to a MemoryStore through their config.memory block to gain semantic, cross-session memory on top of the runtime's local short-term window.

Full Specification

yaml
apiVersion: kaos.tools/v1alpha1
kind: MemoryStore
metadata:
  name: shared-memory
  namespace: my-namespace
spec:
  # Memory engine (default: mem0)
  engine: mem0

  # Required: storage backend
  storage:
    # "local" for a single-replica PVC-backed store, "external" for pgvector
    type: local

    # For local storage: chroma vector store on a persistent volume
    local:
      provider: chroma          # only chroma is supported
      persistentVolume:
        size: "5Gi"             # default 5Gi
      collection: kaos_memory   # vector collection name (default kaos_memory)

    # For external storage: managed pgvector database
    # external:
    #   provider: pgvector       # only pgvector is supported
    #   connectionSecretRef:     # secret holding the DSN
    #     name: pgvector-dsn
    #     key: dsn
    #   embeddingDims: 1536      # vector dimensions (default 1536)
    #   collection: kaos_memory  # vector collection name (default kaos_memory)

  # Replicas override. When unset, defaults by storage mode: external stores
  # run 2 replicas for availability, local stores run 1. Must be 1 in local mode.
  # replicas: 2

  # Required: models used for extraction and embedding
  models:
    summarization:
      modelAPI: my-modelapi     # ModelAPI in the same namespace
      model: gpt-4o-mini
    embedding:
      modelAPI: my-modelapi
      model: text-embedding-3-small

  # Optional: verbatim short-term window tuning
  shortTerm:
    tokenBudget: 4096           # token bound on the verbatim window (default 4096)
    hardEventCap: 2000          # event-count ceiling on the window (default 2000)

  # Optional: medium-term rolling digest tuning (folds short-term overflow)
  mediumTerm:
    enabled: false              # rolling digest off by default (overflow is dropped)
    compactionTrigger: 0        # fold trigger in tokens; 0 = tokenBudget
    compactionTarget: 0         # fold target in tokens; 0 = tokenBudget / 2
    digestRetention: 20         # digest versions retained (default 20)
    systemPrompt: ""            # summariser prompt override (default: built-in)

  # Optional: long-term semantic tier tuning (recall shape + fact extraction)
  longTerm:
    enabled: true               # false skips extraction and recalls no facts
    defaultTopK: 10             # recall result count when a request omits top_k
    # scoreThreshold: 0.4       # minimum similarity in [0,1]; unset = no threshold
    rerank: false               # engine reranking of recalled facts
    extraction:
      concurrency: 4            # concurrent extraction workers (default 4)
      maxRetries: 2             # retries per failed extraction task (default 2)
      systemPrompt: ""          # fact-extraction prompt override (default: built-in)

  # Optional: bounded request executor size (default 8)
  requestConcurrency: 8

  # Default write/forget failure mode for bound agents (default: soft)
  # "soft" tolerates memory-write failures; "strict" surfaces them as errors.
  defaultFailureMode: soft

  # Maximum read scope for every bound agent.
  # When omitted, agents fall back to "agent".
  maxReadScope: agent

Storage Modes

Local

Local mode runs a single memory-service replica backed by a chroma vector store on a PersistentVolumeClaim. It is intended for development and single-node clusters. replicas must be 1 — the CRD rejects higher values in local mode because the PVC is not shared across pods.

yaml
spec:
  storage:
    type: local
    local:
      provider: chroma
      persistentVolume:
        size: "5Gi"

External

External mode connects the memory service to a managed pgvector database via a DSN stored in a Kubernetes Secret. Because the service is stateless over the shared database, this mode runs multiple replicas and is the production path.

yaml
spec:
  storage:
    type: external
    external:
      provider: pgvector
      connectionSecretRef:
        name: pgvector-dsn
        key: dsn
      embeddingDims: 1536
  # replicas defaults to 2 in external mode; set explicitly to override

The DSN is injected into the service as KAOS_MEMORY_EXTERNAL_DSN via a secretKeyRef, and embeddingDims is passed as KAOS_MEMORY_EXTERNAL_DIMS. The referenced Secret must exist in the same namespace. External stores default to two replicas guarded by a PodDisruptionBudget (see High availability and operations).

Models

Both summarization and embedding model references are required. Each points at a ModelAPI in the same namespace plus a concrete model name. The controller resolves the referenced ModelAPIs and holds the MemoryStore in Pending until they are Ready; the summarization ModelAPI's cluster-local Service endpoint (suffixed with /v1) becomes the service's model base URL. Generated ModelAPI NetworkPolicies admit same-namespace MemoryStore pods for this direct model traffic while other workload pods remain gateway-only. Models bind lazily at first use, so the store can reach Ready from storage reachability before any embedding or summarization call is made.

FieldTypeDescription
models.summarization.modelAPIstringModelAPI providing the summarization/extraction model
models.summarization.modelstringSummarization model name
models.embedding.modelAPIstringModelAPI providing the embedding model
models.embedding.modelstringEmbedding model name

Memory Tiers

The shortTerm, mediumTerm, and longTerm blocks tune the three memory tiers as typed fields. Every field is optional: an absent field projects nothing onto the service, leaving the memory-service default in place, and an explicit container.env entry still overrides the projected value.

  • shortTerm bounds the verbatim conversation window by tokenBudget and hardEventCap.
  • mediumTerm opts into the rolling digest that folds short-term overflow instead of dropping it. Folding is amortised by two compaction marks: compactionTrigger (fold starts) and compactionTarget (fold evicts down to). 0 means derived — the token budget and half the token budget respectively. The CRD enforces the service invariant at apply time: 0 < compactionTarget < compactionTrigger <= tokenBudget (after derivation), so a misconfigured store is rejected by kubectl apply instead of crash-looping at pod startup.
  • longTerm shapes semantic recall (defaultTopK, scoreThreshold, rerank) and the fact-extraction executor (extraction). Setting enabled: false turns the semantic tier off by configuration: writes skip fact extraction entirely and recall returns no facts (not degraded); the conversational tiers keep working.

Spec Reference

FieldTypeDefaultDescription
enginestringmem0Memory engine. Only mem0 is supported
storage.typestringlocal or external (required)
storage.local.providerstringchromaLocal vector store provider
storage.local.persistentVolume.sizestring5GiPVC size for local storage
storage.external.providerstringpgvectorExternal vector store provider
storage.external.connectionSecretRefSecretKeySelectorSecret + key holding the pgvector DSN (required for external)
storage.external.embeddingDimsint1536Embedding vector dimensions
storage.local.collection / storage.external.collectionstringkaos_memoryVector collection name
replicasintmode-awareService replicas. Defaults to 2 for external, 1 for local. Must be 1 in local mode
models.summarizationobjectSummarization/extraction model reference (required)
models.embeddingobjectEmbedding model reference (required)
shortTerm.tokenBudgetint4096Token bound on the verbatim short-term window
shortTerm.hardEventCapint2000Event-count ceiling on the short-term window
mediumTerm.enabledboolfalseFold short-term overflow into the rolling digest instead of dropping it
mediumTerm.compactionTriggerint0Token level that triggers a fold; 0 derives it from tokenBudget
mediumTerm.compactionTargetint0Token level a fold evicts down to; 0 derives tokenBudget / 2
mediumTerm.digestRetentionint20Digest versions retained
mediumTerm.systemPromptstringbuilt-inSummariser prompt override for digest folds
longTerm.enabledbooltrueLong-term tier switch; false skips extraction and recalls no facts
longTerm.defaultTopKint10Recall result count when a request omits top_k
longTerm.scoreThresholdfloatunsetMinimum similarity score for recalled facts, in [0,1]
longTerm.rerankboolfalseEngine reranking of recalled facts
longTerm.extraction.concurrencyint4Concurrent extraction workers
longTerm.extraction.maxRetriesint2Retries per failed extraction task
longTerm.extraction.systemPromptstringbuilt-inFact-extraction prompt override
requestConcurrencyint8Bounded request executor size
defaultFailureModestringsoftDefault write/forget failure mode for bound agents (soft or strict)
maxReadScopestringagentMaximum read scope for bound agents: session, agent, or user

Status

FieldTypeDescription
phasestringPending, Ready, or Failed
readyboolWhether the store is serving
endpointstringIn-cluster service URL agents connect to
messagestringHuman-readable status detail
deploymentobjectUnderlying Deployment status

When ready, the store exposes an endpoint of the form http://memorystore-<name>.<namespace>.svc.cluster.local:8080, which the operator injects into bound agents as MEMORY_STORE_ENDPOINT.

High availability and operations

Replicas and disruption budget. External stores are stateless over the shared pgvector database, so they default to two replicas and are guarded by a PodDisruptionBudget pinning minAvailable: 1 — voluntary disruptions (node drains, rollouts) cannot drain the fleet to zero. Local stores are single-writer over a PersistentVolume and stay at one replica with no budget. Set replicas explicitly to override the external default; local mode rejects any value other than 1.

Health and readiness. The service exposes /healthz (liveness: the process is up) and /readyz (readiness: both memory tiers are reachable, returning 503 otherwise). The operator wires these as the Deployment's liveness and readiness probes, so a store only reports Ready once it can serve.

Failure mode and degradation. The store's defaultFailureMode (soft by default) governs how write and forget failures surface to bound agents. Under soft, a memory-write failure is tolerated: the agent's turn proceeds and the write is retried in the background. Under strict, the failure is surfaced as an error. Recall is always best-effort regardless of mode — if the long-term tier is unavailable, recall degrades to the short-term window rather than failing the turn. An individual Agent can override the store default in its config.memory.failureMode.

Maximum read scope. maxReadScope is the store-owner ceiling. An Agent's config.memory.maxReadScope cannot exceed it; when omitted, the agent inherits the store ceiling.

Provisioning a development database. For local development, kaos system install --pgvector-memory-enabled provisions a pgvector Postgres in the install namespace and writes a kaos-memory-pgvector connection Secret, ready to reference from an external-mode store's connectionSecretRef. This is a development convenience — production deployments point connectionSecretRef at a managed pgvector database.

Binding an Agent

Agents attach to a MemoryStore through their config.memory block. See the Agent CRD memory section for the full binding surface (type, read scopes, tools, and failure mode).

yaml
apiVersion: kaos.tools/v1alpha1
kind: Agent
metadata:
  name: assistant
  namespace: my-namespace
spec:
  modelAPI: my-modelapi
  model: gpt-4o-mini
  config:
    memory:
      type: remote
      memoryStore: shared-memory
      maxReadScope: user
      tools: all

Memory binding is degraded-aware once an agent is running: if the referenced MemoryStore later becomes missing or not ready, the agent keeps serving and reports a MemoryDegraded status condition, falling back to its pod-local short-term window until the store becomes available. The agent's initial creation, however, waits for the bound store: with waitForDependencies enabled (the default), an agent whose MemoryStore is missing or not yet ready stays Waiting until the store is Ready, so it never starts up degraded.

Released under the Apache 2.0 License.