#multi-agent

1 messages · Page 1 of 1 (latest)

wind tendon
#

I’m designing a dedicated “Naval” persona agent and want to confirm best practices.

Current setup:

  • Main interaction channel: Discord
  • I already run a cron job that sends “Naval voice” messages from an existing agent

Target setup:

  • A dedicated naval agent (not just a style prompt on main)
  • Cron messages sent by naval
  • I can directly ask questions to naval in Discord

Questions:

  1. Is this the recommended pattern: agents.list + Discord bindings routing + cron --agent naval?
  2. For Discord DMs, is session.dmScope: per-channel-peer the safest default for this use case?
  3. For routing priority, should I define a specific binding for my user ID to naval, then fallback to main?
  4. Any known gotchas with requireMention, groupPolicy, or allowlists in this setup?
  5. Any recommended guardrails for persona consistency (SOUL.md) vs operational rules (AGENTS.md)?

Example intent (simplified):

  • naval handles my direct DM / mention
  • main handles everything else
  • cron jobs explicitly target --agent naval

Would love to sanity-check this architecture before I implement it fully. Thanks!

lapis plazaBOT
#

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

paper turtleBOT
#
  1. Yes — that’s the intended pattern.

A typical cron example (isolated run + delivery) looks like:

openclaw cron add \
  --name "Naval ping" \
  --cron "0 9 * * *" --tz "UTC" \
  --session isolated \
  --message "Write today's Naval-inspired thought." \
  --agent naval \
  --announce --channel discord --to "channel:123456789012345678"
#
  1. session.dmScope: "per-channel-peer" is the safest default for Discord DMs if >1 person can DM the bot.
    It prevents the classic “DM context leak” where multiple DM senders share one conversation. If it’s truly single-user, main is fine, but “safe by default” = per-channel-peer.
    Docs: https://docs.openclaw.ai/concepts/session (see “Secure DM mode”)

  2. Yes: bind “you → naval”, fall back to main.
    You usually don’t even need an explicit fallback binding if main is the default agent, but the “mental model” is right: peer binding beats everything else. For Discord DM routing, the peer id is your Discord user id (string). Example:

{
  agents: {
    list: [
      { id: "main", default: true, workspace: "~/.openclaw/workspace" },
      { id: "naval", workspace: "~/.openclaw/workspace-naval" },
    ],
  },
  bindings: [
    {
#
      agentId: "naval",
      match: { channel: "discord", peer: { kind: "direct", id: "987654321012345678" } }
    },
    // optional: route a dedicated guild channel to naval too
    // { agentId:"naval", match:{ channel:"discord", peer:{ kind:"channel", id:"<channelId>" } } },
  ],
}

Docs: https://docs.openclaw.ai/concepts/multi-agent

  1. Gotchas (Discord + groups + allowlists)
  • requireMention placement (Discord): it’s per guild/channel under channels.discord.guilds... (a common mistake is setting it “globally” in the wrong place). Docs: https://docs.openclaw.ai/channels/discord
  • groupPolicy: "allowlist" + empty allowlist = “why is my bot silent?” You must allowlist the guild (and optionally channels). Docs: https://docs.openclaw.ai/channels/groups
  • Role-based routing/allowlists require Discord “Server Members Intent”. Without it, role matching/routing won’t behave. Docs: https://docs.openclaw.ai/channels/discord
  • Mention gating ≠ routing. Routing picks an agent by peer/guild/role; requireMention only decides whether to reply. If you want “mention Naval in a shared channel but everything else goes to main”, you generally need either a dedicated channel bound to naval, or role-based routing for you (which will route all your messages in that guild to naval).
  • Per-agent auth is separate. Your naval agent needs its own auth profiles; otherwise cron runs under naval will fail even if main works. Docs: https://docs.openclaw.ai/concepts/multi-agent
#
  1. Guardrails: persona vs ops rules
  • Put voice/persona in the naval workspace’s SOUL.md (style, tone, “Naval-inspired”, etc.).
  • Put non-negotiables / tool discipline / safety / refusal rules in AGENTS.md (these should override persona).
  • Enforce the important parts in config, not just prompts: consider per-agent tools.allow/deny + sandbox for the naval agent if you want it to stay “writer/thinker” and not do operational stuff. Docs: https://docs.openclaw.ai/concepts/multi-agent (per-agent tools/sandbox examples)

One extra practical note: if you mean “Naval Ravikant voice”, I’d explicitly frame it as “Naval-inspired” in SOUL.md (don’t let the agent claim to literally be him), especially if any of this is visible to others in guild channels.

wind tendon
# paper turtle 5) **Guardrails: persona vs ops rules** - Put **voice/persona** in the `naval` w...

Thanks again for your earlier guidance — quick follow-up on strict isolation.

I now run main + naval in one gateway, and routing/session separation is working.
I also want Naval’s long-term memory to be fully isolated from main.

Question:
What is the officially recommended way to enforce per-agent long-term memory isolation?

Context:

  • Sessions are already separated per agent.
  • We use the memory-lancedb memory slot.
  • I want Naval-only memory (no recall/capture crossover with main).

Would you recommend:

  1. per-agent memory backend/config (if supported),
  2. separate gateway profile/state dir for Naval, or
  3. disabling shared auto-recall/auto-capture and relying on workspace memory files for Naval?

Any best-practice pattern you recommend would help.

paper turtleBOT
#

Strict per-agent long-term memory isolation in OpenClaw is basically:

  • Guaranteed if “memory = files in the agent workspace” (each agent has its own MEMORY.md + memory/*.md), and you use the default memory tooling (memory-core) that indexes that agent’s workspace.
  • Not guaranteed with memory-lancedb in a single gateway, because it’s one global memory plugin instance with one DB path and it does not namespace entries by agentId.

The key gotcha: memory-lancedb is gateway-global

memory-lancedb defaults to storing in ~/.openclaw/memory/lancedb (single location), and its auto-recall/auto-capture hooks don’t tag memories with an agent id. So main + naval will recall/capture from the same pool.

That means option (1) “per-agent memory backend/config” is not supported for memory-lancedb within one gateway, because:

  • the memory slot is global (plugins.slots.memory), and
  • only one memory plugin is active, with one config payload.

Recommended best-practice patterns

A) If you want strict isolation and one gateway: use workspace memory (+ memory-core)

This is the “official” model: memory is Markdown in each agent’s workspace (source of truth), and semantic search/indexing is per-agent.

#

B) If you must keep memory-lancedb and want strict isolation: separate gateways (separate state dirs)

This corresponds to your option (2). It’s the only way to keep memory-lancedb and guarantee no crossover without changing code.

Caveat: two gateways generally can’t both “own” the same Discord bot connection/token at once, so you typically end up with:

  • separate Discord bots/accounts, or
  • only one gateway connected to Discord (the other runs jobs / internal work only).

C) “Disable auto-recall/auto-capture and rely on workspace files”

This is basically option (3), and it’s a totally reasonable compromise if you stay on memory-lancedb for some reason — but I’d rather just go with (A) and switch to memory-core, since it matches the official memory model and is naturally per-agent.

If you want memory-lancedb and one gateway and per-agent isolation

That needs a plugin change: store agentId (or workspace id) alongside each memory entry and filter recall/capture by it (or use per-agent table/db path). That’s not a config-only solution today.

If you tell me whether you’re open to “separate gateways” or you want to stay “single gateway”, I can suggest the cleanest concrete config direction for your setup.

wind tendon
# paper turtle - https://docs.openclaw.ai/tools/plugin #### B) If you must keep `memory-lanced...

quick config question for OpenClaw v2026.2.13.

I see two ways to define the default agent:

  • agent.default (mentioned in some docs/examples)
  • agents.list[].default (visible in schema/types)

Which is the current officially recommended method, and what is the precedence if both are set?

Hi OpenClaw team, we’re reviewing a multi-agent setup on v2026.2.13 and want to confirm a few behaviors from official perspective.

  1. Default agent definition
    I see both agent.default (docs/examples) and agents.list[].default (schema/types). Which is officially recommended now, and what is the precedence if both are present?

  2. Invalid binding target behavior
    If bindings[].agentId references an agent that is not present in agents.list, what is the exact behavior?
    (a) binding ignored
    (b) fallback to default agent
    (c) validation/runtime error or warning

  3. Security of /v1/chat/completions
    When gateway.http.endpoints.chatCompletions.enabled=true, is there a supported way to disable/restrict x-openclaw-session-key overrides?
    If not, is disabling chatCompletions the recommended security posture unless strictly required?

  4. Cron global disable semantics
    If cron.enabled=false while jobs still exist and are marked enabled in storage, should execution always be fully paused?
    Also, what should happen to nextRunAt in that state?

paper turtleBOT
#
  1. Default agent definition (v2026.2.13)
    Use agents.list[].default. That’s the current, schema-backed way.

Runtime precedence (from the actual resolver logic):

  • If agents.list is empty/missing → default agent id is "main".
  • Else if one or more entries have default: true → the first such entry wins (and OpenClaw prints a warning if multiple are marked default).
  • Else → the first entry in agents.list wins.

There is no current supported agent.default key in the v2026.2.13 config schema. If you saw something like that, it’s either:

  • stale docs, or
  • confusion with legacy routing.defaultAgentId (which is a known legacy key and gets auto-migrated to agents.list[].default).

Docs that reflect the current behavior: https://docs.openclaw.ai/concepts/multi-agent and config reference: https://docs.openclaw.ai/gateway/configuration-reference


#
  1. Invalid binding target (bindings[].agentId not in agents.list)
    In a multi-agent config (i.e. agents.list is non-empty): it falls back to the default agent at runtime.
    So the binding can still “match”, but the routed agent becomes the default agent.

Important nuance: there is no config validation error for this today (bindings don’t currently zod-validate agentId membership), so you won’t necessarily notice unless you watch routing/debug logs.

(If agents.list is empty, routing doesn’t have a “known agent set” to validate against, and will effectively accept the binding’s agentId — which usually isn’t what you want. If you’re using bindings, you should have agents.list.)


  1. Security of /v1/chat/completions + x-openclaw-session-key override
    Today: there is no built-in switch to disable/restrict x-openclaw-session-key overrides while keeping chatCompletions enabled. The header is always honored when present. (Same story for /v1/responses.)

So the supported posture is:

  • keep gateway.http.endpoints.chatCompletions.enabled=false unless you truly need it, and/or
  • treat Gateway credentials as high-trust (because holders can route into arbitrary session keys via that header), and
  • if you must expose it to less-trusted clients, do it behind a reverse proxy that strips x-openclaw-session-key (and ideally also restricts x-openclaw-agent-id / model overrides depending on your threat model).