Skip to content

Agent Orchestration

Use these tools and presets to coordinate other agents, save reusable Dynamic Workflows, change runtime configuration, import OpenClaw-style workspaces, and keep long-lived Claude coding sessions alive across turns.

What This Page Covers

This page documents the built-in tools in the agent-orchestration group. Use these tools when you need multi-agent coordination, reusable workflow runs, runtime config changes, config-only presets, or persistent Claude Agent SDK sessions.

Tools On This Page

  • [subagents] - Spawn Matrix-backed sub-agent sessions and message them later by session key or label.
  • [delegate] - Run another configured agent as a one-shot specialist and return its answer inline.
  • [dynamic_workflow] - Create, update, run, and inspect saved Dynamic Workflows with persisted report artifacts.
  • [report_publishing] - Publish authorized report artifacts through revocable public links.
  • [config_manager] - Inspect MindRoom config and create, update, validate, or template agents and teams.
  • [self_config] - Let an agent read and update only its own configuration.
  • [openclaw_compat] - Config-only preset that expands to native MindRoom tools.
  • [claude_agent] - Persistent Claude Agent SDK sessions with optional gateway support and per-session labels.

Common Setup Notes

All eight entries on this page are MindRoom-native orchestration features rather than third-party OAuth integrations. Only [claude_agent] has tool-specific credential fields. [delegate] and [self_config] can be added automatically based on agent config, so they are not limited to explicit tools: entries. agents.<name>.delegate_to auto-enables [delegate] when the list is non-empty and the current delegation depth is below the hard limit of 3. agents.<name>.allow_self_config or defaults.allow_self_config auto-enables [self_config]. [config_manager] and [self_config] both save changes by revalidating the full runtime config before rewriting config.yaml. [subagents] requires a live Matrix tool runtime context with room_id, requester_id, Matrix client access, and a writable storage path. [dynamic_workflow] requires a live tool runtime context, a writable storage path, and a configured agent model. [report_publishing] requires a live tool runtime context, a writable storage path, and an authorized report source. [openclaw_compat] is a config preset, not a runtime toolkit. Config.expand_tool_names() expands presets and implied tools while deduping and preserving order. For [openclaw_compat], that means matrix_message is added directly and attachments is added indirectly through Config.IMPLIED_TOOLS.

[subagents]

subagents creates and tracks Matrix-backed sub-agent sessions that can continue across multiple tool calls.

What It Does

subagents exposes agents_list(), sessions_spawn(), sessions_send(), and list_sessions(). All four calls return JSON strings with a status field, a tool field, and operation-specific payload data. agents_list() returns the current agent name plus agents, a sorted array of row objects with name, can_delegate, can_spawn, and description. name is the value to pass as agent_id when the relevant capability flag allows that operation. can_spawn means the agent is eligible in the current room, and can_delegate means the agent is listed in the caller's delegate_to allowlist. sessions_spawn(task, summary, tag, label=None, agent_id=None) requires a non-empty task plus a normalized summary and tag. sessions_spawn() posts a fresh room-level Matrix message that mentions the target agent, then treats the resulting event ID as the root of a new isolated session thread. After the spawn succeeds, it writes the requested thread summary and tag through the lower-level thread summary and thread tag APIs. If you pass a label and the current (agent_name, room_id, requester_id) scope already has a matching tracked session, sessions_spawn() reuses that session instead of creating a new one and still applies the requested summary and tag to the existing thread. If the post-spawn summary or tag write fails, the spawn still succeeds and the response includes a warnings list describing the follow-up failure. sessions_send() sends a follow-up message into an existing tracked session. If you omit session_key, sessions_send() defaults to the current room or thread session key from create_session_id(room_id, thread_id). If you pass label without session_key, sessions_send() resolves the most recent in-scope session with that label. If you pass agent_id, sessions_send() prefixes the outgoing message with that agent's current full Matrix ID before sending it. Tracked sessions are persisted in subagents/session_registry.json under the current runtime storage root. list_sessions() paginates those tracked sessions with a default limit of 50 and a maximum of 200. Isolated spawned sessions require thread-capable agents. If the target agent uses thread_mode=room, sessions_spawn() fails and threaded sessions_send() calls to that session also fail.

Configuration

This tool has no tool-specific inline configuration fields.

Example

agents:
  coordinator:
    display_name: Coordinator
    role: Break work into long-running threaded sub-sessions
    model: sonnet
    tools:
      - subagents
agents_list()
sessions_spawn(
    task="Review the failing deployment and propose a rollback plan.",
    summary="Investigate the failing deployment and propose a safe rollback plan.",
    tag="incident-rollback",
    label="incident-42",
    agent_id="ops",
)
sessions_send(
    message="Add a short list of commands we should run first.",
    label="incident-42",
)
list_sessions(limit=20)

Notes

  • Session tracking is scoped to the current agent_name, room_id, and requester_id, so labels are not global across unrelated conversations.
  • sessions_spawn() returns normalized summary and tag values in the success payload and may include warnings if the follow-up summary or tag write fails after the session is created.
  • Use [subagents] when you want a continuing Matrix thread that other agents or humans can revisit later.
  • Use [delegate] instead when you want a one-shot specialist answer returned directly as the tool result.

[delegate]

delegate runs another configured agent as a fresh one-shot specialist and returns that agent's response inline.

What It Does

delegate exposes one tool call, delegate_task(agent_name, task). The delegated agent is created with create_agent() and runs independently with no shared session or chat history from the caller. The caller waits for the delegated agent to finish, and the delegated agent's response.content becomes the tool result. MindRoom gives the delegated agent any already-published last-good knowledge indexes and schedules missing or stale refresh work in the background. Interactive questions are disabled for delegated runs. Unlike [subagents], [delegate] does not create a Matrix thread, does not write to the room timeline, and does not keep a reusable session handle. If agent_name is not in the caller's allowed delegate_to list, the tool returns an error string. Empty tasks are rejected.

Configuration

This tool has no tool-specific inline configuration fields. Enable it by setting delegate_to on the agent config. MindRoom adds the tool automatically when delegate_to is non-empty, so listing delegate in tools: is usually unnecessary.

Example

agents:
  lead:
    display_name: Lead
    role: Coordinate specialist agents
    model: sonnet
    delegate_to:
      - code
      - research

  code:
    display_name: Code
    role: Implement and debug code changes
    model: sonnet
    tools:
      - coding
      - shell

  research:
    display_name: Research
    role: Gather sources and summarize findings
    model: sonnet
    tools:
      - duckduckgo
delegate_task(
    agent_name="research",
    task="Summarize the three main risks in this proposal and cite supporting facts.",
)

Notes

  • Config.validate_delegate_to() rejects self-delegation and unknown target agents at config-load time.
  • Recursive delegation is supported, but only up to a maximum depth of 3.
  • Use [subagents] when you need an ongoing threaded workflow.
  • Use [delegate] when you need a synchronous specialist answer inside the current run.

[dynamic_workflow]

dynamic_workflow lets an agent save a reusable workflow, publish immutable revisions, run the active revision, and inspect stored run records.

What It Does

dynamic_workflow exposes create_workflow(), validate_workflow(), update_workflow(), run_workflow(), get_workflow_run(), list_workflows(), and list_workflow_revisions(). All calls return JSON strings with a status field and operation-specific payload data. Saved specs live under MINDROOM_STORAGE_PATH/dynamic_workflows/. Each update creates a new immutable revisions/<revision>.yaml file and updates the small workflow.yaml pointer file. Each run pins the active revision at start time, writes a runs/<run_id>.json record, and writes report.md, report.html, and step_outputs.json under that run's artifact directory. If MINDROOM_PUBLIC_URL is set, successful and failed run payloads include a private report URL under /reports/private/.... Private report routes authorize the dashboard requester against the run's requested_by identity. Use [report_publishing] to publish a completed Dynamic Workflow run report through a revocable public URL under /reports/public/<slug>. If MINDROOM_PUBLIC_URL is unset, the report artifacts are still persisted on disk and listed in the run payload.

Configuration

Enable the tool by adding dynamic_workflow to the agent that should be allowed to create and run workflows. The current implementation supports agent-scoped workflows from agent tools. Room and tenant scopes are reserved for a future approval policy, so tool calls with scope="room" or scope="tenant" return an error today.

agents:
  coordinator:
    display_name: Coordinator
    role: Build and run reusable Dynamic Workflows
    model: sonnet
    tools:
      - dynamic_workflow

Spec Shape

Workflow specs are declarative JSON/YAML objects with schema_version: 1. The top-level fields are id, name, description, kind, inputs, participants, workflow, outputs, and permissions. kind must be workflow. inputs supports an object schema with required, properties, property type, property description, and property enum. Participants can be ephemeral_agent or room_agent. An ephemeral_agent can declare id, name, role, description, model, tools, and instructions. Ephemeral participant tools may grant any registered tool except agent-infrastructure tools (memory, delegate, self_config, compact_context, dynamic_workflow, dynamic_tools). Every participant tool must also be listed in permissions.tools. Participant tool calls require per-call user approval in the originating room unless the tool is pre-approved by the caller's dynamic_workflow allowed_tools config. Setting allowed_tools to ["*"] pre-approves every granted tool. A room_agent can declare id, agent, and an empty tools list. Room-agent participants must already be available to the requester in the current room, use their configured model, and run without tools, skills, knowledge, durable state, or preloaded context files. Step types are transform_step, agent_step, and report_step. transform_step renders a template without calling a model. agent_step renders a prompt and sends it to the selected participant. report_step renders Markdown report content from input and prior step outputs. Outputs declare id, type, and from_step. Output type may be text, markdown, json, or html_report. Permissions support runtime caps, model caps, and tool grants. permissions.data must keep matrix_history, attachments, and knowledge_bases disabled until approval-backed data grants exist.

Example

create_workflow(
    spec={
        "schema_version": 1,
        "id": "brief-report",
        "name": "Brief Report",
        "description": "Create a short HTML report from one topic.",
        "kind": "workflow",
        "inputs": {
            "type": "object",
            "required": ["topic"],
            "properties": {"topic": {"type": "string"}},
        },
        "participants": [
            {
                "id": "writer",
                "kind": "ephemeral_agent",
                "name": "Report Writer",
                "model": "claude-sonnet-5",
                "tools": ["duckduckgo", "website"],
            },
        ],
        "workflow": [
            {
                "id": "write",
                "type": "agent_step",
                "participant": "writer",
                "prompt": "Research the web and write a concise cited report about {input.topic}.",
            },
        ],
        "outputs": [{"id": "report_html", "type": "html_report", "from_step": "write"}],
        "permissions": {
            "max_runtime_seconds": 1800,
            "max_concurrent_agents": 4,
            "max_total_agents": 8,
            "models": ["claude-sonnet-5"],
            "tools": ["duckduckgo", "website"],
            "data": {"matrix_history": "none", "attachments": "none", "knowledge_bases": []},
        },
    },
    reason="initial report workflow",
)
run_workflow("brief-report", {"topic": "Agno factories"})
list_workflows()
get_workflow_run("brief-report", "run_...")

Pre-approving participant tools

Configure allowed_tools on the calling agent's dynamic_workflow tool entry to skip per-call approval for trusted tools.

agents:
  builder:
    display_name: Workflow Builder
    tools:
      - dynamic_workflow:
          allowed_tools: [duckduckgo, website]

Use allowed_tools: ["*"] to pre-approve every tool a workflow grants. Tools outside allowed_tools still run, but each call posts an approval card in the originating room and waits for the requester's decision.

Notes

  • Dynamic Workflow runs execute synchronously on the current tool call path today.
  • Long-running background workflow management, workflow-activation approval cards, Matrix history grants, attachment grants, and knowledge-base grants are future work.
  • Ephemeral agents can only use models allowed by both the workflow permissions and the caller's current model policy.
  • Granted tools run with the calling agent's tool routing (credentials, worker sandboxing, and egress proxying), and the tool-hook bridge applies plugin gating plus the per-call approval flow.
  • Room-agent participants can reuse only agents that normal room routing would expose to the requester.
  • Runtime caps are enforced for sync and async runs, and async runs are marked failed at the deadline even if participant cancellation is delayed.

[report_publishing]

report_publishing lets an agent intentionally publish authorized report artifacts through revocable public links.

What It Does

report_publishing exposes publish_report() and revoke_public_report(slug). All calls return JSON strings with a status field and operation-specific payload data. The tool does not accept arbitrary filesystem paths. It publishes only registered source references that the current Matrix requester is authorized to read. The current source types are dynamic_workflow_run and static_site. Use dynamic_workflow_run to publish a completed Dynamic Workflow HTML report. Use static_site to publish a copied workspace directory that contains index.html and optional CSS, JavaScript, images, fonts, or JSON assets. A static_site source path may also point at one workspace HTML file, which is copied and served as index.html. The static site source path is workspace-relative and the published copy is stored under MINDROOM_STORAGE_PATH/report_publishing/artifacts/<slug>/. A static site snapshot may contain at most 200 files and 10 MiB of total data, and publishing fails with an explanatory error beyond either limit. Static site links serve under the trailing-slash form /reports/public/<slug>/, and the slash-less form redirects there so relative asset URLs resolve. JavaScript is allowed for static sites, but the public route serves static sites with a sandbox CSP that omits allow-same-origin and sets connect-src 'none'. That means scripts can drive local page interactivity, but they cannot act as logged-in MindRoom dashboard code or call MindRoom APIs. Published link records live under MINDROOM_STORAGE_PATH/report_publishing/. Public report links serve the registered artifact without dashboard authentication until revoke_public_report(slug) revokes the slug. The slug is the public-report identifier returned by publish_report(). If MINDROOM_PUBLIC_URL is set, successful publish payloads include the absolute public URL.

Configuration

Enable the tool by adding report_publishing to any agent that should be allowed to publish report artifacts.

agents:
  coordinator:
    display_name: Coordinator
    role: Build workflows and publish report links
    model: sonnet
    tools:
      - dynamic_workflow
      - report_publishing

Example

publish_report(
    source_type="dynamic_workflow_run",
    source={"workflow_id": "brief-report", "run_id": "run_..."},
    confirm_public=True,
)
publish_report(
    source_type="static_site",
    source={"path": "public-demo", "title": "Public Demo"},
    confirm_public=True,
)
revoke_public_report("pub_...")

Notes

  • confirm_public=True is required so accidental publish calls fail closed.
  • Dynamic Workflow source references default to scope="agent" and may include an explicit scope.
  • Static site publishing requires an agent workspace and publishes an immutable copy, so later workspace edits need a new publish_report() call.
  • An agent has a workspace when it uses memory_backend: file or a private: workspace configuration, and the source path resolves against that canonical workspace root.
  • Only the run requester or the user who published the link may revoke it.
  • Additional registered report sources can be added without changing Dynamic Workflow storage.
  • No extra proxy route is needed when /reports/public/* already reaches the MindRoom backend.
  • If the dashboard frontend and Python backend are split across upstreams, route /reports/public/* to the Python backend and do not put dashboard-login middleware on that path.
  • Set MINDROOM_PUBLIC_URL to the externally reachable dashboard origin, such as https://mindroom.lab.mindroom.chat, so publish payloads include clickable absolute URLs.

[config_manager]

config_manager is the broad config-authoring toolkit for inspecting MindRoom and creating or updating agents and teams.

What It Does

config_manager exposes get_info(), manage_agent(), and manage_team(). get_info(info_type, name=None) supports mindroom_docs, config_schema, available_models, agents, teams, available_tools, tool_details, agent_config, and agent_template. tool_details requires name and reads from live TOOL_METADATA, so it includes real config fields and statuses from the current worktree. agent_config returns the authored YAML for a specific agent. agent_template generates starter YAML for one of the built-in template types: researcher, developer, social, communicator, analyst, or productivity. manage_agent() supports create, update, and validate. Agent creates and updates validate tool names against the live registry and validate knowledge base IDs against the current config. When a plain string tool list replaces an existing tool list, config_manager preserves inline overrides for retained tools instead of flattening them away. On create, include_default_tools falls back to true when you omit it. manage_team() creates a new team with coordinate or collaborate mode and rejects unknown member agents or duplicate team names. All writes go through full runtime config validation before config.yaml is saved.

Configuration

This tool has no tool-specific inline configuration fields.

Example

agents:
  builder:
    display_name: Builder
    role: Create and maintain MindRoom agents and teams
    model: sonnet
    tools:
      - config_manager
get_info("available_tools")
get_info("tool_details", name="claude_agent")
manage_agent(
    operation="create",
    agent_name="triage",
    display_name="Triage",
    role="Sort incoming requests and hand them to the right specialist.",
    tools=["duckduckgo", "subagents"],
    model="default",
    rooms=["lobby"],
)
manage_team(
    team_name="incident_team",
    display_name="Incident Team",
    role="Coordinate incident response across ops and code agents.",
    agents=["ops", "code"],
    mode="coordinate",
)

Notes

  • [config_manager] is broader and more privileged than [self_config] because it can inspect and modify other agents and teams.
  • manage_team() creates teams, but it does not expose a separate update operation on this branch.
  • Use Agent Configuration for the full authored schema outside the tool's curated helper surface.

[self_config]

self_config lets an agent inspect and update only its own config entry.

What It Does

self_config exposes get_own_config() and update_own_config(). get_own_config() returns the current agent's authored YAML block. update_own_config() only changes fields that you pass explicitly. On this branch, update_own_config() can modify display_name, role, instructions, tools, model, rooms, markdown, learning, learning_mode, knowledge_bases, skills, include_default_tools, show_tool_calls, thread_mode, num_history_runs, num_history_messages, compress_tool_results, max_tool_calls_from_history, and context_files. The update path validates tool names against the live registry and validates knowledge base IDs against the current config. It also preserves inline tool overrides for retained tools when a string-only tool list is provided. Updates are validated through AgentConfig.model_validate() before the file is saved. Only the current agent can be changed. There is no path to modify other agents or teams through this tool.

Configuration

This tool has no tool-specific inline configuration fields. The normal way to enable it is agents.<name>.allow_self_config: true or defaults.allow_self_config: true.

Example

defaults:
  allow_self_config: false

agents:
  research:
    display_name: Research
    role: Research and summarize external sources
    model: sonnet
    allow_self_config: true
    tools:
      - duckduckgo
      - wikipedia
get_own_config()
update_own_config(
    instructions=[
        "Cite sources for factual claims.",
        "Prefer concise summaries with clear takeaways.",
    ],
    tools=["duckduckgo", "wikipedia", "subagents"],
    thread_mode="room",
    context_files=["SOUL.md", "USER.md"],
)

Notes

  • self_config blocks privileged self-escalation by rejecting config_manager in its tools update list.
  • include_default_tools=True is also rejected when defaults.tools contains blocked privileged tools such as config_manager.
  • Use [self_config] for narrow self-tuning at runtime and [config_manager] for full config-authoring workflows.

[openclaw_compat]

openclaw_compat is a config-only preset for OpenClaw-style workspace portability.

What It Does

openclaw_compat is not a runtime toolkit. The registered factory returns an empty Toolkit, and the real behavior comes from Config.TOOL_PRESETS. Config.expand_tool_names() expands openclaw_compat into shell, coding, duckduckgo, website, browser, scheduler, subagents, and matrix_message. matrix_message then implies attachments, so the effective enabled set also includes attachments even though the preset does not list it directly. Preset expansion dedupes while preserving order, so adding openclaw_compat alongside one of its member tools does not create duplicates. This preset is meant for OpenClaw-compatible workspace behavior inside MindRoom rather than for cloning the full OpenClaw gateway control plane.

Configuration

This preset has no inline configuration fields and cannot use defer or initial. Configure individual member tools directly when they need lazy loading.

Example

agents:
  openclaw:
    display_name: OpenClawAgent
    role: OpenClaw-style personal assistant with a file-first workspace
    model: opus
    include_default_tools: false
    learning: false
    memory_backend: file
    context_files:
      - SOUL.md
      - AGENTS.md
      - USER.md
      - IDENTITY.md
      - TOOLS.md
      - HEARTBEAT.md
    tools:
      - openclaw_compat
      - python

Notes

  • [openclaw_compat] is a preset name that belongs in tools: but does not expose callable runtime methods of its own.
  • Use the dedicated OpenClaw Workspace Import guide for workspace layout, file memory behavior, and migration details.
  • If you only need one or two of the member tools, configure those tools directly instead of using the preset.

[claude_agent]

claude_agent keeps persistent Claude Agent SDK coding sessions alive across turns and exposes explicit session lifecycle controls.

What It Does

claude_agent exposes claude_start_session(), claude_send(), claude_session_status(), claude_interrupt(), and claude_end_session(). claude_send() automatically creates the session if it does not already exist, so claude_start_session() is optional. Session keys are namespaced by agent identity and Agno run session ID, with optional session_label suffixes for parallel sub-sessions. The same session key is serialized by an asyncio.Lock, so concurrent calls to one label run one after the other. Different session_label values create distinct Claude sessions that can proceed independently. Idle sessions expire after session_ttl_minutes, which defaults to 60 minutes. The process-wide session manager keeps at most max_sessions active sessions per agent namespace, defaulting to 200. resume and fork_session only apply when creating a new session. fork_session=True requires a non-empty resume session ID. If a session already exists for the computed key, passing resume or fork_session returns an error instead of silently changing the live session. claude_session_status() reports age, idle time, and the underlying Claude session ID once Claude has returned a result. On SDK failures, the tool includes recent Claude CLI stderr lines in its error output to help debug gateway or CLI issues.

Configuration

Option Type Required Default Notes
api_key password no null Anthropic API key or gateway-compatible key material. Usually stored in credentials JSON or dashboard setup instead of inline YAML.
anthropic_base_url url no null Optional Anthropic-compatible gateway root URL. Use the host root, not a /v1 suffix.
anthropic_auth_token password no null Optional bearer token for Anthropic-compatible gateways.
disable_experimental_betas boolean no false Sets CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1 for gateway compatibility.
cwd text no null Working directory passed to the Claude Agent SDK client.
model text no null Claude model override. When omitted, the tool falls back to the current agent model ID when one is available.
permission_mode text no default One of default, acceptEdits, plan, or bypassPermissions. Invalid values fall back to default.
continue_conversation boolean no false Continue the same Claude conversation context across queries in one session.
allowed_tools text no null Comma-separated Claude Code tool names to allow.
disallowed_tools text no null Comma-separated Claude Code tool names to deny.
max_turns number no null Maximum Claude turns per query. Values below 1 are normalized up to 1.
system_prompt text no null Extra system prompt passed directly to the Claude Agent SDK.
cli_path text no null Optional path to the Claude CLI executable.
session_ttl_minutes number no 60 Idle-session expiration window in minutes. Values below 1 are normalized up to 1.
max_sessions number no 200 Maximum live sessions per agent namespace. Values below 1 are normalized up to 1.

Example

agents:
  code:
    display_name: Code Agent
    role: Coding assistant with persistent Claude sessions
    model: default
    tools:
      - claude_agent:
          model: claude-sonnet-5
          cwd: /workspace/project
          permission_mode: acceptEdits
          continue_conversation: true
          session_ttl_minutes: 180
          max_sessions: 20
{
  "api_key": "sk-ant-or-proxy-key",
  "model": "claude-sonnet-5",
  "permission_mode": "default",
  "continue_conversation": true,
  "session_ttl_minutes": 60,
  "max_sessions": 200
}
{
  "api_key": "sk-dummy",
  "anthropic_base_url": "http://litellm.local",
  "anthropic_auth_token": "sk-dummy",
  "disable_experimental_betas": true
}
claude_send(
    prompt="Refactor the failing test and explain the diff.",
    session_label="bugfix",
)
claude_session_status(session_label="bugfix")
claude_interrupt(session_label="bugfix")
claude_end_session(session_label="bugfix")

Notes

  • Dashboard setup and mindroom_data/credentials/claude_agent_credentials.json both feed the same tool credential fields, because runtime credentials are stored as <service>_credentials.json.
  • For Anthropic-compatible gateways, set anthropic_base_url to the gateway root without /v1, because the Claude client appends its own API path.
  • Some gateways reject Claude beta headers, so disable_experimental_betas: true is the compatibility switch for that case.
  • When you use MindRoom's OpenAI-compatible API, keep the same X-Session-Id across requests so the same Claude session key is reused.
  • See OpenAI-Compatible API for request-level session continuity details.