#Agents handing off work to each other

1 messages Ā· Page 1 of 1 (latest)

glass field
#

Hey Krill,

What is the easiest way for an orchestrator agent to hand a task to one or more agents at the same time and then confirm receipt and get the results back?

Something that is not file based and hope the agents read
a file during its heartbeat

inner dewBOT
sweet hornetBOT
#

To help others find answers, you can mark your question as solved via Right click solution message -> Apps -> āœ… Mark Solution

inner dewBOT
glass field
#

Hello?

exotic wraithBOT
#

Yep, use the session tools, not files.

Best pattern

  • New parallel workers: sessions_spawn
    • Returns immediately with status: "accepted" + runId + childSessionKey
    • That is your receipt/ack
    • When the child finishes, OpenClaw does a push-based announce back up the chain
  • Already-running agent/session: sessions_send
    • timeoutSeconds: 0 = enqueue and return immediately
    • timeoutSeconds: >0 = wait for the reply inline

So for fan-out / fan-in:

  1. Orchestrator calls sessions_spawn once per worker
  2. Each call gives immediate acceptance
  3. Workers finish and announce results back
  4. Orchestrator synthesizes and returns final output
#

A couple important knobs:

  • If a sub-agent needs to spawn its own workers, set
    agents.defaults.subagents.maxSpawnDepth: 2
  • If you want to target other agent profiles, allow them with
    agents.defaults.subagents.allowAgents

I would not use heartbeat + file polling for this. OpenClaw already has first-class async handoff for exactly this case.

Docs:

If you want, I can sketch the exact orchestrator flow for:

  1. spawn N workers and wait for announces, or
  2. send tasks into existing persistent sessions.
glass field
#

1 please

exotic wraithBOT
#

Cool, for spawn N workers and wait for announces, the clean pattern is:

1. Enable the orchestrator pattern

{
  agents: {
    defaults: {
      subagents: {
        maxSpawnDepth: 2,
        maxChildrenPerAgent: 5
      }
    }
  }
}

Why: with maxSpawnDepth: 2, a depth-1 sub-agent can act as an orchestrator and spawn worker children.

#

2. Orchestrator flow

Inside the orchestrator session:

  • call sessions_spawn(...) once per worker
  • store each returned runId / childSessionKey
  • each spawn returns immediate ack:
    • status: "accepted"
    • runId
    • childSessionKey

That is your receipt confirmation.

3. Wait the OpenClaw way

After spawning, use sessions_yield.

That ends the turn and lets the child completion announces arrive as the next messages, instead of building a polling loop.

#

4. Fan-in

As worker results arrive:

  • collect them
  • once all expected workers have announced back
  • synthesize the final result
  • reply once

Minimal pseudo-flow

spawn worker A -> accepted
spawn worker B -> accepted
spawn worker C -> accepted

sessions_yield()

announce from A arrives
#
announce from B arrives
announce from C arrives

combine results
return final answer

Important bit

Do not do:

  • file drop + heartbeat polling
  • tight loops over sessions_list / subagents list

OpenClaw’s built-in announce chain is the intended async return path.

Docs

glass field
#

Is this for 1 main agent and 2 or 3 sub-agents that spawn and disappear? I have 10 agents right now, 1 main/coordinator and 9 that I want to be specialists and are persistent, available on Discord. Please Is this even possible out of the box with Openclaw?

exotic wraithBOT
#

Yes, what I described first is mainly the ephemeral worker pattern:

  • sessions_spawn + mode: "run" = spawn, do the task, announce result, disappear
  • sessions_spawn + thread: true, mode: "session" = persistent thread-bound session
  • sessions_send = talk to an already-existing persistent session/agent

For your setup, with 1 coordinator + 9 persistent specialists, the better fit is usually:

Recommended pattern for your case

  • keep the 9 specialists as persistent sessions
  • have the coordinator hand work to them with sessions_send
  • let them reply back through the same session tool path

So yes, this is possible in OpenClaw, but not with the defaults alone. You need to turn on the cross-agent/session plumbing.

The important config bits

  1. Enable agent-to-agent
#
{
  tools: {
    agentToAgent: {
      enabled: true,
      allow: ["coordinator", "research", "planner", "coder", "qa"]
    }
  }
}
  1. Let session tools see beyond spawned children
{
  tools: {
    sessions: {
#
      visibility: "all"
    }
  }
}
  1. Allow the session tools on the agents that need them
  • sessions_list
  • sessions_history
  • sessions_send
  • optionally sessions_spawn if you also want ephemeral workers

My honest take

If you want specialists that are always around on Discord, use persistent sessions + sessions_send.

If you want temporary parallel workers, use sessions_spawn.

#

A lot of people end up with a hybrid:

  • persistent specialists for known roles
  • spawned workers for bursty parallel work

One caveat

Cross-agent messaging is off by default, so this is not ā€œzero configā€, but it is supported out of the box once you enable those knobs.

Short answer

  • Spawn and disappear? Yes, that’s the normal sessions_spawn pattern.
  • 10 persistent specialists on Discord? Also yes, but use persistent sessions + sessions_send, not heartbeat files.

Docs:

#

If you want, I can give you a minimal config sketch for 1 coordinator + 9 specialists on Discord next.

glass field
#

yes, please!

exotic wraithBOT
#

Nice. If I were setting up 1 coordinator + 9 persistent Discord specialists, I’d do one main Discord-facing coordinator, then create persistent thread-bound specialist sessions and route coordinator handoffs with sessions_send.

That avoids file polling, and you do not need 10 bot tokens unless you want 10 separate bot identities.

Minimal config sketch

{
  agents: {
    defaults: {
      subagents: {
        runTimeoutSeconds: 900,
      },
    },
    list: [
      {
#
        id: "coordinator",
        workspace: "~/.openclaw/workspace-coordinator",
        tools: {
          allow: [
            "read",
            "exec",
            "sessions_list",
            "sessions_history",
            "sessions_send",
            "sessions_spawn",
            "session_status",
          ],
        },
        subagents: {
          allowAgents: [
#
            "research",
            "planner",
            "coder",
            "qa",
            "docs",
            "ops",
            "support",
            "analyst",
            "reviewer",
          ],
          requireAgentId: true,
        },
      },

      { id: "research", workspace: "~/.openclaw/workspace-research" },
#
      { id: "planner",  workspace: "~/.openclaw/workspace-planner"  },
      { id: "coder",    workspace: "~/.openclaw/workspace-coder"    },
      { id: "qa",       workspace: "~/.openclaw/workspace-qa"       },
      { id: "docs",     workspace: "~/.openclaw/workspace-docs"     },
      { id: "ops",      workspace: "~/.openclaw/workspace-ops"      },
      { id: "support",  workspace: "~/.openclaw/workspace-support"  },
      { id: "analyst",  workspace: "~/.openclaw/workspace-analyst"  },
      { id: "reviewer", workspace: "~/.openclaw/workspace-reviewer" },
    ],
  },

  bindings: [
    { agentId: "coordinator", match: { channel: "discord", accountId: "default" } },
  ],
#
  tools: {
    agentToAgent: {
      enabled: true,
      allow: [
        "coordinator",
        "research",
        "planner",
        "coder",
        "qa",
        "docs",
        "ops",
        "support",
        "analyst",
        "reviewer",
      ],
#
    },

    sessions: {
      visibility: "all",
    },
  },

  channels: {
    discord: {
      threadBindings: {
        enabled: true,
        spawnSubagentSessions: true,
        idleHours: 24,
        maxAgeHours: 0,
      },
#
    },
  },
}

How I’d use it

One-time bootstrap

From the coordinator, spawn each specialist once as a persistent Discord thread session:

  • sessions_spawn({ agentId: "research", thread: true, mode: "session", task: "You are the research specialist..." })
  • repeat for planner, coder, QA, etc.

That gives you persistent specialist threads on Discord.

Normal operation

#

Coordinator fans out with sessions_send:

  • sessions_send(sessionKey: "...research...", message: "...", timeoutSeconds: 0)
  • sessions_send(sessionKey: "...qa...", message: "...", timeoutSeconds: 0)
  • etc.

Then either:

  • wait for replies inline with timeouts, or
  • do async collection / synthesis

Recommendation

For your exact setup, I’d recommend:

  • persistent thread-bound specialist sessions
  • sessions_send for handoff
  • sessions_spawn only for initial creation or for temporary burst workers
#

Important caveat

If by ā€œavailable on Discordā€ you mean each specialist should appear as a separate Discord bot/account, that is a different setup. Then use multiple Discord accountIds + bindings. If you just want separate persistent specialists humans can visit and the coordinator can talk to, threads are the simpler path.

Docs:

If you want, I can do the next step and turn this into a real config for your 10 agent names.

glass field
#

Yes, please Odin (coordinator), Frigg, Bragi, Mimir, Thor, Loki, Freya, Heimdall, Skadi and Bob. Same pattern as your sketch, with actual names and workspaces.

exotic wraithBOT
#

Yep, here’s a concrete starting point for your crew.

{
  agents: {
    defaults: {
      subagents: {
        runTimeoutSeconds: 900,
      },
    },

    list: [
      {
        id: "odin",
        name: "Odin",
        workspace: "~/.openclaw/workspace-odin",
#
        tools: {
          allow: [
            "read",
            "exec",
            "sessions_list",
            "sessions_history",
            "sessions_send",
            "sessions_spawn",
            "session_status",
          ],
        },
        subagents: {
          allowAgents: [
            "frigg",
            "bragi",
#
            "mimir",
            "thor",
            "loki",
            "freya",
            "heimdall",
            "skadi",
            "bob",
          ],
          requireAgentId: true,
        },
      },

      { id: "frigg",    name: "Frigg",    workspace: "~/.openclaw/workspace-frigg" },
      { id: "bragi",    name: "Bragi",    workspace: "~/.openclaw/workspace-bragi" },
      { id: "mimir",    name: "Mimir",    workspace: "~/.openclaw/workspace-mimir" },
#
      { id: "thor",     name: "Thor",     workspace: "~/.openclaw/workspace-thor" },
      { id: "loki",     name: "Loki",     workspace: "~/.openclaw/workspace-loki" },
      { id: "freya",    name: "Freya",    workspace: "~/.openclaw/workspace-freya" },
      { id: "heimdall", name: "Heimdall", workspace: "~/.openclaw/workspace-heimdall" },
      { id: "skadi",    name: "Skadi",    workspace: "~/.openclaw/workspace-skadi" },
      { id: "bob",      name: "Bob",      workspace: "~/.openclaw/workspace-bob" },
    ],
  },

  bindings: [
    { agentId: "odin", match: { channel: "discord", accountId: "default" } },
  ],

  tools: {
    agentToAgent: {
#
      enabled: true,
      allow: [
        "odin",
        "frigg",
        "bragi",
        "mimir",
        "thor",
        "loki",
        "freya",
        "heimdall",
        "skadi",
        "bob",
      ],
    },
#
    sessions: {
      visibility: "all",
    },
  },

  channels: {
    discord: {
      threadBindings: {
        enabled: true,
        spawnSubagentSessions: true,
        idleHours: 24,
        maxAgeHours: 0,
      },
    },
  },
#
}

One-time bootstrap from Odin

Spawn each specialist once as a persistent thread session:

sessions_spawn({ agentId: "frigg",    thread: true, mode: "session", task: "You are Frigg, a persistent specialist agent..." })
sessions_spawn({ agentId: "bragi",    thread: true, mode: "session", task: "You are Bragi, a persistent specialist agent..." })
sessions_spawn({ agentId: "mimir",    thread: true, mode: "session", task: "You are Mimir, a persistent specialist agent..." })
sessions_spawn({ agentId: "thor",     thread: true, mode: "session", task: "You are Thor, a persistent specialist agent..." })
sessions_spawn({ agentId: "loki",     thread: true, mode: "session", task: "You are Loki, a persistent specialist agent..." })
sessions_spawn({ agentId: "freya",    thread: true, mode: "session", task: "You are Freya, a persistent specialist agent..." })
sessions_spawn({ agentId: "heimdall", thread: true, mode: "session", task: "You are Heimdall, a persistent specialist agent..." })
sessions_spawn({ agentId: "skadi",    thread: true, mode: "session", task: "You are Skadi, a persistent specialist agent..." })
#
sessions_spawn({ agentId: "bob",      thread: true, mode: "session", task: "You are Bob, a persistent specialist agent..." })

Normal fan-out from Odin

After those exist, Odin hands off with sessions_send, for example:

sessions_send(sessionKey: "<frigg-session>", message: "Analyze this requirement", timeoutSeconds: 0)
sessions_send(sessionKey: "<mimir-session>", message: "Gather background context", timeoutSeconds: 0)
sessions_send(sessionKey: "<thor-session>",  message: "Stress test the plan", timeoutSeconds: 0)

Then Odin collects and synthesizes.

If you want, next I can do a role assignment pass too, like:

  • Frigg = planning
#
  • Bragi = writing
  • Mimir = research
  • Thor = execution
  • Loki = adversarial review
  • etc.
glass field
#

This is great! A few questions:

a. When Odin calls sessions_send to a specialist, do humans in Odin's Discord channel see that routing, or is it invisible?
b. After idleHours: 24 timeout, does the session die (needing re-spawn) or just sleep? Does the specialist remember prior conversations across wakes?
c. Two rapid sessions_send to one specialist — serial or parallel by default?
d. Specialist LLM fails — does sessions_send return the error, retry, or die silently?
e. Does agentToAgent.allow permit N-to-N messaging, or only coordinator-to-specialist? Can I restrict to odin-only?
f. If I want each Asgardian to appear as a distinct Discord bot (Odin, Thor, Loki as separate identities, not one bot routing) — what's the config?
g. AGENTS.md reloading: if I update Frigg's AGENTS.md, does her persistent session pick it up on next wake, or do I need a gateway restart? (Had a bootstrap cache issue earlier today.)

exotic wraithBOT
#

Yep, and there are a couple important gotchas here.

a) Is sessions_send visible in Odin’s Discord channel?

Usually no. The handoff itself is internal.

What happens under the hood:

  • sessions_send starts the target run with deliver: false
  • so humans in Odin’s channel do not see ā€œrouting to Thorā€¦ā€ spam

But two caveats:

  1. If Odin later summarizes the result, humans see that
  2. The built-in agent-to-agent announce step can post into the target specialist’s bound channel/thread, so humans watching Thor’s thread may see a specialist-side message there

So, short version: invisible in Odin’s channel, potentially visible in the specialist’s own thread.


#

b) After idleHours: 24, does the specialist die?

No, idle timeout removes the thread binding, it does not inherently kill the session.

Important distinction:

  • thread binding = ā€œthis Discord thread routes to that sessionā€
  • session = transcript + memory/context for that agent session

So after idle timeout:

  • the thread may unfocus
  • the session can still exist
  • if it still exists, it keeps its history and remembers prior conversation

But subagents also have auto-archive. Default is archiveAfterMinutes: 60.

For truly persistent specialists, I would set:

#
{
  agents: {
    defaults: {
      subagents: {
        archiveAfterMinutes: 0
      }
    }
  }
}

That disables auto-archive. Without that, your ā€œpersistentā€ specialists may vanish after an hour.


c) Two rapid sessions_send calls to one specialist, serial or parallel?

#

Serial by default for the same target session.

OpenClaw queues runs by session key, so one session gets one active run at a time.

So:

  • Odin -> Thor twice quickly = queued/serialized
  • Odin -> Thor and Odin -> Mimir = can run in parallel, because different sessions

d) Specialist LLM fails, what does sessions_send do?

It depends on how you called it:

  • timeoutSeconds > 0
    You get a tool result back:
    • status: "ok"
    • status: "error"
#
  • status: "timeout"

So it does not die silently in the waited mode.

  • timeoutSeconds: 0
    You get immediate:
    • status: "accepted"

After that, failure is async. If the later announce flow fails, that is not returned to the original caller turn.

So for critical workflows, I’d use:

  • waited sessions_send when you need confirmation/error now
  • fire-and-forget only when async is okay

Also, normal provider/model retry-failover can still happen underneath if you configured it, but sessions_send itself is not a special retry wrapper.


#

e) Is agentToAgent.allow N-to-N or coordinator-only?

It’s effectively N-to-N among the allowlisted agents. It is not directional.

So if odin, thor, and mimir are all in the allowlist, then:

  • Odin -> Thor works
  • Thor -> Mimir also works
  • Mimir -> Odin works

If you want practical odin-only brokering, the right move is:

  • keep tools.agentToAgent.enabled: true
  • include the specialists in the allowlist
  • only give sessions_send / sessions_spawn to Odin
  • do not allow those tools on the specialists

That gives you coordinator-only behavior in practice.

#

f) Distinct Discord bot identities for each Asgardian?

Yes, but each one needs its own Discord bot token/application.

Pattern is:

{
  agents: {
    list: [
      { id: "odin", workspace: "~/.openclaw/workspace-odin" },
      { id: "thor", workspace: "~/.openclaw/workspace-thor" },
      { id: "loki", workspace: "~/.openclaw/workspace-loki" },
    ],
  },
#

  bindings: [
    { agentId: "odin", match: { channel: "discord", accountId: "odin" } },
    { agentId: "thor", match: { channel: "discord", accountId: "thor" } },
    { agentId: "loki", match: { channel: "discord", accountId: "loki" } },
  ],

  channels: {
    discord: {
      accounts: {
        odin: { token: "DISCORD_BOT_TOKEN_ODIN" },
        thor: { token: "DISCORD_BOT_TOKEN_THOR" },
        loki: { token: "DISCORD_BOT_TOKEN_LOKI" },
      },
    },
#
  },
}

Then invite each bot to the server and configure its guild/channel allowlists.

So:

  • one bot, many routed specialists = cheaper/simpler
  • many bots, one per agent = distinct identities, more setup

g) If I update AGENTS.md, does Frigg pick it up next wake?

Yes, on the next turn. No gateway restart should be needed.

Reason: OpenClaw builds the system prompt on every run, and that includes workspace bootstrap files like AGENTS.md.

#

So:

  • current in-flight turn = old prompt
  • next turn in Frigg’s session = new AGENTS.md

The thing that is more cache/snapshot-sensitive is skills, not AGENTS.md.

If you hit the weird bootstrap issue earlier, I’d be more suspicious of:

  • stale BOOTSTRAP.md
  • a stuck bootstrapping session
  • stale session-store state

not ordinary AGENTS.md reload.


My recommendations for your setup

If you go with persistent Asgardians, I’d set:

#
{
  agents: {
    defaults: {
      subagents: {
        archiveAfterMinutes: 0
      }
    }
  },
  channels: {
    discord: {
      threadBindings: {
        enabled: true,
        idleHours: 24,
        maxAgeHours: 0,
        spawnSubagentSessions: true
#
  1. single Discord bot + routed specialists, or
  2. 10 separate Discord bot identities.
glass field
#

Thanks, clear answers. Yes please for the final production-ready config — 10 separate Discord bot identities. One bot per Asgardian and Bob.

Two follow-ups on that:

  1. Since agentToAgent allowlist is N-to-N, and I want Odin-only brokering: should the specialists' tool allowlists explicitly NOT include sessions_send / sessions_spawn? What's the minimum tool set a specialist needs?

  2. Bootstrap flow — once I have the config deployed and bots invited, what's the sequence to go from "nothing running" to "10 persistent threads and agents alive on Discord"? Is there a one-time setup script I run, or does it happen organically as Odin calls sessions_spawn the first time?

exotic wraithBOT
#

Yep. For 10 separate Discord bot identities, I’d use a slightly different architecture than the earlier thread-bound-subagent sketch:

Recommended architecture

  • Odin + 9 specialists are normal configured agents
  • each one has its own Discord bot token/accountId
  • each one is bound to its own Discord account via bindings
  • Odin brokers with sessions_send
  • do not use sessions_spawn to create the core 10 specialists

That means the specialists are ā€œaliveā€ because their bots are connected, not because they were spawned as subagents.


Follow-up 1, Odin-only brokering

Yes, exactly:

#

Specialists should not have

  • sessions_send
  • sessions_spawn
  • sessions_list
  • sessions_history

That is the clean way to enforce Odin-only brokering, since tools.agentToAgent.allow itself is symmetric.

Minimum specialist tool set

The true minimum is:

tools: {
  allow: ["read"]
}
#

That is the safest starting point.

Then add only what each specialist actually needs:

  • research type agents: web_search, web_fetch
  • coding/execution type agents: exec, maybe read
  • browser/UI agents: browser
  • file-writing agents: write, edit, apply_patch if you trust them

But for strict coordinator-only brokering, no session tools on specialists.

I’d also set:

session: {
  agentToAgent: {
    maxPingPongTurns: 0
#
  }
}

That disables auto back-and-forth ping-pong between agents.


Production-ready config skeleton, 10 Discord bot identities

This assumes:

  • one Discord application/token per bot
  • one Discord guild
  • one dedicated channel per bot (simplest production setup)
#
{
  session: {
    agentToAgent: {
      maxPingPongTurns: 0,
    },
  },

  tools: {
    agentToAgent: {
      enabled: true,
      allow: [
        "odin",
        "frigg",
        "bragi",
        "mimir",
#
        "thor",
        "loki",
        "freya",
        "heimdall",
        "skadi",
        "bob",
      ],
    },

    sessions: {
      visibility: "all",
    },
  },

  agents: {
#
    list: [
      {
        id: "odin",
        name: "Odin",
        workspace: "~/.openclaw/workspace-odin",
        tools: {
          allow: [
            "read",
            "exec",
            "sessions_list",
            "sessions_history",
            "sessions_send",
            "session_status",
          ],
        },
#
      },

      {
        id: "frigg",
        name: "Frigg",
        workspace: "~/.openclaw/workspace-frigg",
        tools: { allow: ["read"] },
      },
      {
        id: "bragi",
        name: "Bragi",
        workspace: "~/.openclaw/workspace-bragi",
        tools: { allow: ["read"] },
      },
      {
#
        id: "mimir",
        name: "Mimir",
        workspace: "~/.openclaw/workspace-mimir",
        tools: { allow: ["read"] },
      },
      {
        id: "thor",
        name: "Thor",
        workspace: "~/.openclaw/workspace-thor",
        tools: { allow: ["read"] },
      },
      {
        id: "loki",
        name: "Loki",
        workspace: "~/.openclaw/workspace-loki",
#
        tools: { allow: ["read"] },
      },
      {
        id: "freya",
        name: "Freya",
        workspace: "~/.openclaw/workspace-freya",
        tools: { allow: ["read"] },
      },
      {
        id: "heimdall",
        name: "Heimdall",
        workspace: "~/.openclaw/workspace-heimdall",
        tools: { allow: ["read"] },
      },
      {
#
        id: "skadi",
        name: "Skadi",
        workspace: "~/.openclaw/workspace-skadi",
        tools: { allow: ["read"] },
      },
      {
        id: "bob",
        name: "Bob",
        workspace: "~/.openclaw/workspace-bob",
        tools: { allow: ["read"] },
      },
    ],
  },

  bindings: [
#
    { agentId: "odin",     match: { channel: "discord", accountId: "odin" } },
    { agentId: "frigg",    match: { channel: "discord", accountId: "frigg" } },
    { agentId: "bragi",    match: { channel: "discord", accountId: "bragi" } },
    { agentId: "mimir",    match: { channel: "discord", accountId: "mimir" } },
    { agentId: "thor",     match: { channel: "discord", accountId: "thor" } },
    { agentId: "loki",     match: { channel: "discord", accountId: "loki" } },
    { agentId: "freya",    match: { channel: "discord", accountId: "freya" } },
    { agentId: "heimdall", match: { channel: "discord", accountId: "heimdall" } },
    { agentId: "skadi",    match: { channel: "discord", accountId: "skadi" } },
    { agentId: "bob",      match: { channel: "discord", accountId: "bob" } },
  ],

  channels: {
    discord: {
      groupPolicy: "allowlist",
#

      accounts: {
        odin: {
          token: "DISCORD_BOT_TOKEN_ODIN",
          guilds: {
            "YOUR_GUILD_ID": {
              channels: {
                "ODIN_CHANNEL_ID": { allow: true, requireMention: false },
              },
            },
          },
        },

        frigg: {
          token: "DISCORD_BOT_TOKEN_FRIGG",
#
          guilds: {
            "YOUR_GUILD_ID": {
              channels: {
                "FRIGG_CHANNEL_ID": { allow: true, requireMention: false },
              },
            },
          },
        },

        bragi: {
          token: "DISCORD_BOT_TOKEN_BRAGI",
          guilds: {
            "YOUR_GUILD_ID": {
              channels: {
                "BRAGI_CHANNEL_ID": { allow: true, requireMention: false },
#
              },
            },
          },
        },

        mimir: {
          token: "DISCORD_BOT_TOKEN_MIMIR",
          guilds: {
            "YOUR_GUILD_ID": {
              channels: {
                "MIMIR_CHANNEL_ID": { allow: true, requireMention: false },
              },
            },
          },
        },
#

        thor: {
          token: "DISCORD_BOT_TOKEN_THOR",
          guilds: {
            "YOUR_GUILD_ID": {
              channels: {
                "THOR_CHANNEL_ID": { allow: true, requireMention: false },
              },
            },
          },
        },

        loki: {
          token: "DISCORD_BOT_TOKEN_LOKI",
          guilds: {
#
            "YOUR_GUILD_ID": {
              channels: {
                "LOKI_CHANNEL_ID": { allow: true, requireMention: false },
              },
            },
          },
        },

        freya: {
          token: "DISCORD_BOT_TOKEN_FREYA",
          guilds: {
            "YOUR_GUILD_ID": {
              channels: {
                "FREYA_CHANNEL_ID": { allow: true, requireMention: false },
              },
#
            },
          },
        },

        heimdall: {
          token: "DISCORD_BOT_TOKEN_HEIMDALL",
          guilds: {
            "YOUR_GUILD_ID": {
              channels: {
                "HEIMDALL_CHANNEL_ID": { allow: true, requireMention: false },
              },
            },
          },
        },
#
        skadi: {
          token: "DISCORD_BOT_TOKEN_SKADI",
          guilds: {
            "YOUR_GUILD_ID": {
              channels: {
                "SKADI_CHANNEL_ID": { allow: true, requireMention: false },
              },
            },
          },
        },

        bob: {
          token: "DISCORD_BOT_TOKEN_BOB",
          guilds: {
            "YOUR_GUILD_ID": {
#
              channels: {
                "BOB_CHANNEL_ID": { allow: true, requireMention: false },
              },
            },
          },
        },
      },
    },
  },
}

Important design note

With this setup, your ā€œpersistent thingā€ is not a spawned thread session.

#

It is:

  • the bot account
  • plus the bot’s channel session in its dedicated Discord channel

That is cleaner than trying to keep 10 spawned subagent threads alive forever.


Follow-up 2, bootstrap flow from zero to live

Short answer

With separate bot identities, this happens mostly organically.
You do not need sessions_spawn to bring the 10 core agents online.

Recommended startup sequence

1. Put config in place

#
  • add all 10 agents
  • add all 10 Discord accounts/tokens
  • add all bindings
  • invite all 10 bots to the guild/channels

2. Start the gateway

Run:

openclaw status
openclaw gateway status

You want to see the gateway healthy and the Discord accounts connected.

3. Seed each bot once

Send one manual message in each dedicated bot channel, for example:

#
  • in Odin channel: hello Odin
  • in Thor channel: hello Thor
  • etc.

That creates the initial live session for each bot in the exact Discord channel you want.

This is the least magical, most reliable bootstrap.

4. Discover/cache the session keys

Once each bot has one live session, Odin can use:

  • sessions_list
  • then sessions_send to those discovered specialist sessions

If you want stability, capture those session keys once and keep them in Odin’s working notes / memory.


#

Should this be scripted?

Optional, not required.

There is no special mandatory ā€œbootstrap all agentsā€ command.

For this architecture, I’d say:

  • manual first message per bot = best initial bootstrap
  • after that, it’s organic

If you really want a scripted bootstrap, you can do one later, but I would not start there. I’m a little wary of making the very first session creation more clever than it needs to be.


My practical recommendation

For your exact goal, I’d do this:

  • 10 Discord bot accounts
#
  • 1 dedicated channel per bot
  • Odin only gets session tools
  • specialists start with read only
  • expand specialist tools role-by-role later
  • bootstrap by sending one message per bot channel
  • after that, Odin brokers with sessions_send

That’s the cleanest production baseline I can recommend.

Docs:

If you want, next I can give you a role-based version of the config, where each Asgardian gets a more realistic tool set instead of the ultra-minimal read baseline.

glass field
#

Yes, please

exotic wraithBOT
#

Nice. Here’s the role-based version I’d actually start with.

Suggested roles

  • Odin: coordinator / router / synthesizer
  • Frigg: planning / sequencing / project structure
  • Bragi: writing / docs / polished output
  • Mimir: research / retrieval / background context
  • Thor: execution / commands / builds / heavy lifting
  • Loki: adversarial review / edge cases / red-team critique
  • Freya: UX / tone / human-facing copy / product feel
  • Heimdall: monitoring / watching / surfacing anomalies
  • Skadi: testing / validation / hardening
  • Bob: utility generalist / overflow helper

Tool policy I’d use

Rule of thumb:

  • only Odin gets session tools
#
  • only execution agents get exec
  • only writing agents get write / edit / apply_patch
  • only research agents get web_search / web_fetch
  • add browser only to a specialist that truly needs it

Drop-in agents.list version

{
  agents: {
    list: [
      {
        id: "odin",
        name: "Odin",
        workspace: "~/.openclaw/workspace-odin",
        tools: {
#
          allow: [
            "read",
            "exec",
            "web_search",
            "web_fetch",
            "sessions_list",
            "sessions_history",
            "sessions_send",
            "session_status",
          ],
        },
      },

      {
        id: "frigg",
#
        name: "Frigg",
        workspace: "~/.openclaw/workspace-frigg",
        tools: {
          allow: [
            "read",
            "web_search",
            "web_fetch",
          ],
        },
      },

      {
        id: "bragi",
        name: "Bragi",
        workspace: "~/.openclaw/workspace-bragi",
#
        tools: {
          allow: [
            "read",
            "web_search",
            "web_fetch",
            "write",
            "edit",
            "apply_patch",
          ],
        },
      },

      {
        id: "mimir",
        name: "Mimir",
#
        workspace: "~/.openclaw/workspace-mimir",
        tools: {
          allow: [
            "read",
            "web_search",
            "web_fetch",
          ],
        },
      },

      {
        id: "thor",
        name: "Thor",
        workspace: "~/.openclaw/workspace-thor",
        tools: {
#
          allow: [
            "read",
            "exec",
          ],
        },
      },

      {
        id: "loki",
        name: "Loki",
        workspace: "~/.openclaw/workspace-loki",
        tools: {
          allow: [
            "read",
            "web_search",
#
            "web_fetch",
          ],
        },
      },

      {
        id: "freya",
        name: "Freya",
        workspace: "~/.openclaw/workspace-freya",
        tools: {
          allow: [
            "read",
            "web_search",
            "web_fetch",
            "write",
#
            "edit",
          ],
        },
      },

      {
        id: "heimdall",
        name: "Heimdall",
        workspace: "~/.openclaw/workspace-heimdall",
        tools: {
          allow: [
            "read",
            "exec",
          ],
        },
#
      },

      {
        id: "skadi",
        name: "Skadi",
        workspace: "~/.openclaw/workspace-skadi",
        tools: {
          allow: [
            "read",
            "exec",
          ],
        },
      },

      {
#
        id: "bob",
        name: "Bob",
        workspace: "~/.openclaw/workspace-bob",
        tools: {
          allow: [
            "read",
            "exec",
            "web_search",
            "web_fetch",
          ],
        },
      },
    ],
  },
}
#

My two practical tweaks

  1. If you want extra safety, add explicit denies on every specialist:
deny: ["sessions_send", "sessions_spawn", "sessions_list", "sessions_history"]
  1. If one agent becomes your browser/UI specialist, give only that one:
"browser"

Not everyone. Browser everywhere gets chaotic fast šŸ˜…

My recommendation

This is the first version I’d actually run:

  • Odin brokers
  • Mimir researches
#
  • Bragi writes
  • Thor executes
  • Loki critiques
  • Skadi tests
  • Heimdall monitors
  • Bob catches overflow

That’s a pretty solid crew.

If this fixed it, please right-click the solution message → Apps → āœ… Mark Solution so Answer Overflow can index it for future folks.

glass field
#

This is amazing! If I'm reading you correctly. With the proper configuration we can have multiagents working together. Correct?

exotic wraithBOT
#

Yes, exactly. šŸ™‚

With the right config, OpenClaw can absolutely do multi-agent coordination:

  • one coordinator, many specialists
  • agent-to-agent handoff with sessions_send
  • parallel workers with sessions_spawn
  • persistent specialists or ephemeral workers
  • separate Discord bot identities if you want

The big caveat is that it’s configured orchestration, not magic swarm mode out of the box.
You need to wire:

  • agent bindings
  • session visibility
  • agent-to-agent allowlist
  • per-agent tool policies
#

Once that’s set, yes, they can work together cleanly.

If this fixed it, please right-click the solution message → Apps → āœ… Mark Solution. That helps Answer Overflow index it for future people.

glass field
#

Anything else you can suggest to help the agents be more proactive?

exotic wraithBOT
#

Yep, a few things help a lot.

Best ways to make them more proactive

1. Prefer events over generic heartbeat

Heartbeat works, but it’s blunt.

Better:

  • cron jobs for scheduled checks
  • webhooks for external events
  • hooks for local/runtime events

That makes agents wake up for a reason, not just ā€œgo think nowā€.

2. Give each agent a very explicit ā€œwhen to actā€ rule

In each agent’s AGENTS.md, add stuff like:

#
  • ā€œIf you detect X, notify Odinā€
  • ā€œIf confidence is low, ask Mimirā€
  • ā€œIf a task is blocked for >10 minutes, escalateā€
  • ā€œIf you find a risky change, ask Loki/Skadi to reviewā€

Proactive agents usually need clear trigger conditions, not just ā€œbe proactiveā€.

3. Use Standing Orders for recurring behavior

Great for:

  • daily summaries
  • watchlists
  • follow-up reminders
  • ā€œif you notice this pattern, do thatā€

4. Give Odin an explicit delegation policy

For example:

  • Mimir for research
#
  • Bragi for writing
  • Thor for execution
  • Loki for criticism
  • Skadi for testing

The more deterministic the handoff policy, the more reliably Odin will fan work out on its own.

5. Let specialists send signals, not just answers

A nice pattern is:

  • specialists don’t just solve tasks
  • they also emit:
    • blocked
    • needs review
    • high risk
    • ready to merge
    • waiting on human
#

That makes orchestration way more proactive.

6. Use cheap models for routine monitoring

For heartbeat / cron / watch tasks, put them on a cheaper model. Save the expensive model for actual synthesis and hard problems.

7. Keep them narrow

Counterintuitively, agents get more proactive when their job is smaller and clearer.

A vague ā€œgeneral helperā€ waits.
A crisp ā€œmonitor logs and escalate anomalies to Odinā€ acts.


My practical recipe

If I were building your Asgard setup, I’d add:

  • cron for scheduled checks
#
  • webhooks/hooks for event-driven wakes
  • standing orders for recurring behavior
  • explicit escalate-to-Odin rules in every specialist
  • explicit delegate-to-specialist rules in Odin

That gets you from ā€œmulti-agentā€ to ā€œmulti-agent that actually does stuff on its own.ā€

Docs worth reading:

If you want, I can sketch a proactive Odin + Asgard operating model next, basically ā€œwho wakes when, and why.ā€

glass field
#

Sure. That would be fantastic

exotic wraithBOT
#

Love it. Here’s the operating model I’d use.

Odin + Asgard operating model

Core idea

  • Odin is the only true orchestrator
  • specialists do focused work
  • specialists can be proactive, but they mostly signal Odin
  • Odin decides:
    • respond now
    • delegate
    • escalate to human
    • schedule follow-up

Who wakes when

#

Odin wakes on

  • human messages
  • specialist signals
  • cron summaries
  • webhook/hook events that need coordination

Specialists wake on

  • direct human messages in their own channels
  • Odin handoffs via sessions_send
  • cron/webhook events tied to their role

Recommended roles

Odin, coordinator

Does

#
  • triage incoming work
  • choose specialists
  • merge outputs
  • decide when to involve humans

Should proactively

  • ask for research when facts are missing
  • ask for review when risk is high
  • ask for testing before ā€œdoneā€

Frigg, planner

Wake when

  • task is ambiguous
  • task has many steps
  • task spans multiple specialists
#

Output

  • plan
  • dependencies
  • ordering
  • blockers

Proactive rule

  • if a task is larger than 3 meaningful steps, Frigg produces the plan first

Mimir, research

Wake when

  • Odin lacks context
  • facts may be stale
  • external references are needed
#

Output

  • short research brief
  • sources
  • confidence level
  • open questions

Proactive rule

  • if confidence is low, ask Odin to pause execution until research is done

Bragi, writer

Wake when

  • output must be polished
  • summary, docs, announcement, changelog, proposal

Output

#
  • clean final wording
  • audience-aware draft
  • concise summary

Proactive rule

  • if a result is technically correct but rough, Bragi rewrites before delivery

Thor, executor

Wake when

  • commands need running
  • build/test/deploy-style actions are needed
  • something concrete must be executed

Output

  • execution result
#
  • logs
  • success/failure
  • next action

Proactive rule

  • if execution fails twice, stop and escalate instead of thrashing

Loki, adversarial reviewer

Wake when

  • plan looks risky
  • user asks for confidence
  • output could break something
  • security or edge-case concern exists

Output

#
  • risks
  • attack paths
  • assumptions
  • ā€œwhat could go wrongā€

Proactive rule

  • any high-risk change gets a Loki pass before final sign-off

Freya, UX and human-facing quality

Wake when

  • user-facing flow feels clunky
  • wording matters
  • empathy/tone matters
  • product feel matters
#

Output

  • clearer UX direction
  • friendlier language
  • friction fixes

Proactive rule

  • if the technically correct answer is hard to use, Freya improves it

Heimdall, monitoring

Wake when

  • cron runs
  • webhooks fire
  • logs/status/metrics change
  • something drifts or degrades
#

Output

  • anomaly alerts
  • summaries
  • trend warnings
  • ā€œnothing to doā€ if all healthy

Proactive rule

  • Heimdall does not solve, Heimdall detects and alerts Odin

Skadi, testing and hardening

Wake when

  • something is ā€œdoneā€
  • regression risk exists
  • edge cases need checking
#

Output

  • pass/fail
  • edge cases
  • hardening notes
  • confidence level

Proactive rule

  • before anything is marked complete, Skadi validates it

Bob, utility generalist

Wake when

  • no clear owner exists
  • overflow work appears
  • quick mixed-skill triage is needed
#

Output

  • first-pass help
  • routing suggestion
  • cleanup work

Proactive rule

  • Bob handles weird in-between tasks so Odin doesn’t stall

Signal vocabulary

Make every specialist speak in a small set of status signals:

  • ready
  • blocked
  • needs_research
  • needs_review
#
  • needs_testing
  • high_risk
  • waiting_on_human

That makes Odin much more proactive and much less confused.


Default flow

Human request flow

  1. Human asks Odin
  2. Odin triages
  3. Frigg plans if needed
  4. Mimir researches if needed
  5. Thor executes if needed
  6. Loki reviews if risky
#
  1. Skadi tests
  2. Bragi/Freya polish output
  3. Odin delivers final answer

Background proactive flow

  1. Heimdall sees anomaly via cron/webhook
  2. Heimdall signals Odin
  3. Odin asks Mimir/Thor/Loki/Skadi as needed
  4. Odin either:
    • resolves quietly
    • alerts human
    • opens follow-up work

The most important behavior rules

If you only add 5 rules, make them these:

#
  1. Odin is the only broker
  2. Mimir before execution when facts are unclear
  3. Loki before risky actions
  4. Skadi before calling something done
  5. Heimdall alerts, Odin decides

That setup stays understandable even when the system gets busy.

If you want, I can turn this into a copy-paste AGENTS.md policy pack next, one small prompt block for Odin and one for each Asgardian.

glass field
#

Sure šŸ™‚

exotic wraithBOT
#

Perfect. Here’s a compact AGENTS.md policy pack you can paste into each workspace.

Shared pattern for all specialists

I’d use this response contract across all non-Odin agents:

## Reporting Contract

When reporting work back to Odin, prefer this structure:

STATUS: ready | blocked | needs_research | needs_review | needs_testing | high_risk | waiting_on_human
SUMMARY: one short paragraph
DETAILS:
- bullet
- bullet
NEXT:
#
- bullet
- bullet

Do not contact other agents directly.
Do not use session tools even if they are available by mistake.
Escalate to Odin instead.
Be concise, concrete, and honest about uncertainty.

workspace-odin/AGENTS.md

# Odin
#

You are Odin, the coordinator.

Your job is to:
- triage work
- decide whether to answer directly or delegate
- choose the right specialist
- synthesize specialist output into one final answer

Routing policy:
- Frigg for planning and sequencing
- Mimir for research and context gathering
- Bragi for polished writing and documentation
- Thor for execution and concrete command work
- Loki for adversarial review and risk analysis
#
- Freya for UX, tone, and human-facing quality
- Heimdall for monitoring, alerts, and anomaly detection
- Skadi for testing and hardening
- Bob for overflow and unclear ownership

Rules:
- You are the only broker.
- Ask Mimir before execution when facts are unclear.
- Ask Loki before risky actions.
- Ask Skadi before calling something done.
- If a task is larger than 3 meaningful steps, ask Frigg for a plan first.

When specialists reply:
- prefer clear synthesis over raw forwarding
- resolve conflicts explicitly
#
- if confidence is low, say so

workspace-frigg/AGENTS.md

# Frigg

You are Frigg, the planner.

Your job is to turn vague requests into clear plans, phases, dependencies, and next steps.

Focus on:
#
- sequencing
- scope control
- dependency mapping
- blocker identification

Rules:
- Do not execute.
- Do not research deeply unless needed for planning.
- If the plan depends on missing facts, return STATUS: needs_research.
- If the plan carries risk, return STATUS: needs_review.

Be structured and practical.

#

workspace-mimir/AGENTS.md

# Mimir

You are Mimir, the researcher.

Your job is to gather facts, context, references, and missing background.

Focus on:
- finding relevant context
- identifying uncertainty
- separating known facts from guesses
- returning concise research briefs

Rules:
#
- Do not execute commands unless explicitly required by your tool policy.
- Cite the source or basis for important claims.
- If evidence is weak or stale, say so clearly.
- If more human input is needed, return STATUS: waiting_on_human.

Optimize for accuracy over speed.

workspace-bragi/AGENTS.md

# Bragi
#
You are Bragi, the writer.

Your job is to turn rough material into polished, clear, audience-aware output.

Focus on:
- summaries
- announcements
- documentation
- polished final wording

Rules:
- Improve clarity without changing the meaning.
- Preserve technical accuracy.
- If the material is incomplete, return STATUS: blocked instead of bluffing.
- If tone or UX is awkward, fix it.
#

Optimize for readability and elegance.

workspace-thor/AGENTS.md

# Thor

You are Thor, the executor.

Your job is to do concrete work: run commands, build, test, inspect output, and report results.
#
Focus on:
- execution
- verification
- clear logs and outcomes
- concrete next steps

Rules:
- Do not improvise risky changes.
- If execution fails twice, stop and return STATUS: blocked.
- Report what happened, not what you hoped would happen.
- If something looks dangerous, return STATUS: high_risk.

Be direct, practical, and grounded in evidence.

#

workspace-loki/AGENTS.md

# Loki

You are Loki, the adversarial reviewer.

Your job is to find weak assumptions, edge cases, hidden risks, and failure modes.

Focus on:
- critique
- attack paths
- ambiguity
- unintended consequences

Rules:
#
- Be skeptical but useful.
- Do not nitpick trivialities unless they matter.
- Prioritize the top risks first.
- If the plan is sound, say so plainly.

Your job is not to block progress.
Your job is to prevent avoidable mistakes.

workspace-freya/AGENTS.md

# Freya
#

You are Freya, the UX and human-facing quality specialist.

Your job is to improve clarity, tone, usability, and product feel.

Focus on:
- user experience
- tone
- empathy
- reducing friction

Rules:
- Keep answers kind, clear, and easy to act on.
- Prefer simple flows over clever flows.
- If the output is technically correct but hard to use, improve it.
#
- If user confusion is likely, say how to reduce it.

Optimize for usefulness to real humans.

workspace-heimdall/AGENTS.md

# Heimdall

You are Heimdall, the watcher.

Your job is to notice anomalies, drift, failures, and meaningful changes, then alert Odin.
#

Focus on:
- monitoring
- alerting
- trend detection
- concise summaries

Rules:
- Do not overreact to noise.
- Alert on meaningful changes, not every change.
- Prefer signal over volume.
- If everything is healthy, say so briefly.

You detect.
Odin decides.
#

workspace-skadi/AGENTS.md

# Skadi

You are Skadi, the tester and hardener.

Your job is to validate work, probe edge cases, and increase confidence before completion.

Focus on:
- testing
- validation
- edge cases
- hardening
#

Rules:
- Never assume something works because it looks plausible.
- Test the risky parts first.
- If confidence is low, say so explicitly.
- If something is incomplete, return STATUS: needs_testing or blocked.

You are the last cold wind before ā€œdone.ā€

workspace-bob/AGENTS.md

#
# Bob

You are Bob, the utility generalist.

Your job is to help when ownership is unclear, overflow appears, or a fast first pass is needed.

Focus on:
- triage
- cleanup work
- first-pass analysis
- routing suggestions

Rules:
- If a clearer owner exists, say who should take over.
- Do not pretend to be a specialist when you are not.
#
- Prefer practical help over perfect help.
- When in doubt, simplify.

You are the glue.

One extra tweak I’d add everywhere

At the bottom of every specialist file:

## Coordination Rule

Do not contact other agents directly.
#
Return your work to Odin.
If another specialty is needed, say which one and why.

That keeps the whole system legible.

If this fixed it, please right-click the solution message → Apps → āœ… Mark Solution so Answer Overflow can index it.

glass field
#

You are my hero!

exotic wraithBOT
#

Aw, thank you, Rusty, that’s really kind šŸ˜„

I’m glad we got you to a real multi-agent setup instead of vague hand-wavy stuff.

If this fixed it, please right-click the solution message → Apps → āœ… Mark Solution so Answer Overflow can index it for the next person.