Agent Configuration
Agents are the core building blocks of MindRoom. Each agent is a specialized AI actor with specific capabilities.
Basic Agent
agents:
assistant:
display_name: Assistant
role: A helpful AI assistant
model: sonnet
rooms: [lobby]
Full Configuration
agents:
developer:
# Display name shown in Matrix
display_name: Developer
# Role description - guides the agent's behavior
role: Generate code, manage files, execute shell commands
# Model to use (defined in models section)
model: sonnet
# Tools the agent can use (plain names or inline config overrides)
tools:
- file
- shell
- github
# Per-agent tool config override (single-key dict syntax):
# - shell:
# extra_env_passthrough: "DAWARICH_*"
# enable_run_shell_command: true
# Skills the agent can use (defined in skills section or plugins)
skills:
- my_custom_skill
# Custom instructions
instructions:
- Always read files before modifying them
- Use clear variable names
- Add comments for complex logic
# Rooms to join (will be created if they don't exist)
rooms:
- lobby
- dev
# Accept all, none, or matching inviter ID patterns
accept_invites: true
# Conversation access is separate from invitation acceptance
access:
current_room_members: false
members_of_rooms:
- lobby
users: []
# Enable markdown formatting
markdown: true
# Enable Agno Learning for this agent
learning: true
# Learning mode: always (automatic) or agentic (tool-driven)
learning_mode: always
# Memory backend override for this agent (optional: mem0, file, or none)
memory_backend: file
# Assign agent to one or more configured knowledge bases (optional)
knowledge_bases: [docs]
# Optional: additional files loaded into each freshly built agent instance
context_files:
- SOUL.md
- AGENTS.md
- USER.md
- IDENTITY.md
- TOOLS.md
- HEARTBEAT.md
# Whether to include defaults.tools for this agent (default: true)
include_default_tools: true
# Response mode: "thread" (replies in Matrix threads) or "room" (plain room messages)
thread_mode: thread
# Optional room-specific overrides for thread mode
# Keys may be managed room aliases/names or Matrix room IDs
room_thread_modes:
lobby: thread
bridge_telegram: room
"!abc123:example.com": room
# Tools to run in the sandbox proxy instead of the main process (optional, inherits from defaults)
worker_tools: [shell, file]
# How sandbox runtimes are shared (optional, inherits from defaults)
worker_scope: user_agent
# Allow this agent to read and modify its own config at runtime
allow_self_config: false
# Delegate tasks to other agents via tool calls
delegate_to:
- research
- finance
# History context controls (all optional, inherit from defaults)
num_history_runs: null
num_history_messages: null
compress_tool_results: false
max_tool_calls_from_history: null
# Required compaction is enabled by default.
# Eligible models and history policies use native compaction at the threshold.
# Set enabled: false to disable automatic native and pre-reply text compaction.
compaction:
enabled: true
threshold_percent: 0.8
reserve_tokens: 16384
timeout_seconds: 600
# Keep <workspace>/thread_exports/ current with YAML exports of this agent's rooms
# (true enables the defaults; see Thread Exports below)
thread_exports: true
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
display_name |
string | required | Human-readable name shown in Matrix as the bot's display name |
role |
string | "" |
System prompt describing the agent's purpose — guides its behavior and expertise |
model |
string | "default" |
Model name (must match a key in the models section) |
tools |
list | [] |
Agent-specific tool entries — plain strings or single-key dicts with config overrides (see Tools and Per-Agent Tool Configuration); effective tools are tools + defaults.tools with duplicates removed |
include_default_tools |
bool | true |
When true, append defaults.tools to this agent's tools; set to false to opt this agent out |
skills |
list | [] |
Skill names the agent can use (see Skills) |
instructions |
list | [] |
Extra lines appended to the system prompt after the role |
rooms |
list | [] |
Room aliases to auto-join; rooms are created if they don't exist |
accept_invites |
bool or list[string] | true |
Accept all inbound Matrix room invites with true, none with false or [], or only inviters matching an exact or wildcard Matrix user ID in the list. Accepted ad-hoc room IDs are persisted so memberships survive restarts and room cleanup. Approval-gated tools require the router in the room; agents can recover a missing router with their built-in zero-argument invite_router tool when the router's policy allows the current Matrix transport account |
markdown |
bool | null |
When enabled, the agent is instructed to format responses as Markdown. Inherits from defaults.markdown (default: true) |
learning |
bool | null |
Enable Agno Learning — the agent builds a persistent profile of user preferences and adapts over time. Inherits from defaults.learning (default: true) |
learning_mode |
string | null |
always: agent automatically learns from every interaction. agentic: agent decides when to learn via a tool call. Inherits from defaults.learning_mode (default: "always") |
memory_backend |
string | null |
Memory backend override for this agent ("mem0", "file", or "none"). Inherits from global memory.backend when omitted |
memory_search |
object | null |
File-memory search override for this agent. Supports mode, include, and include_entrypoint; omitted fields inherit from global memory.search |
private |
object | null |
Optional requester-private state for one shared agent definition |
knowledge_bases |
list | [] |
Knowledge base IDs from top-level knowledge_bases; semantic bases add indexed RAG search while file-mode bases expose workspace file paths for agents with file-aware tools |
access |
object | null |
Conversation-access policy with current_room_members, members_of_rooms, and users. Omitting it grants members of this agent's own managed rooms. See Authorization |
credential_managers |
list | [] |
Concrete Matrix user IDs allowed to manage this agent's credentials and OAuth connections. Independent of access: a credential manager gains no conversation access, and a responder user gains no credential authority |
context_files |
list | [] |
File paths (relative to the agent's workspace) loaded into each agent instance and prepended to role context (under Personality Context) |
thread_mode |
string | "thread" |
thread: responses are sent in Matrix threads (default). room: responses are sent as plain room messages with a single persistent session per room — ideal for bridges (Telegram, Signal, WhatsApp) and mobile |
room_thread_modes |
map | {} |
Per-room thread mode overrides keyed by room alias/name or Matrix room ID. Values are thread or room. Overrides apply before thread_mode fallback |
num_history_runs |
int | null |
Number of prior Agno runs to include as history context (null = all). Mutually exclusive with num_history_messages |
num_history_messages |
int | null |
Max messages from history. Mutually exclusive with num_history_runs |
compress_tool_results |
bool | null |
Compress tool results in history to save context. Inherits from defaults.compress_tool_results (default: false). On Anthropic and Vertex Claude models, setting this to true can mutate replayed tool messages and invalidate prompt-cache prefixes |
compaction |
object | defaults.compaction |
Per-agent required-compaction overrides |
max_tool_calls_from_history |
int | null |
Limit tool call messages replayed from history (null = no limit) |
show_tool_calls |
bool | null |
Show tool-call markers and trace metadata in Matrix messages. Inherits from defaults.show_tool_calls (default: true). When false, inline markers and io.mindroom.tool_trace are omitted from sent Matrix message content. Routed tools may still show generic worker warmup text such as Preparing isolated worker..., but that copy never includes tool identifiers or tool-trace metadata. Note: this flag is not currently enforced by the OpenAI-compatible /v1/chat/completions path. |
worker_tools |
list | null |
Tool names to run in the sandbox proxy instead of the main process. Inherits from defaults.worker_tools. When omitted everywhere, MindRoom uses its built-in default. Set to [] to disable proxying for this agent |
worker_scope |
string | null |
How sandbox runtimes are shared for non-private agents. shared: one per agent. user: one per user (shared across agents). user_agent: one per user+agent pair. Inherits from defaults.worker_scope. Do not set this when the agent uses private, because private.per already defines the requester partition for that agent |
allow_self_config |
bool | null |
Give this agent a scoped tool to read and modify its own configuration at runtime. Inherits from defaults.allow_self_config (default: false). Lighter-weight alternative to the config_manager tool |
delegate_to |
list | [] |
Allowed agent names for run_subagent, including itself if listed (see Agent Delegation) |
thread_exports |
bool or object | null |
Continuously export every thread from rooms this agent is joined to as YAML under <workspace>/thread_exports/. true enables the defaults; an object sets invited_rooms and private_room_scope (see Thread Exports) |
Each entry in knowledge_bases must match a key under knowledge_bases in config.yaml.
See Knowledge Bases for mode: semantic and mode: files.
Per-agent fields with a null default inherit from the defaults section at runtime.
Per-agent values override them.
memory.backend is the global memory default, and agents.<name>.memory_backend overrides it per agent.
Use memory_backend: none for stateless agents that should skip prompt memory lookup, automatic memory persistence, and the explicit memory tool.
agents.<name>.memory_search can override mode, include, and include_entrypoint when the effective memory backend is file.
Unset memory_search fields inherit from top-level memory.search.
show_stop_button and enable_streaming are global-only settings in defaults and cannot be overridden per-agent.
The dashboard Agents tab exposes this as the Memory Backend selector for each agent.
Agents use agents.<name>.accept_invites, while teams and the router use their own accept_invites options with the same durable invite semantics.
true accepts every valid invitation, false and [] reject every invitation, and a list accepts exact or wildcard Matrix user IDs after human-only alias resolution; non-human accounts retain their exact transport ID.
Invite acceptance and responder access are independent, so joining a room does not authorize its inviter to interact with the agent.
The agent continues to apply access.users, access.current_room_members, and access.members_of_rooms to every interaction after joining.
Approval-gated tools are stricter than plain ad-hoc chat access.
When approval needs a missing router, the agent can call invite_router to invite it into the current room and then retry.
The tool waits briefly for joined membership and, if the invite remains pending, tells the agent to retry only after the router joins.
The router accepts and persists that internal invite when router.accept_invites allows the current Matrix transport account's user ID.
For a team execution, that identity is the team's Matrix account rather than the member agent's account.
MindRoom uses native provider compaction when the active model and history policy support it, with portable text compaction as the fallback.
Per-agent compaction supports enabled, threshold_tokens, threshold_percent, replay_window_tokens, reserve_tokens, model, fallback_model, and timeout_seconds.
When the active runtime model has a known context_window, MindRoom always computes a per-run replay plan that reduces or disables persisted replay before the model call if needed.
Automatic compaction is enabled by default through defaults.compaction.
threshold_tokens and threshold_percent control the native provider trigger; on text-only routes they remain soft planning thresholds.
Native compaction runs inside ordinary provider requests and stores a provider-specific checkpoint alongside the original conversation.
The next request replays the latest compatible checkpoint and its following messages.
Canonical runs remain stored for model switching and portable text compaction.
See native compaction eligibility for supported routes and fallback conditions.
Destructive text compaction runs before the reply when history exceeds the hard replay budget or when explicitly requested.
You can tune compaction behavior with these settings:
- Use
replay_window_tokensto cap persisted replay and required-compaction planning below the model's real context window without lowering the provider request limit. - Use
reserve_tokensto leave hard-budget headroom. - Use
modelto choose the summary model. - Use
fallback_modelto name a different model config retried once when the summary model refuses for safeguards; the same input is reused when it fits, otherwise it is rebuilt under the fallback model's own context budget, and after success that model serves the remaining chunks. - Use
timeout_secondsto bound each primary, retry, or fallback summary request; it defaults to 600 seconds, while an explicitly shorter provider timeout remains the stricter cap. - Set
enabled: falseto disable automatic native and pre-reply text compaction for this agent.
When the active runtime model window is known, replay safety uses the smaller of it and replay_window_tokens.
When that model window is unknown, an explicit replay_window_tokens still supplies the replay-planning window.
Each compaction summary input chunk is sized independently from the selected compaction model's real context_window, after reserve, prompt overhead, and a safety margin.
Destructive compaction requires the resolved summary input budget to exceed 2,000 tokens.
With the default reserve_tokens, this makes destructive compaction unavailable when the compaction model's context window is roughly 10,000 tokens or smaller; lowering reserve_tokens restores availability for such small windows.
If you set compaction.model, that summary model must also define its own context_window, but only for the durable summary-generation pass.
compaction.fallback_model must also name a configured model with its own context_window; a fallback naming the summary model's alias, or another alias resolving to the same provider and model ID, is ignored because it would resend the refused request to the same model.
If the current reply needs required compaction to preserve usable history, MindRoom sends Compacting history..., compacts before the model call, and edits that same notice with the result.
Manual compact_context records a durable request that runs before the next reply in the same conversation scope.
Manual compact_context remains available when a compaction model and context window are configured and the resolved summary input budget exceeds 2,000 tokens.
MindRoom does not run a separate background post-response compaction path.
It always plans the replay that is safe for the current model call when the active runtime model has a known context_window.
That replay planner can keep configured replay, reduce raw replay, fall back to summary-only replay, or disable persisted replay for the run.
Portable text compaction rewrites the persisted Agno session in SQLite.
Older compacted runs are removed from session.runs and replaced by the merged session.summary, so raw pre-compaction runs are not retained for later audit or debugging.
Learning data is persisted under agents/<name>/learning/<agent>.db, so it survives container restarts when the storage directory is mounted.
context_files are resolved relative to the agent's workspace directory (agents/<name>/workspace/).
When the effective memory backend is file, the agent's canonical file memory root is that same workspace directory.
Absolute paths and .. traversal are rejected.
Each part of the Personality Context section is headed by the resolved path of the file it was read from, and the section states that those files are already inlined so the agent does not spend a turn re-reading them.
When the rendered section exceeds defaults.max_preload_chars, MindRoom drops earlier file bodies first, trims the final surviving body from its end, and leaves a per-file marker giving each affected path and omitted-character count, followed by a summary marker for the section.
A dropped file therefore still appears with its path, so the agent can open it when it needs the omitted part.
If the configured cap cannot contain the section heading plus all required per-file and summary markers, agent materialization fails explicitly instead of silently removing source paths.
Per-Agent Tool Configuration
Tools can be plain strings or single-key dicts with inline config overrides. This lets you customize tool behavior per agent without affecting other agents that use the same tool.
agents:
code:
tools:
- file # no override, uses defaults
- shell: # per-agent override
extra_env_passthrough: "DAWARICH_*"
enable_run_shell_command: true
research:
tools:
- shell # uses global defaults (no overrides)
- duckduckgo
Merge Order
MindRoom resolves tool configuration in layers:
- Tool constructor defaults (hardcoded in tool code)
- Credentials (dashboard or credential store)
defaults.toolsoverrides (global inline config)agents.<name>.toolsoverrides (per-agent inline config)- Runtime overrides (sandbox proxy, init overrides)
Within the authored layers (defaults.tools and agents.<name>.tools), each field has three possible states:
- Key omitted: keep the value from the next lower layer unchanged.
- Concrete value: override the next lower layer with that value.
__MINDROOM_INHERIT__: clear an inherited authored override and fall back to the next lower layer.
When the same tool appears in both defaults.tools and agents.<name>.tools, MindRoom merges them field-by-field.
Per-agent values win for overlapping keys, non-overlapping keys are kept from both, and __MINDROOM_INHERIT__ removes the inherited authored value instead of passing the literal string to the tool.
Defaults with Overrides
defaults.tools also accepts the single-key dict syntax for global overrides that apply to all agents:
defaults:
tools:
- scheduler
- shell:
enable_run_shell_command: true # global default for all agents
Filtering Toolkit Functions
Registered Agno Toolkit integrations accept include_tools and exclude_tools inline overrides even when those fields are not declared by the concrete toolkit constructor.
include_tools is an allowlist, while exclude_tools is a denylist applied after the toolkit registers its functions.
Use the function names exposed by the tool catalog.
Unsupported non-Toolkit integrations reject these fields during config validation.
Clearing An Inherited Override
Use __MINDROOM_INHERIT__ when an agent should keep the tool but stop inheriting one authored field from defaults.tools.
Optional-field example:
defaults:
tools:
- shell:
extra_env_passthrough: "DAWARICH_*"
enable_run_shell_command: true
agents:
research:
tools:
- shell:
extra_env_passthrough: __MINDROOM_INHERIT__
research still inherits enable_run_shell_command: true, but extra_env_passthrough falls back to the lower layer (persisted tool config if set, otherwise the tool's normal default).
For sandboxed shell, provider API keys and other committed runtime credentials are denied by default in both worker startup env and command env.
Use extra_env_passthrough when a specific exported process env value must be visible to shell commands.
Required non-secret field example:
defaults:
tools:
- clickup:
master_space_id: "space-default"
agents:
ops:
tools:
- clickup:
master_space_id: __MINDROOM_INHERIT__
ops still uses the clickup tool, but master_space_id no longer inherits "space-default".
MindRoom falls back to the next lower layer, which is usually the stored tool config from the dashboard or credential store.
include_default_tools vs __MINDROOM_INHERIT__
include_default_tools: falseis coarse-grained: it removes every tool and every override inherited fromdefaults.toolsfor that agent.__MINDROOM_INHERIT__is fine-grained: it keeps the tool and the rest of the inherited fields, but clears one specific authored override.
Security Restrictions
Not all config fields can be overridden inline:
type="password"fields are blocked (credentials must go through the dashboard or credential store)base_diris blocked (runtime-only, set by the workspace system)- Fields with
authored_override: falsein the tool metadata are blocked
MindRoom validates overrides at config load time and rejects unknown field names, wrong value types, and blocked fields with a clear error message.
Backward Compatibility
Existing configs with plain string tool lists work unchanged:
Config Manager
The !config chat command and the config_manager tool preserve inline overrides when updating tool lists.
Adding or removing tools via chat does not discard existing per-agent overrides on other tools.
Worker Routing
worker_tools decides which tools run in the sandbox proxy instead of the main MindRoom process.
When omitted, MindRoom routes coding, docker, file, python, and shell through the proxy by default.
Registry-backed tools can be listed in worker_tools, and MindRoom will attempt to route them through the worker runtime.
Tools whose catalog metadata sets requires_primary_runtime=True stay in the primary runtime even when listed.
Dedicated Docker workers also receive a projected read-only config snapshot so config-relative plugins, knowledge bases, and other worker-safe assets remain available without exposing unrelated primary-runtime state.
Agent-scoped workers snapshot only that agent's projected context files and assigned knowledge bases, while scopes that intentionally share one worker across multiple agents keep the broader shared projection for that worker.
Writable file-memory paths are rewritten into worker-owned state instead of being mounted from the host config tree.
Config-adjacent .env files are intentionally masked as files inside those Docker workers.
A filtered public startup-runtime env payload can still propagate from exported env vars and allowed .env values.
worker_scope controls how those sandbox runtimes are reused between calls.
Some integrations require worker_scope unset or shared because their credentials or sessions are shared at runtime.
That list includes spotify and homeassistant.
Configured mcp_<server_id> tools work on every worker scope: generated OAuth providers follow the selected agent's effective credential scope, while non-OAuth servers use the shared MCP session without requester credentials.
For OAuth-backed MCP, shared uses one agent-owned connection, user reuses one requester-owned connection across agents, user_agent isolates each requester-agent pair, and unscoped uses one installation-level connection.
Among those shared-scope integrations, homeassistant always stays local regardless of worker_tools and is never proxied to the sandbox.
Credential-backed integrations that declare requires_primary_runtime=True also always stay local.
spotify can still be proxied through the sandbox.
The built-in memory, delegate, and self_config tools are also created directly in the primary runtime today and are not routed through worker_tools.
The supported worker_scope values are:
shared: one runtime per agent, shared by all users.user: one runtime per user, shared across that user's agents.user_agent: one runtime per user+agent pair.
Leave worker_scope unset for unscoped execution — calls still run in the sandbox, but each call gets a fresh runtime instead of a persistent one.
worker_scope also affects dashboard credential support and OpenAI-compatible agent eligibility.
Filesystem Isolation
worker_scope controls runtime reuse, not filesystem security.
When the effective memory backend is file, tools like shell, file, python, and coding get a default working directory (base_dir) at the agent's canonical workspace root.
Without file-backed workspace state, those tools keep their normal defaults such as the current directory.
Even when set, base_dir is a convenience, not a hard boundary.
Isolation depends on the worker backend:
- Kubernetes dedicated workers (
shared,user_agent, unscoped): the runtime can only see its own agent's storage directory plus its worker-local scratch space. This is the strongest isolation available today. - Kubernetes dedicated workers (
user): the runtime can see all agents' storage, becauseusermode intentionally shares one runtime across multiple agents for a single user. Treat this as a shared workstation. - Shared-runner and local backends: no hard filesystem boundary today, regardless of scope.
Use user_agent if you need per-agent filesystem isolation.
For per-workspace env that an agent can edit (PATH, package indexes, npm cache locations, etc.), drop a .mindroom/worker-env.sh script in the agent workspace; MindRoom sources it before each worker-routed shell or python request.
MindRoom-owned workspace identity, cache, and virtualenv env names are reasserted after the hook, so hooks cannot redirect HOME, MINDROOM_AGENT_WORKSPACE, XDG_CONFIG_HOME, XDG_DATA_HOME, XDG_STATE_HOME, XDG_CACHE_HOME, PIP_CACHE_DIR, UV_CACHE_DIR, PYTHONPYCACHEPREFIX, or VIRTUAL_ENV.
With worker_scope: user, the same runtime can move between several agent workspaces, and the hook is discovered from the current request's workspace — different agents get different overlays automatically.
See Workspace env hook for filename, filtering, and failure semantics.
Where Agent Data Lives
Agents without private store all their data in one canonical directory: agents/<name>/ (context files, workspace, memory, sessions, learning).
Changing worker_scope changes how tool runtimes are isolated.
It does not change where that non-private agent's data lives.
All runtimes for the same non-private agent read and write the same storage directory.
If multiple runtimes run concurrently, files and databases in that directory must tolerate concurrent access.
Agents that use private are different.
They materialize one canonical state root per requester-scoped private instance under private_instances/<scope-key>/<agent>/.
Workers mount those canonical private-instance roots.
They do not own them.
The dashboard's generic credential forms only work for unscoped agents and agents with worker_scope=shared.
The Google Drive, Docs, Gmail, Calendar, and Sheets OAuth providers are an exception: the dashboard can connect scoped user and user_agent credentials, while the tools still execute in the primary MindRoom runtime.
GitHub managed OAuth credentials always use the requester's user scope, independently of the agent's worker_scope.
Tools without a scoped OAuth provider still manage user and user_agent credentials through their worker runtime instead.
For more details on storage layout and isolation, see Sandbox Proxy Isolation.
Private Instances
Use private when one shared agent definition should behave like a template that materializes a separate requester-local instance at runtime.
The YAML definition stays shared.
The private root, copied files, file-memory workspace, and private knowledge path do not.
Private agents cannot be configured as team members.
Explicit Matrix messages that tag a private agent with other agents can form an ad hoc team for that requester.
That exception is direct only: a shared team member that reaches a private agent through delegate_to is still rejected.
private.per is not a second spelling of worker_scope.
private.per chooses who gets a separate private instance of the agent's state.
MindRoom then uses that same requester partition for worker execution, but that is an internal consequence of private execution, not the public meaning of worker_scope.
knowledge_bases:
company_docs:
path: ./company_docs
watch: false
agents:
mind:
display_name: Mind
role: A persistent personal AI companion
model: sonnet
tools: [file, shell]
worker_tools: [file, shell]
memory_backend: file
memory_search:
mode: semantic
include:
- memory/**/*.md
include_entrypoint: false
private:
per: user
root: mind_data
template_dir: ./mind_template
context_files:
- SOUL.md
- AGENTS.md
- USER.md
- IDENTITY.md
- TOOLS.md
- HEARTBEAT.md
- MEMORY.md
knowledge:
path: memory
watch: false
knowledge_bases: [company_docs]
Example template directory:
mind_template/
├── SOUL.md
├── AGENTS.md
├── USER.md
├── IDENTITY.md
├── TOOLS.md
├── HEARTBEAT.md
├── MEMORY.md
└── memory/
In the example above, each requester gets their own effective mind_data/ root under a canonical private-instance state root in shared storage.
That private root is not created next to config.yaml.
It is not stored under workers/<worker>/.
Workers mount the same canonical private-instance root when they execute that requester scope.
For a mind agent with private.per: user, different users get different private mind_data/ trees even though the agent definition is shared.
Private Fields
| Field | Type | Default | Description |
|---|---|---|---|
private.per |
user or user_agent |
required | Which requester boundary gets its own private instance of the agent's state. MindRoom also uses that same boundary for the agent's internal execution scope |
private.root |
string | <agent_name>_data |
Private root name under the canonical private-instance state root. Must be a relative path and cannot escape with .. |
private.template_dir |
string | null |
Optional local directory copied recursively into each private root without overwriting existing files. Relative paths are resolved from config.yaml, and absolute paths are also allowed. MindRoom raises an error when the directory does not exist |
private.context_files |
list | null |
Optional files loaded into role context from inside the private root. Each path is relative to the private root and cannot escape it |
private.knowledge |
object | null |
Optional PrivateAgentKnowledge indexed from inside the private root. Sub-fields below. See Knowledge Bases |
private.knowledge.enabled |
bool | true |
Whether to index PrivateAgentKnowledge for this private agent instance. Set to false to disable indexing |
private.knowledge.description |
string | "" |
Short description of what the private knowledge contains. Agents see this in the search_knowledge_base tool description so they know when the source is relevant |
private.knowledge.path |
string | null |
Path to a private knowledge directory relative to the private root |
private.knowledge.watch |
bool | true |
When true, PrivateAgentKnowledge schedules background refresh on access. When false, direct external edits require explicit refresh |
private.knowledge.chunk_size |
int | 5000 |
Maximum characters per indexed chunk (min: 128) |
private.knowledge.chunk_overlap |
int | 0 |
Overlapping characters between adjacent chunks (min: 0) |
private.knowledge.git |
object | null |
Optional Git sync configuration for PrivateAgentKnowledge (same schema as top-level knowledge_bases.<id>.git) |
Runtime Behavior
- MindRoom resolves the canonical private-instance state root from
private.per. - MindRoom creates the effective private root inside that canonical private-instance state root.
- If
private.template_diris set, MindRoom copies the template directory into the private root without overwriting files that already exist there. - MindRoom loads any
private.context_filesfrom that private root when the agent is created or reloaded. - If
memory_backend: fileis enabled, MindRoom uses that same private root as the file-memory root for that requester. - If
private.knowledge.pathis configured, MindRoom indexes that private-root-relative path as PrivateAgentKnowledge for that requester only.
Important Rules
privateis explicit opt-in.privatedoes not automatically enable file memory.privatedoes not automatically load any context files.privatedoes not automatically create a private knowledge base.- Private agents cannot be configured as team members.
- Explicit Matrix ad hoc teams can include directly tagged private agents for requester-scoped execution.
- Shared team members that reach a private agent through
delegate_toare rejected. - If
private.template_diris omitted, MindRoom still creates the private root. - Private agents require an active requester-scoped runtime context.
- MindRoom raises an error instead of silently falling back to a shared config-relative path when that requester scope is missing.
- Set
memory_backend: fileif you wantMEMORY.mdandmemory/inside the private root to be the agent's actual file memory. - Set
memory_backend: noneif the private agent should stay stateless while still using its private files and knowledge configuration. - Set
private.context_filesexplicitly for any copied files you want loaded into role context. - Set
private.knowledge.pathexplicitly for any copied files or folders you want indexed as PrivateAgentKnowledge. - Omit
private.knowledgeentirely, or setprivate.knowledge.enabled: false, when you do not want PrivateAgentKnowledge indexing. privatecannot be combined withworker_scope.- Top-level
knowledge_basesremain shared or company-wide corpora, so one agent can use both PrivateAgentKnowledge and shared knowledge in the same run. - Top-level
context_filesremain the shared workspace-relative mechanism used by single-user setups, including the defaultmindroom config initoutput. - Custom templates are fully supported.
- The Mind-style filenames shown above are a convention, not a requirement, unless you choose to reference them in
private.context_filesorprivate.knowledge.path.
Thread Exports
thread_exports keeps a YAML copy of the agent's conversation history inside its workspace, so its file and shell tools can grep past threads without any Matrix API access.
agents:
code:
thread_exports: true # defaults below
research:
thread_exports:
invited_rooms: false # config rooms only
private_room_scope: owner # private agents only
| Option | Type | Default | Description |
|---|---|---|---|
invited_rooms |
bool | true |
Also export user-created rooms the agent joined through invites. Current membership is always required |
private_room_scope |
string | "owner_and_agent" |
Private agents only. Within the agent's configured and invited rooms, owner_and_agent requires both the requester and agent to be joined; owner requires only the requester |
Exports land at <storage_root>/agents/<agent>/workspace/thread_exports/<urlencoded room key>/<urlencoded thread id>.yaml, the same layout mindroom threads export writes.
Inside the agent's own tools that directory is $MINDROOM_AGENT_WORKSPACE/thread_exports/.
Each thread file holds version, room metadata, thread metadata including the latest thread summary as thread.summary, and a messages list.
Each room directory also holds an index.json mapping every thread file to its message count, participants, latest summary, and last activity, sorted by most recent activity.
MindRoom re-exports a room within about two seconds of a message, edit, redaction, or membership change in it, batching everything that arrives in that window into one pass, and runs one full pass at startup and after every config reload.
A full pass also removes exports for threads and rooms that no longer exist or that the agent may no longer read, and clears the export tree of any configured agent whose thread_exports was removed.
A full pass that could export no room at all skips that directory-wide removal, because an empty result cannot be told apart from a failed one; the same guard and its manual-cleanup guidance are described under threads export.
Files are rewritten only when a thread's content changed.
Agents may edit or delete their exported files; deleted files return on the next pass that touches the room.
Each workspace is populated only through that agent's running Matrix account and principal-bound event-journal projection, so a pass costs no Matrix history call for threads that agent has seen.
Security and Retention
Thread export authorization controls which data future passes may write. Export cleanup is best-effort workspace maintenance, not a revocation or data-erasure boundary. Previously exported data may remain or may have been copied or committed by the agent. Principal isolation does not trigger a one-time purge or migration of existing exports.
Shared agents export only rooms where the agent's own Matrix account is currently joined.
Private agents (private:) get one export tree per materialized instance under <storage_root>/private_instances/<scope-key>/<agent>/<private root>/thread_exports/; each tree stays within that agent's configured and invited rooms and is scoped to the requester's current room memberships, so one requester's private workspace never accumulates other users' conversations.
A membership lookup failure blocks new writes for that room and leaves existing files in place until a successful lookup proves that access was revoked.
Semantic Search Over Exports
The exports are plain YAML, so file-aware tools already cover keyword search.
With an embedder configured (memory.embedder), point a knowledge base at the export directory for semantic search through search_knowledge_base.
knowledge_bases:
code_threads:
path: ./mindroom_data/agents/code/workspace/thread_exports
description: Exported Matrix conversation history for the code agent
exclude_patterns: ["*/index.json"]
agents:
code:
thread_exports: true
knowledge_bases: [code_threads]
For a private agent, index the private-root-relative path instead:
agents:
secret:
thread_exports: true
private:
per: user
knowledge:
path: thread_exports
description: Your exported conversation history
The active thread's file rewrites on every message, so a watching semantic index re-embeds that thread per message. This is negligible with a local embedder but costs real money with paid embedding APIs in busy rooms.
Thread Mode Resolution
Thread mode is resolved per message using the current room ID.
For an agent, MindRoom checks room_thread_modes in this order.
First, it checks an exact room ID key.
Second, it checks the managed room key/alias associated with that room ID.
Third, it resolves each configured room_thread_modes key to a room ID and matches that against the current room.
If none match, it falls back to thread_mode.
For a team, MindRoom resolves mode per member agent for that room.
If all member agents resolve to the same mode, the team uses that mode.
If member modes differ, the team defaults to thread.
For the router, MindRoom resolves mode using agents relevant to the active room.
This includes agents directly configured for the room and agents included via teams.<name>.rooms.
If all relevant agents resolve to the same mode, the router uses that mode.
If modes are mixed, the router defaults to thread.
File-Based Context Loading
You can inject file content directly into an agent's role context without using a knowledge base.
context_files behavior:
- Paths are relative to the agent's workspace (
agents/<name>/workspace/) private.context_filespaths are resolved relative to the effective private root- Existing files are loaded in list order and added under
Personality Context - Missing files are skipped with a warning in logs
MindRoom loads the files when it builds an agent instance. The normal Matrix and OpenAI-compatible reply paths build fresh agent instances per reply/request, so editing a context file affects the next reply without restarting the process.
Agent Delegation
Set delegate_to to the agent names allowed as subagents; the dashboard labels this list Allowed subagents.
The model-facing tools are run_subagent(task: str, agent_name: str | None = None) and continue_subagent(subagent_id: str, message: str).
When configured, a delegation tool is automatically added to the agent, so you do not need to include "delegate" in the tools list.
The delegated agent starts its own session with no inherited caller history while retaining its configured workspace, memory, requester scope, model, and tool policy.
The caller waits for the child to execute the task, then receives its answer, stable subagent ID, and an audit reference as the tool result.
Use continue_subagent with that ID for a follow-up in the same child session after its previous turn returns.
The ID stays scoped to the original caller, requester, and conversation across parent turns and restarts.
Follow-ups recheck current permissions, preserve nesting depth, and create separate audit records.
The task must include relevant context, constraints, and expected output, because the child does not inherit the conversation.
Listing the caller itself allows a fresh copy with the same configured capabilities.
Omitting agent_name or passing None selects the caller itself; the same delegate_to allowlist still applies.
For an ongoing Matrix conversation, use matrix_message.
Each child writes redacted execution records under .mindroom/delegations/YYYY-MM-DD/<delegation-id>/ in its resolved workspace, and the caller receives .mindroom/delegation_receipts/YYYY-MM-DD/<delegation-id>.json in its resolved workspace.
Approval-gated child calls use the native Matrix approval flow in the source room and thread while the parent-child continuation remains durable.
agents:
leader:
display_name: Leader
role: Orchestrate tasks by delegating to specialist agents
model: sonnet
delegate_to: [leader, code, research]
rooms: [lobby]
code:
display_name: CodeAgent
role: Generate code, manage files
model: sonnet
tools: [file, shell]
delegate_to: [research] # can further delegate
rooms: [lobby]
research:
display_name: ResearchAgent
role: Research topics and provide summaries
model: sonnet
tools: [duckduckgo]
rooms: [lobby]
Constraints:
- Targets must reference existing agent names in the config
- An agent may delegate to itself only when its own name appears in
delegate_to - Recursive delegation is supported (agent A delegates to B, B delegates to C) up to a maximum depth of 3
- Native Matrix delegation runs one child at a time per parent; direct tool calls can run children in parallel
Naming Rules
Agent and team YAML keys must contain only alphanumeric characters and underscores (matching ^[a-zA-Z0-9_]+$).
Agent and team names must be distinct — the same key cannot appear in both agents: and teams:.
Defaults
The defaults section sets fallback values for supported per-agent override fields and global-only agent behavior.
Supported override fields inherit when omitted, defaults.tools is merged only when include_default_tools is true, and global-only defaults apply to every agent.
defaults:
tools: # Tools added to every agent by default (set [] to disable)
- scheduler
# Per-agent tool config overrides also work in defaults:
# - shell:
# enable_run_shell_command: true
markdown: true # Format responses as Markdown
learning: true # Enable Agno Learning
learning_mode: always # "always" or "agentic"
max_preload_chars: 50000 # Hard cap for preloaded context from context_files
tool_output_auto_save_threshold_bytes: 51200 # Auto-save supported tool outputs larger than 50 KiB
show_stop_button: true # Show a stop button while agent is responding (global-only, cannot be overridden per-agent)
num_history_runs: null # Number of prior runs to include (null = all)
num_history_messages: null # Max messages from history (null = use num_history_runs)
enable_streaming: true # Stream agent responses via progressive message edits
streaming:
update_interval: 5.0 # Steady-state seconds between streamed edits
min_update_interval: 0.5 # Fast-start seconds between early edits
interval_ramp_seconds: 15.0 # Set 0 to disable interval ramping
max_idle: 2.0 # Event-driven idle ceiling before the next edit
compress_tool_results: false # Safer default; enabling can invalidate Anthropic/Vertex Claude prompt caches
compaction:
enabled: true
threshold_percent: 0.8
reserve_tokens: 16384
timeout_seconds: 600
max_tool_calls_from_history: null # Limit tool call messages replayed from history (null = no limit)
show_tool_calls: true # Show tool-call markers and trace metadata; hidden mode still allows generic worker warmup copy
worker_tools: null # Tool names to route through workers (null = use MindRoom's default routing policy, [] = disable)
worker_scope: null # Worker runtime reuse for proxied tools (shared, user, user_agent)
allow_self_config: false # Allow agents to read/modify their own config at runtime
defaults.streaming is global-only and controls the timing of progressive message edits for streaming responses.
To opt out a specific agent: