Ensembles¶
Ensembles are the recommended way to get started with Sympozium. A Ensemble is a CRD that bundles multiple pre-configured agent personas — each with a system prompt, skills, tool policy, schedule, and memory seeds. Activating a pack is a single action: the Ensemble controller stamps out all the Kubernetes resources automatically.
Why Ensembles?¶
Without Ensembles, setting up even one agent requires creating a Secret, Agent, SympoziumSchedule, and memory ConfigMap by hand. Ensembles collapse that into: pick a pack → enter your API key → done.
How It Works¶
Ensemble "platform-team" (3 personas)
│
├── Activate via TUI or Web UI (wizard → API key → confirm)
│
└── Controller stamps out:
├── Secret: platform-team-openai-key
├── Agent: platform-team-security-guardian
│ ├── SympoziumSchedule: ...security-guardian-schedule (every 30m)
│ └── ConfigMap: ...security-guardian-memory (seeded)
├── Agent: platform-team-sre-watchdog
│ ├── SympoziumSchedule: ...sre-watchdog-schedule (every 5m)
│ └── ConfigMap: ...sre-watchdog-memory (seeded)
├── Agent: platform-team-platform-engineer
│ ├── SympoziumSchedule: ...platform-engineer-schedule (weekdays 9am)
│ └── ConfigMap: ...platform-engineer-memory (seeded)
│
└── (if sharedMemory.enabled):
├── PVC: platform-team-shared-memory-db
├── Deployment: platform-team-shared-memory
└── Service: platform-team-shared-memory
All generated resources have ownerReferences pointing back to the Ensemble — delete the pack and everything gets garbage-collected.
Persona Relationships & Workflows¶
Ensembles support typed relationships between personas, enabling coordination patterns beyond independent scheduling:
Relationship Types¶
| Type | Behaviour | Example |
|---|---|---|
delegation |
Source requests target, awaits result, then continues | Researcher delegates to Writer |
sequential |
Source must complete before target starts | Writer finishes → Reviewer begins |
supervision |
Source monitors target (observability only) | Lead supervises Writer and Reviewer |
stimulus |
Injects a pre-configured prompt into target when all agents are serving | Kickoff triggers Lead Researcher |
Workflow Types¶
The workflowType field on a Ensemble describes the overall orchestration pattern:
| Value | Description |
|---|---|
autonomous |
Default. Personas run independently on their own schedules. |
pipeline |
Personas execute in sequence defined by sequential edges. |
delegation |
Personas can actively delegate to each other at runtime. |
Defining Relationships¶
apiVersion: sympozium.ai/v1alpha1
kind: Ensemble
metadata:
name: research-delegation-example
spec:
workflowType: delegation
personas:
- name: researcher
systemPrompt: "You are a research analyst..."
- name: writer
systemPrompt: "You are a technical writer..."
- name: reviewer
systemPrompt: "You are a quality reviewer..."
relationships:
- source: researcher
target: writer
type: delegation
timeout: "10m"
resultFormat: markdown
- source: writer
target: reviewer
type: sequential
timeout: "5m"
Stimulus¶
A Stimulus is a lightweight configuration node that automatically injects a prompt into a target agent when all ensemble pods reach the Serving phase. It enables workflows to self-start without requiring a manual message in the feed or an external trigger.
How It Works¶
- Define a
stimulusspec on the ensemble with anameandprompt. - Draw a
stimulusrelationship from the stimulus name to the target agent config. - When all agents in the ensemble are running (all pods reach Serving phase), the controller creates an AgentRun on the target with the configured prompt.
- If the ensemble is disabled and re-enabled, the stimulus fires again on the next full-readiness transition.
- The stimulus can also be manually re-triggered via the UI button or API.
Example¶
apiVersion: sympozium.ai/v1alpha1
kind: Ensemble
metadata:
name: research-pipeline
spec:
workflowType: pipeline
stimulus:
name: kickoff
prompt: "Begin the daily research workflow. Summarize developments in AI safety from the last 24 hours."
agentConfigs:
- name: lead
systemPrompt: "You are a lead researcher coordinating the team."
- name: analyst
systemPrompt: "You are a data analyst."
relationships:
- source: kickoff
target: lead
type: stimulus
- source: lead
target: analyst
type: sequential
Manual Re-trigger¶
The stimulus can be re-triggered at any time via the API:
Or via the "Re-trigger Stimulus" button on the workflow canvas in the UI.
Feed Integration¶
When a stimulus is delivered (automatically or manually), a system message appears in the feed: "Stimulus prompt sent (readiness)" or "Stimulus prompt sent (manual)".
Shared Workflow Memory¶
By default, each persona in a Ensemble has its own private memory — an isolated SQLite database that only that persona can access. Shared Workflow Memory adds a second, pack-level memory pool that all personas can read from (and optionally write to), enabling cross-persona knowledge sharing.
Enabling Shared Memory¶
apiVersion: sympozium.ai/v1alpha1
kind: Ensemble
metadata:
name: research-delegation-example
spec:
sharedMemory:
enabled: true
storageSize: "1Gi"
accessRules:
- persona: lead
access: read-write
- persona: researcher
access: read-write
- persona: writer
access: read-write
- persona: reviewer
access: read-only
How It Works¶
When shared memory is enabled, the Ensemble controller provisions:
- PVC:
<pack>-shared-memory-db— persistent storage for the shared SQLite database - Deployment:
<pack>-shared-memory— the sameskill-memoryserver image used for private memory - Service:
<pack>-shared-memory— ClusterIP service on port 8080
All resources have ownerReferences to the Ensemble and are cleaned up on deletion.
Agent Tools¶
Agents in the pack receive three additional tools alongside their private memory tools:
| Tool | Description | Access |
|---|---|---|
workflow_memory_search |
Search shared team knowledge contributed by any persona | All |
workflow_memory_store |
Store findings for other personas (auto-tagged with source persona) | read-write only |
workflow_memory_list |
List shared entries, filterable by persona or tag | All |
Access Control¶
Each persona can be granted read-write or read-only access via accessRules. If no rules are specified, all personas default to read-write.
- read-write: Can search, list, and store entries
- read-only: Can search and list, but cannot store (the
workflow_memory_storetool is not registered)
Access control is enforced client-side in the agent runner — sufficient because the memory server is in-cluster behind a ClusterIP with no untrusted clients.
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. Inspired by biological cell membranes, it transforms the flat shared memory pool into a structured medium where agents share state selectively rather than broadcasting everything.
Why a Membrane?¶
Without a membrane, all shared memory entries are equally visible to all personas. This works for small teams, but breaks down at scale:
- A reviewer doesn't need raw data dumps from the researcher
- Token costs grow linearly with shared state size
- A single failing delegation can cascade through the entire ensemble
- Old entries accumulate and dilute search relevance
The membrane addresses each of these with a dedicated mechanism.
Enabling the Membrane¶
apiVersion: sympozium.ai/v1alpha1
kind: Ensemble
metadata:
name: research-delegation-example
spec:
sharedMemory:
enabled: true
storageSize: "1Gi"
membrane:
defaultVisibility: public
permeability:
- agentConfig: researcher
defaultVisibility: trusted
exposeTags: ["findings", "data"]
acceptTags: ["summary"]
- agentConfig: writer
defaultVisibility: public
acceptTags: ["findings", "data"]
- agentConfig: reviewer
defaultVisibility: private
trustGroups:
- name: content-team
agentConfigs: ["researcher", "writer"]
tokenBudget:
maxTokens: 100000
action: halt
circuitBreaker:
consecutiveFailures: 3
timeDecay:
ttl: "168h"
decayFunction: linear
Permeability (Visibility Tiers)¶
Every memory entry has a visibility level: public, trusted, or private.
| Visibility | Who can see it |
|---|---|
public |
All personas in the ensemble |
trusted |
Personas in the same trust group + the author |
private |
Only the persona that created it |
Each persona can override the ensemble default via a permeability rule:
defaultVisibility: The visibility tier applied to entries this persona createsexposeTags: Tags this persona publishes through the membrane. Entries with other tags are treated as private.acceptTags: Tags this persona wants to receive. Search results are filtered to matching tags only.
Trust Groups¶
Trust groups define which personas can see each other's trusted entries. If no trust groups are configured, trust is derived automatically from delegation and supervision relationships.
trustGroups:
- name: research-delegation-example
agentConfigs: ["researcher", "writer"]
- name: editorial
agentConfigs: ["writer", "editor"]
In this example, the writer can see trusted entries from both the researcher (via research-delegation-example) and the editor (via editorial).
Token Budget¶
Token budgets set a ceiling on total token consumption across all agent runs in an ensemble.
| Field | Description |
|---|---|
maxTokens |
Maximum total tokens (input+output) across all runs. 0 = unlimited. |
maxTokensPerRun |
Maximum tokens for any single AgentRun. 0 = unlimited. |
action |
halt (default) — block new runs when exceeded. warn — allow runs but log a warning. |
When a run completes, the controller adds its token usage to status.tokenBudgetUsed. Before creating a new run, the controller checks whether the budget has been exceeded.
Circuit Breaker¶
The circuit breaker protects against cascading delegation failures. After consecutiveFailures delegate children fail in a row, the circuit breaker opens and rejects further spawn requests until a delegate succeeds (which resets the counter).
When the circuit breaker is open, delegate_to_persona calls immediately return an error instead of spawning a child run. This prevents runaway token consumption from repeated failing delegations.
Time Decay¶
Time decay excludes old entries from search results without deleting them. This keeps the shared memory relevant as the team's knowledge evolves.
| Field | Description |
|---|---|
ttl |
Entries older than this are excluded from search. Format: "24h", "168h" (7 days). |
decayFunction |
linear (default) or exponential — controls how relevance decreases with age. |
Provenance Tracking¶
Every memory entry tracks its source agent and an optional parent ID for derivation chains. This enables:
- Attribution: Which persona created this entry?
- Lineage: What chain of reasoning led to this conclusion?
- Monotonic sequencing: Entries have a
seqnumber for replay and event sourcing
The memory server exposes a /provenance?id=N endpoint that returns the full derivation chain from root to the given entry.
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). The paper proposes a six-layer architecture for multi-agent coordination, drawing on biological analogues, distributed systems theory, and recent findings from the Superminds Test (2M+ agents, zero collective intelligence without structured substrate).
Auto-Context Injection¶
When an agent starts, the runner automatically queries both private and shared memory for task-relevant context. The system prompt includes two sections:
- Your Past Findings (Private Memory) — from the persona's own memory
- Team Knowledge (Shared Workflow Memory) — from the pack's shared pool
Attribution¶
Entries stored via workflow_memory_store are automatically tagged with the source persona's instance name. This enables filtering by persona (e.g., "show me what the researcher found") without relying on agents to self-tag correctly.
delegate_to_persona Tool¶
Agents that belong to a Ensemble automatically receive the delegate_to_persona tool. This allows an agent to delegate a task to another persona in the same pack:
Tool: delegate_to_persona
Arguments:
targetPersona: "writer"
task: "Write a report based on these findings: ..."
The tool is blocking — the parent agent waits (up to 10 minutes) for the child to complete and receives the result directly. Under the hood, the tool writes a spawn request to /ipc/spawn/, the SpawnRouter creates a child AgentRun via the Spawner (validating the relationship edge exists), and when the child finishes, the SpawnRouter delivers the result back through NATS to the parent's IPC bridge. The parent's DelegateStatus is populated with the child run name, target persona, phase, and result. During the wait, the parent AgentRun transitions to AwaitingDelegate phase (timeout checking is paused).
Visual Canvas¶
The Web UI provides two canvas views for visualising persona relationships:
- Per-pack canvas (Persona detail page → Workflow tab): editable — drag to connect personas, pick relationship type, save back to the CRD
- Global canvas (Ensembles list page → Canvas view): read-only — shows all enabled packs together with live run status
- Dashboard widget (Team Canvas panel): compact view with pack selector dropdown and live run status highlighting
Persona nodes show live run status with animated indicators:
- Running: pulsing blue ring + task preview
- Serving: pulsing violet ring
- AwaitingDelegate: pulsing amber ring
- Failed: red ring
- Succeeded: green ring
Built-in Packs¶
| Pack | Category | Agents | Description |
|---|---|---|---|
platform-team |
Platform | Security Guardian, SRE Watchdog, Platform Engineer | Core platform engineering — security audits, cluster health, manifest review |
devops-pipeline-example |
DevOps | Incident Responder, Cost Analyzer | DevOps workflows — incident triage, resource right-sizing |
developer-team |
Development | Tech Lead, Backend Dev, Frontend Dev, QA Engineer, Code Reviewer, DevOps Engineer, Docs Writer | A 2-pizza software development team that collaborates on a single GitHub repository |
research-delegation-example |
Research | Lead, Researcher, Writer, Reviewer | A coordinated research and reporting team demonstrating delegation, sequential, and supervision relationships |
observability-mcp-example |
Observability | Grafana Analyst, Log Investigator | Observability workflows using MCP servers for Grafana and Loki |
Activating a Pack in the Web UI¶
- Navigate to Ensembles in the sidebar
- Click Enable on a pack to open the onboarding wizard
- Choose your AI provider and paste an API key
- Optionally bind channels (Telegram, Slack, Discord, WhatsApp)
- Confirm — the controller creates all instances within seconds
Activating via kubectl¶
# 1. Create the provider secret
kubectl create secret generic my-pack-openai-key \
--from-literal=OPENAI_API_KEY=sk-...
# 2. Patch the Ensemble with authRefs to trigger activation
kubectl patch ensemble platform-team --type=merge -p '{
"spec": {
"authRefs": [{"provider": "openai", "secret": "my-pack-openai-key"}]
}
}'
The controller detects the authRefs change and reconciles — creating Agents, Schedules, and memory ConfigMaps for each persona.
Writing Your Own Ensemble¶
apiVersion: sympozium.ai/v1alpha1
kind: Ensemble
metadata:
name: my-team
spec:
description: "My custom agent team"
category: custom
version: "1.0.0"
workflowType: delegation
personas:
- name: planner
displayName: "Planner"
systemPrompt: |
You plan work and delegate to the executor.
skills:
- k8s-ops
- memory
schedule:
type: heartbeat
interval: "1h"
task: "Check for pending work and delegate to the executor."
- name: executor
displayName: "Executor"
systemPrompt: |
You execute tasks assigned by the planner.
skills:
- k8s-ops
- memory
relationships:
- source: planner
target: executor
type: delegation
timeout: "15m"
Apply it with kubectl apply -f my-team.yaml, then activate through the Web UI or TUI.
Tip
See the Developer Team Pack for a detailed example of a complex Ensemble with seven collaborating agents.