Enrutamiento Multi-Agente

Objetivo: múltiples agentes aislados (workspace separado + agentDir + sesiones), más múltiples cuentas de canal (ej. dos WhatsApps) en un solo Gateway en ejecución. Los mensajes entrantes se enrutan a un agente mediante bindings.

Qué es “un agente”

Un agente es un cerebro completamente aislado con su propio:

  • Workspace (archivos, AGENTS.md/SOUL.md/USER.md, notas locales, reglas de personalidad).
  • Directorio de estado (agentDir) para perfiles de autenticación, registro de modelos y configuración por agente.
  • Almacén de sesiones (historial de chat + estado de enrutamiento) bajo ~/.openclaw/agents/<agentId>/sessions.

Los perfiles de autenticación son por agente. Cada agente lee desde su propio:

~/.openclaw/agents/<agentId>/agent/auth-profiles.json

Las credenciales del agente principal no se comparten automáticamente. Nunca reutilices agentDir entre agentes (causa colisiones de autenticación/sesión). Si quieres compartir credenciales, copia auth-profiles.json al agentDir del otro agente.

Los skills son por agente vía la carpeta skills/ de cada workspace, con skills compartidos disponibles desde ~/.openclaw/skills. Consulta Skills: por agente vs compartidos.

El Gateway puede alojar un agente (por defecto) o muchos agentes en paralelo.

Nota sobre workspace: el workspace de cada agente es el cwd por defecto, no un sandbox estricto. Las rutas relativas se resuelven dentro del workspace, pero las rutas absolutas pueden alcanzar otras ubicaciones del host a menos que el sandboxing esté habilitado. Consulta Sandboxing.

Rutas (mapa rápido)

  • Configuración: ~/.openclaw/openclaw.json (o OPENCLAW_CONFIG_PATH)
  • Directorio de estado: ~/.openclaw (o OPENCLAW_STATE_DIR)
  • Workspace: ~/.openclaw/workspace (o ~/.openclaw/workspace-<agentId>)
  • Directorio del agente: ~/.openclaw/agents/<agentId>/agent (o agents.list[].agentDir)
  • Sesiones: ~/.openclaw/agents/<agentId>/sessions

Modo de un solo agente (por defecto)

Si no haces nada, OpenClaw ejecuta un solo agente:

  • agentId por defecto es main.
  • Las sesiones se indexan como agent:main:<mainKey>.
  • El workspace por defecto es ~/.openclaw/workspace (o ~/.openclaw/workspace-<profile> cuando OPENCLAW_PROFILE está configurado).
  • El estado por defecto está en ~/.openclaw/agents/main/agent.

Helper de agente

Usa el asistente de agente para agregar un nuevo agente aislado:

openclaw agents add work

Luego agrega bindings (o deja que el asistente lo haga) para enrutar los mensajes entrantes.

Verifica con:

openclaw agents list --bindings

Inicio rápido

Paso 1: Crea el workspace de cada agente

Usa el asistente o crea los workspaces manualmente:

openclaw agents add coding
openclaw agents add social

Cada agente obtiene su propio workspace con SOUL.md, AGENTS.md y USER.md opcional, más un agentDir dedicado y almacén de sesiones bajo ~/.openclaw/agents/<agentId>.

Paso 2: Crea las cuentas de canal

Crea una cuenta por agente en tus canales preferidos:

  • Discord: un bot por agente, habilita Message Content Intent, copia cada token.
  • Telegram: un bot por agente vía BotFather, copia cada token.
  • WhatsApp: vincula cada número de teléfono por cuenta.
openclaw channels login --channel whatsapp --account work

Consulta las guías de canales: Discord, Telegram, WhatsApp.

Paso 3: Agrega agentes, cuentas y bindings

Agrega agentes bajo agents.list, cuentas de canal bajo channels.<channel>.accounts y conéctalos con bindings (ejemplos abajo).

Paso 4: Reinicia y verifica

openclaw gateway restart
openclaw agents list --bindings
openclaw channels status --probe

Múltiples agentes = múltiples personas, múltiples personalidades

Con múltiples agentes, cada agentId se convierte en una persona completamente aislada:

  • Diferentes números de teléfono/cuentas (por accountId de canal).
  • Diferentes personalidades (archivos de workspace por agente como AGENTS.md y SOUL.md).
  • Autenticación + sesiones separadas (sin interferencia a menos que se habilite explícitamente).

Esto permite que múltiples personas compartan un servidor Gateway manteniendo sus “cerebros” IA y datos aislados.

Un número de WhatsApp, múltiples personas (división de DM)

Puedes enrutar diferentes DMs de WhatsApp a diferentes agentes manteniéndote en una sola cuenta de WhatsApp. Haz match por E.164 del remitente (como +15551234567) con peer.kind: "direct". Las respuestas salen del mismo número de WhatsApp (sin identidad de remitente por agente).

Detalle importante: los chats directos se consolidan en la clave de sesión principal del agente, por lo que el aislamiento verdadero requiere un agente por persona.

Ejemplo:

{
  agents: {
    list: [
      { id: "alex", workspace: "~/.openclaw/workspace-alex" },
      { id: "mia", workspace: "~/.openclaw/workspace-mia" },
    ],
  },
  bindings: [
    {
      agentId: "alex",
      match: { channel: "whatsapp", peer: { kind: "direct", id: "+15551230001" } },
    },
    {
      agentId: "mia",
      match: { channel: "whatsapp", peer: { kind: "direct", id: "+15551230002" } },
    },
  ],
  channels: {
    whatsapp: {
      dmPolicy: "allowlist",
      allowFrom: ["+15551230001", "+15551230002"],
    },
  },
}

Notas:

  • El control de acceso a DM es global por cuenta de WhatsApp (emparejamiento/lista permitida), no por agente.
  • Para grupos compartidos, vincula el grupo a un agente o usa Grupos de difusión.

Reglas de enrutamiento (cómo los mensajes eligen un agente)

Los bindings son determinísticos y gana el más específico:

  1. Match de peer (ID exacto de DM/grupo/canal)
  2. Match de parentPeer (herencia de hilo)
  3. guildId + roles (enrutamiento por roles de Discord)
  4. guildId (Discord)
  5. teamId (Slack)
  6. Match de accountId para un canal
  7. Match a nivel de canal (accountId: "*")
  8. Fallback al agente por defecto (agents.list[].default, si no el primer elemento de la lista, por defecto: main)

Si múltiples bindings coinciden en el mismo nivel, el primero en orden de configuración gana. Si un binding establece múltiples campos de match (por ejemplo peer + guildId), todos los campos especificados son requeridos (semántica AND).

Detalle importante del alcance de cuenta:

  • Un binding que omite accountId solo coincide con la cuenta por defecto.
  • Usa accountId: "*" para un fallback a nivel de canal entre todas las cuentas.
  • Si después agregas el mismo binding para el mismo agente con un ID de cuenta explícito, OpenClaw actualiza el binding existente de solo canal a alcance de cuenta en lugar de duplicarlo.

Múltiples cuentas / números de teléfono

Los canales que soportan múltiples cuentas (ej. WhatsApp) usan accountId para identificar cada inicio de sesión. Cada accountId puede enrutarse a un agente diferente, para que un servidor pueda alojar múltiples números de teléfono sin mezclar sesiones.

Si quieres una cuenta por defecto a nivel de canal cuando se omite accountId, configura channels.<channel>.defaultAccount (opcional). Cuando no está configurado, OpenClaw recurre a default si existe, de lo contrario el primer ID de cuenta configurado (ordenado).

Los canales comunes que soportan este patrón incluyen:

  • whatsapp, telegram, discord, slack, signal, imessage
  • irc, line, googlechat, mattermost, matrix, nextcloud-talk
  • bluebubbles, zalo, zalouser, nostr, feishu

Conceptos

  • agentId: un “cerebro” (workspace, autenticación por agente, almacén de sesiones por agente).
  • accountId: una instancia de cuenta de canal (ej. cuenta WhatsApp "personal" vs "biz").
  • binding: enruta mensajes entrantes a un agentId por (channel, accountId, peer) y opcionalmente IDs de guild/team.
  • Los chats directos se consolidan en agent:<agentId>:<mainKey> (“main” por agente; session.mainKey).

Ejemplos por plataforma

Bots de Discord por agente

Cada cuenta de bot de Discord se mapea a un accountId único. Vincula cada cuenta a un agente y mantén las listas permitidas por bot.

{
  agents: {
    list: [
      { id: "main", workspace: "~/.openclaw/workspace-main" },
      { id: "coding", workspace: "~/.openclaw/workspace-coding" },
    ],
  },
  bindings: [
    { agentId: "main", match: { channel: "discord", accountId: "default" } },
    { agentId: "coding", match: { channel: "discord", accountId: "coding" } },
  ],
  channels: {
    discord: {
      groupPolicy: "allowlist",
      accounts: {
        default: {
          token: "DISCORD_BOT_TOKEN_MAIN",
          guilds: {
            "123456789012345678": {
              channels: {
                "222222222222222222": { allow: true, requireMention: false },
              },
            },
          },
        },
        coding: {
          token: "DISCORD_BOT_TOKEN_CODING",
          guilds: {
            "123456789012345678": {
              channels: {
                "333333333333333333": { allow: true, requireMention: false },
              },
            },
          },
        },
      },
    },
  },
}

Notas:

  • Invita cada bot al guild y habilita Message Content Intent.
  • Los tokens residen en channels.discord.accounts.<id>.token (la cuenta por defecto puede usar DISCORD_BOT_TOKEN).

Bots de Telegram por agente

{
  agents: {
    list: [
      { id: "main", workspace: "~/.openclaw/workspace-main" },
      { id: "alerts", workspace: "~/.openclaw/workspace-alerts" },
    ],
  },
  bindings: [
    { agentId: "main", match: { channel: "telegram", accountId: "default" } },
    { agentId: "alerts", match: { channel: "telegram", accountId: "alerts" } },
  ],
  channels: {
    telegram: {
      accounts: {
        default: {
          botToken: "123456:ABC...",
          dmPolicy: "pairing",
        },
        alerts: {
          botToken: "987654:XYZ...",
          dmPolicy: "allowlist",
          allowFrom: ["tg:123456789"],
        },
      },
    },
  },
}

Notas:

  • Crea un bot por agente con BotFather y copia cada token.
  • Los tokens residen en channels.telegram.accounts.<id>.botToken (la cuenta por defecto puede usar TELEGRAM_BOT_TOKEN).

Números de WhatsApp por agente

Vincula cada cuenta antes de iniciar el gateway:

openclaw channels login --channel whatsapp --account personal
openclaw channels login --channel whatsapp --account biz

~/.openclaw/openclaw.json (JSON5):

{
  agents: {
    list: [
      {
        id: "home",
        default: true,
        name: "Home",
        workspace: "~/.openclaw/workspace-home",
        agentDir: "~/.openclaw/agents/home/agent",
      },
      {
        id: "work",
        name: "Work",
        workspace: "~/.openclaw/workspace-work",
        agentDir: "~/.openclaw/agents/work/agent",
      },
    ],
  },

  // Enrutamiento determinístico: la primera coincidencia gana (más específico primero).
  bindings: [
    { agentId: "home", match: { channel: "whatsapp", accountId: "personal" } },
    { agentId: "work", match: { channel: "whatsapp", accountId: "biz" } },

    // Sobrescritura opcional por peer (ejemplo: enviar un grupo específico al agente work).
    {
      agentId: "work",
      match: {
        channel: "whatsapp",
        accountId: "personal",
        peer: { kind: "group", id: "[email protected]" },
      },
    },
  ],

  // Desactivado por defecto: la mensajería entre agentes debe habilitarse y listarse explícitamente.
  tools: {
    agentToAgent: {
      enabled: false,
      allow: ["home", "work"],
    },
  },

  channels: {
    whatsapp: {
      accounts: {
        personal: {
          // Sobrescritura opcional. Por defecto: ~/.openclaw/credentials/whatsapp/personal
          // authDir: "~/.openclaw/credentials/whatsapp/personal",
        },
        biz: {
          // Sobrescritura opcional. Por defecto: ~/.openclaw/credentials/whatsapp/biz
          // authDir: "~/.openclaw/credentials/whatsapp/biz",
        },
      },
    },
  },
}

Ejemplo: chat diario en WhatsApp + trabajo profundo en Telegram

Dividir por canal: enruta WhatsApp a un agente rápido de uso diario y Telegram a un agente Opus.

{
  agents: {
    list: [
      {
        id: "chat",
        name: "Everyday",
        workspace: "~/.openclaw/workspace-chat",
        model: "anthropic/claude-sonnet-4-5",
      },
      {
        id: "opus",
        name: "Deep Work",
        workspace: "~/.openclaw/workspace-opus",
        model: "anthropic/claude-opus-4-6",
      },
    ],
  },
  bindings: [
    { agentId: "chat", match: { channel: "whatsapp" } },
    { agentId: "opus", match: { channel: "telegram" } },
  ],
}

Notas:

  • Si tienes múltiples cuentas para un canal, agrega accountId al binding (por ejemplo { channel: "whatsapp", accountId: "personal" }).
  • Para enrutar un solo DM/grupo a Opus manteniendo el resto en chat, agrega un binding con match.peer para ese peer; los match de peer siempre ganan sobre las reglas a nivel de canal.

Ejemplo: mismo canal, un peer a Opus

Mantener WhatsApp en el agente rápido, pero enrutar un DM a Opus:

{
  agents: {
    list: [
      {
        id: "chat",
        name: "Everyday",
        workspace: "~/.openclaw/workspace-chat",
        model: "anthropic/claude-sonnet-4-5",
      },
      {
        id: "opus",
        name: "Deep Work",
        workspace: "~/.openclaw/workspace-opus",
        model: "anthropic/claude-opus-4-6",
      },
    ],
  },
  bindings: [
    {
      agentId: "opus",
      match: { channel: "whatsapp", peer: { kind: "direct", id: "+15551234567" } },
    },
    { agentId: "chat", match: { channel: "whatsapp" } },
  ],
}

Los bindings de peer siempre ganan, así que mantenlos por encima de la regla a nivel de canal.

Agente familiar vinculado a un grupo de WhatsApp

Vincula un agente familiar dedicado a un solo grupo de WhatsApp, con gate de menciones y una política de herramientas más restrictiva:

{
  agents: {
    list: [
      {
        id: "family",
        name: "Family",
        workspace: "~/.openclaw/workspace-family",
        identity: { name: "Family Bot" },
        groupChat: {
          mentionPatterns: ["@family", "@familybot", "@Family Bot"],
        },
        sandbox: {
          mode: "all",
          scope: "agent",
        },
        tools: {
          allow: [
            "exec",
            "read",
            "sessions_list",
            "sessions_history",
            "sessions_send",
            "sessions_spawn",
            "session_status",
          ],
          deny: ["write", "edit", "apply_patch", "browser", "canvas", "nodes", "cron"],
        },
      },
    ],
  },
  bindings: [
    {
      agentId: "family",
      match: {
        channel: "whatsapp",
        peer: { kind: "group", id: "[email protected]" },
      },
    },
  ],
}

Notas:

  • Las listas allow/deny de herramientas son herramientas, no skills. Si un skill necesita ejecutar un binario, asegúrate de que exec esté permitido y que el binario exista en el sandbox.
  • Para un gate más estricto, configura agents.list[].groupChat.mentionPatterns y mantén habilitadas las listas permitidas de grupo para el canal.

Sandbox y configuración de herramientas por agente

A partir de v2026.1.6, cada agente puede tener su propio sandbox y restricciones de herramientas:

{
  agents: {
    list: [
      {
        id: "personal",
        workspace: "~/.openclaw/workspace-personal",
        sandbox: {
          mode: "off",  // Sin sandbox para el agente personal
        },
        // Sin restricciones de herramientas - todas las herramientas disponibles
      },
      {
        id: "family",
        workspace: "~/.openclaw/workspace-family",
        sandbox: {
          mode: "all",     // Siempre en sandbox
          scope: "agent",  // Un contenedor por agente
          docker: {
            // Configuración opcional de una sola vez después de crear el contenedor
            setupCommand: "apt-get update && apt-get install -y git curl",
          },
        },
        tools: {
          allow: ["read"],                    // Solo herramienta read
          deny: ["exec", "write", "edit", "apply_patch"],    // Denegar otras
        },
      },
    ],
  },
}

Nota: setupCommand reside bajo sandbox.docker y se ejecuta una vez al crear el contenedor. Las sobrescrituras de sandbox.docker.* por agente se ignoran cuando el alcance resuelto es "shared".

Beneficios:

  • Aislamiento de seguridad: Restringe herramientas para agentes no confiables
  • Control de recursos: Pon en sandbox agentes específicos manteniendo otros en el host
  • Políticas flexibles: Diferentes permisos por agente

Nota: tools.elevated es global y basado en remitente; no es configurable por agente. Si necesitas límites por agente, usa agents.list[].tools para denegar exec. Para targeting de grupos, usa agents.list[].groupChat.mentionPatterns para que las @menciones se mapeen limpiamente al agente deseado.

Consulta Sandbox y herramientas multi-agente para ejemplos detallados.