Memory Configuration¶
SynthOrg agents have persistent memory that spans conversations and tasks. The memory system stores experiences, knowledge, skills, and relationships, and retrieves relevant memories to inject into the agent's context. This guide covers how to configure memory backends, persistence levels, retrieval tuning, shared organisational memory, and consolidation.
Memory Architecture¶
The memory system has two concerns:
- Agent memory: per-agent memories (what an agent has learned, experienced, and knows) stored in a pluggable memory backend
- Operational data: structured records (tasks, cost records, messages, audit entries) stored in a persistence backend (SQLite)
graph TD
Agent["Agent"]
Retriever["Retrieval Pipeline"]
Backend["Memory Backend<br/><small>sqlvector (pgvector / sqlite-vec)</small>"]
OrgMem["Shared Org Memory<br/><small>Core policies + extended facts</small>"]
Persistence["Persistence Backend<br/><small>SQLite / Postgres</small>"]
Agent -->|"recall"| Retriever
Agent -->|"store"| Backend
Retriever --> Backend
Retriever --> OrgMem
Agent -.->|"tasks, costs"| Persistence
Memory Types¶
Agents store five types of memory:
| Type | Description | Typical Lifetime |
|---|---|---|
| Working | Current task context, active plans | Task duration |
| Episodic | Past events, conversations, outcomes | Configurable retention |
| Semantic | Learned facts, domain knowledge | Long-term |
| Procedural | Skills, patterns, how-to knowledge | Long-term |
| Social | Relationships, collaboration history | Long-term |
Memory Levels¶
The level field controls how long memories persist:
| Level | Value | Behaviour |
|---|---|---|
| Persistent | persistent |
Memories survive across all sessions and projects |
| Project | project |
Memories persist for the duration of a project |
| Session | session |
Memories persist for the current session only (default) |
| None | none |
No memory storage |
Agent Memory Configuration¶
Configure memory in the memory section of your company config:
memory:
backend: "sqlvector"
storage:
data_dir: "/data/memory"
options:
retention_days: null # null = keep forever
max_memories_per_agent: 10000
shared_knowledge_base: true
retrieval:
strategy: context
relevance_weight: 0.7
recency_weight: 0.3
min_relevance: 0.3
max_memories: 5 # tuned top-k after ranking; MMR on by default
diversity_penalty_enabled: true
include_shared: true
consolidation:
interval: daily
max_memories_per_agent: 10000
The per-agent persistence level lives on the agent's MemoryConfig.type (default session), not
in this company-wide section.
Top-Level Memory Fields¶
| Field | Type | Default | Description |
|---|---|---|---|
backend |
string | "sqlvector" |
Memory backend: "sqlvector" (durable, semantic), "composite" (per-namespace routing), or "inmemory" (ephemeral, discouraged) |
storage |
MemoryStorageConfig | (defaults) | Storage backend settings |
options |
MemoryOptionsConfig | (defaults) | Behaviour options |
retrieval |
MemoryRetrievalConfig | (defaults) | Retrieval pipeline settings |
consolidation |
ConsolidationConfig | (defaults) | Consolidation settings |
procedural |
ProceduralMemoryConfig | (defaults) | Procedural skill auto-generation |
Checking Memory Health¶
GET /health reports memory in one of three states, shown as a card in the
dashboard's system-health popover:
| State | Meaning |
|---|---|
durable |
Wired on a store that survives restarts and retrieves by meaning |
degraded |
Wired, but not fully durable: the ephemeral keyword backend, a failed health probe, a missing dense index (keyword-only recall), or maintenance disabled |
off |
No backend wired at all, whatever the configured type. Usually no embedding model resolved |
degraded and off are surfaced rather than silently tolerated: memory that
quietly degrades to substring matching looks healthy while recalling the wrong
thing. Reaching durable takes more than embedder configuration: a durable
backend must be wired on a store that survives restarts, an embedding model must
resolve for semantic recall, and the readiness probe must pass. Setting the
memory.embedder_* overrides alone lifts off only when a durable backend is
already wired; a wired-but-degraded durable backend still fails the readiness
probe, so the fault stays visible rather than masquerading as healthy.
Storage Configuration¶
| Field | Type | Default | Description |
|---|---|---|---|
data_dir |
string | "/data/memory" |
Directory for memory artefacts kept outside the database (Docker volume mount) |
Vectors and their lexical index live in the operational database, so there is no separate vector-store or history-store to configure or back up.
Note
The data_dir path is validated to reject parent-directory traversal (..) to prevent path escape attacks.
Memory Options¶
| Field | Type | Default | Description |
|---|---|---|---|
retention_days |
int or null | null |
Days to retain memories (null = forever) |
max_memories_per_agent |
int | 10000 |
Upper bound on memories per agent |
shared_knowledge_base |
bool | true |
Whether shared knowledge is enabled |
The consolidation cadence is consolidation.interval, not an option here:
that is the field the scheduler reads and the memory.consolidation_interval
setting mirrors.
Retrieval Pipeline¶
When an agent needs context, the retrieval pipeline queries the memory backend, ranks results, and injects the top matches into the agent's prompt.
Retrieval Fields¶
| Field | Type | Default | Description |
|---|---|---|---|
strategy |
string | "context" |
Injection strategy (only "context") |
relevance_weight |
float | 0.7 |
Weight for backend relevance score (0.0--1.0) |
recency_weight |
float | 0.3 |
Weight for recency decay score (0.0--1.0) |
recency_decay_rate |
float | 0.01 |
Exponential decay rate per hour |
personal_boost |
float | 0.1 |
Boost for personal memories over shared (0.0--1.0) |
min_relevance |
float | 0.3 |
Minimum combined score to include a memory |
max_memories |
int | 5 |
Tuned top-k injected after ranking (1--100) |
include_shared |
bool | true |
Whether to query shared org memory |
default_relevance |
float | 0.5 |
Score for entries missing a relevance score |
injection_point |
string | "system" |
Where to inject: "system" (system prompt) or "user" |
memory_filter_strategy |
string | "off" |
Post-ranking filter: "off" (no filter), "tag_based" (only non-inferable-tagged memories), or "passthrough" (inject all) |
fusion_strategy |
string | "linear" |
Ranking fusion: "linear" (relevance + recency) or "rrf" (Reciprocal Rank Fusion over multiple ranked lists) |
rrf_k |
int | 60 |
RRF smoothing constant (only with RRF strategy, 1--1000) |
diversity_penalty_enabled |
bool | true |
Apply MMR diversity re-ranking (context strategy only; off for other strategies) |
diversity_lambda |
float | 0.7 |
MMR trade-off: 1.0 pure relevance, 0.0 maximum diversity |
candidate_pool_multiplier |
int | 3 |
Dense/lexical over-fetch width before ranking narrows to max_memories |
Weight Tuning¶
For the linear fusion strategy, relevance_weight + recency_weight must equal 1.0:
retrieval:
relevance_weight: 0.7 # prioritize semantic relevance
recency_weight: 0.3 # with some recency bias
- Higher
relevance_weight: better for knowledge-heavy tasks where the most relevant memory matters regardless of when it was stored - Higher
recency_weight: better for conversational contexts where recent interactions are more important personal_boost: adds a bonus to the agent's own memories over shared org memories (0.1 = 10% boost)
Shared Organisational Memory¶
Beyond per-agent memory, SynthOrg supports shared organisational memory: knowledge available to all agents.
org_memory:
core_policies:
- "All code must pass review before merging."
- "Customer data is never logged or stored in plain text."
- "Budget decisions require CFO approval above 50 units in the configured currency."
extended_store:
max_retrieved_per_query: 5
Org Memory Fields¶
| Field | Type | Default | Description |
|---|---|---|---|
core_policies |
list | [] |
Policy texts injected into every agent's system prompt |
extended_store |
ExtendedStoreConfig | (defaults) | Extended facts store |
write_access |
WriteAccessConfig | (defaults) | Write access control |
How It Works¶
The hybrid prompt + retrieval backend uses two layers:
- Core policies: short, critical rules injected directly into every agent's system prompt. These are always available and never filtered.
- Extended store: a searchable database of organisational facts, procedures, and conventions. These are retrieved on demand via the retrieval pipeline (up to
max_retrieved_per_queryper query).
Consolidation & Archival¶
Over time, agent memories accumulate. Consolidation manages memory volume through retention rules and archival:
consolidation:
interval: daily
max_memories_per_agent: 10000
retention:
default_retention_days: null # keep forever by default
rules: [] # per-category overrides
archival:
enabled: false
age_threshold_days: 90
dual_mode:
enabled: false
dense_threshold: 0.5
summarization_model: "example-capable-001"
max_summary_tokens: 200
max_facts: 20
anchor_length: 150
Consolidation Fields¶
| Field | Type | Default | Description |
|---|---|---|---|
interval |
string | "daily" |
Run frequency: hourly, daily, weekly, never |
max_memories_per_agent |
int | 10000 |
Upper bound on memories per agent |
Retention¶
Per-category retention rules (uniform across all agents):
| Field | Type | Default | Description |
|---|---|---|---|
default_retention_days |
int or null | null |
Default retention (null = forever) |
rules |
list | [] |
Per-category retention rules |
Archival¶
When archival is enabled, memories older than age_threshold_days are archived using one of two modes:
| Mode | When Used | Description |
|---|---|---|
| Abstractive | Sparse/conversational content | LLM generates a summary of the memory |
| Extractive | Dense/factual content | Verbatim key facts + start/mid/end anchors preserved |
The archival system classifies each memory by density score and routes to the appropriate mode:
| Field | Type | Default | Description |
|---|---|---|---|
archival.enabled |
bool | false |
Whether archival is active |
archival.age_threshold_days |
int | 90 |
Minimum age before archival |
archival.dual_mode.enabled |
bool | false |
Enable density-aware dual-mode |
archival.dual_mode.dense_threshold |
float | 0.5 |
Score threshold for DENSE classification |
archival.dual_mode.summarization_model |
string | null |
Model for abstractive summaries (required when enabled) |
archival.dual_mode.max_summary_tokens |
int | 200 |
Max tokens for summaries (50--1000) |
archival.dual_mode.max_facts |
int | 20 |
Max extracted key facts (1--100) |
archival.dual_mode.anchor_length |
int | 150 |
Character length per anchor snippet (50--500) |
Note
When dual_mode.enabled is true, summarization_model must be set. This model is used for abstractive archival and should be a cost-effective model.
Procedural Memory¶
When an agent fails a task and recovers, the procedural pipeline asks a model what it would do differently, and stores the answer as a reusable skill. Later tasks recall that skill instead of rediscovering the same workaround.
procedural:
enabled: true
model: null # unset: the proposer makes no LLM call
temperature: 0.3
max_tokens: 1500
min_confidence: 0.5
skill_md_directory: null # set to also write portable SKILL.md files
| Field | Setting key | Applies | Description |
|---|---|---|---|
enabled |
memory.procedural_enabled |
Next task | Master switch. When off, every capture short-circuits and no LLM call is made |
min_confidence |
memory.procedural_min_confidence |
Next task | Quality floor: proposals rated below it are discarded |
temperature |
memory.procedural_temperature |
Next restart | Sampling temperature for the proposer |
max_tokens |
memory.procedural_max_tokens |
Next restart | Response token budget for the proposer |
skill_md_directory |
memory.procedural_skill_md_directory |
Next restart | Directory for SKILL.md materialisation; unset keeps skills in the backend only |
model |
(company config) | Next restart | Proposer model. Unset means the proposer skips rather than guessing a model |
enabled and min_confidence are re-resolved on every capture, so pausing skill
generation or tightening the quality floor takes effect on the next task. The rest
are baked into the frozen proposer config at startup.
Practical Example¶
A complete memory configuration for a research lab that prioritises long-term knowledge retention:
memory:
backend: "sqlvector"
storage:
data_dir: "/data/memory"
options:
retention_days: null
max_memories_per_agent: 50000
shared_knowledge_base: true
retrieval:
strategy: context
relevance_weight: 0.8 # strong relevance bias for research
recency_weight: 0.2
personal_boost: 0.05
min_relevance: 0.4 # higher threshold for quality
max_memories: 30 # more context for complex tasks
include_shared: true
consolidation:
interval: weekly
max_memories_per_agent: 50000
archival:
enabled: true
age_threshold_days: 180
dual_mode:
enabled: true
dense_threshold: 0.6
summarization_model: "example-basic-001"
max_summary_tokens: 300
max_facts: 30
org_memory:
core_policies:
- "All research findings must be reproducible."
- "Cite sources for all claims."
extended_store:
max_retrieved_per_query: 10
Memory Admin API¶
Operators with the CEO or SYSTEM role can manage embedding fine-tuning at runtime through the /admin/memory/fine-tune* endpoints (MemoryFineTuneController in src/synthorg/api/controllers/memory/fine_tune.py, guarded by require_roles(HumanRole.CEO, HumanRole.SYSTEM)).
Start a fine-tune run¶
curl -X POST http://localhost:3001/api/v1/admin/memory/fine-tune \
-H "Content-Type: application/json" \
-H "Cookie: ${SESSION}" \
-d '{"agent_id": "sarah_chen"}' | jq
Resume, cancel, or check status¶
# Resume a paused run
curl -X POST http://localhost:3001/api/v1/admin/memory/fine-tune/resume/${RUN_ID} \
-H "Cookie: ${SESSION}"
# Read current status
curl http://localhost:3001/api/v1/admin/memory/fine-tune/status \
-H "Cookie: ${SESSION}" | jq
# Cancel the active run
curl -X POST http://localhost:3001/api/v1/admin/memory/fine-tune/cancel \
-H "Cookie: ${SESSION}"
Preflight check, checkpoints, deploy / rollback¶
# Validate configuration before running
curl -X POST http://localhost:3001/api/v1/admin/memory/fine-tune/preflight \
-H "Content-Type: application/json" \
-H "Cookie: ${SESSION}" \
-d '{"agent_id": "sarah_chen"}' | jq
# List available checkpoints
curl http://localhost:3001/api/v1/admin/memory/fine-tune/checkpoints \
-H "Cookie: ${SESSION}" | jq
# Deploy or roll back a specific checkpoint
curl -X POST http://localhost:3001/api/v1/admin/memory/fine-tune/checkpoints/${CHECKPOINT_ID}/deploy \
-H "Cookie: ${SESSION}"
curl -X POST http://localhost:3001/api/v1/admin/memory/fine-tune/checkpoints/${CHECKPOINT_ID}/rollback \
-H "Cookie: ${SESSION}"
# Delete a checkpoint
curl -X DELETE http://localhost:3001/api/v1/admin/memory/fine-tune/checkpoints/${CHECKPOINT_ID} \
-H "Cookie: ${SESSION}"
Admin endpoints on the backlog¶
Consolidation, reindex, procedural-skill management, and organisation-memory promotion are described in the Memory design page but are not exposed as REST endpoints today. These operations happen on agent-lifecycle boundaries (consolidation cycles, startup reindex, procedural-memory auto-generation); a dedicated admin surface is tracked on the GitHub issue tracker under the memory label.
See Also¶
- Company Configuration: full configuration reference
- Design: Memory: memory architecture in the design spec
- Library Reference: Memory: API documentation