Persistent Memory¶
Each Agent can enable persistent memory — a SQLite database with FTS5 full-text search, served by a memory sidecar that runs alongside agent pods. The database lives on a PersistentVolume, so memory survives across ephemeral agent runs.
Agents interact with memory through three tools exposed via file-based JSON IPC (the same pattern used by MCP tools):
| Tool | Description |
|---|---|
memory_search(query, top_k?) |
Full-text search across stored memories. Returns the top k results (default 10). |
memory_store(content, tags?) |
Store a new memory entry with optional tags for categorisation. |
memory_list(tags?, limit?) |
List memories, optionally filtered by tags. |
How It Works¶
- The
memorySkillPack adds a memory sidecar (cmd/memory-server/) to the agent pod. - A PersistentVolumeClaim is created per instance to hold
memory.db— the SQLite database. - The agent and memory sidecar share an
/ipcvolume. The agent writes JSON tool requests; the sidecar responds with results. - SQLite FTS5 indexes all stored content for fast full-text search.
- Because the PVC outlives individual pods, memories persist across runs.
graph LR
A["Agent Container"] -- "JSON IPC<br/>/ipc volume" --> M["Memory Sidecar"]
M -- "reads / writes" --> DB[("SQLite + FTS5<br/>on PVC")]
Enabling Memory¶
Add the memory SkillPack to your instance's skills list:
apiVersion: sympozium.ai/v1alpha1
kind: Agent
metadata:
name: my-agent
spec:
skills:
- skillPackRef: memory
Or reference it from a Ensemble:
apiVersion: sympozium.ai/v1alpha1
kind: Ensemble
metadata:
name: sre-watchdog
spec:
personas:
- name: sre-watchdog
skills:
- skillPackRef: k8s-ops
- skillPackRef: memory
memory:
seeds:
- "Track recurring issues for trend analysis"
- "Note any nodes that frequently report NotReady"
Seed memories are inserted into the SQLite database when the instance is first created.
SkillPack Configuration¶
The memory SkillPack is defined at config/skills/memory.yaml. It follows the standard SkillPack pattern — Markdown instructions mounted at /skills/ plus a sidecar container:
- Skills layer: Instructions that teach the agent when and how to use
memory_search,memory_store, andmemory_list. - Sidecar layer: The
memory-servercontainer that manages the SQLite database and responds to IPC requests. - No RBAC required: The memory sidecar only accesses its own PVC — it does not talk to the Kubernetes API.
Data Persistence¶
| Aspect | Detail |
|---|---|
| Storage | One PVC per instance, named <instance>-memory |
| Database | SQLite 3 with FTS5 extension |
| Lifecycle | PVC persists until the Agent is deleted (or manually removed) |
| Backup | Standard PV backup tools apply (Velero, volume snapshots, etc.) |
| Upgradeable | The SQLite schema is designed to support a future upgrade path to vector search |
Viewing Memory¶
View an agent's stored memories through the TUI:
Or query the database directly by exec-ing into the memory sidecar during a run:
kubectl exec <pod> -c memory-server -- sqlite3 /data/memory.db "SELECT content, tags FROM memories ORDER BY created_at DESC LIMIT 10;"
Shared Workflow Memory¶
When agents work together in a Ensemble, each persona has its own private memory by default. Shared Workflow Memory adds a pack-level memory pool that all personas can access, enabling team knowledge accumulation.
Private vs Shared Memory¶
| Aspect | Private Memory | Shared Workflow Memory |
|---|---|---|
| Scope | One instance | All personas in a Ensemble |
| Storage | <instance>-memory-db PVC |
<pack>-shared-memory-db PVC |
| Tools | memory_search, memory_store, memory_list |
workflow_memory_search, workflow_memory_store, workflow_memory_list |
| Access | Always read-write | Per-persona: read-write or read-only |
| Attribution | N/A (single owner) | Auto-tagged with source persona name |
| Auto-context | Top 3 results injected as "Your Past Findings" | Top 3 results injected as "Team Knowledge" |
Enabling¶
Add sharedMemory to the Ensemble spec:
apiVersion: sympozium.ai/v1alpha1
kind: Ensemble
metadata:
name: research-delegation-example
spec:
sharedMemory:
enabled: true
storageSize: "1Gi"
accessRules:
- persona: researcher
access: read-write
- persona: reviewer
access: read-only
Infrastructure¶
The Ensemble controller provisions three Kubernetes resources:
graph LR
A1["Agent Pod<br/>(researcher)"] -- "WORKFLOW_MEMORY_SERVER_URL" --> SM["Shared Memory Server"]
A2["Agent Pod<br/>(writer)"] -- "WORKFLOW_MEMORY_SERVER_URL" --> SM
A3["Agent Pod<br/>(reviewer)"] -- "WORKFLOW_MEMORY_SERVER_URL<br/>(read-only)" --> SM
SM -- "reads / writes" --> DB[("SQLite + FTS5<br/>on shared PVC")]
- PVC:
<pack>-shared-memory-db—ReadWriteOnce, single replica - Deployment:
<pack>-shared-memory— sameskill-memoryimage,Recreatestrategy - Service:
<pack>-shared-memory— ClusterIP on port 8080
Agent pods receive two env vars:
- WORKFLOW_MEMORY_SERVER_URL — points to the shared memory service
- WORKFLOW_MEMORY_ACCESS — read-write or read-only (from access rules)
A wait-for-shared-memory init container ensures the server is ready before the agent starts.
Tools¶
| Tool | Description |
|---|---|
workflow_memory_search(query, top_k?) |
Full-text search across all team knowledge |
workflow_memory_store(content, tags?) |
Store findings for other personas (auto-tagged with source persona) |
workflow_memory_list(tags?, limit?) |
List entries, filterable by tag or persona |
The workflow_memory_store tool is only available to personas with read-write access. The source persona name is automatically added as a tag for attribution.
Synthetic Membrane¶
The Synthetic Membrane is an optional layer on top of Shared Workflow Memory that adds selective permeability, provenance tracking, token budgets, circuit breakers, and time decay. It transforms the flat shared memory pool into a structured medium where agents share state selectively.
Add a membrane block inside sharedMemory:
spec:
sharedMemory:
enabled: true
storageSize: "1Gi"
membrane:
defaultVisibility: public
permeability:
- agentConfig: researcher
defaultVisibility: trusted
exposeTags: ["findings"]
- agentConfig: reviewer
defaultVisibility: private
trustGroups:
- name: content-team
agentConfigs: ["researcher", "writer"]
tokenBudget:
maxTokens: 100000
action: halt
circuitBreaker:
consecutiveFailures: 3
timeDecay:
ttl: "168h"
Key capabilities:
| Feature | What it does |
|---|---|
| Permeability | Three-tier visibility (public/trusted/private) per persona with tag-level selectivity |
| Trust groups | Named groups of personas that can see each other's "trusted" entries |
| Token budget | Caps total token consumption across all runs; halts or warns on breach |
| Circuit breaker | Opens after N consecutive delegation failures, blocking further spawns |
| Time decay | Excludes old entries from search results via configurable TTL |
| Provenance | Every entry tracks its source agent and derivation chain via parent_id |
When the membrane is configured, agent pods receive additional env vars (WORKFLOW_MEMBRANE_VISIBILITY, WORKFLOW_MEMBRANE_TRUST_PEERS, WORKFLOW_MEMBRANE_ACCEPT_TAGS, WORKFLOW_MEMBRANE_MAX_AGE) that the agent runner uses to filter store and search calls automatically.
See Ensembles — Synthetic Membrane for full configuration reference.
Further Reading
The membrane design is based on the Synthetic Membrane research paper: "The Synthetic Membrane: A Shared Permeable Boundary for Multi-Agent AI Systems" (April 2026).
Viewing Shared Memory¶
Query the shared memory via the API:
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:9090/api/v1/ensembles/research-delegation-example/shared-memory
Or exec into the shared memory pod:
kubectl exec deploy/research-delegation-example-shared-memory -c memory-server -- \
sqlite3 /data/memory.db "SELECT content, tags FROM memories ORDER BY created_at DESC LIMIT 10;"
Migration from ConfigMap Memory (Legacy)¶
The previous ConfigMap-based memory system (<instance>-memory ConfigMap with MEMORY.md) is preserved as a legacy fallback. If an instance has spec.memory.enabled: true but does not include the memory SkillPack, the controller falls back to the ConfigMap approach.
To migrate:
- Add
memoryto the instance's skills list. - Existing ConfigMap memories can be imported by storing them via
memory_storeduring the first run — the agent's skill instructions include guidance for this. - Once migrated, you can disable the legacy ConfigMap by removing
spec.memory.enabledor setting it tofalse.
Both systems can coexist during the transition period. The memory sidecar takes precedence when both are present.