#Trouble shooting.
1 messages · Page 1 of 1 (latest)
You’re describing a persistent “second brain” (own workspace + SOUL/identity + long-lived sessions) that also runs on a schedule and posts into a dedicated Discord channel. In OpenClaw terms that’s Multi‑Agent Routing, not sub-agents.
Mental model (what’s what)
- Agent = a whole isolated persona/brain: its own workspace, SOUL.md, memory, auth, and session store on disk. This is what you want for “has its own soul”.
- Sub-agent (
sessions_spawn) = a helper run spawned by an agent. Useful for parallel work, but it’s not “a full independent persona” (and doesn’t load SOUL.md etc). - Heartbeat / Cron = how you make an agent “alive in the background” without literally keeping an LLM running 24/7.
- Heartbeat (persistent main session context): https://docs.openclaw.ai/gateway/heartbeat
- Cron (scheduled jobs; good for daily/weekly reports): https://docs.openclaw.ai/automation/cron-jobs
Recommended architecture (clean + scalable)
1) Create a dedicated stocks agent (persistent)
Use the built-in helper:
openclaw agents add stocks
openclaw agents list --bindings
That gives you a separate workspace (where you put SOUL.md, USER.md, a watchlist file, etc) and its own session store under:
~/.openclaw/agents/stocks/sessions/
2) Use 2 Discord channels (optional but nicer)
#stocks-reports→ where it posts scheduled briefs (one-way, low-noise)#stocks-chat→ where you (or your main agent) can talk to it
Then bind inbound Discord messages to the stocks agent only for the chat channel (so people chatting in reports doesn’t derail it).
Bindings shape uses peer.kind: "channel":
Example (JSON5-ish, in ~/.openclaw/openclaw.json):
{
agents: {
list: [
{ id: "main", default: true },
{ id: "stocks", name: "Stocks Agent", workspace: "~/.openclaw/workspace-stocks" },
],
},
bindings: [
{
agentId: "stocks",
match: { channel: "discord", peer: { kind: "channel", id: "STOCKS_CHAT_CHANNEL_ID" } },
},
],
}
3) Make it “autonomous” with per-agent Heartbeat (best for persistence)
Heartbeat runs in the agent’s main session, so it can maintain ongoing context naturally.
{
agents: {
list: [
{
id: "stocks",
heartbeat: {
every: "1h",
target: "discord",
to: "channel:STOCKS_REPORTS_CHANNEL_ID",
prompt: "Check watchlist + major movers + upcoming catalysts. Post a concise brief. If nothing notable, reply HEARTBEAT_OK."
}
}
]
}
}
Docs: https://docs.openclaw.ai/gateway/heartbeat
4) Add Cron for “market open / market close” style reports (optional)
Cron is great for “post at 9:35am ET every weekday”, and it survives restarts.
You can also pin the job to the stocks agent:
openclaw cron add \
--name "Market open brief" \
--cron "35 9 * * 1-5" \
--tz "America/New_York" \
--session isolated \
--agent stocks \
--message "Market open brief: top news, movers, watchlist updates." \
--announce \
--channel discord \
--to "channel:STOCKS_REPORTS_CHANNEL_ID"
Docs: https://docs.openclaw.ai/automation/cron-jobs
“I need to speak to the stocks agent via the main agent”
That’s agent-to-agent messaging using the session tools (sessions_send, etc). This is explicitly supported, but you need to enable it:
{
tools: {
agentToAgent: {
enabled: true,
allow: ["main", "stocks"]
}
}
}
Then your main agent can sessions_send into the stocks agent session (e.g. agent:stocks:main) and get a controlled reply flow.
- Docs (session tools + agent-to-agent behavior): https://docs.openclaw.ai/concepts/session-tool
Mission Control dashboard idea
Start with the built-in Control UI, but if you want your own “agent ops” panel, the clean way is the Gateway’s HTTP Tools Invoke endpoint (POST /tools/invoke) so your dashboard can call things like sessions_list, cron.list, cron.add, etc (still gated by auth + tool policy):
Two quick questions so I can tailor the exact config
- Do you want the stocks agent to be interactive in Discord (people can ask it questions in
#stocks-chat), or reports-only (no inbound messages except via main agent)? - What cadence: hourly, market open/close, or only when big movers/news?
(Also: if any of this is used for real trading, treat it as research/automation, not financial advice—keep a human approval step before execution.)
Yes I’d like to chat with it. In the stocks channel Or if am chatting in the main and I don’t want to go out I can just @ it. And also want to be able to chat with it via Mission Control ui. Basically as I scale I wanna be able to chat with them via the ui as well so Mission Control got easy
If you want “a real independent brain with its own SOUL + persistent memory/sessions” and you want to chat with it from multiple places, the clean way is:
- Multi-agent for persistence (a dedicated
stocksagent) - Agent-to-agent messaging when you want to “talk to it from main without leaving”
- (Optional) Discord multi-account if you want “@mention it” to literally mean a different Discord bot identity
Here are the 3 workable patterns on Discord (pick what matches your “@ it” requirement):
Option A (simplest): 1 Discord bot, 2 channels
#main→ routed tomainagent#stocks→ routed tostocksagent (full chat there)
Then when you’re in #main and don’t want to switch channels, you just ask main to forward.
This is standard bindings routing:
https://docs.openclaw.ai/concepts/multi-agent
Option B (closest to “@ it in the same channel”): 2 Discord bot accounts (multi-account)
You create two Discord applications/bots:
- Bot 1 = “Main”
- Bot 2 = “Stocks”
Configure channels.discord.accounts and route by bindings[].match.accountId (multi-account is supported):
https://docs.openclaw.ai/gateway/configuration#channelstelegramaccounts--channelsdiscordaccounts--channelsslackaccounts--channelssignalaccounts--channelsimessageaccounts
Then in any channel you can literally do:
@MainBot ...@StocksBot ...
…and OpenClaw can route those to different agents deterministically.
Option C (works today, one channel): “soft @stocks” via main agent forwarding
Discord routing can’t dynamically pick an agent inside the same channel just because text contains @stocks (bindings are deterministic and Discord broadcast-to-multiple-agents isn’t a thing yet; broadcasts are WhatsApp-only right now).
But you can get the UX you want by teaching the main agent:
- “If a message starts with
@stocks(or/stocks), forward it to the stocks agent and relay the reply back here.”
To do that you enable agent-to-agent messaging:
{
tools: {
agentToAgent: { enabled: true, allow: ["main", "stocks"] }
}
}
Docs: https://docs.openclaw.ai/concepts/session-tool
Then the main agent uses sessions_send to the stocks agent’s main session (or a dedicated session key) and posts the response back.
Mission Control UI (chat with any agent from the UI)
You basically have two approaches:
1) Use the built-in Control UI (already a “mission control” baseline)
It already has: chat, sessions, cron jobs, skills, nodes, config, etc.
https://docs.openclaw.ai/web/control-ui
2) Build your own Mission Control
Two HTTP surfaces are designed exactly for this:
- OpenAI-compatible chat endpoint (lets your UI “chat with agent X” by setting agent id):
https://docs.openclaw.ai/gateway/openai-http-api
You’d enable:
Then send requests with{ gateway: { http: { endpoints: { chatCompletions: { enabled: true } } } } }x-openclaw-agent-id: stocks(ormodel: "openclaw:stocks").
- Tools Invoke endpoint (call a single tool like
cron.list,sessions_list, etc.):
https://docs.openclaw.ai/gateway/tools-invoke-http-api
That combo is enough to build a real “agent dashboard”: agent list, status, chat panes, cron controls.
One question to pick the right design
When you say “I can just @ it” in the main channel, do you mean:
- “Type
@stocks …and main forwards it” (Option C), or - “Actually mention a different Discord bot user (
@StocksBot)” (Option B)?
If you tell me which one, I’ll give you the exact minimal config skeleton (agents + bindings + discord accounts + where the channel IDs go).
i juist need the most effective and clean achitechure , such that the tick agent is an agent of his own with his own md files so it can be specifically doctored to hanldle stocks , and anytime i wanna talk to it , i just go into the stock channel and know fully well all our convo is fully stocks , andif i have to reach out to it via main ~general channel i can just use @ so main still forwards to him and he responds back to the stock channle and main nottifies me that he has responded . does that make sense
Yep, that flow makes total sense — and the cleanest way to get it in OpenClaw is:
- A real separate
stocksagent (its own workspace + SOUL/AGENTS/USER files, its own sessions on disk) - A dedicated Discord channel that routes to that agent (so everything in there is 100% stocks)
- Main forwards “@stocks …” messages into the stocks channel session (so the stocks agent replies in the stocks channel), and main posts a short “done” note back in
#general.
That’s the “effective + clean” architecture.
1) Create the persistent stocks agent (its own MD files)
This is Multi‑Agent Routing (persistent “brain”), not subagents.
Docs: https://docs.openclaw.ai/concepts/multi-agent
CLI:
openclaw agents add stocks
Then put your stocks-specific prompt files in the stocks workspace (whatever path you set for it), e.g.
~/.openclaw/workspace-stocks/SOUL.md~/.openclaw/workspace-stocks/AGENTS.md~/.openclaw/workspace-stocks/USER.md- plus a
WATCHLIST.md, etc.
2) Route the Discord stocks channel to the stocks agent
Bind that one Discord channel to agentId: "stocks".
Config sketch (placeholders):
{
agents: {
list: [
{ id: "main", default: true },
{ id: "stocks", name: "Stocks", workspace: "~/.openclaw/workspace-stocks" },
],
},
bindings: [
// Everything in #stocks goes to the stocks agent
{ agentId: "stocks", match: { channel: "discord", peer: { kind: "channel", id: "STOCKS_CHANNEL_ID" } } },
// (optional) everything else in Discord goes to main (or leave default)
{ agentId: "main", match: { channel: "discord" } },
],
}
Discord allowlist docs (recommended): https://docs.openclaw.ai/channels/discord
3) Let main forward “@stocks …” into the stocks channel (and notify you)
This is agent-to-agent messaging via sessions_send.
Key trick for your requirement (“stocks replies back to the stocks channel”):
- Main should send to the stocks channel session key, not to some generic stocks “main” session.
That session key is deterministic:
agent:stocks:discord:channel:STOCKS_CHANNEL_ID
Enable agent-to-agent + disable ping-pong (so it stays one-way and clean)
Turn on agent-to-agent and set ping-pong turns to 0:
{
tools: {
agentToAgent: { enabled: true, allow: ["main", "stocks"] }
},
session: {
agentToAgent: {
maxPingPongTurns: 0
}
}
}
(That maxPingPongTurns setting is the important “keep it clean” knob.)
Docs: https://docs.openclaw.ai/gateway/configuration (search agentToAgent.maxPingPongTurns)
Teach main the forwarding rule (in main’s AGENTS.md or SOUL.md)
Add something like this to main agent instructions:
- If a message in
#generalstarts with@stocks(or/stocks), then:- Strip the prefix
sessions_sendtoagent:stocks:discord:channel:STOCKS_CHANNEL_IDwithtimeoutSecondsset (so main can confirm completion)- Reply in
#generalwith: “Sent to stocks; reply posted in #stocks.”
This gives you exactly:
- Stocks agent stays “pure” in the stocks channel
- General stays clean
- You still get the convenience of “ask from general”
Important note: this @stocks is just a text prefix, not a real Discord mention (unless you run a second Discord bot account). It’s the least moving parts solution.
4) Mission Control UI chatting with the stocks agent
Two levels:
A) Use the built-in Control UI now (good baseline)
It already does chat + sessions + cron + agent events:
https://docs.openclaw.ai/web/control-ui
B) If you build your own Mission Control UI later
Use the Gateway HTTP endpoints:
- OpenAI-compatible chat endpoint (target a specific agent via header / model):
https://docs.openclaw.ai/gateway/openai-http-api - Single-tool calls for ops panels (sessions list, cron list, etc.):
https://docs.openclaw.ai/gateway/tools-invoke-http-api
Quick confirmation questions (so I don’t guess your IDs wrong)
- Do you already have the Discord channel ID for
#stocksand#generalhandy? (If not, tell me your server setup and I’ll point you to the quickest way to grab them.) - Do you want the forwarding trigger to be
@stocksor a slash-style prefix like/stocks? (Slash-style is less ambiguous / less likely to be used accidentally.)
i have started the setup so do i ssay yes to copy auth from main ?and what does that mean agent@agent:~$ openclaw agents add stock
🦞 OpenClaw 2026.2.6-3 (85ed6c7) — Your inbox, your infra, your rules.
┌ Add OpenClaw agent
│
â—‡ Workspace directory
│ /home/agent/.openclaw/workspace-stock
│
â—† Copy auth profiles from "main"?
│ ○ Yes / ● No
Say Yes unless you intentionally want this stocks agent to use a totally different set of model credentials / billing accounts.
What “Copy auth profiles from main” means
OpenClaw stores model/provider credentials (Anthropic/OpenAI/etc) as auth profiles per agent (separate “brains”). A brand new agent starts with no model auth, so it may immediately fail with “no API key / no credentials” until you set it up.
Choosing Yes will copy main’s model auth profiles into the new agent’s auth store so the stocks agent can talk to models right away.
- It does not copy your Discord bot token / channel config (those live under
channels.discord...in the main config). - It does not mix conversations/sessions/memory. Those stay isolated by agent.
Docs (multi-agent): each agent has its own auth file under:
~/.openclaw/agents/<agentId>/agent/auth-profiles.json
https://docs.openclaw.ai/concepts/multi-agent
When to say “No”
Say No only if you want one of these:
- Separate provider accounts (different Anthropic/OpenAI keys, different billing)
- A “locked down” stocks agent you’ll authenticate later with a limited set of providers
If you choose No, you’ll just need to authenticate for the stock agent afterwards (via the models auth commands / wizard).
For your “clean + effective architecture” goal: Yes is the smooth path.
Copy auth profiles from "main"?
│ Yes
│
◇ Auth profiles ─────────────────────╮
│ │
│ Copied auth profiles from "main". │
│ │
├─────────────────────────────────────╯
│
â—‡ Configure model/auth for this agent now?
│ Yes
│
â—‡ Model/auth provider
│ OpenRouter
│
â—‡ OpenRouter auth method
│ OpenRouter API key
│
◇ Model configured ─────────────────────────────────────────╮
│ │
│ Default model set to openrouter/auto for agent "stock". │
│ │
├────────────────────────────────────────────────────────────╯
│
◇ Model check ───────────────────────────────────────────────────────╮
│ │
│ Model not found: openrouter/auto. Update agents.defaults.model or │
│ run /models list. │
│ │
├─────────────────────────────────────────────────────────────────────╯
i might have tio update that m odel when done cuase the model wasnt found , im sure we can come back to that
──────────────────────────────────────────────────────────────────────╯
│
â—‡ Select a channel
│ Discord (Bot API)
│
â—† Discord already configured. What do you want to do?
│ ● Modify settings
│ ○ Skip (leave as-is)
â””
i picked discord as i already have discound so since we wanna set just a channel for agent stock , do i pick modify now or skip ?
Yep — you can ignore the auth part now (that’s fine), but you should fix the model string before you expect the stock agent to reply reliably.
Why you’re seeing “Model not found: openrouter/auto”
OpenClaw’s OpenRouter model IDs are expected to look like:
openrouter/<upstream-provider>/<upstream-model>
So openrouter/auto doesn’t match the normal OpenRouter pattern and isn’t in OpenClaw’s known model catalog, hence the “not found” warning.
Docs: https://docs.openclaw.ai/providers/openrouter
Quick fix (recommended)
-
Pick a real OpenRouter model id (copy it from OpenRouter / or from OpenClaw’s model picker).
- In chat you can run:
/models list(that’s what the wizard hint is referring to) - Or in CLI:
openclaw models list --all --provider openrouter(if you have a populated catalog)
- In chat you can run:
-
Set that model on the
stockagent in config.
You’ll need the index of the stock agent entry:
openclaw config get agents.list
Find the entry where id: "stock" and note its index, then set:
openclaw config set agents.list[N].model "openrouter/<provider>/<model>"
- Restart the gateway after config edits:
openclaw gateway restart
Pick Modify settings.
Reason: to make your architecture work, the Discord channel(s) you care about must be allowed in channels.discord.guilds.<guild>.channels, otherwise the gateway will just ignore them (even if bindings exist).
What to do in “Modify”
When it asks you which guild/channels to allow, make sure you include at least:
- your current support channel (so you don’t lock yourself out while testing)
#general(where you’ll do the “@stocks … forward” command)#stocks(the dedicated stocks chat channel)
Then set mention gating per channel the way you want:
#stocks:requireMention: false(so it’s a normal chat, all stocks, no constant @mentioning)#general:requireMention: true(recommended so the bot doesn’t talk on every message)
Docs (Discord allowlist + requireMention): https://docs.openclaw.ai/channels/discord
Important gotcha from the docs: if you configure channels at all, anything not listed is denied by default, so don’t only add #stocks unless you truly want to block everything else.
About the “Model not found: openrouter/auto”
Totally fine to “come back to it”, but just know: until you set a real OpenRouter model id, the stock agent may fail to reply.
To fix later:
openclaw models list --all --provider openrouter- pick one and set it on the agent (
agents.list[].model), then restart gateway.
If you tell me the three Discord channel IDs (general, stocks, current help channel), I can paste the exact config snippet you want (safe, minimal, doesn’t break your current channel).
- Verify auth+model for that agent:
openclaw models status --agent stock --probe
(That command is great because it checks the agent’s resolved model + whether the provider auth actually works.)
Good news
- You did the right thing copying auth profiles — that just means the
stockagent can use the same provider credentials asmainwithout extra setup. - The “model not found” warning is purely about the model id string, not your API key.
If you paste the output of openclaw config get agents.list (feel free to redact anything secret), I can tell you the exact agents.list[N] index to edit.
i will come back to sortiung out model later , lets finish setting up so now do i pick yes or no for update discord channel access Select a channel
│ Discord (Bot API)
│
â—‡ Discord already configured. What do you want to do?
│ Modify settings
│
â—‡ Discord account
│ default (primary)
│
â—‡ Discord token already configured. Keep it?
│ Yes
│
â—† Update Discord channels access?
│ ○ Yes / ● No
Pick Yes for “Update Discord channels access?”
That step is where OpenClaw updates the Discord allowlist (channels.discord.guilds.<guild>.channels...). Without that, the bot may simply ignore messages in #stocks / #general even if your multi-agent bindings are correct.
What to include when it asks which channels are allowed
Make sure you allow at least:
- this current troubleshooting channel (so you don’t lock yourself out mid-setup)
#general(where you’ll do the “@stocks …” forwarding)#stocks(the dedicated stocks-only chat channel)
Mention gating (recommended)
When it asks per-channel settings:
#stocks: requireMention = false (so it behaves like a normal chat in there)#general: requireMention = true (so it doesn’t respond to every random message)
Discord config reference: https://docs.openclaw.ai/channels/discord
After this, we still need to do the binding that routes #stocks → the stock agent (that’s separate from channel access).
will main have access to that stocks channle also , such that i can chat with main from inside stock channle , or i explicitely make it only stock has acces to stock
Discord channel access is bot-level, not agent-level.
So if you allow #stocks in channels.discord.guilds.<guild>.channels, that means:
- the Discord bot account can read/write in
#stocks - then your bindings decide which agent handles messages that arrive there
What happens with your “pure stocks channel” setup
If you bind #stocks → agentId: "stock":
- Anything you type in
#stockswill be handled by the stock agent (good: pure context) - The main agent won’t “see” inbound messages from
#stocks(unless you explicitly forward them)
But yes: since it’s the same Discord bot identity, main can still send messages into #stocks if you explicitly make it (via session tools / message tool). It just won’t be the default responder there.
How to “chat with main from inside #stocks” without breaking purity
Two clean patterns:
Option 1 (cleanest): make a thread inside #stocks called “main”
- Discord threads have their own channel IDs.
- You can bind:
#stocks(channel id A) →stock#stocksthread “main” (thread id B) →main
So you stay “inside stocks”, but separated context.
Option 2: a forwarding prefix
In #stocks, you type:
/main …(or@main …as plain text)
…and the stock agent forwards that to main via sessions_send, then posts main’s answer back (either in #stocks or better: in a dedicated thread).
This keeps #stocks mostly stocks, while still giving you an escape hatch.
If you tell me whether you prefer thread-based or prefix-forwarding, I’ll give you the exact binding shape + the session key to use.
Select a channel
│ Discord (Bot API)
│
â—‡ Discord already configured. What do you want to do?
│ Modify settings
│
â—‡ Discord account
│ default (primary)
│
â—‡ Discord token already configured. Keep it?
│ Yes
│
â—‡ Update Discord channels access?
│ Yes
│
â—‡ Discord channels access
│ Allowlist (recommended)
│
â—‡ Discord channels allowlist (comma-separated)
│ */general-loudspeaker, */chart-with-upwards-trend-stock-investments-pound
│
◇ Discord channels ───────────────────────────────────╮
│ │
│ Unresolved (kept as typed): */general-loudspeaker, │
│ */chart-with-upwards-trend-stock-investments-pound │
│ │
├──────────────────────────────────────────────────────╯
│
â—† Select a channel
│ ○ Telegram (Bot API)
│ ○ WhatsApp (QR link)
│ ● Discord (Bot API) (configured)
│ ○ Google Chat (Chat API)
│ ○ Slack (Socket Mode)
│ ○ Signal (signal-cli)
│ ○ iMessage (imsg)
│ ○ Feishu/Lark (飞书)
│ ○ Nostr (NIP-04 DMs)
│ ○ Microsoft Teams (Bot Framework)
│ ○ Mattermost (plugin)
│ ○ Nextcloud Talk (self-hosted)
│ ○ Matrix (plugin)
│ ○ BlueBubbles (macOS app)
│ ○ LINE (Messaging API)
│ ○ Zalo (Bot API)
│ ○ Zalo (Personal Account)
│ ○ Tlon (Urbit)
│ ○ Finished
â”” im getting unersolved , and keeps asking me to put set the discord ocver again
That “Unresolved (kept as typed)” warning is happening because the wizard couldn’t map what you typed to a real Discord channel.
In your case it’s because you typed entries like:
*/general-loudspeaker
That */ prefix is not a Discord channel name/ID, so it can’t resolve it.
Do this (best / cleanest)
When it asks for the allowlist, paste channel IDs (comma-separated). IDs never need “resolving” and won’t break if you rename channels.
How to get IDs:
- In Discord: User Settings → Advanced → Developer Mode ON
- Right-click the channel → Copy Channel ID
- Paste like:
1470..., 1471...
Use the IDs for:
- your current troubleshooting channel (so you don’t lock yourself out)
#general#stocks
If you insist on names (works but more fragile)
Enter just the channel names without */:
general-loudspeaker, chart-with-upwards-trend-stock-investments-pound
…but IDs are strongly preferred.
“It keeps asking me to set Discord over again”
After you configure Discord, the wizard returns to “Select a channel” because it’s letting you configure other channels too. If you’re done with channels, select Finished.
Once your channel access list is correct, we’ll do the final step: bind #stocks → the stock agent.
Discord channels access
│ Allowlist (recommended)
│
â—‡ Discord channels allowlist (comma-separated)
│ 1469820904606400758, 1468636162871660566
│
◇ Discord channels ────────────────────────────────────────────╮
│ │
│ Resolved channels: 1469820904606400758, 1468636162871660566 │
│ │
├───────────────────────────────────────────────────────────────╯
│
â—‡ Select a channel
│ Discord (Bot API)
│
â—‡ Discord already configured. What do you want to do?
│ Modify settings
│
â—† Discord account
│ ● default (primary)
│ ○ Add a new account
â”” its back there again asking to set discoud even after ir resolved
?
You’re not stuck — the wizard is just telling you it couldn’t resolve the channel identifiers you typed.
Fix the “Unresolved (kept as typed)” thing
At the “Discord channels allowlist (comma-separated)” prompt, don’t use */channel-name.
Instead, paste Discord Channel IDs (best), comma-separated.
How to get Channel IDs:
- Discord → User Settings → Advanced → Developer Mode ON
- Right‑click
#general→ Copy Channel ID - Right‑click
#stocks→ Copy Channel ID - Paste them like:
123456789012345678, 234567890123456789
Also include this troubleshooting channel’s ID too, so you don’t accidentally lock the bot out while testing.
If you still see “Unresolved” even with IDs, paste them as:
GUILD_ID/CHANNEL_ID(same comma-separated format).
(The*/...wildcard is what’s biting you.)
Why it keeps asking you to “set Discord” again
After you finish Discord config, the wizard goes back to “Select a channel” so you can configure other channels too.
If you’re done with channels, choose Finished.
Once you’ve got the allowlist in place, the next step is bindings: #stocks → agentId: stock.
what do i pick here
â—† Configure DM access policies now? (default: pairing)
│ ○ Yes / ● No
â””
Pick based on whether you want to use Discord DMs with the bot (this is separate from channel access / your stocks channel setup).
Recommended (most people): Yes
Choose Yes if you want any of these:
- DM the bot privately for admin stuff / quick tests
- Receive exec approval prompts in DMs (Discord does approvals via DM buttons)
- A “backdoor” to recover if you mess up channel allowlists
Then keep the default DM policy = pairing (secure). You’ll just approve the first DM once.
If you don’t want DMs at all: No
Choose No if you only ever want to talk in server channels (#general, #stocks) and you don’t plan to use DM-based approvals.
Either choice won’t affect your plan to have #stocks be “stocks-only” routed to the stock agent.
Route selected channels to this agent now? (bindings)
│ ○ Yes / ● No
â””
note i only added general and stock channle id to this agent
Pick Yes if the wizard is about to let you choose only the #stocks channel to bind to the stock agent.
Your target setup is:
#stocks→ agentstock#general(and this troubleshooting channel) → agentmain
So when you say Yes, make sure you only select the stocks channel in the next step. Do not route #general to stock, or you’ll lose the “main in general” behavior.
If the wizard tries to route all selected channels to stock
Then pick No here, and we’ll add bindings manually afterward (safe + explicit). The binding you want looks like:
{
bindings: [
{ agentId: "stock", match: { channel: "discord", peer: { kind: "channel", id: "STOCKS_CHANNEL_ID" } } },
{ agentId: "main", match: { channel: "discord" } },
],
}
(That “peer/channel id” binding is the most-specific rule, so it wins for #stocks.)
After the wizard finishes, run:
openclaw agents list --bindings
and confirm only #stocks is routed to stock.
Got it — but that’s the one thing you don’t want if you want #general to stay “main”.
There are two separate concepts that look similar in the wizard:
1) Discord channel access (allowlist)
This is just “can the bot read/write there at all?”
- Here it’s correct to include both
#generaland#stocks(and your troubleshooting channel) so you don’t lock yourself out.
2) Bindings (routing) = which agent handles inbound messages
This is where you should be strict:
#stocks→agentId: stock#general→agentId: main(or just let it fall through to main via a default binding)
So if you routed both #general and #stocks to the stock agent, then messages in #general will now be handled by the stock brain (not what you want).
Quick check (do this now)
Run:
openclaw agents list --bindings
If you see #general bound to stock, we need to remove that binding.
Clean binding layout (what you want)
The minimal bindings should look like this (replace the IDs):
bindings: [
{ agentId: "stock", match: { channel: "discord", peer: { kind: "channel", id: "STOCKS_CHANNEL_ID" } } },
{ agentId: "main", match: { channel: "discord" } },
]
Notes:
- The first rule is “most specific”, so it wins for
#stocks. - Everything else Discord goes to
main.
If you paste the output of openclaw agents list --bindings (just that), I’ll tell you exactly which entry to remove / what to replace it with.
â—‡ Configure DM access policies now? (default: pairing)
│ No
│
â—‡ Route selected channels to this agent now? (bindings)
│ Yes
Updated ~/.openclaw/openclaw.json
Workspace OK: ~/.openclaw/workspace-stock
Sessions OK: ~/.openclaw/agents/stock/sessions
│
â”” Agent "stock" ready.
agent@agent:~$ i didnt get the chnace to pick it just complated after i clicked yes
That’s expected behavior: when you hit Yes, the wizard auto-created the bindings immediately (it didn’t prompt again) — and it likely bound both #general and #stocks to the stock agent.
No panic; fix is just: remove the #general → stock binding, keep only #stocks → stock.
Step 1 — show me what it wrote
Run this and paste the output:
openclaw agents list --bindings
(Alternative if that doesn’t show enough detail:)
openclaw config get bindings
What we want the final routing to be
#stocks→stock- everything else (including
#general) →main(either via an explicit binding or just bymainbeing the default agent)
So your bindings should effectively look like:
bindings: [
{ agentId: "stock", match: { channel: "discord", peer: { kind: "channel", id: "STOCKS_CHANNEL_ID" } } },
// optional: { agentId: "main", match: { channel: "discord" } },
]
Once you paste the bindings output, I’ll tell you exactly which entry to delete / what the corrected array should be.
(Also: “Discord channel allowlist” is bot-level access; it’s fine that both channels are allowlisted. Bindings are what make #stocks “stocks-only”.)
agent@agent:~$ openclaw agents list --bindings
🦞 OpenClaw 2026.2.6-3 (85ed6c7) — Meta wishes they shipped this fast.
Agents:
- main (default)
Identity: 🌹 Jarvis (IDENTITY.md)
Workspace: ~/.openclaw/workspace
Agent dir: ~/.openclaw/agents/main/agent
Model: openrouter/stepfun/step-3.5-flash:free
Routing rules: 0
Routing: default (no explicit rules) - stock
Workspace: ~/.openclaw/workspace-stock
Agent dir: ~/.openclaw/agents/stock/agent
Model: openrouter/auto
Routing rules: 1
Routing rules:- discord accountId=default
Routing rules map channel/account/peer to an agent. Use --bindings for full rules.
Channel status reflects local config/creds. For live health: openclaw channels status --probe.
agent@agent:~$
- discord accountId=default
Right now your wizard created a too-broad binding:
stockhas:- discord accountId=default
That means ALL Discord messages (on the default Discord account) will be routed to the stock agent — including #general. That’s why you didn’t get a chance to “pick”: the wizard just bound the whole Discord account.
What you want instead is:
- Specific binding:
#stockschannel →stockagent - Catch-all binding: everything else on Discord →
mainagent
Fix it (safe + explicit)
You need your Discord channel ID for #stocks
Use the channel ID you copied earlier (right-click channel → Copy Channel ID).
Then run (replace STOCKS_CHANNEL_ID):
openclaw config set bindings '[
{
"agentId": "stock",
"match": {
"channel": "discord",
"accountId": "default",
"peer": { "kind": "channel", "id": "STOCKS_CHANNEL_ID" }
}
},
{
"agentId": "main",
"match": { "channel": "discord", "accountId": "default" }
}
]' --json
Restart gateway (bindings are config):
openclaw gateway restart
Verify:
openclaw agents list --bindings
You should then see:
stockrouting rule:discord … peer=channel:<stocksId>(something specific)mainrouting rule:discord accountId=default(catch-all)
Note about Discord “allowlist”
This does not change which channels the bot can access. That’s controlled by channels.discord.guilds...channels...allow. Keep #general and #stocks allowlisted there — that part is fine.
If you paste your STOCKS_CHANNEL_ID here, I’ll paste back the exact command with it filled in.
i ran the command after the update now have this Agents:
- main (default)
Identity: 🌹 Jarvis (IDENTITY.md)
Workspace: ~/.openclaw/workspace
Agent dir: ~/.openclaw/agents/main/agent
Model: openrouter/stepfun/step-3.5-flash:free
Routing rules: 1
Routing: default (no explicit rules)
Routing rules:- discord accountId=default
- stock
Workspace: ~/.openclaw/workspace-stock
Agent dir: ~/.openclaw/agents/stock/agent
Model: openrouter/auto
Routing rules: 1
Routing rules:- discord accountId=default peer=channel:1469820904606405758
Routing rules map channel/account/peer to an agent. Use --bindings for full rules.
Channel status reflects local config/creds. For live health: openclaw channels status --probe.
- discord accountId=default peer=channel:1469820904606405758
Perfect — that output is exactly the clean routing shape you want:
stockhas the most-specific rule:peer=channel:1469820904606405758
→ only that Discord channel routes to the stock agent.mainhas the catch‑all:discord accountId=default
→ everything else on Discord (including#general) routes to main.
Because OpenClaw routing is “most-specific wins”, the peer=channel:… binding will always beat the generic accountId=default binding. So you’re good.
Quick sanity test (recommended)
- Send “test” in #stocks → should be handled by stock agent.
- Send “test” in #general → should be handled by main agent.
If stock doesn’t answer right now, it’s likely just the openrouter/auto model not found issue (not routing). For a quick temporary fix, set the stock agent’s model to the same model as main later.
Next step: enable “@stock forwarding” from #general
To get your desired UX (“I’m in #general, I type @stock …, main forwards, stock replies in #stocks, and main confirms”), you need agent-to-agent messaging enabled.
Add this to config:
{
tools: {
agentToAgent: { enabled: true, allow: ["main", "stock"] }
},
session: {
agentToAgent: { maxPingPongTurns: 0 }
}
}
Then teach main (in main’s AGENTS.md or SOUL.md) a rule like:
- If message starts with
@stockor/stock:- forward the request to session key:
agent:stock:discord:channel:1469820904606405758
- then reply in #general: “Sent to #stocks — check there.”
If you want, paste your current bindings block (openclaw config get bindings) and I’ll tell you exactly where to drop the agentToAgent config so it stays tidy.
igvme thecommado addis conig {
tools: {
agentToAgent: { enabled: true, allow: ["main", "stock"] }
},
session: {
agentToAgent: { maxPingPongTurns: 0 }
}
}
Run these two commands (they patch your existing config safely), then restart the gateway:
openclaw config set tools.agentToAgent '{"enabled":true,"allow":["main","stock"]}' --json
openclaw config set session.agentToAgent.maxPingPongTurns 0 --json
openclaw gateway restart
Verify it stuck:
openclaw config get tools.agentToAgent
openclaw config get session.agentToAgent
analso the commto set stock to smamodel iusemain
To set stock to the same default model as main, do this:
- First, confirm the agent list index for
stock:
openclaw config get agents.list
You’ll see something like [{ id: "main", ... }, { id: "stock", ... }].
- Then set the
stockagent’s model to match main (from your output, main is usingopenrouter/stepfun/step-3.5-flash:free). Ifstockisagents.list[1]:
openclaw config set agents.list[1].model '"openrouter/stepfun/step-3.5-flash:free"' --json
openclaw gateway restart
If stock isn’t index [1], replace 1 with whatever index it is.
gent@agent:~$ openclaw config get agents.list
🦞 OpenClaw 2026.2.6-3 (85ed6c7)
Chat automation for people who peaked at IRC.
[
{
"id": "main"
},
{
"id": "stock",
"name": "stock",
"workspace": "/home/agent/.openclaw/workspace-stock",
"agentDir": "/home/agent/.openclaw/agents/stock/agent",
"model": "openrouter/auto"
}
]
agent@agent:~$ so now i wan stock to use this model openrouter/stepfun/step-3.5-flash:free dont just assume im tryingto maksock use global setings , just happen that i want t t use thismodel also , anf i it doesndo well , i can explicitrly run another updatecommandto chnagehe model alll opf this while making sire i dontafect main
Cool — since stock is agents.list[1], you can change only that agent’s model without touching main.
Run exactly:
openclaw config set agents.list[1].model '"openrouter/stepfun/step-3.5-flash:free"' --json
openclaw gateway restart
That updates just the stock agent’s per-agent override (agents.list[1].model). main stays unchanged.
Verify:
openclaw agents list --bindings
openclaw models status --agent stock --probe
Later, if you want to switch stock again (still without affecting main), you run the same openclaw config set agents.list[1].model ... with a different model string.
howe do i confirm stock is agent list 1 as ypou said {Cool — since stock is agents.list[1],}
You already confirmed it in the output you pasted.
openclaw config get agents.list returned an array with two entries:
- index 0:
{ "id": "main" }
- index 1:
{ "id": "stock", ... }
Arrays are 0-based indexed, so the second item is agents.list[1].
If you want a quick “show me just the IDs in order” view, you can also do:
openclaw config get agents.list[0].id
openclaw config get agents.list[1].id
It should print main then stock.
perfect so does that mean i can chnage channle name it wot affect anything since it i added channled id when setting up , if yes then we good , lets test the set up
Yes — if your routing/allowlist is based on channel IDs, you can rename the Discord channel as much as you want and nothing breaks.
Only things that would break are:
- deleting/recreating the channel (new ID), or
- if you used names/slugs in config instead of IDs (you mostly avoided that).
Test checklist (2 minutes)
-
In #stocks (the channel with id
1469820904606405758), send:hello stock
Expect: the stock agent replies.
-
In #general, send:
hello main
Expect: the main agent replies.
-
In #general, test forwarding trigger (for now use a simple prefix like):
@stock what are today’s biggest movers and why?
Expect:
- main replies in #general: “Forwarded to #stocks” (or similar)
- stock posts the actual answer in #stocks
If step (1) fails but (2) works, it’s almost always the stock model/auth (now fixed) or Discord channel allowlist. If you hit issues, paste:
openclaw agents list --bindingsopenclaw channels status --probe(if you’re comfortable sharing it; it redacts secrets)
i think to do that we need to update mains agent md and other required md , but sio you know stock works it responded in its own channel ,
Yep — the remaining piece is just teaching the main agent a “forwarding macro”.
Since your stock agent already replies correctly inside the stocks channel, all we need is:
- In #general: you write something like
@Jarvis /stock … - Main agent recognizes
/stock …and callssessions_sendto the stocks channel session - Stock replies in #stocks
- Main replies in #general with “done / posted in #stocks”
1) Edit MAIN’s instructions (main workspace)
Main agent workspace is ~/.openclaw/workspace (from your agents.list).
Edit:
nano ~/.openclaw/workspace/AGENTS.md
Add a section like this (paste + tweak wording):
## Discord forwarding: /stock
When I'm in Discord and the user message in #general starts with `/stock` (or `@stock` as plain text),
I should forward it to the stock agent's Discord stocks channel session:
- Target sessionKey: agent:stock:discord:channel:1469820904606405758
Process:
1) Strip the `/stock` prefix.
2) Call sessions_send(sessionKey=that key, message=the cleaned request, timeoutSeconds=60).
3) Do NOT paste the full stock answer back into #general.
4) Reply in #general with a short confirmation like:
"Sent to #stocks — reply posted there."
Important: how to trigger it in #general
If your #general is mention-gated (recommended), you’ll usually need to @mention the bot to wake it up, e.g.:
@Jarvis /stock what are today’s biggest movers and why?
(Use /stock as the “router command”; it’s more reliable than trying to parse a real Discord @mention.)
2) Refresh the session (so it picks up the new AGENTS.md)
In #general, send:
/new
(or restart the gateway; /new is easier)
3) Test
In #general:
@Jarvis /stock quick test: say hello
Expected:
- Stock posts “hello” (or similar) in #stocks
- Main replies in #general: “Sent to #stocks…”
If you want, paste your current ~/.openclaw/workspace/AGENTS.md (or just the part you add) and I’ll sanity-check the wording so it reliably triggers and doesn’t cause double-posting.
note i never have this problem before , i had configured main in such a way that only in general could i create new sessions i dont remember how i did it , but now after all this settins we did even in general main cant use /new again openclaw
APP
— 9:36 PM
You are not authorized to use this command.
Only you can see this • Dismiss message also instock stock cant do same in its own chanelle also , need to figire out how to set what channle can use the commands like i did for genral earlier
That “OpenClaw APP → You are not authorized to use this command” is Discord’s native slash command system talking.
It’s not that “main can’t /new” — it’s that your Discord user isn’t allowlisted to execute commands in that guild/channel right now.
On Discord, native slash commands honor the same allowlists, and if you’re not allowlisted, Discord still shows you the command UI but OpenClaw rejects it (docs mention this explicitly). Source: https://docs.openclaw.ai/channels/discord (see “Native command notes”)
Fix (recommended): allowlist your Discord user for that guild (then /new works)
1) Copy your Discord User ID + Guild ID
- Discord settings → Advanced → Developer Mode ON
- Right-click your user → Copy User ID
- Right-click the server → Copy Server ID
2) Add yourself to the guild users allowlist
Run (replace IDs):
openclaw config set 'channels.discord.guilds["YOUR_GUILD_ID"].users' '["YOUR_USER_ID"]' --json
openclaw gateway restart
Then try /new again in #general and in #stocks.
If you want “/new only works in #general (not in #stocks)”
Instead of a guild-wide users allowlist, do per-channel:
openclaw config set 'channels.discord.guilds["YOUR_GUILD_ID"].channels["GENERAL_CHANNEL_ID"].users' '["YOUR_USER_ID"]' --json
openclaw gateway restart
(And don’t add the users allowlist on the stocks channel.)
Alternative (if you used to do it this way): disable native slash commands and use text commands
This makes /new be treated as a normal message again (text command parsing), like older setups:
openclaw config set commands.native false --json
openclaw gateway restart
After restart, /new should be handled as a text command (assuming commands.text: true, which is the default).
If you paste:
openclaw config get channels.discord.guilds
(you can redact anything), I can tell you exactly which guild key you should edit and whether you already have a users allowlist somewhere that’s currently excluding you.
openclaw config set 'channels.discord.guilds["1468636162364246869"].users' '["1040213479622943794"]' --json
openclaw gateway restart i ran this and still not allowed
That makes sense — and your command wasn’t “wrong”, it just isn’t the thing that actually controls command ownership in Discord.
What’s happening
Discord /new is treated as an owner-only command. The most reliable way to define “who is an owner for commands” is:
commands.ownerAllowFrom
Your per-guild channels.discord.guilds[...].users is useful, but it can get bypassed/overridden (especially if there are per-channel users entries).
Fix (fast, definitive)
Run:
openclaw config set commands.ownerAllowFrom '["discord:1040213479622943794"]' --json
openclaw gateway restart
Then try /new again in Discord.
Notes:
- Use the prefixed form
discord:<id>exactly like above (it’s unambiguous). - This does not change routing/bindings; it only makes you “owner” for commands.
If it still fails (next thing to check)
Show me this output:
openclaw config get channels.discord.guilds["1468636162364246869"].channels
openclaw config get commands
Reason: if any channel has "users": [] set under ...channels..., it can accidentally block owner detection in that channel.
Try the commands.ownerAllowFrom fix first though — it’s the cleanest.
agent@agent:~$ openclaw config get channels.discord.guilds["1468636162364276869"].channels
openclaw config get commands
🦞 OpenClaw 2026.2.6-3 (85ed6c7)
Gateway online—please keep hands, feet, and appendages inside the shell at all times.
{
"1469061354752184465": {
"allow": true
},
"1469060251251773506": {
"allow": true
},
"1469059668616806676": {
"allow": true
},
"1469060709248667689": {
"allow": true
},
"1469058886278316174": {
"allow": true
},
"1469054996271206531": {
"allow": true
},
"1468688847155105895": {
"allow": true
},
"1468636162871660566": {
"allow": true
},
"1469820904606400758": {
"allow": true
}
}
🦞 OpenClaw 2026.2.6-3 (85ed6c7)
Welcome to the command line: where dreams compile and confidence segfaults.
{
"native": "auto",
"nativeSkills": "auto",
"restart": true,
"ownerAllowFrom": [
"discord:1040213429622943794"
]
}
agent@agent:~$
?
Run this exactly (this is the “make me command-owner on Discord” switch), then restart:
openclaw config set commands.ownerAllowFrom '["discord:1040213479622943794"]' --json
openclaw gateway restart
Then confirm it’s actually set:
openclaw config get commands.ownerAllowFrom
Now try /new again in Discord.
If it STILL says “not authorized”
Paste these two outputs (they’re short):
openclaw config get commands
openclaw config get channels.discord.guilds["1468636162364246869"]
Most common cause at that point: you’re running /new from a channel that has a per-channel users allowlist that doesn’t include you (or you’re testing from a different Discord user than 1040213479622943794).
okay still didnt work , but going yby what you said letes do it this way ,i need a command that makes me able to use that / inside the channel , so here is channle id 1468636162871660566 and here is user id 1040213429622943794 this should fix it
The reason it still didn’t work: on Discord, native /... commands are authorized only if you match a configured user allowlist for that guild/channel (or the DM allowlist). Setting commands.ownerAllowFrom does not control Discord slash-command auth the way I implied earlier — sorry, that was the wrong knob for this specific Discord “OpenClaw APP not authorized” error.
For Discord guild channels, the check is effectively:
channels.discord.guilds.<guild>.channels.<channel>.usersorchannels.discord.guilds.<guild>.users
If neither list exists (or your ID isn’t in it), you get “You are not authorized to use this command.”
Fix it for just that channel (recommended)
Use your guild id 1468636162364246869, channel id 1468636162871660566, and your user id (double-check it—your message has a different ID than earlier):
openclaw config set 'channels.discord.guilds["1468636162364246869"].channels["1468636162871660566"].users' '["1040213429622943794"]' --json
openclaw gateway restart
Now try /new again in that channel.
Confirm it’s actually in config
openclaw config get 'channels.discord.guilds["1468636162364246869"].channels["1468636162871660566"].users'
If you also want /new in the stocks channel
Run the same command for the stocks channel ID too (replace with your stocks channel id):
openclaw config set 'channels.discord.guilds["1468636162364246869"].channels["STOCKS_CHANNEL_ID"].users' '["1040213429622943794"]' --json
openclaw gateway restart
Important: your Discord user id must be exact
Earlier you used 1040213479622943794, now you wrote 1040213429622943794. If even 1 digit is wrong, it will never authorize.
If you’re unsure, re-copy it from Discord:
Developer Mode ON → right-click your username → Copy User ID.
If it still fails after the per-channel users set, paste this:
openclaw config get 'channels.discord.guilds["1468636162364246869"]'
and I’ll tell you exactly where the wizard stored your guild/channel rules (sometimes it uses a slug key, and we need to edit that entry instead).
still wont work , can i just run this to restart openclaw sudo systemctl restart openclaw if it will make a diuffrece or maybe its th bot that needs a restart
sudo systemctl restart openclaw might help only if your Gateway is actually running as a systemd service named openclaw (often it isn’t). The more common situation is:
- Gateway runs as a user service, or
- Gateway runs in a shell (no systemd), and
systemctlwon’t touch it.
Also: restarting won’t fix “not authorized” if the running Gateway isn’t even using the config file you’re editing — and that’s a very common cause of “I changed config but nothing changes”.
Do this first (this tells us the truth)
Run and paste the output:
openclaw gateway status
That command usually shows whether Config (cli) and Config (service) match. If they don’t match, you’ve been editing one file while the running service reads another.
Correct restart command (works regardless of systemd)
Use:
openclaw gateway restart
That is “restart the bot” (Discord connection restarts with it).
If openclaw gateway status shows config mismatch
Run:
openclaw doctor
openclaw gateway restart
Doctor repairs the service to point at the right entrypoint/config.