#just wanted to ask if my config is valid logically, where can i improve add/edit it

1 messages · Page 1 of 1 (latest)

elder ploverBOT
#

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

plain basinBOT
#

If your “family agent” is on WhatsApp and it (a) can’t remember, (b) “misses info”, and (c) anyone can restart the gateway, those are usually three separate config issues:

1) “It can’t keep memories”

OpenClaw memory is just Markdown files in the agent workspace. If the agent can’t write to the workspace, it will never “remember”. Docs: https://docs.openclaw.ai/concepts/memory

Common causes:

  • Tool allowlist blocks writing: if that agent’s tools.allow does not include write (or you deny group:fs), it can’t save memory/YYYY-MM-DD.md or MEMORY.md.
  • Sandbox workspace is read-only: if the agent runs sandboxed with workspaceAccess: "ro" or "none", memory writes (and the automatic “memory flush”) are skipped.
  • You’re not consistently hitting the same agent/workspace (routing/bindings): with 3 agents, if messages sometimes route to a different agentId, it’ll look like “it forgot”.

What to do:

2) “While relaying information it misses info”

On WhatsApp groups, the bot often only “wakes up” when mentioned/replied-to. Until then it buffers some history and injects it when triggered.

#

Two knobs from the WhatsApp docs:

  • channels.whatsapp.historyLimit (default 50) controls how many “missed” group messages get injected as context once the bot is triggered.
  • Group activation /activation always vs /activation mention affects whether it only responds on mention (safer/cheaper) or is “always on” in that group (more context, more cost/risk).

WhatsApp docs: https://docs.openclaw.ai/channels/whatsapp

3) “Anyone can restart gateway”

This is usually because /restart is enabled by default as a chat command, and any authorized sender can run it. Docs: https://docs.openclaw.ai/tools/slash-commands

Fix options:

  • Hard-disable it:
    • set commands.restart: false
  • Or restrict who is allowed to use commands/directives at all:
    • set commands.allowFrom to only your number/user(s)

Also consider disabling WhatsApp “config writes” if you don’t want config changes initiated via the channel:

  • channels.whatsapp.configWrites: false (WhatsApp doc mentions this)
#

What I need from you (so we don’t guess)

Paste:

  1. openclaw --version
  2. openclaw status --all (it’s designed to be shareable; tokens are redacted)
  3. The relevant parts of your openclaw.json (only these blocks):
  • agents (and per-agent tools/sandbox if set)
  • bindings
  • channels.whatsapp
  • commands
  • session

Also: is this happening in a WhatsApp group, DMs, or both? That changes the “missing info” + memory behavior a lot.

plain basinBOT
#

Pulled your paste — a few things jump out that map exactly to the 3 problems you described.

A) “Family agent can’t keep memories”

In your config all WhatsApp traffic is routed to the relationships agent:

bindings: [
  { agentId: "relationships", match: { channel: "whatsapp" } }
]

So any “memory” for WhatsApp will live in /home/exedev/.openclaw/workspace-relationships/, not your main workspace.

Also: you set

#
session: { dmScope: "per-channel-peer" }

This is good for privacy/security, but it means each family member DM is a separate session, so the agent will not “remember what person A said” when person B DMs later unless it was written to disk memory.

What to do:

  1. Make sure you’re asking it to write memory (OpenClaw memory is Markdown-on-disk; it won’t “just remember” unless it writes). Docs: https://docs.openclaw.ai/concepts/memory
  2. Verify memory indexing is healthy for that agent:
  3. If your goal is “shared family knowledge across DMs”, keep dmScope: per-channel-peer (recommended) and adjust the relationships agent prompt (SOUL/AGENTS) to:
    • “When user says remember / important family info → write to memory”
    • “Before answering family questions → run memory_search”

B) “It misses info while relaying”

#

If this is happening in a WhatsApp group, the default behavior is: it only reliably responds when triggered (mentions / reply-to), and then it injects some backlog (default is 50 messages).

You currently don’t have any channels.whatsapp.groups config, so you’re relying on defaults.

What to do (pick the behavior you want):

  • If you want the bot to “see everything” in the family group: allow that group explicitly and disable mention-gating for it.
  • If you want to keep mention-gating, increase the backlog injection so it “catches up” better:
    • set channels.whatsapp.historyLimit higher (e.g. 100–200)

WhatsApp behavior + history injection docs: https://docs.openclaw.ai/channels/whatsapp

C) “Anyone can restart gateway”

This one is 100% explained by your config:

commands: {
#
  restart: true
}

By default, any authorized sender (your WhatsApp allowlist / pairing) can run /restart. So if you allowlist multiple family members, they can all restart it.

Fix options:

  1. Easiest: turn it off
commands: { restart: false }
  1. Better: keep restart, but restrict commands to only you using commands.allowFrom. To do that safely, first run /whoami from WhatsApp as the owner/admin, then put that ID into commands.allowFrom. Docs: https://docs.openclaw.ai/tools/slash-commands

Also worth running:

  • openclaw security audit (and optionally --fix)
#

Docs: https://docs.openclaw.ai/gateway/security and https://docs.openclaw.ai/cli/security


One extra thing (not your question, but important): your coder agent has agentDir set to the workspace path:

{ id: "coder", workspace: ".../workspace-coder", agentDir: ".../workspace-coder" }

Multi-agent docs explicitly warn not to reuse/mispoint agentDir (it can cause state/auth/session weirdness). Recommended layout is under ~/.openclaw/agents/<agentId>/agent. Docs: https://docs.openclaw.ai/concepts/multi-agent


Quick question so I can give you the exact snippet to paste: are you using the family agent mainly in (1) WhatsApp DMs, (2) a WhatsApp group, or (3) both?

#

Your config explains all 3 symptoms pretty cleanly — the fixes are mostly policy/routing, not “WhatsApp is broken”.

1) Why the family agent “can’t keep memories”

All WhatsApp traffic is routed to relationships:

{ agentId: "relationships", match: { channel: "whatsapp" } }

So any memory files live in:
/home/exedev/.openclaw/workspace-relationships/ (not the main workspace).

The bigger gotcha: you’re using QMD memory backend, and QMD recall is DM-only by default unless you open its scope. So if you’re testing in a WhatsApp group, memory_search can be denied → it looks like the bot “forgets”. (Docs call this out: you must loosen memory.qmd.scope to allow groups.)
Docs: https://docs.openclaw.ai/concepts/memory

Fix (if you want memory recall inside a WhatsApp group):
Add a QMD scope rule that allows that group session key (safest: only that one group, not all groups). Session keys for WhatsApp groups look like:

#

agent:relationships:whatsapp:group:<jid>

memory: {
  backend: "qmd",
  qmd: {
    // keep your existing fields...
    scope: {
      default: "deny",
      rules: [
        { action: "allow", match: { chatType: "direct" } },

        // Allow only ONE specific WhatsApp family group:
        { action: "allow", match: { rawKeyPrefix: "agent:relationships:whatsapp:group:120363...@g.us" } },
      ],
    },
#
  }
}

If you tell me whether your problem is DMs vs a group, and (if group) the group JID, I can give you the exact line to paste.

2) “While relaying info it misses info”

In WhatsApp groups, the bot often only “wakes up” on mention/reply, and then injects only a limited backlog. If you want it to miss less context, bump the history injection:

channels: {
  whatsapp: {
    historyLimit: 200, // default is 50
  }
}
#

Docs: https://docs.openclaw.ai/channels/whatsapp (see “Pending group history injection” + historyLimit)

If you want it to respond without being mentioned, configure the specific group with requireMention: false (or use /activation always, but that’s higher cost + more spam risk).

3) “Anyone can restart gateway”

You explicitly enabled it:

commands: { restart: true }

So any authorized sender (anywhere you allow them: WhatsApp allowlist, Telegram allowlist, etc.) can run /restart.

Most practical fix: disable restart command entirely:

commands: { restart: false }
#

If you want restart enabled but only for you: set commands.allowFrom to only your sender id(s). Easiest way: send /whoami from your own chat, copy the sender id string exactly, then:

commands: {
  restart: true,
  allowFrom: {
    "*": ["<PASTE_YOUR_SENDER_ID_HERE>"]
  }
}

Docs: https://docs.openclaw.ai/tools/slash-commands

One more important bug in your config (unrelated, but fix it)

Your coder agent has:

#
agentDir: "/home/exedev/.openclaw/workspace-coder"

agentDir should not point at the workspace — it should be a dedicated per-agent state dir (otherwise you’ll get weird auth/session collisions over time). Multi-agent docs: https://docs.openclaw.ai/concepts/multi-agent


If you answer just this, I’ll give you the tightest “final” patch:

  • Are you using the family agent mostly in WhatsApp DMs, a WhatsApp group, or both?
  • If group: what’s the group JID (120363...@g.us)?
#

Got it — WhatsApp DMs only, and you want it to “remember across multiple people DMs”.

1) Cross‑DM memory: your config is already set up correctly for privacy, but you must use disk memory

You have:

session: { dmScope: "per-channel-peer" }

That means each family member DM is a separate session (good). But “cross DMs” only works if the agent writes shared facts into its workspace memory files (Markdown), and then reads them back via memory_search.

In your setup, WhatsApp routes to agent relationships, so the shared memory location is:

  • /home/exedev/.openclaw/workspace-relationships/MEMORY.md
  • /home/exedev/.openclaw/workspace-relationships/memory/YYYY-MM-DD.md

What to do (practical):

#
  • Create one shared file like memory/family.md and always write durable facts there (names, preferences, birthdays, schedules, etc.).
  • Instruct the agent (in that agent’s AGENTS.md or SOUL.md) something like:
    • “When you learn a durable family fact, write it to memory/family.md.”
    • “Before answering questions about family, run memory_search.”

Sanity check from the CLI (this is the fastest way to confirm memory is working):

openclaw memory status --agent relationships --deep
openclaw memory search --agent relationships "some unique test phrase"

Docs: https://docs.openclaw.ai/cli/memory

If it’s writing but “not recalling immediately”: with QMD, indexing can be async—run:

openclaw memory index --agent relationships --verbose
#

2) “Anyone can restart gateway” — yes, because you enabled it

You currently have:

commands: { restart: true }

So any sender who is authorized (your WhatsApp allowlist) can run /restart.

You have two clean options:

Option A (recommended): just disable restart from chat

commands: { restart: false }

Option B: allow /restart only for YOU

  1. In WhatsApp DM, send: /whoami
#
  1. Copy the sender id it prints (exactly)
  2. Put that into:
commands: {
  restart: true,
  allowFrom: {
    "*": ["<PASTE_THE_/whoami_VALUE_HERE>"]
  }
}

Docs: https://docs.openclaw.ai/tools/slash-commands

3) “It misses info” in DMs

In DMs there’s no group “history injection” stuff — so if it’s “missing info”, 90% of the time it’s just not reading/writing memory, or you’re asking it to remember things without explicitly making it write.

#

A quick test: in WhatsApp DM tell it:

“Write this exact line into memory/family.md: MEMTEST-12345 and then confirm by reading it back.”

If it can’t do that, then we look at tool/sandbox restrictions (but your posted config doesn’t show any obvious tool denylist).

One question to finish this properly

When you said “done allow from” — did you mean:

  • channels.whatsapp.allowFrom (who can DM the bot), or
  • commands.allowFrom (who can run /restart, /config, directives, etc.)?

If you paste what /whoami returns for your own WhatsApp DM (you can redact the phone number if it contains it, but keep the format), I can tell you exactly what to put into commands.allowFrom so only you can restart.

#

Cool — then you’re on the right lever.

Goal: only you can run /restart (and other commands/directives)

  1. From your own WhatsApp DM to the bot, run:
  • /whoami
  1. Take the sender id it prints and set:
commands: {
  restart: true, // or false if you want to disable it completely
  allowFrom: {
    "*": ["<PASTE_YOUR_/whoami_SENDER_ID_HERE>"]
  }
}
#

That makes commands/directives authorized only for that id. Everyone else can still chat (per your channels.whatsapp.allowFrom), but they won’t be able to /restart, /model, /elevated, etc.
Docs: https://docs.openclaw.ai/tools/slash-commands

  1. Restart the gateway after changing config:
openclaw gateway restart

If you want family to use some commands but not restart

Easiest is still: disable restart globally:

commands: { restart: false }

Because commands.allowFrom is all-or-nothing for “command auth”.

#

Paste the output of /whoami (redact any phone number digits if you want, but keep the overall format), and I’ll tell you if it looks correct for WhatsApp and exactly what to paste into commands.allowFrom.

#

Yes — you can sandbox just the relationships agent. Sandboxing is per-agent via agents.list[].sandbox (it overrides agents.defaults.sandbox). Docs: https://docs.openclaw.ai/gateway/sandboxing and https://docs.openclaw.ai/tools/multi-agent-sandbox-tools

Minimal “sandbox relationships, keep memory working, allow browser”

Add this to your agents.list entry for relationships:

agents: {
  list: [
    {
      id: "relationships",
      sandbox: {
        mode: "all",
        scope: "agent",

        // IMPORTANT: without rw, the agent can’t persist Markdown memory in its workspace.
        workspaceAccess: "rw",
#

        // Optional but recommended if you want web installs/tools inside exec:
        // docker: { network: "bridge" },

        // This enables a Chromium+CDP browser *inside the sandbox*.
        browser: {
          enabled: true,
          // keep allowHostControl false unless you really want it to drive your host browser
          // allowHostControl: false,
        },
      },
    },
  ],
}
#

Notes:

  • workspaceAccess: "rw" is what makes “remembering” actually stick (memory is Markdown in the workspace).
  • The sandboxed browser is controlled by the normal browser tool, and sandboxed sessions may default to target="sandbox". Browser docs: https://docs.openclaw.ai/tools/browser

Important clarification about “run openclaw inside the sandbox”

If by “use openclaw” you mean “run openclaw ... via exec”:

  • exec in a sandbox runs inside the container, and the container usually won’t have the openclaw binary installed unless you install it there (custom image or sandbox.docker.setupCommand + network + writable root).
  • If you instead set exec host=gateway (or use elevated), that runs on the host and bypasses sandbox isolation.

So: sandbox is great for isolating tools, but it doesn’t magically make host CLIs available inside the container.

After you change config

Run:

If you had old containers already:

#
  • openclaw sandbox recreate --agent relationships
  • and if you enable the sandbox browser: openclaw sandbox recreate --agent relationships --browser

If you tell me what you want relationships to be able to do with exec (none / safe commands / full), I can suggest a sane tool policy for a family DM agent.

#

Yep — and “safe commands” is the right instinct for a family/relationships agent.

There are two different things people mean by this:

  1. Sandboxing (Docker) = limits filesystem/process blast radius
  2. Command allowlisting = limits what exec is allowed to run

Recommendation for a relationships agent (best-practice)

Don’t allow exec at all for the relationships agent. Give it:

  • memory read/write (so it can actually remember)
  • web_fetch/web_search + browser (for info gathering)
  • no shell access

That’s the cleanest way to avoid “someone DMs it and it runs something”.

Example per-agent config:

#
{
  agents: {
    list: [
      {
        id: "relationships",
        sandbox: {
          mode: "all",
          scope: "agent",
          workspaceAccess: "rw",
          browser: { enabled: true },
        },
        tools: {
          // keep it tight; add more only if you need it
          allow: [
            "group:memory",
#
            "group:web",
            "browser",
            "read", "write", "edit"
          ],
          deny: [
            "group:runtime",     // exec + process
            "group:automation",  // cron + gateway
            "nodes",
            "canvas"
          ]
        }
      }
    ]
  }
}
#

Docs:

If you really want exec, “safe commands” needs a different approach

OpenClaw doesn’t have a perfect “allow only these shell commands” filter for sandbox exec strings. The robust way is:

  • Keep relationships agent sandboxed
  • Still deny exec there
  • Do any CLI work in a separate “ops/coder” agent where you run exec on the gateway host with approvals + allowlist (so you can strictly control binaries)

For host exec hardening, see:

Quick way to verify your sandbox is actually applied

After editing config + restarting:

#
openclaw gateway restart
openclaw sandbox explain --agent relationships

CLI docs: https://docs.openclaw.ai/cli/sandbox

If you tell me what you mean by “safe commands” (e.g. “allow sqlite3 + jq only”, or “allow git”, etc.), I can suggest whether to:

  • keep exec fully denied (my default for relationships), or
  • split into a separate agent that’s built for exec with approvals.
#

Yes — OpenClaw supports approval-gated exec for the gateway host (and for nodes). It’s called Exec approvals. Docs: https://docs.openclaw.ai/tools/exec-approvals

How it works (important mental model):

  • exec can run in a sandbox or on the real gateway/node host.
  • Exec approvals are the “interlock” for host execution (host=gateway or host=node): allowlist + prompt (“Allow once / Always allow / Deny”).
  • Approvals live on the execution host in: ~/.openclaw/exec-approvals.json
  • If a prompt is required but no UI is reachable, askFallback decides (default recommended: deny).

Minimal setup (main agent has exec with approvals)

1) Lock commands so family can’t change exec mode / approve things

Since you already want commands.allowFrom, keep it so only you can run directives like /exec and approve prompts with /approve.

Docs (commands auth): https://docs.openclaw.ai/tools/slash-commands

2) Make main agent run exec on the gateway with allowlist+prompt

In config:

#
tools: {
  exec: {
    host: "gateway",        // run on gateway host (not sandbox)
    security: "allowlist",  // only allow allowlisted binaries without prompting
    ask: "always",          // prompt every time (safest)
    // ask: "on-miss",       // (optional) only prompt if not allowlisted
  },
  elevated: {
    enabled: false,         // recommended: don’t allow bypassing approvals
  },
}

(You can also do this only for the main agent via agents.list[].tools.exec.* if you prefer.)

Exec tool docs: https://docs.openclaw.ai/tools/exec

#

3) Configure the approvals policy + allowlist

Easiest ways:

Control UI → Nodes → Exec approvals (Gateway target)

or via CLI (openclaw approvals docs): https://docs.openclaw.ai/cli/approvals
Examples:

openclaw approvals get --gateway

# Add a safe allowlisted binary (example)
openclaw approvals allowlist add --gateway --agent main "/usr/bin/uptime"

If you set ask: "always", you’ll get a prompt for every command.
If you set ask: "on-miss", allowlisted binaries run without prompting, everything else prompts.

#

Optional: approve from chat (instead of UI)

You can forward approval prompts into a chat and respond with:

/approve <id> allow-once|allow-always|deny

That’s also in the exec approvals doc (section “Approval forwarding to chat channels”).


If you tell me where you want to approve (Control UI only vs approve-from-Telegram/WhatsApp), I’ll suggest the cleanest config so only you can approve and nobody in family DMs can trigger/approve exec.

#

Yes — you can approve exec from WhatsApp, and you only need a couple config changes.

1) Forward exec approval prompts to your WhatsApp DM

Add this to openclaw.json:

approvals: {
  exec: {
    enabled: true,

    // simplest: send approval prompts to these targets
    mode: "targets",

    // only for the main agent (so family/relationships agent never spams approvals)
    agentFilter: ["main"],
#
    targets: [
      {
        channel: "whatsapp",
        // WhatsApp target format is E.164 (docs: openclaw message)
        to: "+15551234567"
      }
    ]
  }
}

When an exec needs approval, you’ll get a WhatsApp message and you can reply:

  • /approve <id> allow-once
  • /approve <id> allow-always
  • /approve <id> deny
#

3) Main agent: exec should require approvals (allowlist + ask)

For the main agent, set exec to run on the gateway host, and require prompts:

agents: {
  list: [
    {
      id: "main",
      tools: {
        exec: {
          host: "gateway",
          security: "allowlist",
          ask: "always"     // prompts every time (safest)
          // ask: "on-miss"  // prompts only when not allowlisted
        }
      }
#
    }
  ]
},

tools: {
  elevated: { enabled: false } // don’t allow bypassing approvals
}

Then maintain the allowlist in Control UI (Nodes → Exec approvals → Gateway) or via CLI:
openclaw approvals allowlist add --gateway --agent main "/usr/bin/uptime"
Docs: https://docs.openclaw.ai/cli/approvals

4) Relationships agent: keep it “no exec”

Since WhatsApp DMs route to relationships in your config, I’d explicitly deny runtime tools there:

#
agents: {
  list: [
    {
      id: "relationships",
      tools: {
        deny: ["group:runtime"] // blocks exec + process
      }
    }
  ]
}

That way family can’t even trigger approval prompts; only your main agent can.


#

If you paste your /whoami result from WhatsApp (just the id string), I can tell you exactly what to put into commands.allowFrom so /approve works for you but nobody else.

#

Sandboxing isn’t required to run a family/relationships agent — but for the security model you described (“let family use browser + shell tools, but never touch my main PC / main+coder workspaces”), sandboxing is the cleanest way to get there.

Below is a setup that addresses your 3 concerns.


0) Key clarification (important)

commands.allowFrom only controls slash commands/directives (/restart, /exec, /approve, etc.).

It does not stop the model from using tools during normal chat unless you also restrict tools (and/or sandbox them).

So you want tool policy + sandboxing, not just command allowlists.


1) “No one should be able to change main/coder workspace — only relationships workspace”

Do this:

#

A) Sandbox the relationships agent and only mount its workspace

For the relationships agent:

agents: {
  list: [
    {
      id: "relationships",
      sandbox: {
        mode: "all",
        scope: "agent",

        // This ensures any writes go only to the relationships workspace
        workspaceAccess: "rw",

        // If you want browser inside the sandbox:
#
        browser: { enabled: true },

        // If you want it to fetch/install stuff from the internet via exec:
        // docker: { network: "bridge" },
      },
    },
  ]
}

With this, even if the relationships agent uses exec/write, it’s operating inside a Docker container whose writable workspace is the relationships workspace only.

B) Also set filesystem tools to workspace-only (extra safety)

Add globally (good baseline even without sandboxing):

#
tools: {
  fs: { workspaceOnly: true }
}

(That prevents accidental reads/writes outside the workspace when tools run on the host.)


2) “I want shell tools + browser for everyone, but don’t want it to affect my main PC; if it affects host, require allowlist/approval”

Split it like this:

Relationships agent (family DMs): exec allowed only in sandbox

  • Allow exec, but keep it sandboxed (so it can’t touch your host).
  • Do not allow elevated host exec for this agent.
#

Example:

agents: {
  list: [
    {
      id: "relationships",
      tools: {
        // allow the capabilities you want for family
        allow: ["group:fs", "group:runtime", "group:web", "group:memory", "browser"],

        // prevent anything that can mutate gateway/config or reach other devices
        deny: ["group:automation", "nodes", "canvas"],

        // critical: don’t let this agent ever use host-elevated exec
        elevated: { enabled: false },
#
      }
    }
  ]
}

Main agent (you): host exec with approvals

Keep host exec for you only, with approvals:

  • Configure exec approvals (~/.openclaw/exec-approvals.json) via Control UI or openclaw approvals …
  • Forward approval prompts to WhatsApp (so you can /approve)

Config to forward approvals:

#
approvals: {
  exec: {
    enabled: true,
    mode: "targets",
    agentFilter: ["main"],
    targets: [{ channel: "whatsapp", to: "+YOUR_NUMBER" }]
  }
}

And keep commands.allowFrom locked to you so only you can /approve:

commands: {
  allowFrom: { "*": ["<YOUR_ID_FROM_/whoami>"] },
#
  restart: false
}

Docs for approvals: https://docs.openclaw.ai/tools/exec-approvals


3) “Multiple family members DM the relationships agent; I want cross-memory + remember owner + relay but stop pinging / abort misuse”

A) Cross-memory across DMs

You already did the correct thing with:

session: { dmScope: "per-channel-peer" }

That isolates conversation context per person (privacy). Cross-DM “memory” should come from disk memory, not shared chat context.

#

So: in the relationships workspace, keep a shared memory file like:

  • memory/family.md

And teach the relationships agent (in its AGENTS.md or SOUL.md) rules like:

  • “When you learn durable family facts, write to memory/family.md.”
  • “Before answering family questions, run memory_search.”

This gives you shared “family brain” while keeping DM sessions separate.

Docs: https://docs.openclaw.ai/concepts/memory

B) Remember who the owner is

Two layers:

  1. Hard security layer (recommended): owner-only commands.allowFrom (you already want this). That guarantees only you can /restart, /approve, /exec, etc.
  2. Soft behavior layer: store “Owner = +E.164 number / name” in memory/family.md and tell the agent to treat that sender as “operator/owner”.

C) “Relay messages” without getting abused

#

This is the risky part. Relaying means the agent can message other people on WhatsApp. If you allow that to everyone, someone can spam.

My recommendation:

  • Do not give the relationships agent cross-context messaging tools by default.
  • Instead: make it draft the message text and ask the owner to approve (you) — or require /send on in that session before it can relay.

There’s a built-in owner-only control:

If you tell me how you currently “relay” (are you using the message tool? or sessions_send?), I’ll give the exact safest config for that path.


Quick “do I still need sandboxing?”

  • If you deny exec/process/browser for family: sandboxing is optional.
  • If you want family to have shell + browser but keep host safe: yes, sandboxing is strongly recommended (relationships agent only is fine).
#

If you paste your current relationships agent tools block (or confirm you haven’t set one yet), I can propose the tightest allow/deny list that matches exactly what you want it to do.

#

“Shared chat context” and “nobody else can have it” are in tension in a multi‑DM WhatsApp setup.

What’s actually possible (and what isn’t)

  • If you set shared DM context (session.dmScope: "main"), then every person who can DM the bot shares the same context. That means any family member can indirectly see/steer what you discussed with the bot (context leakage risk). Docs call this out as unsafe for multi-user inboxes.
  • There is no way to have one single shared context “in the model’s head” but guarantee other allowed DM senders can’t influence or extract it. If they share the session, they can prompt it out.

So you have 2 sane patterns:

Pattern A (recommended): private shared context for you, isolated DMs for everyone else

Keep your global DM isolation:

session: { dmScope: "per-channel-peer" }

Then route your WhatsApp DM to the main agent (your private context + tools), and route everyone else to relationships.

#

Example bindings (add your number explicitly above the catch-all):

bindings: [
  // you -> main agent
  {
    agentId: "main",
    match: { channel: "whatsapp", peer: { kind: "direct", id: "+YOUR_NUMBER" } }
  },

  // everyone else on WhatsApp -> relationships agent
  { agentId: "relationships", match: { channel: "whatsapp" } },
]

Result:

  • You get a consistent, private ongoing session (for your DM).
#
  • Family members get their own isolated sessions (no leaking between them).
  • “Cross-family memory” is done via disk memory in the relationships workspace (e.g. memory/family.md), not by sharing chat context.

Pattern B: shared context for the family = use a WhatsApp group

If you truly want “one shared conversation” among family, put them in a single WhatsApp group with the bot. Then the shared context is safe because it’s literally shared/visible to everyone in the group anyway.

(Doing “shared context” across separate DMs is where it becomes unsafe.)


For your stated goals

  1. Shared chat context, but nobody else gets it → Pattern A (route your DM to main, keep dmScope per-channel-peer).
  2. Relationships agent cross-memory → keep DMs isolated, but write shared facts into workspace-relationships/memory/family.md and have the agent use memory_search before answering.

If you tell me whether you want you = main agent and family = relationships agent (sounds like yes), I can paste a complete minimal config block (bindings + command lockdown + tool restrictions) that matches that exactly.

#

Do both.

  • Sandboxing is what stops the “family agent” from touching your host machine / other workspaces even if it gets tricked.
  • Tool/exec policies are what stop it from doing dangerous things even inside the sandbox (and they’re your last line of defense if anything ever runs on host).

If your requirements are:

  1. relationships agent can only affect relationships workspace
  2. main agent can do powerful stuff, but only with approvals/allowlist
  3. browser state should be persistent (logins/cookies)

…then this is the clean setup.


A) Relationships agent (family DMs): sandbox + persistent sandbox browser + no host impact

#

1) Sandbox it “always” and keep the same container

Use scope: "agent" so the container (and its browser state) persists across DMs:

agents: {
  list: [
    {
      id: "relationships",
      sandbox: {
        mode: "all",
        scope: "agent",
        workspaceAccess: "rw",     // so memory files persist in workspace-relationships
        browser: { enabled: true } // Chromium inside the sandbox
      },

      // Strongly consider denying the high-risk “control plane” tools here:
#
      tools: {
        deny: [
          "group:automation", // cron + gateway
          "nodes",
          "agentToAgent"      // prevents leaking into other agents
        ]
      }
    }
  ]
}

Persistence note: sandboxed browser cookies/logins persist as long as that sandbox container isn’t recreated/pruned. If you run openclaw sandbox recreate …, you’re effectively “factory resetting” that sandbox environment.

Docs: https://docs.openclaw.ai/gateway/sandboxing

#

2) Add global filesystem guardrails anyway

Even with sandboxing, this is a good baseline:

tools: {
  fs: { workspaceOnly: true }
}

This makes it much harder for any host-running fs tool to read/write outside workspaces.


B) Main agent (you): host exec with approvals + persistent managed browser

1) Keep your main agent unsandboxed (or sandbox optional)

Your main agent is the one you’ll approve commands for, so it can run on host and still be safe because of approvals.

#

2) Exec approvals (host) + approve from WhatsApp

You already want “approve from WhatsApp”. Keep:

  • commands.allowFrom = only you (so nobody else can /approve, /exec, /restart)
  • approvals.exec forwarding to your WhatsApp DM
  • main agent exec set to host: "gateway" and prompt via approvals

Forward approval prompts to WhatsApp:

approvals: {
  exec: {
    enabled: true,
    mode: "targets",
    agentFilter: ["main"],
    targets: [{ channel: "whatsapp", to: "+YOUR_NUMBER" }]
  }
#
}

Lock commands to only you:

commands: {
  restart: false,
  allowFrom: { "*": ["<YOUR_/whoami_ID>"] }
}

Main agent exec defaults (host + allowlist + prompt):

agents: {
  list: [
#

3) Persistent browser for main agent

You already have browser.enabled: true and defaultProfile: "openclaw" in your config — that’s the managed persistent profile (separate from your personal Chrome profile). That’s exactly what you want for “persistent things in the browser”.

Docs: https://docs.openclaw.ai/tools/browser


C) About “shared chat context” vs “shared memory” (your DM-only family setup)

For multiple family members in DMs, you should keep:

session: { dmScope: "per-channel-peer" }

That prevents private-context leakage between family members (this is a big deal).

#

Then do “shared family knowledge” via disk memory in the relationships workspace (e.g. memory/family.md), not by sharing one DM session. That gives you “cross-memory” without letting one person mine another person’s DM context.

Docs: https://docs.openclaw.ai/concepts/session (secure DM mode) and https://docs.openclaw.ai/concepts/memory


One more critical thing (based on your paste earlier)

Your tools.agentToAgent.enabled was true and allowed all agents. If your goal is “nobody else gets main/coder context”, I would disable agent-to-agent or allow only main → others (not relationships → main).

Otherwise the relationships agent can potentially bounce prompts into main/coder sessions.


If you want, paste your current agents.list blocks for main and relationships (just those two), and I’ll rewrite them into one cohesive “drop-in” config snippet that matches your exact intent (including a safe default tool allowlist for relationships: browser + memory + web, but no gateway/nodes/agentToAgent).

#

Do both: sandboxing + tool/exec policy. That’s the combo that gets you:

  • family can use “power tools” (browser/exec) without touching your host
  • your main agent can still do host-level exec, but only with approvals
  • browser state stays persistent (cookies/logins), and sandbox state stays persistent (as long as you don’t recreate/prune containers)

Below is a concrete “shape” that matches your 3 goals.


1) Hard boundary: relationships agent can only affect relationships workspace

Add per-agent sandboxing for relationships:

agents: {
  list: [
#
    {
      id: "relationships",
      workspace: "/home/exedev/.openclaw/workspace-relationships",

      sandbox: {
        mode: "all",
        scope: "agent",          // one long-lived container for this agent (persistence)
        workspaceAccess: "rw",   // REQUIRED for memory persistence

        // If you want web_fetch + package installs to work from inside sandboxed tools:
        docker: { network: "bridge" },

        // Persistent browser inside Docker:
        browser: { enabled: true },
#
        // Optional: keep it around longer (so browser logins + installs persist)
        prune: { idleHours: 720, maxAgeDays: 90 },
      },

      tools: {
        // “Full-ish” tools but no control-plane / no cross-agent messaging:
        deny: [
          "group:automation", // cron + gateway
          "nodes",
          "agentToAgent",
          "sessions_send",
          "sessions_spawn",
          "message"           // IMPORTANT: prevents “relay/spam other people”
        ]
      }
#
    }
  ]
}

Also add this global guardrail (helps even if something runs on host later):

tools: { fs: { workspaceOnly: true } }

This makes it much harder for any agent to read/write outside its workspace via fs tools.

Docs: https://docs.openclaw.ai/gateway/sandboxing


#

2) Main agent: host exec but only with approvals (approve from WhatsApp)

A) Lock commands/directives (so only you can /approve, /restart, /exec, etc.)

commands: {
  restart: false,
  allowFrom: { "*": ["<YOUR_/whoami_ID>"] }
}

B) Forward exec approval prompts to your WhatsApp DM

approvals: {
  exec: {
    enabled: true,
    mode: "targets",
    agentFilter: ["main"],
#
    targets: [{ channel: "whatsapp", to: "+YOUR_NUMBER" }]
  }
}

Then you approve by replying in WhatsApp:

  • /approve <id> allow-once
  • /approve <id> allow-always
  • /approve <id> deny

Docs: https://docs.openclaw.ai/tools/exec-approvals

C) Main agent exec defaults = host + allowlist + prompt

agents: {
#
  list: [
    {
      id: "main",
      tools: {
        exec: { host: "gateway", security: "allowlist", ask: "always" }
      }
    }
  ]
},
tools: {
  elevated: { enabled: false } // don’t allow bypassing approvals
}

#

3) DMs with multiple family members: “shared memory” without shared chat context

For DMs, keep:

session: { dmScope: "per-channel-peer" }

This is the correct privacy setting.

Then “cross memory” happens via disk memory in the relationships workspace, not by sharing one DM transcript. Concretely:

  • create/use workspace-relationships/memory/family.md
  • instruct the relationships agent to always write durable family facts there, and to run memory_search before answering.

That gives you “shared family brain” across all DMs without letting family members see each other’s DM chat context.

Docs: https://docs.openclaw.ai/concepts/session and https://docs.openclaw.ai/concepts/memory

#

Persistence: “in browser, in docker, everywhere”

You’ll get persistence if you follow these rules:

  • Don’t run openclaw sandbox recreate … unless you want a reset
  • increase sandbox.prune.idleHours/maxAgeDays (as above)
  • for sandboxed browser persistence: keep scope: "agent" + don’t prune/recreate

Also, sandbox browser persistence is separate from your host “openclaw” browser profile. That’s good (two different trust zones).


Quick sanity checklist

After you change config:

#
openclaw gateway restart
openclaw sandbox explain --agent relationships
openclaw sandbox list --browser

If you want, paste your current top-level blocks for tools, commands, approvals, and memory (redact secrets) and I’ll merge the snippets into your existing config cleanly (so you don’t accidentally override something).

#

If you keep the relationships agent deny: ["message", "sessions_send", ...] like in that snippet, then no — the relationships agent will not be able to proactively “relay” (send messages) to other people/chats. That’s exactly why I suggested denying it: it prevents a family member from turning the bot into a spam cannon.

The safe way to still relay to friends

Relay should be a you-only capability (main agent), not something every family DM can trigger.

Do this:

  1. Only you get routed to the main agent on WhatsApp (everyone else still goes to relationships).
  2. Only the main agent gets the message tool (and cross-context sending if you need it).

1) Add a binding so your WhatsApp DM goes to main

Put this binding above the catch-all WhatsApp binding:

bindings: [
  {
    agentId: "main",
#
    match: { channel: "whatsapp", peer: { kind: "direct", id: "+YOUR_NUMBER" } }
  },
  { agentId: "relationships", match: { channel: "whatsapp" } }
]

2) Allow message only on main, keep it denied on relationships

agents: {
  list: [
    {
      id: "main",
      tools: {
        allow: ["message"] // plus whatever else you want on main
      }
#
    },
    {
      id: "relationships",
      tools: {
        deny: ["message", "sessions_send", "sessions_spawn", "agentToAgent"]
      }
    }
  ]
}

3) Enable cross-context sending only where you actually need it

To “relay to friends” from main, you likely need within WhatsApp cross-context sending:

#
tools: {
  message: {
    crossContext: {
      allowWithinProvider: true,
      allowAcrossProviders: false
    }
  }
}

Important limitation / warning

OpenClaw has exec approvals (great), but there is no equivalent “approval prompt” for the message tool. So if you enable message for the relationships agent, you should assume any allowed DM sender can social-engineer it into messaging random people.

So: relationships = no relay, main (you-only) = relay is the safest split.

If you paste what you currently have under tools.message.crossContext (you had it already in the big config paste) and confirm whether you want relays WhatsApp-only or also Telegram/Discord, I’ll give you the tightest settings for that.

#

WhatsApp-only relay is totally doable — just make sure only your main agent has the ability to send to arbitrary WhatsApp targets, and your relationships agent cannot.

1) Route your WhatsApp DM to main, everyone else to relationships

Put this above the catch‑all WhatsApp binding:

bindings: [
  {
    agentId: "main",
    match: { channel: "whatsapp", peer: { kind: "direct", id: "+YOUR_NUMBER" } }
  },

  { agentId: "relationships", match: { channel: "whatsapp" } },
]

Now: you DM the bot → main agent (relay allowed).

#

Family DMs → relationships agent (relay not allowed).

2) Allow WhatsApp cross-context sending, but ONLY within WhatsApp

Change this (you currently had allowAcrossProviders=true in your paste) to:

tools: {
  message: {
    crossContext: {
      allowWithinProvider: true,
      allowAcrossProviders: false
    }
  }
}

That means: main agent can message other WhatsApp chats/numbers, but can’t jump to Telegram/Discord etc.

#

3) Tool policy: main can message, relationships cannot

This is the critical safety piece:

agents: {
  list: [
    {
      id: "main",
      tools: {
        allow: ["message"]   // you can relay from your DM
      }
    },

    {
      id: "relationships",
      tools: {
#
        deny: [
          "message",         // prevents relaying/spam from family DMs
          "sessions_send",
          "sessions_spawn",
          "agentToAgent"
        ]
      }
    }
  ]
}

Important gotcha: if you have a global tools.deny: ["message"], then you can’t re-enable it per-agent. So keep message allowed globally and deny it only on relationships.

Why this split matters

There is no “message approvals” UI like there is for exec. So if the relationships agent can call message, any family member could potentially social-engineer it into messaging random people. Keeping message exclusive to your main DM avoids that.

#

If you want, paste your current top-level tools block (just that block), and I’ll tell you exactly what to change without breaking your existing setup.

#

Your current tools block has two settings that break your “WhatsApp-only + no cross-agent leakage” goal:

  1. allowAcrossProviders: true (lets the bot hop WhatsApp → Telegram/Discord/etc)
  2. agentToAgent.enabled: true with allow: ["main","relationships","coder"] (lets agents talk to each other, which is exactly how private context can leak across your boundaries)

Here’s what I’d change.


1) Make messaging WhatsApp-only

Change:

message: {
  crossContext: {
    allowWithinProvider: true,
#
    allowAcrossProviders: true
  }
}

to:

message: {
  crossContext: {
    allowWithinProvider: true,
    allowAcrossProviders: false
  }
}
#

Now it can still relay within WhatsApp, but cannot jump providers.


2) Disable agent-to-agent messaging (recommended)

Change:

agentToAgent: {
  enabled: true,
  allow: ["main", "relationships", "coder"]
}

to:

#
agentToAgent: { enabled: false }

This removes a major “escape hatch” where the relationships agent could potentially bounce instructions/context into main/coder.

If you must keep agent-to-agent for some workflow, tell me what for — but for your use case, disabling it is the right default.


3) Keep your “relay” ability, but only from main (per-agent tool policy)

You’ll also want per-agent tool restrictions (because the top-level tools block is global defaults).

  • main: allow message
  • relationships: deny message (so family can’t turn it into a spam cannon)

Example:

#
agents: {
  list: [
    {
      id: "main",
      tools: { allow: ["message"] }
    },
    {
      id: "relationships",
      tools: {
        deny: ["message", "sessions_send", "sessions_spawn", "agentToAgent"]
      }
    }
  ]
}
#

(And make sure your bindings route your WhatsApp DM to main, everyone else to relationships, like we discussed.)


Your updated tools block would look like:

tools: {
  web: { fetch: { enabled: true } },
  media: { image: { enabled: true }, video: { enabled: true, deepgram: { detectLanguage: true, punctuate: false, smartFormat: true } } },
  links: { enabled: true },
  sessions: { visibility: "self" },

  message: {
    crossContext: {
      allowWithinProvider: true,
      allowAcrossProviders: false
#
    }
  },

  agentToAgent: { enabled: false }
}

After this, restart the gateway (openclaw gateway restart) and you should be in the “WhatsApp-only relay, no cross-provider, no cross-agent leakage” posture.

#

You can get better diagnostics, but for anti-spam you need to be clear about one thing:

Reality check

The message tool has no “approval prompt” system like exec does. So if an agent has message + cross-context enabled, the only hard safety controls are:

  • which agent has the tool
  • who can reach that agent (bindings)
  • and whether cross-context is enabled (allowWithinProvider)

So “don’t spam” = mostly policy/routing, not “turn on approvals”.


Recommended setup (WhatsApp-only relay, non-spammy)

1) Keep cross-context WhatsApp only (you already want this)

Change to:

#
tools: {
  message: {
    crossContext: {
      allowWithinProvider: true,
      allowAcrossProviders: false
    }
  }
}

2) Only main can relay; relationships cannot

agents: {
  list: [
    { id: "main", tools: { allow: ["message"] } },
#

    { id: "relationships", tools: { deny: ["message"] } }
  ]
}

3) Route your WhatsApp DM to main, everyone else to relationships

Put your DM binding above the catch-all:

bindings: [
  { agentId: "main", match: { channel: "whatsapp", peer: { kind: "direct", id: "+YOUR_NUMBER" } } },
  { agentId: "relationships", match: { channel: "whatsapp" } }
]
#

This alone prevents “family member tells bot to message my friend” because they never reach the agent that has the tool.


Better diagnostics when a send fails

A) Turn on verbose temporarily in your main DM session

In your DM with the bot:

  • /verbose on (or /verbose full if you need details)

That will include more tool failure detail in-chat.

B) Check gateway logs (best signal)

On the gateway host:

openclaw logs --follow
#

C) Reproduce with the CLI (most deterministic)

From the gateway host:

openclaw message send --channel whatsapp --target +1555... --message "test"

Docs: https://docs.openclaw.ai/cli/message.md


If you want a hard anti-spam gate (actual approvals)

Since message tool doesn’t have approvals, the “hard gate” trick is:

  • keep message tool disabled (or don’t rely on it)
  • send via exec running openclaw message send ...
  • and let exec approvals prompt you “allow once / deny”
#

This is heavier, but it’s the only way to get an approval step for relays today.

Docs: https://docs.openclaw.ai/tools/exec-approvals


If you tell me which “better diagnostics” you mean (tool errors in chat vs logs vs metrics), I can point you to the exact switches to turn on (without making WhatsApp noisy).

#

You can use the message tool and still keep it “non-spammy”, but the trick is: there’s no approvals system for message (unlike exec). So you prevent spam by who is allowed to reach the agent that has message, plus a manual confirmation workflow, plus optional loop protection.

The safe pattern (WhatsApp-only relay)

1) Keep message cross-context WhatsApp-only

tools: {
  message: {
    crossContext: {
      allowWithinProvider: true,
      allowAcrossProviders: false
    }
  }
}

2) Only main gets message; relationships does not

#
agents: {
  list: [
    { id: "main", tools: { allow: ["message"] } },

    { id: "relationships", tools: { deny: ["message"] } }
  ]
}

3) Route only your WhatsApp DM to main
Put this binding before the catch-all WhatsApp one:

bindings: [
  { agentId: "main", match: { channel: "whatsapp", peer: { kind: "direct", id: "+YOUR_NUMBER" } } },
  { agentId: "relationships", match: { channel: "whatsapp" } }
#
]

Result:

  • Family can’t relay/spam because they never reach the agent that can send to arbitrary targets.
  • You can relay to friends from your DM with the bot (main agent).

“Better diagnostics” for message sends

Best options:

  1. In your DM session (main), temporarily enable:
  • /verbose on (or /verbose full)
  1. Follow gateway logs while testing:
#
openclaw logs --follow
  1. Reproduce with CLI (most deterministic error output):
openclaw message send --channel whatsapp --target +1555... --message "test"

Docs: https://docs.openclaw.ai/cli/message.md


“Don’t spam the relay” (practical guardrails)

Since message has no approvals, use one (or both) of these:

A) Human-in-the-loop habit (simple, effective)

Instruct your main agent (in AGENTS.md for main) something like:

#
  • “When asked to relay, draft the message + recipient and ask me to reply CONFIRM SEND before sending.”

Not cryptographically enforced, but it prevents accidental sends.

B) Enable tool loop detection (stops runaway repeats)

tools: {
  loopDetection: { enabled: true }
}

This won’t stop a single malicious send, but it helps prevent “model got stuck and sent 10 messages”.


One more thing: you currently have agentToAgent.enabled: true. If your goal is “no cross-agent leakage / no weird relays”, I’d set: