#Make a specific openclaw agent answer on a specific Signal group
1 messages · Page 1 of 1 (latest)
That binding shape looks right.
If main still answers, the two usual gotchas are:
-
peer.idmust be the exact raw SignalgroupId- not the group name
- not
signal:group:<id> - not an invite/link id
-
If you have multiple Signal accounts, omitting
match.accountIdonly matches the default account.- For a quick test, try:
{
agentId: "secondary",
match: {
channel: "signal",
accountId: "*",
peer: {
kind: "group",
id: "groupidhere"
}
}
}
Also, within the same match tier, the first matching binding wins, so a duplicate earlier binding can steal it.
Can you paste these 3 things?
openclaw --version
openclaw agents bindings --json
openclaw logs --follow
Then send one test message in that Signal group and paste the relevant log lines.
Docs:
- https://docs.openclaw.ai/channels/channel-routing
- https://docs.openclaw.ai/channels/signal
- https://docs.openclaw.ai/gateway/configuration-reference
- https://docs.openclaw.ai/help/faq
If you want, I can help read the agents bindings --json output with you and spot the mismatch fast.
how do i get the exact group id
Fastest way right now:
- send one test message in that Signal group
- run:
openclaw sessions --all-agents --active 10 --json
Then look for a session key like:
agent:main:signal:group:<groupId>
That <groupId> is the exact value you want in the binding.
Since main is answering right now, you can also narrow it to:
openclaw sessions --agent main --active 10 --json
Then use:
{
agentId: "secondary",
match: {
channel: "signal",
peer: {
kind: "group",
id: "<that exact groupId>"
}
}
}
If you have multiple Signal accounts, add accountId too, or use accountId: "*" while testing.
Docs:
- https://docs.openclaw.ai/channels/signal
- https://docs.openclaw.ai/channels/channel-routing
- https://docs.openclaw.ai/cli/sessions
If you paste the openclaw sessions --agent main --active 10 --json output, I can point to the exact field.
openclaw sessions --all-agents --active 10 --json
Config warnings:\n- plugins.entries.active-memory: plugin disabled (bundled (disabled by default)) but config is present
Config warnings:\n- plugins.entries.active-memory: plugin disabled (bundled (disabled by default)) but config is present
Config warnings:\n- plugins.entries.active-memory: plugin disabled (bundled (disabled by default)) but config is present
Config warnings:\n- plugins.entries.active-memory: plugin disabled (bundled (disabled by default)) but config is present
{
"path": null,
"stores": [
{
"agentId": "main",
"path": "/home/user/.openclaw/agents/main/sessions/sessions.json"
},
{
"agentId": "secondary",
"path": "/home/user/.openclaw/agents/secondary/sessions/sessions.json"
},
{
"agentId": "third",
"path": "/home/user/.openclaw/agents/third/sessions/sessions.json"
}
],
"allAgents": true,
"count": 1,
"activeMinutes": 10,
"sessions": [
{
"key": "agent:main:signal:group:REDACTED",
"updatedAt": 1776682773844,
"ageMs": 50845,
"sessionId": "ca92a363-78c1-4d10-9707-b786c79adec8",
"systemSent": true,
"abortedLastRun": false,
"totalTokens": null,
"totalTokensFresh": false,
"model": "gemma-4-31B",
"modelProvider": "llamacpp",
"contextTokens": 262144,
"agentId": "main", // HERE'S THE ISSUE! IT SHOULD BE SECONDARY
"kind": "group"
}
]
}
check the comment on agentId
Yep, I checked it, and that agentId: "main" is the symptom, not the root cause.
If the binding were matching, that session key would be:
agent:secondary:signal:group:REDACTED
So right now the Signal group is still falling through to the default route.
The next thing I need is:
openclaw agents bindings --json
That tells us whether OpenClaw actually loaded your binding.
Two likely outcomes:
-
Your binding is missing from the loaded bindings
- config path/shape issue
- hot reload didn’t pick it up
- typo in
agentIdorbindingsplacement
-
Your binding is present, but still not matching
- most likely Signal
accountIdmismatch - quick test: add
accountId: "*"to that binding
- most likely Signal
Example test binding:
{
agentId: "secondary",
match: {
channel: "signal",
accountId: "*",
peer: {
kind: "group",
id: "REDACTED"
}
}
}
Also, the active-memory warnings are unrelated here.
Paste openclaw agents bindings --json and I’ll tell you exactly what’s off.
[
{
"agentId": "main",
"match": {
"channel": "signal",
"peer": {
"kind": "direct",
"id": "MYID"
}
},
"description": "signal peer=direct:MYID"
},
{
"agentId": "secondary",
"match": {
"channel": "signal",
"peer": {
"kind": "group",
"id": "REDACTED"
}
},
"description": "signal peer=group:REDACTED"
},
{
"agentId": "third",
"match": {
"channel": "signal",
"peer": {
"kind": "direct",
"id": "FRIENDID"
}
},
"description": "signal peer=direct:FRIENDID"
},
]
but when I look at sessions, main still handles it:
agent:main:signal:group:REDACTED
Nice, this narrows it down a lot.
Your main binding is peer.kind: "direct", so it should not steal a Signal group message. That means the secondary binding is loaded, but the runtime still isn’t matching it.
The two most likely causes now are:
-
Signal account scope
- omitted
accountIdonly matches the default Signal account - if that group is arriving on a different Signal account, it falls through to
main
- omitted
-
stale runtime state
- config is loaded, but the gateway is still routing with old state
I’d try this exact test:
{
agentId: "secondary",
match: {
channel: "signal",
accountId: "*",
peer: {
kind: "group",
id: "REDACTED"
}
}
}
Then restart once:
openclaw gateway restart
Then send one new message in that Signal group and rerun:
openclaw sessions --all-agents --active 10 --json
If it still comes out as:
agent:main:signal:group:REDACTED
then I’d call this a likely bug, not config error.
If you hit that point, please file a GitHub issue with:
openclaw --versionopenclaw agents bindings --jsonopenclaw sessions --all-agents --active 10 --json
Issue tracker: https://github.com/openclaw/openclaw/issues
Docs: https://docs.openclaw.ai/channels/channel-routing https://docs.openclaw.ai/gateway/configuration-reference
If you want, paste your channels.signal config too, especially if you use multiple Signal accounts.
how do i init that agent in TUI first?
You don’t need to init it first for routing to work, but if you want to bootstrap secondary manually first, do this:
openclaw tui
Then in the TUI:
/agent secondary
or press Ctrl+G and pick secondary.
Then send any message, even just:
hi
That first run will bootstrap the agent workspace.
If secondary does not exist yet, create it first:
openclaw agents add secondary
That launches the agent onboarding flow. After that, go back to TUI and switch with:
/agent secondary
Useful docs:
- https://docs.openclaw.ai/web/tui
- https://docs.openclaw.ai/cli/agents
- https://docs.openclaw.ai/start/bootstrapping
If you want, next I can help you verify whether secondary has actually bootstrapped cleanly.
do i need two different signal accounts?
No, not for this.
One Signal account/number can still route:
- one group ->
secondary - another group ->
main - specific DMs -> other agents
So for multi-agent routing, you do not need two Signal accounts.
You’d only want multiple Signal accounts if you need:
- different outbound phone numbers / identities
- different per-account Signal config
- separate bot accounts for different use cases
One important nuance from the Signal docs: if you run the bot on your personal Signal account, it ignores your own messages for loop protection. For “I message the bot and it replies,” a separate bot number is recommended.
So if you only have one Signal account configured, then your routing problem is probably not an account-count issue.
Docs:
If you want, I can help narrow the next most likely cause from here.
how to set the default openclaw agent?
Set default: true on the agent you want in agents.list.
Example:
{
agents: {
list: [
{
id: "secondary",
default: true,
workspace: "~/.openclaw/workspace-secondary"
},
{
id: "main",
workspace: "~/.openclaw/workspace"
},
{
id: "third",
workspace: "~/.openclaw/workspace-third"
}
]
}
}
A couple of gotchas:
- only one agent should have
default: true - if none has it, OpenClaw uses the first entry in
agents.list - this affects fallback routing and commands/TUI sessions where no explicit agent is selected
So yes, if you want secondary to be the default, make it default: true and remove that flag from main.
Docs:
- https://docs.openclaw.ai/gateway/configuration-reference
- https://docs.openclaw.ai/concepts/multi-agent
If you want, paste your agents.list block and I’ll show the exact edit.
even after setting secondary as the default and the binding to the signal group... main still answers the group
Yeah, that’s the big tell.
An exact peer binding should beat the default agent every time. And if you even changed the default to secondary but live Signal traffic still lands on main, then this is no longer a normal config mistake.
The two things I’d check next are:
- the daemon is using a different config/profile than the CLI
- the gateway runtime is stale or there’s a bug
Please run these and paste the output:
openclaw --version
openclaw gateway status
openclaw status --all
Then do one restart:
openclaw gateway restart
and test the Signal group again.
Why these matter:
openclaw gateway statusshows which config the running service is likely using- if that path/profile is different from the file you edited, that explains everything
- if it’s the same config and a restart still routes to
main, I’d treat it as a likely bug
At that point, please file a GitHub issue with:
openclaw --version
openclaw gateway statusopenclaw agents bindings --jsonopenclaw sessions --all-agents --active 10 --json
Issue tracker: https://github.com/openclaw/openclaw/issues
Docs: https://docs.openclaw.ai/help/faq https://docs.openclaw.ai/channels/channel-routing
If you paste openclaw gateway status next, I can sanity-check it with you.
./agents outputs:
agents:
(none)
If you mean /agents in the TUI, then agents: (none) is a huge clue.
That does not line up with the earlier CLI output where you had:
mainsecondarythird
So I’m pretty confident now that your CLI and the running TUI/gateway are not looking at the same config/profile/runtime.
In other words, you likely edited one OpenClaw config, but the live gateway that Signal is hitting is using another one.
Please run these from the same shell/profile you use to start TUI:
openclaw --version
openclaw gateway status
openclaw agents list --bindings
If you use profiles, make sure you use the same one everywhere, for example:
openclaw --profile myprofile gateway status
openclaw --profile myprofile tui
openclaw --profile myprofile agents list --bindings
Also, if your TUI is connected to a remote gateway, the agents/workspaces live on the gateway host, not your local machine.
So yes, agents: (none) strongly suggests wrong gateway / wrong profile / wrong config path, not a bad Signal binding.
Docs:
- https://docs.openclaw.ai/web/tui
- https://docs.openclaw.ai/help/faq
- https://docs.openclaw.ai/concepts/multi-agent
If you paste openclaw gateway status, I can help pinpoint exactly where it’s reading config from.
now openclaw ignores me in a group
Ah, that’s a different layer than routing.
bindings choose which agent should answer.
But Signal group messages still have to pass group access + mention gating first.
For Signal, the common reasons it ignores a group are:
channels.signal.groupPolicyis stillallowlistchannels.signal.groupAllowFromdoes not include yourequireMentionis on, but Signal has no native mentions, so you need textmentionPatterns
Quickest permissive test:
{
channels: {
signal: {
groupPolicy: "open",
groups: {
"*": { requireMention: false }
}
}
}
}
Then restart:
openclaw gateway restart
If that makes it reply, then the problem is definitely group gating, not bindings.
Safer version for just your group:
{
channels: {
signal: {
groupPolicy: "allowlist",
groupAllowFrom: ["+1555YOURNUMBER"],
groups: {
"REDACTED": { requireMention: false }
}
}
}
}
If you do want mention-only behavior on Signal, you need mention patterns, for example:
{
agents: {
list: [
{
id: "secondary",
groupChat: { mentionPatterns: ["openclaw", "@openclaw"] }
}
]
}
}
Important nuance: DM pairing does not unlock group triggers. Groups still need groupPolicy / groupAllowFrom.