#discord bot refuse to execute tools

1 messages ¡ Page 1 of 1 (latest)

civic moon
#

Hi, I'm running openclaw with my local vllm, for example, ollama/qwen3:8b, and connects to discord through a bot. In my local openclaw tui, I was able to ask it to ls my home dir without issue. But when same query was sent through discord bot, it says something like "I cannot directly exectute commands ..." and advise me to execute ls command in my local machine .. All other normal chat queries sent through discord bot seems working fine.

Any idea what might be wrong here?

fossil graniteBOT
#

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

strong mirageBOT
#

This usually isn’t “Discord vs TUI” as such — it’s that your Discord messages are landing in a different session security context (often non‑main → sandboxed) and/or a different agent/tool profile, so the model never even sees the exec tool. When exec is not in the tool list, many models respond with the generic “I can’t run commands” style text.

First: what version are you on?

  • openclaw --version

Then, the quickest way to confirm what’s happening is to reproduce the Discord message, then run:

  • openclaw sandbox explain

That prints the effective sandbox mode + tool allow/deny for the session and usually makes the problem obvious. (Docs: https://docs.openclaw.ai/gateway/sandbox-vs-tool-policy-vs-elevated)

The common root causes

  1. Sandboxing for non-main sessions
    If you have agents.defaults.sandbox.mode: "non-main", then guild channels are “non-main” and run in Docker by default. The FAQ calls this pattern out explicitly.
    Source: https://docs.openclaw.ai/help/faq (see “Can I keep DMs personal but make groups public sandboxed with one agent”)
#
  1. Tool policy excludes runtime tools
    If your tool policy is set to a restrictive profile (like tools.profile: "messaging") or you have an allowlist that doesn’t include runtime tools, then exec/process won’t be available.

Key knobs to check:

  • tools.profile (profiles listed here: https://docs.openclaw.ai/tools)
  • tools.allow / tools.deny
  • if sandboxed: tools.sandbox.tools.allow / tools.sandbox.tools.deny (this one surprises people)

In config terms, exec lives in group:runtime (docs: https://docs.openclaw.ai/tools).

What to paste here (redact tokens)

If you paste these, I can tell you exactly which key is blocking it:

  • openclaw --version
  • openclaw sandbox explain
  • openclaw config get tools
#
  • openclaw config get agents.defaults.sandbox
  • (if you use multiple agents/bindings) openclaw config get agents.list and openclaw config get bindings

One security note: enabling exec from a Discord guild channel is effectively “remote shell by chat”, so it’s worth keeping it DM-only / allowlisted even if you make it work.

civic moon
#

@strong mirage

openclaw --version: 2026.2.26

openclaw sandbox explain

:lobster: OpenClaw 2026.2.26 (bc50708) — Claws out, commit in—let's ship something mildly responsible.

Effective sandbox:
  agentId: main
  sessionKey: agent:main:main
  mainSessionKey: agent:main:main
  runtime: direct
  mode: off scope: agent perSession: false
  workspaceAccess: none workspaceRoot: /xxx/.openclaw/sandboxes

Sandbox tool policy:
  allow (default): exec, process, read, write, edit, apply_patch, image, sessions_list, sessions_history, sessions_send, sessions_spawn, subagents, session_status
  deny  (default): browser, canvas, nodes, cron, gateway, telegram, whatsapp, discord, irc, googlechat, slack, signal, imessage

Elevated:
  enabled: true
  channel: webchat
  allowedByConfig: false
  failing gates: allowFrom (tools.elevated.allowFrom.webchat)

Fix-it:
  - tools.sandbox.tools.allow
  - tools.sandbox.tools.deny
  - agents.list[].tools.sandbox.tools.allow
  - agents.list[].tools.sandbox.tools.deny
  - tools.elevated.enabled
  - tools.elevated.allowFrom.webchat

Docs: docs.openclaw.ai/sandbox
strong mirageBOT
#

Good data point: that sandbox explain output is for your main session (sessionKey: agent:main:main, mode: off). So it’s not showing what Discord is using.

What we need is the Discord session key, then run sandbox explain against that session.

1) Find the Discord session key

Run (right after you send a message in Discord to make it “active”):

openclaw sessions --all-agents --active 120
# or:
openclaw sessions --all-agents --active 120 --json

You should see something with discord in the key, e.g. agent:main:discord:....

2) Explain that session

Then:

#
openclaw sandbox explain --session "<PASTE_DISCORD_SESSION_KEY_HERE>"

Paste that output here.

3) Also paste your effective tool config

Because your symptom (“I can’t execute commands…”) almost always means exec is not in the tool list for that Discord session (tool profile/allowlist/byProvider/per-agent policy), please also paste (redact secrets):

openclaw config get tools
openclaw config get agents.list
openclaw config get bindings   # if you use routing/bindings

What I expect we’ll find

One of these is usually true for Discord sessions:

#
  • Discord is routed to a different agent that has tools.profile: "messaging" (or an allow list that excludes group:runtime), so exec never gets offered to the model.
  • Discord sessions are “non-main” and sandboxed, and your sandbox tool policy (tools.sandbox.tools.* or agents.<id>.tools.sandbox.tools.*) is restricting tools.
  • Provider-specific restriction like tools.byProvider.ollama is narrowing tools for the Discord-run model but not for your TUI model.

Once you paste the Discord session’s sandbox explain, I can point to the exact config key that’s blocking exec.

civic moon
#

@strong mirage

openclaw sandbox explain --session agent:main:discord:channel:787050814426316833

🦞 OpenClaw 2026.2.26 (bc50708) — IPC, but it's your phone.

Effective sandbox:
  agentId: main
  sessionKey: agent:main:discord:channel:787050814426316833
  mainSessionKey: agent:main:main
  runtime: direct
  mode: off scope: agent perSession: false
  workspaceAccess: none workspaceRoot: /xxx/.openclaw/sandboxes

Sandbox tool policy:
  allow (default): exec, process, read, write, edit, apply_patch, image, sessions_list, sessions_history, sessions_send, sessions_spawn, subagents, session_status
  deny  (default): browser, canvas, nodes, cron, gateway, telegram, whatsapp, discord, irc, googlechat, slack, signal, imessage

Elevated:
  enabled: true
  channel: (unknown)
  allowedByConfig: false

Fix-it:
  - tools.sandbox.tools.allow
  - tools.sandbox.tools.deny
  - agents.list[].tools.sandbox.tools.allow
  - agents.list[].tools.sandbox.tools.deny
  - tools.elevated.enabled

Docs: docs.openclaw.ai/sandbox
strong mirageBOT
#

Nice — that rules out the “non‑main sessions are sandboxed + sandbox tool policy blocks exec” theory.

From your sandbox explain --session agent:main:discord:channel:...:

  • runtime: direct
  • mode: off

So sandboxing is not involved for that Discord channel session.

That leaves the other big reason you’d see “I can’t execute commands” in one channel but not in TUI:

Discord channel-level tool restrictions (tools / toolsBySender)

OpenClaw can restrict tools per group/room/channel, and Discord is one of the surfaces that supports it (nested under the guild/channel config). Docs:
https://docs.openclaw.ai/channels/groups#groupchannel-tool-restrictions-optional

If your Discord channel config has something like tools: { deny: ["exec"] } (or an allowlist that doesn’t include exec / group:runtime), then the model won’t be offered exec in that channel — and it will respond exactly like you’re seeing.

#

Quick check

Can you run and paste (redact tokens/secrets):

openclaw config get channels.discord.guilds
openclaw config get tools

And if you want to self-check faster: search that output for tools, toolsBySender, deny, allow.

What the fix typically looks like

  • Remove/adjust the channel’s tools.deny: ["exec"], or
  • Add a per-sender exception via toolsBySender (so only you can use exec in that channel)

The docs call out the precedence rules and show examples (same idea applies to Discord; it’s just nested under channels.discord.guilds.*.channels.*).

Once you paste the channels.discord.guilds block (or just the specific guild/channel entry), I can point to the exact stanza to change.

civic moon
#
openclaw config get channels.discord.guilds

🦞 OpenClaw 2026.2.26 (bc50708) — The UNIX philosophy meets your DMs.

Config path not found: channels.discord.guilds
openclaw config get tools


🦞 OpenClaw 2026.2.26 (bc50708) — If it works, it's automation; if it breaks, it's a "learning opportunity."

Config path not found: tools
#

@strong mirage

strong mirageBOT
#

Yep — those “Config path not found” errors just mean those keys aren’t present in your openclaw.json, not that the feature doesn’t exist.

Two gotchas here:

1) Discord “guilds” is often under the account

If you’re using the default Discord account config, the path is usually:

openclaw config get channels.discord.accounts
openclaw config get channels.discord.accounts.default.guilds
# (and/or)
openclaw config get channels.discord.accounts.default
openclaw config get channels.discord

In multi-account setups it’s very common that channels.discord.guilds is empty/missing, but channels.discord.accounts.default.guilds is where the per-guild/per-channel settings (including tools / toolsBySender) live.

#

What we’re hunting for is any stanza like:

  • guild-level: ...guilds.<GUILD>.tools: { deny: ["exec"] }
  • channel-level: ...guilds.<GUILD>.channels.<CHANNEL>.tools: { deny: ["exec"] }
  • sender override: toolsBySender: { "id:<you>": { alsoAllow: ["exec"] } }

Docs for this mechanism: https://docs.openclaw.ai/channels/groups#groupchannel-tool-restrictions-optional

2) Tool policy might be under the agent, not top-level tools

Similarly, tools can be configured per-agent, so top-level tools may be absent. Check:

openclaw config get agents.defaults.tools
openclaw config get agents.list

#

Next step

Can you paste the output of these (redact tokens)?

openclaw config get channels.discord.accounts
openclaw config get channels.discord.accounts.default.guilds
openclaw config get agents.defaults.tools
openclaw config get agents.list

Once we see where your Discord channel is defined, we can point to the exact tools / toolsBySender line that’s causing the “can’t execute commands” behavior.

#

I didn’t get any command output from that last ping — can you paste the results of the commands?

Start with these two (they’ll tell us whether you even have a Discord block / which config file you’re editing):

openclaw config file
openclaw config get channels.discord

Then (only if channels.discord exists):

openclaw config get channels.discord.accounts
openclaw config get channels.discord.accounts.default
openclaw config get channels.discord.accounts.default.guilds
#

And to rule out “Discord is using a different model than your TUI session”, also paste:

openclaw sessions --all-agents --active 120 --json

(That JSON includes the model per session key — we want to compare your agent:main:main session vs agent:main:discord:channel:....)

If channels.discord comes back as “Config path not found”, that means you’re likely running Discord from env defaults (e.g. just DISCORD_BOT_TOKEN) and there aren’t any per-channel tool restrictions configured — in that case the next most likely cause is model/tool-calling reliability or Discord using a different model.

civic moon
#
openclaw config get channels.discord

🦞 OpenClaw 2026.2.26 (bc50708) — If it works, it's automation; if it breaks, it's a "learning opportunity."

{
  "enabled": true,
  "token": "__OPENCLAW_REDACTED__",
  "groupPolicy": "open",
  "streaming": "off"
}

@strong mirage

strong mirageBOT
#

Cool — so you do have a channels.discord block, but it’s very minimal:

  • groupPolicy: "open"
  • no guilds / per-channel overrides shown
  • nothing there that would intentionally deny exec

At this point we need to answer one very specific question:

In that Discord channel session, is exec actually being offered to the model, and if yes, what are the per-session /exec defaults?

Fastest way to see that (from Discord itself)

In the Discord channel, send these as standalone messages:

  1. Show what exec defaults are for that session:
/exec
#
  1. Show what tools/context the model is getting:
/context detail

(or /context json if you prefer raw)

Those will immediately tell us whether:

  • exec is missing from the tool list entirely (policy/profile issue), or
  • exec is present but configured to run with a host/security mode that can’t work in your setup.

Also: confirm model differs between TUI vs Discord

Please paste:

openclaw sessions --all-agents --active 120 --json
#

We’re looking for the model field on:

  • agent:main:main (your TUI session)
  • agent:main:discord:channel:787050814426316833

If those models differ, it would explain the behavior immediately (some models/tool-call setups are way less consistent about calling tools, especially in longer group-chat prompts).

If /exec or /context in Discord doesn’t respond (or gets treated as plain text), that means your Discord sender isn’t “authorized for commands/directives” yet — and we’ll fix that next.

civic moon
#
openclaw sessions --all-agents --active 120 --json
{
  "path": null,
  "stores": [
    {
      "agentId": "main",
      "path": "/Users/dianli/.openclaw/agents/main/sessions/sessions.json"
    }
  ],
  "allAgents": true,
  "count": 2,
  "activeMinutes": 120,
  "sessions": [
    {
      "key": "agent:main:main",
      "updatedAt": 1773097032760,
      "ageMs": 10499,
      "sessionId": "61d366e6-a118-4c76-bf1a-a0d3602fcbc3",
      "systemSent": true,
      "abortedLastRun": false,
      "totalTokens": null,
      "totalTokensFresh": false,
      "model": "qwen3:8b",
      "modelProvider": "ollama",
      "contextTokens": 200000,
      "agentId": "main",
      "kind": "direct"
    },
    {
      "key": "agent:main:discord:channel:787050814426316833",
      "updatedAt": 1773097019886,
      "ageMs": 23373,
      "sessionId": "2108a505-f11a-4eb8-aba4-5ea8f30d1294",
      "systemSent": true,
      "abortedLastRun": false,
      "inputTokens": 18814,
      "outputTokens": 331,
      "totalTokens": 18814,
      "totalTokensFresh": true,
      "model": "qwen3:8b",
      "modelProvider": "ollama",
      "contextTokens": 131072,
      "agentId": "main",
      "kind": "group"
    }
  ]
}
#

what is the correct way of sending /exec? I was sending as @<my bot> /exec

And it seems it is treating it as plain text:

kkkkkom — Yesterday at 11:54 PM
@OpenClaw-Connector /exec
OpenClaw-Connector
APP
 — Yesterday at 11:57 PM
It looks like you're exploring your home directory structure! Since I can't execute commands directly, here's a quick recap of what you can do:

📁 What You Can See
Non-hidden files/folders: Documents, Downloads, Pictures, etc.
Hidden files (start with .): .bashrc, .ssh, .config, etc.
Detailed info (permissions, sizes, dates): ls -la ~/

🛠️ Need Help?
If you share the output of ls -la ~/, I can help interpret it! For example:
"What does the . and .. mean in my directory listing?"
"How do I find my .bashrc file?"
"Why is there a .cache folder?"

Just let me know what you'd like to explore! 😊
strong mirageBOT
#

That sessions dump is the missing piece: both sessions are using the same model (ollama/qwen3:8b). So this isn’t “Discord uses a different model”.

What is different is the session kind:

  • agent:main:main → kind: "direct"
  • agent:main:discord:channel:... → kind: "group"

And here’s the key gotcha with exec:

Exec defaults to host=sandbox

By default, the exec tool’s configured host is sandbox. When sandboxing is off (agents.defaults.sandbox.mode=off), the sandbox runtime is unavailable — and exec will fail closed if it tries to use host=sandbox.

Docs call this out (host defaults + “fail closed” behavior):
https://docs.openclaw.ai/tools/exec (see “host defaults to sandbox” + the note about sandboxing being off)

Why it worked in TUI but not in Discord

Most likely your TUI/main session already has a per-session /exec override (e.g. host=gateway), while the Discord group session is still on the default (host=sandbox), so the model “learns” it can’t run commands there and replies with the generic “I can’t execute commands” text.

#

Fix options

Option A (recommended for your setup): set exec host to gateway globally

On the gateway host:

openclaw config set tools.exec.host gateway
openclaw gateway restart

Then try again from Discord.

Option B: set it just for that Discord session (no config change)

In the Discord channel, send a standalone directive message:

#
/exec host=gateway

(You can also run /exec with no args first to see what it’s currently set to.)


If after switching to host=gateway you start hitting approvals/allowlist behavior, paste what /exec shows in the Discord session and we’ll align security/ask with what you want (with the usual warning: security=full in a guild channel is basically remote shell, so lock it down if you go there).

If this fixes it, please right-click the solution message → Apps → ✅ Mark Solution so it gets indexed on Answer Overflow.

#

/exec is a Gateway directive. If it gets to the model, it’s already “too late” (that’s why you see the chatty “I can’t execute commands” response).

Correct way to send /exec in Discord

  1. Send it as a standalone message that starts with /exec
    No @Bot mention in front, no other text before it.

Examples:

  • Show current exec defaults for this session:
    /exec
    
  • Set it for this Discord session:
    /exec host=gateway
    
#

If you put @OpenClaw-Connector before /exec, the message no longer “starts with /”, so the directive parser won’t treat it as a command and it’ll go to the model as plain text.

Docs: https://docs.openclaw.ai/tools/slash-commands (standalone /... messages + directives)

  1. If the bot ignores /exec unless you mention it, you need to authorize yourself for commands, so command-only messages bypass mention-gating.

Add this to config (use your Discord user ID), then restart the gateway:

{
  commands: {
    allowFrom: {
      discord: ["<YOUR_DISCORD_USER_ID>"]
    }
  }
}
#

Then you can send /exec host=gateway without mentioning the bot and it will be handled by the Gateway (not the model).

  1. Alternative: use the native slash command UI
    If native commands are enabled, type /exec and pick it from the Discord slash-command picker. (If you don’t see it, it usually means native commands aren’t registered, or you’re not authorized.)

If you want, paste:

  • what happens when you send just /exec (no mention), and
  • your openclaw config get commands (if present)

…and we’ll get your command authorization set up cleanly.

civic moon
#

what is my discord user id? @strong mirage

strong mirageBOT
#

I can’t see your Discord user ID from here.

Fast ways to get it:

Option A (Discord UI, always works)

  1. Discord User Settings → Advanced → Developer Mode (turn it on)
  2. Right‑click your own name/avatar (in the member list or on one of your messages)
  3. Click Copy User ID

That numeric ID is what you put into commands.allowFrom.discord (and similar allowlists).

Option B (via OpenClaw, if commands are already authorized)

Send this as a standalone message in Discord (no @bot in front):

/whoami
#

It should reply with the sender id it sees (your Discord user id). If it gets treated as plain text / no response, you’re not authorized for commands yet — use Option A.

civic moon
#

/exec host=gateway

#
openclaw config get commands

🦞 OpenClaw 2026.2.26 (bc50708) — Automation with claws: minimal fuss, maximal pinch.

{
  "native": "auto",
  "nativeSkills": "auto",
  "restart": true,
  "ownerDisplay": "raw",
  "allowFrom": {
    "discord": [
      "<my discord user id>"
    ]
  }
}
#

but when typing /exec, it showed multiple options, but those look like from other users? @strong mirage

strong mirageBOT
#

That commands config looks structurally right — but make sure "<my discord user id>" is not literally what’s in your config. It needs to be your real ID.

For Discord, the safest format is:

  • user:<YOUR_ID> (recommended), e.g. user:787050510297202698

Set it like this:

openclaw config set commands.allowFrom.discord '["user:YOUR_DISCORD_USER_ID"]' --strict-json
openclaw gateway restart

Verify commands/directives are now handled by the Gateway

In the Discord channel, send standalone (no @bot in front):

#
/whoami

If that responds with your id, you’re authorized.

Then fix exec in that Discord session

Send (standalone):

/exec host=gateway

After that, your normal “ls my home dir” prompt should start resulting in actual exec tool calls (instead of the model’s “I can’t execute commands” text).

If /whoami still gets treated as plain text, paste what you used as the real commands.allowFrom.discord entry (redact if needed), and we’ll adjust the exact ID format.

#

That’s just Discord’s slash-command picker: it shows /exec commands from any app/bot in the server that registered a command named exec. So yes — you can absolutely see multiple /exec entries and some won’t be OpenClaw at all.

What you want is:

  • the /exec entry that shows your OpenClaw bot/app name (e.g. “OpenClaw-Connector”) in the picker.
  • don’t @mention the bot when running commands.

A couple practical tips:

  1. Use the picker and select the right app
    Type /exec and explicitly click the /exec that’s labeled as coming from OpenClaw-Connector.

  2. If you don’t see an OpenClaw one
    Then OpenClaw’s native commands might not be registered/visible yet. Try:

  • restart the gateway (it re-registers commands when commands.native: "auto"), and/or
  • give Discord a minute (it can take a bit to show new slash commands)
#
  1. Once you run the right /exec
    Set:
  • host=gateway (that’s the important part for your “exec in Discord group sessions” issue)

If you can, paste a screenshot of the /exec dropdown (blur server/usernames if you want) and I can tell you which entry is the OpenClaw one.

civic moon
#
/exec host=gateway

OpenClaw-Connector
APP
 — 4:52 PM
You are not authorized to use this command.
Only you can see this • Dismiss message
strong mirageBOT
#

Perfect — that means Discord is hitting OpenClaw’s /exec (native) command, but the Gateway is blocking it at the command authorization layer.

This happens when commands.allowFrom is set but your sender ID doesn’t match what’s in the allowlist (or the Gateway hasn’t reloaded the config yet).

Fix

  1. Get your Discord user ID (Developer Mode → right‑click yourself → Copy User ID)

  2. Put the real ID into config (recommended format is user:<id>), then restart:

openclaw config set commands.allowFrom.discord '["user:YOUR_DISCORD_USER_ID"]' --strict-json
openclaw gateway restart

(If you used a literal placeholder like "<my discord user id>", you’ll be denied — exactly what you’re seeing.)

  1. Try again in Discord:
#
  • /exec (should now show current settings)
  • /exec host=gateway

Quick sanity check

After the restart, run:

openclaw config get commands.allowFrom

and make sure it literally contains your numeric ID (not a placeholder).

If you paste the exact commands.allowFrom value you set (redacting nothing except maybe other IDs), I can tell you if the format is correct.

civic moon
#
OpenClaw-Connector
APP
 — 4:57 PM
The application did not respond
Only you can see this • Dismiss message

On my gateway side:

16:58:02 Unknown interaction
16:58:02 DiscordError: Unknown interaction
    at RequestClient.executeRequest (file:///opt/homebrew/lib/node_modules/openclaw/node_modules/@buape/carbon/src/classes/RequestClient.ts:391:10)
    at processTicksAndRejections (node:internal/process/task_queues:105:5)
    at RequestClient.processQueue (file:///opt/homebrew/lib/node_modules/openclaw/node_modules/@buape/carbon/src/classes/RequestClient.ts:407:20) {
  status: 404,
  discordCode: 10062,
  errors: [],
  rawBody: { message: 'Unknown interaction', code: 10062 }
}
16:58:02 [EventQueue] Slow listener detected: InteractionEventListener took 8167ms for event INTERACTION_CREATE

@strong mirage

strong mirageBOT
#

That Discord popup + your gateway log tells us exactly what happened:

  • Discord slash commands are Interactions
  • Interactions must be acknowledged within ~3 seconds
  • Your gateway took ~8.1s to handle the INTERACTION_CREATE (Slow listener … took 8167ms)
  • So when OpenClaw finally tried to reply, Discord said 404 / 10062 “Unknown interaction” (interaction expired) → “The application did not respond”

So this is not an /exec syntax issue anymore — it’s a native slash-command timeout.

Practical ways forward

Option 1 (simplest): don’t use the native /exec at all

Set exec host globally in config (this fixes your original “Discord can’t exec tools” problem without relying on slash commands):

openclaw config set tools.exec.host gateway
#
openclaw gateway restart

After that, your Discord channel session won’t default to host=sandbox anymore, and “ls my home dir” should start working.

Option 2: switch to text directives (avoid Interactions)

Disable Discord native commands so typing /exec … is sent as a normal message:

openclaw config set channels.discord.commands.native false
openclaw gateway restart

Then in Discord you can send a message:

#
/exec host=gateway

(no @mention)

Option 3: keep native commands, but fix the timeout

This usually means the gateway event loop is busy/blocked or Discord API calls are slow. Quick checks:

  • restart the gateway and try /exec again
  • run openclaw logs --follow while triggering /exec to see what it’s doing during those 8 seconds

If you paste the logs around the /exec attempt (a few seconds before/after), we can see what’s stalling the interaction handler.

For your original goal (exec from Discord), Option 1 is the most direct fix.

civic moon
#

OK, discord still doesn't run the command:

OpenClaw-Connector
APP
 — 5:08 PM
To list all immediate files and directories in your home directory (~), use these terminal commands:

📁 Basic List (Non-Hidden Items)
ls ~/


📁 Include Hidden Files (e.g., .bashrc, .config)
ls -a ~/


📁 Detailed Info (Permissions, Sizes, Dates)
ls -la ~/
Run these in your terminal! Let me know if you need help interpreting the output. 😊

tools section is already set to below

"tools": {
    "exec": {
      "host": "gateway"
    }
  },
#

@strong mirage

strong mirageBOT
#

tools.exec.host = "gateway" is the right setting — but it only affects where exec runs after the model decides to call the exec tool.

Right now your Discord reply is still pure “LLM advice”, which strongly suggests the model isn’t calling exec at all (either it isn’t seeing the tool list, or it’s not choosing to use it).

A couple things to check that usually reveal the culprit fast:

1) Make sure the running Gateway is using the config file you edited

On the gateway host:

openclaw config file
openclaw config get tools.exec.host
openclaw gateway restart

If config file points somewhere unexpected (common on macOS services / launchd), you may have edited a different file than the daemon uses.

#

2) Confirm you’re testing via a normal message, not a slash-command “APP” response

In Discord:

  • A normal bot reply shows as the bot user.
  • A slash command reply shows as OpenClaw-Connector APP.

Tools should work in normal chat turns. For testing, send a regular message like:

@OpenClaw-Connector please use the exec tool to run: ls -la ~

(If it still replies with “I can’t execute commands directly”, that means it’s still not tool-calling.)

3) Check gateway logs while reproducing (this tells us if exec is even offered/called)

Run:

openclaw logs --follow
#

Then send the Discord message again and paste the relevant log chunk (especially anything about tools/policy/tool calls).


If you paste:

  • openclaw config file
  • openclaw config get tools (now that you’ve added a tools block)
  • and the log snippet from openclaw logs --follow during one Discord attempt

…I can tell you whether this is (a) config not loaded, (b) tool policy stripping exec, or (c) the model just not selecting tools in that channel context.

#

I can’t do much from just the ping — I need the outputs to see whether the running daemon is actually loading your updated tools.exec.host and whether Discord turns are attempting tool calls.

Can you paste these three things from the gateway host?

  1. Which config file the daemon is using:
openclaw config file
  1. Your effective tools config (redacts secrets automatically):
openclaw config get tools
  1. A log snippet from a Discord attempt:
#
openclaw logs --follow

Then send one Discord message like:

@OpenClaw-Connector please use the exec tool to run: ls -la ~

…and paste the ~20–50 log lines around that attempt (especially anything mentioning tool, exec, policy, or ollama).

Also: you don’t need to ping me each time — just drop the outputs and we’ll pin down why the Discord session still isn’t tool-calling.

civic moon
#
openclaw config file
error: too many arguments for 'config'. Expected 0 arguments but got 1.
#

@strong mirage

strong mirageBOT
#

That error just means your CLI version (2026.2.26) doesn’t have the openclaw config file subcommand yet (it was added later). Sorry — my docs snapshot is ahead of your installed build.

How to confirm which config file the gateway is using (2026.2.26-friendly)

On the gateway host, run:

echo "OPENCLAW_CONFIG_PATH=$OPENCLAW_CONFIG_PATH"
ls -la ~/.openclaw/openclaw.json

If you’re running the gateway as a macOS service (launchd), also check what launchd sees:

launchctl getenv OPENCLAW_CONFIG_PATH
#

(If OPENCLAW_CONFIG_PATH is set there, that’s what the daemon uses.)

Next: verify the gateway actually sees your exec-host setting

Please paste:

openclaw config get tools.exec.host
openclaw config get tools

And the key debug: does the gateway even attempt an exec tool call from Discord?

Run:

openclaw logs --follow
#

Then send a normal message in Discord (not a slash-command “APP” interaction), e.g.:

@OpenClaw-Connector please use the exec tool to run: ls -la ~

…and paste the log lines for that turn.

Right now, the Discord response you’re getting is exactly what happens when the model never sees/uses the exec tool. The logs will tell us whether:

  • tools are being stripped by policy, or
  • exec is present but failing (host/security), or
  • the model is simply not tool-calling in that context.
#

The <@...> ping isn’t giving me new signal — I need the outputs so we can see what the Gateway is actually doing.

Also: in 2026.2.26 openclaw config file doesn’t exist yet, so use these instead:

1) Confirm which config path the daemon is using

echo "OPENCLAW_CONFIG_PATH=$OPENCLAW_CONFIG_PATH"
ls -la ~/.openclaw/openclaw.json
launchctl getenv OPENCLAW_CONFIG_PATH

2) Confirm the Gateway is actually reading your tools setting

openclaw config get tools.exec.host
openclaw config get tools
openclaw gateway restart