#Gateway Port Separation for Sandboxed Agents

1 messages Ā· Page 1 of 1 (latest)

devout islandBOT
silver tendon
#

@dusty juniper Any advice?

dusty juniperBOT
#

Yep, a few things jump out.

You probably got bitten by shared state, not just a shared port.

In OpenClaw:

  • multiple agents can live under one gateway
  • multiple gateways on one Mac are possible too, but only if each one has its own:
    • OPENCLAW_CONFIG_PATH
    • OPENCLAW_STATE_DIR
    • agents.defaults.workspace
    • gateway.port

If you only changed the port, Agent 2 can still ā€œfollowā€ Agent 1 because they’re reading the same config/state. That also fits the weird model/auth drift.

Also, a second agent usually does not need a second gateway at all. One gateway can host multiple isolated agents + Telegram accounts. Docs:

#

My advice:

  1. Don’t nuke the machine yet.
  2. First check whether the running service and the CLI are even looking at the same config.
  3. Paste these:
openclaw --version
openclaw gateway status --deep
openclaw status --all
openclaw models status

If you already used profiles, run them as:

#
openclaw --profile <name> gateway status --deep

Big smoking gun: if gateway status --deep shows Config (cli) and Config (service) are different, that’s why ports/settings keep ā€œresettingā€.

If you want, I can help you choose between:

  • recommended: one gateway, multiple agents
  • hard isolation: one profile per gateway, separate ports/services

Paste the output and we can untangle it without going full scorched earth.

silver tendon
#

@dusty juniper Can you tell me exactly how to do the setup for one agent and any subsequent agents so they don’t have this same issue (port is in use error)?

dusty juniperBOT
#

I’m going to pull the exact multi-agent setup pattern from the docs so I can give you a clean recipe instead of hand-wavy advice.

#

Exact setup, first agent

Run onboarding once:

openclaw onboard
openclaw gateway install

That gives you the default gateway and the default agent, which is usually main.

If you want Telegram for that first agent, set it up normally during onboarding, or put it in config.


#

Exact setup, each additional agent

Do not run openclaw onboard again for extra agents.

Instead, add a new agent:

openclaw agents add agent2 \
  --workspace ~/.openclaw/workspace-agent2 \
  --bind telegram:agent2

That creates a separate:

  • workspace
  • agent state dir
  • sessions
#
  • binding

Then give that Telegram account its own bot token in config.

Example config shape:

{
  agents: {
    list: [
      { id: "main", workspace: "~/.openclaw/workspace-main" },
      { id: "agent2", workspace: "~/.openclaw/workspace-agent2" },
    ],
  },
  bindings: [
    { agentId: "main", match: { channel: "telegram", accountId: "default" } },
#
    { agentId: "agent2", match: { channel: "telegram", accountId: "agent2" } },
  ],
  channels: {
    telegram: {
      defaultAccount: "default",
      accounts: {
        default: {
          botToken: "TOKEN_FOR_AGENT1",
          dmPolicy: "pairing",
        },
        agent2: {
          botToken: "TOKEN_FOR_AGENT2",
          dmPolicy: "pairing",
        },
      },
#
    },
  },
}

Then restart:

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

For agent 3, 4, etc.

Same pattern:

#
openclaw agents add agent3 \
  --workspace ~/.openclaw/workspace-agent3 \
  --bind telegram:agent3

Then add channels.telegram.accounts.agent3.botToken and restart.


Why this avoids the port issue

Because you are not starting another gateway.

You are only adding more agents under the same running gateway, so there’s no second process trying to claim port 18789.


#

If you truly want separate gateways per agent

Only do this if you want hard instance isolation.

Then every gateway must use a separate profile:

openclaw --profile agent1 onboard
openclaw --profile agent1 config set gateway.port 18789 --strict-json
openclaw --profile agent1 gateway install --force

openclaw --profile agent2 onboard
openclaw --profile agent2 config set gateway.port 19789 --strict-json
openclaw --profile agent2 gateway install --force

Then check both:

#
openclaw --profile agent1 gateway status --deep
openclaw --profile agent2 gateway status --deep

Important rules for multi-gateway:

  • always use --profile
  • leave at least 20 ports between base ports
  • never share config/state/workspace between instances
  • never run plain openclaw onboard / openclaw gateway install if you mean to modify a profiled instance

Short version

If your goal is just ā€œmultiple personal agents on one Macā€, do this:

#
  • one gateway
  • openclaw agents add ... for each new agent
  • one Telegram bot/account per agent
  • bind each account to its agent

That is the setup I’d recommend for you.

If you want, I can give you a copy-paste example openclaw.json for:

  1. 2 Telegram agents on 1 gateway, or
  2. 2 fully separate profiled gateways.
silver tendon
#

For my existing agent, it says the OpenClaw.json file has an unexpected character ā€œ\ā€ on line 22 but I can’t see it in the json file.

dusty juniperBOT
#

Ah, that’s usually one of two things:

  1. you’re looking at the wrong config file, or
  2. there’s a hidden backslash/control character on that line.

A couple of important gotchas:

  • OpenClaw config is JSON5, not plain JSON.
  • If you’re using a profile, you must inspect the file with the same --profile or you’ll be looking at the wrong file.

Try this first:

openclaw --version
openclaw config file
openclaw gateway status --deep
#

If this agent is profiled, use:

openclaw --profile <name> config file
openclaw --profile <name> gateway status --deep

Then reveal the suspicious lines with hidden chars shown:

sed -n '18,26p' "$(openclaw config file)" | cat -vet

If profiled:

#
sed -n '18,26p' "$(openclaw --profile <name> config file)" | cat -vet

That will expose stuff your editor may hide.

Common causes on that error:

  • a stray \ before a quote
  • a pasted Windows-style path inside a string
  • a hidden escape/control char from copy/paste
  • line numbers being a little off, so the real problem is 1-2 lines above

If you paste lines 18-26 here, I can usually spot it fast.

silver tendon
#

heidi@Kates-Mac-mini ~ % openclaw --profile heidi status
Failed to read config at /Users/heidi/.openclaw-heidi/openclaw.json SyntaxError: JSON5: invalid character '"' at 22:2
at syntaxError (/opt/homebrew/lib/node_modules/openclaw/node_modules/json5/lib/parse.js:1110:17)
at invalidChar (/opt/homebrew/lib/node_modules/openclaw/node_modules/json5/lib/parse.js:1055:12)
at Object.afterPropertyValue (/opt/homebrew/lib/node_modules/openclaw/node_modules/json5/lib/parse.js:676:15)
at Object.default (/opt/homebrew/lib/node_modules/openclaw/node_modules/json5/lib/parse.js:168:37)
at lex (/opt/homebrew/lib/node_modules/openclaw/node_modules/json5/lib/parse.jsšŸ’Æ42)
at Object.parse (/opt/homebrew/lib/node_modules/openclaw/node_modules/json5/lib/parse.js:25:17)
at Object.loadConfig (file:///opt/homebrew/lib/node_modules/openclaw/dist/io-CNTgoVgA.js:18660:24)
at readCliBannerTaglineMode (file:///opt/homebrew/lib/node_modules/openclaw/dist/banner-DRvsS64z.js:13:51)
at resolveTaglineMode (file:///opt/homebrew/lib/node_modules/openclaw/dist/banner-DRvsS64z.js:291:9)
at formatCliBannerLine (file:///opt/homebrew/lib/node_modules/openclaw/dist/banner-DRvsS64z.js:300:9) {
lineNumber: 22,
columnNumber: 2
}

Modified

{
"gateway": {
"mode": "local",

"auth": {   
  "mode": "token",
 ā€œ[redacted]"
}, "port": 18793

},
"channels": {
"telegram": {
"enabled": true,
"botToken": "[redacted]",
"dmPolicy": "allowlist",
}
},
"model": {
"Provider": "anthropic",
{
"gateway": {
"mode": "local",
"auth": {
"mode": "token",
"token": "YOUR_GATEWAY_TOKEN"
},
"port": 18793
},
"channels": {
"telegram": {
"enabled": true,
"botToken": "YOUR_BOT_TOKEN",
"dmPolicy": "allowlist",
"allowFrom": ["YOUR_NUMERIC_TELEGRAM_ID"]

dusty juniperBOT
#

I can already see a couple of broken lines in that pasted snippet. I’m going to verify the right model key before I tell you what the corrected config should look like.

#

Yep, I can see the problem from that snippet.

Your file is malformed in multiple places:

  1. This line is broken:
ā€œ[redacted]"

It should be a real key/value pair, like:

token: "[redacted]"
  1. You appear to have two JSON objects pasted together.
#

I can literally see a second { starting again partway through the file.

  1. This part is not the right model shape:
"model": {
  "Provider": "anthropic",

For OpenClaw, use agents.defaults.model, with a full model ref.


Easiest fix

I’d replace the whole profile config with a minimal known-good file for now:

#
{
  gateway: {
    mode: "local",
    auth: {
      mode: "token",
      token: "YOUR_GATEWAY_TOKEN",
    },
    port: 18793,
  },

  channels: {
    telegram: {
      enabled: true,
      botToken: "YOUR_BOT_TOKEN",
      dmPolicy: "allowlist",
#
      allowFrom: ["YOUR_NUMERIC_TELEGRAM_ID"],
    },
  },

  agents: {
    defaults: {
      model: "anthropic/claude-sonnet-4-6",
    },
  },
}

Then run:

#
openclaw --profile heidi status
openclaw --profile heidi gateway status --deep

What was specifically wrong

  • curly smart quote ā€œ instead of a normal config entry
  • missing token: key
  • duplicate { ... } block pasted into the file
  • wrong model config key

Important note

#

For a profiled setup, make sure you are editing:

/Users/heidi/.openclaw-heidi/openclaw.json

not the default ~/.openclaw/openclaw.json.

If you want, paste the full cleaned file here before you save it and I’ll sanity-check it.

silver tendon
#

Okay I’m just going to go nuclear and start from scratch. Can you tell me how to do that and then walk me through setup for agent 1 and agent 2 so I don’t have this issue again?

dusty juniperBOT
#

I want to make sure the onboarding flag for the port is real before I hand you a copy-paste command.

#

Yep. If you want the cleanest reset with hard isolation, I’d do a fresh rebuild using two profiles and leave the old broken state alone until the new setup is working.

That gives you:

  • separate config
  • separate state
  • separate workspace
  • separate service name
  • separate gateway port

So, ā€œnuclearā€ without actually deleting anything yet. Docs: https://docs.openclaw.ai/gateway/multiple-gateways

Plan

Use:

  • agent1 profile on port 18793
#
  • agent2 profile on port 19789

That leaves plenty of port spacing.


Step 0, do not delete old stuff yet

For now, do not touch the old default setup.
Just build two fresh profiles and ignore the old one.


Step 1, create Agent 1 cleanly

Run:

#
openclaw --profile agent1 onboard --gateway-port 18793

During onboarding for Agent 1:

  • choose local gateway
  • choose your Anthropic setup for Agent 1
  • enter Telegram bot token for Agent 1
  • choose/install daemon when prompted
  • keep this fully isolated to the agent1 profile

Then verify:

openclaw --profile agent1 status
#
openclaw --profile agent1 gateway status --deep
openclaw --profile agent1 models status

What you want to see:

  • gateway reachable
  • correct port 18793
  • correct config/service path
  • Anthropic auth working

Step 2, create Agent 2 cleanly

Run:

#
openclaw --profile agent2 onboard --gateway-port 19789

During onboarding for Agent 2:

  • choose local gateway
  • set up Anthropic separately for Agent 2
  • enter Telegram bot token for Agent 2
  • choose/install daemon when prompted

Then verify:

openclaw --profile agent2 status
openclaw --profile agent2 gateway status --deep
#
openclaw --profile agent2 models status

Step 3, day-to-day commands

From now on, always manage them with the profile flag:

openclaw --profile agent1 status
openclaw --profile agent1 gateway restart

openclaw --profile agent2 status
openclaw --profile agent2 gateway restart
#

If you run bare commands like:

openclaw onboard
openclaw gateway install
openclaw status

you’ll be back in the default profile, which is how this gets confusing again.


Step 4, sanity checks after both are up

Run both:

#
openclaw --profile agent1 gateway status --deep
openclaw --profile agent2 gateway status --deep

Check that:

  • Agent 1 uses 18793
  • Agent 2 uses 19789
  • each one shows its own config path
  • Config (cli) and Config (service) agree for each profile

Rules that prevent this problem

  1. One profile per isolated gateway
#
  1. Never share the same port
  2. Leave at least 20 ports between gateways
  3. Always use the same --profile when managing that agent
  4. Do not re-run plain openclaw onboard once you switch to profiles

My recommendation

Since you explicitly want totally separate gateways, this is the route I’d use.

If you want, next I can give you a literal checklist of what to click/choose in onboarding for Agent 1, then the exact same checklist for Agent 2.

silver tendon
#

I’m fine with all agents being on the same gateway if that’s simplest.

dusty juniperBOT
#

One more thing I want to verify before I give you the full recipe: the cleanest supported way to set up per-agent auth when Agent 2 has its own Anthropic/API credentials.

#

Yep, if you’re okay with one gateway, that’s the simplest path by far, and it avoids the port fight entirely.

I’d do a fresh start in one new profile, then add both agents under that one gateway.

Clean rebuild plan

Use one fresh profile, for example home.

Why this is nice:

  • it leaves the broken old setup alone
  • you only run one gateway
  • Agent 1 and Agent 2 live under that gateway
  • future agents are just agents add ..., no extra port drama

Docs:

#
openclaw --profile home onboard --gateway-port 19789

During onboarding:

  • choose local
  • choose your Anthropic setup for Agent 1 / main
  • install the daemon when prompted
  • skip Telegram for now if possible, because it’s cleaner to add multi-account Telegram after onboarding

Then verify:

openclaw --profile home status
openclaw --profile home gateway status --deep
#
openclaw --profile home models status

Step 2, configure Telegram for Agent 1

Set up Telegram as the default account on this gateway:

openclaw --profile home config set channels.telegram.enabled true --strict-json
openclaw --profile home config set channels.telegram.defaultAccount default
openclaw --profile home config set channels.telegram.accounts.default.botToken "YOUR_AGENT1_BOT_TOKEN"
openclaw --profile home config set channels.telegram.accounts.default.dmPolicy pairing
#

That makes Agent 1’s bot the default Telegram account.


Step 3, add Agent 2

Now add the second agent under the same gateway:

openclaw --profile home agents add agent2 \
  --workspace ~/.openclaw-home/workspace-agent2 \
  --bind telegram:agent2 \
  --model anthropic/claude-sonnet-4-6

That creates a separate:

#
  • workspace
  • sessions
  • agent state
  • Telegram binding

Step 4, configure Telegram for Agent 2

Now add Agent 2’s Telegram bot:

openclaw --profile home config set channels.telegram.accounts.agent2.botToken "YOUR_AGENT2_BOT_TOKEN"
openclaw --profile home config set channels.telegram.accounts.agent2.dmPolicy pairing

#

Step 5, if Agent 2 has its own Anthropic/API credentials

If Agent 2 should use a different Anthropic/API key than Agent 1, configure it separately:

openclaw --profile home secrets configure --agent agent2

That writes Agent 2’s auth into its own per-agent auth store.

If both agents can share the same auth, you can skip this.


Step 6, restart and verify everything

#
openclaw --profile home gateway restart
openclaw --profile home agents list --bindings
openclaw --profile home channels status --probe
openclaw --profile home status

What you want:

  • one gateway on port 19789
  • main bound to Telegram account default
  • agent2 bound to Telegram account agent2

Step 7, pair both Telegram bots

#

Because we used dmPolicy: pairing, do this for each bot:

  1. DM the bot in Telegram
  2. get the pairing code
  3. approve it:
openclaw --profile home pairing list telegram
openclaw --profile home pairing approve telegram <CODE>

Do that once for Agent 1’s bot and once for Agent 2’s bot.


From now on, this is the rule

#
  • Do not run openclaw onboard again for new agents
  • Do not start extra gateways for new agents
  • For every new agent, do:
openclaw --profile home agents add ...

That’s the key difference.


Quick mental model

  • One gateway = one port
  • Many agents = many isolated brains under that gateway
  • Many Telegram bots/accounts = each bot can route to a different agent
#

If you want, next I can give you a final expected config shape for this exact 2-agent Telegram setup so you can compare your file against it.

silver tendon
#

I just reset my computer to factory and kicked off a reinstall of OpenClaw can you tell me (step by step) how to create the two agents? I want them each to have their own workspace and clean config in their own device profile, but if it’s best for them to share a gateway (and both will be performant if they do), that’s fine with me.

dusty juniperBOT
#

Yep. Since you’re starting fresh, I’d do the normal / simplest setup:

  • one gateway
  • two agents
  • each agent gets its own workspace
  • each agent can have its own auth / Google / API keys
  • each agent can have its own Telegram bot

That is the setup I’d recommend. It performs fine. OpenClaw is designed for multiple agents on one gateway.

Important terminology

  • Gateway profile = the whole OpenClaw instance (--profile home)
  • Agent = one isolated brain inside that gateway

So if you want the simplest reliable setup, use:

#
  • 1 gateway profile
  • 2 agents inside it

Step by step

0. Verify install

After OpenClaw finishes installing:

openclaw --version

#

1. Create one fresh gateway profile

Use a brand-new profile so everything starts clean:

openclaw --profile home onboard --gateway-port 19789

During onboarding:

  • choose local
  • set up the main/default agent with your preferred Anthropic auth
  • install the daemon when prompted
  • skip Telegram for now if possible, because multi-bot config is cleaner after onboarding

Then verify:

#
openclaw --profile home status
openclaw --profile home gateway status --deep
openclaw --profile home models status

2. Set up Agent 1’s Telegram bot

Make Agent 1 the default Telegram account on this gateway:

openclaw --profile home config set channels.telegram.enabled true --strict-json
openclaw --profile home config set channels.telegram.defaultAccount default
openclaw --profile home config set channels.telegram.accounts.default.botToken "AGENT1_BOT_TOKEN"
#
openclaw --profile home config set channels.telegram.accounts.default.dmPolicy pairing

That gives the main agent its own Telegram bot.


3. Create Agent 2 with its own workspace

Now add the second agent:

openclaw --profile home agents add agent2 \
  --workspace ~/.openclaw-home/workspace-agent2 \
  --bind telegram:agent2 \
#
  --model anthropic/claude-sonnet-4-6

That creates a separate workspace and separate agent state for Agent 2.


4. Set up Agent 2’s Telegram bot

Now add Agent 2’s bot token:

openclaw --profile home config set channels.telegram.accounts.agent2.botToken "AGENT2_BOT_TOKEN"
openclaw --profile home config set channels.telegram.accounts.agent2.dmPolicy pairing
#

Now:

  • Telegram account default → Agent 1 (main)
  • Telegram account agent2 → Agent 2

5. Give Agent 2 its own credentials, if needed

If Agent 2 should use its own Anthropic/API/Google credentials, run:

openclaw --profile home secrets configure --agent agent2

That is the right path for per-agent secrets/auth.

#

You can use the same pattern later for other per-agent credentials too.


6. Restart and verify

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

You want to see:

  • one gateway on 19789
  • agent main
#
  • agent agent2
  • Telegram bindings for both

7. Pair both Telegram bots

Because we used dmPolicy: pairing, do this once per bot:

  1. DM the bot in Telegram
  2. get the pairing code
  3. approve it:
openclaw --profile home pairing list telegram
openclaw --profile home pairing approve telegram <CODE>
#

Do that for both Agent 1’s bot and Agent 2’s bot.


Rule for every future agent

For Agent 3, 4, etc:

  • do not run openclaw onboard again
  • do not start another gateway
  • just run:
openclaw --profile home agents add ...

That’s what avoids the port-in-use problem.

#

If you want true full gateway separation later

That’s a different setup:

  • openclaw --profile agent1 ...
  • openclaw --profile agent2 ...

But I would not start there. One gateway + multiple agents is much easier.

If you want, I can give you the exact final expected config shape for this 2-agent Telegram setup so you can compare your file line-by-line.

silver tendon
#

What gateway bind method?

dusty juniperBOT
#

Loopback.

For your setup, choose:

  • Gateway mode: local
  • Bind: loopback
  • Auth: token

That’s the safest and simplest when everything is running on the same Mac.

Only use:

  • tailnet / Tailscale Serve if you want to reach the gateway from other devices
  • lan if you explicitly want it exposed on your local network

So for onboarding, pick the option that means localhost / this machine only.

silver tendon
#

I got all the way to hatching the Main profile and it says it’s not connected to the gateway.

dusty juniperBOT
#

That usually means the UI hatched, but the gateway process itself isn’t reachable yet.

Run these in the same profile you just onboarded:

openclaw --version
openclaw --profile home gateway restart
openclaw --profile home gateway status --deep
openclaw --profile home status --all

If your profile name isn’t home, replace it with whatever you used.
If you didn’t use a custom profile, drop --profile home.

What I’m looking for

In gateway status --deep:

#
  • Runtime: running
  • RPC probe: ok
  • correct port
  • Config (cli) and Config (service) matching

If it still says not connected

Run:

openclaw --profile home gateway install --force
openclaw --profile home gateway restart
openclaw --profile home gateway status --deep

That fixes a lot of first-run ā€œservice installed with wrong config/profileā€ cases.

#

Paste the output of gateway status --deep here and I can tell you exactly which part is failing.

silver tendon
#

Regardless of what I say it says ā€œnot connected to gateway - message not sentā€

dusty juniperBOT
#

Yep, that means the client is completely disconnected from the gateway right now, so typing in the hatch won’t do anything yet.

Don’t keep retrying in the UI. Open a separate Terminal and run the commands for the profile you actually used.

If you used the fresh profile I suggested

openclaw --profile home gateway status --deep
openclaw --profile home gateway install --force
openclaw --profile home gateway restart
openclaw --profile home gateway status --deep
openclaw --profile home status --all

If you used the default profile instead

#
openclaw gateway status --deep
openclaw gateway install --force
openclaw gateway restart
openclaw gateway status --deep
openclaw status --all

What I need from you is the output of:

openclaw --profile home gateway status --deep

or the non-profile version if that’s what you used.

The key lines are:

#
  • Runtime: ...
  • RPC probe: ...
  • Listening: ...
  • Config (cli): ...
  • Config (service): ...

If Config (cli) and Config (service) don’t match, we found the bug.
If Runtime is stopped or RPC probe fails, we know the gateway never actually started.

silver tendon
#

It says the port is already use. I did the standard install with port 18789

dusty juniperBOT
#

Perfect, that’s actually a pretty clear failure mode.

18789 is already occupied, so don’t fight it.
For a fresh install, the fastest move is to switch to a clean port like 19789 and keep going.

If you used the default profile

Run:

openclaw config set gateway.port 19789 --strict-json
openclaw gateway install --force
openclaw gateway restart
openclaw gateway status --deep

If you used a named profile

#

Run:

openclaw --profile home config set gateway.port 19789 --strict-json
openclaw --profile home gateway install --force
openclaw --profile home gateway restart
openclaw --profile home gateway status --deep

After that, try the hatch again.

Why this works

OpenClaw defaults to 18789, so if anything is already listening there, the gateway won’t start.
Using 19789 is totally fine, and for a single shared gateway with multiple agents it won’t hurt performance at all.

If gateway status --deep still fails after changing to 19789, paste that output here and I’ll help you nail the next step.

silver tendon
#

It’s working. What’s next?

dusty juniperBOT
#

Nice šŸŽ‰

Next, turn that working gateway into your 2-agent setup.

I’m assuming you’re on the default profile now. If you ended up using a named profile, prepend openclaw --profile <name> to each command below.

1. If Agent 1’s Telegram bot is not configured yet

openclaw config set channels.telegram.enabled true --strict-json
openclaw config set channels.telegram.defaultAccount default
openclaw config set channels.telegram.accounts.default.botToken "AGENT1_BOT_TOKEN"
openclaw config set channels.telegram.accounts.default.dmPolicy pairing

2. Create Agent 2

#
openclaw agents add agent2 \
  --workspace ~/.openclaw/workspace-agent2 \
  --bind telegram:agent2 \
  --model anthropic/claude-sonnet-4-6

3. Add Agent 2’s Telegram bot

openclaw config set channels.telegram.accounts.agent2.botToken "AGENT2_BOT_TOKEN"
openclaw config set channels.telegram.accounts.agent2.dmPolicy pairing

4. Restart and verify

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

5. Pair both bots in Telegram

DM each bot, get its pairing code, then approve:

openclaw pairing list telegram
openclaw pairing approve telegram <CODE>

6. If Agent 2 should use its own API keys / Google creds

#
openclaw secrets configure --agent agent2

That gives Agent 2 its own auth store.

If you want, I can give you the exact expected final config shape for the 2-bot Telegram setup before you run these.

silver tendon
#

How do you want to hatch your bot?
Hatch in TUI (recommended)
OpenClaw tui - ws://127.0.0.1:19789 - agent main - session main
connecting | idle

Pairing required. Run ā€˜OpenClaw devices list’, approve your request ID, then reconnect.
gateway disconnected: pairing required | pairing required: run OpenClaw devices list
agent main | session main | unknown | tokens ?

dusty juniperBOT
#

Nice, that’s actually progress, the gateway is up.

This is not a port problem now.
It just means the TUI device needs to be approved once.

Run:

openclaw devices list

Find the pending requestId, then approve it:

openclaw devices approve <REQUEST_ID>
#

Then reconnect / hatch again.

If you’re using a named profile, do the same with that profile:

openclaw --profile home devices list
openclaw --profile home devices approve <REQUEST_ID>

Then reopen the TUI.

If devices list shows nothing pending, reconnect once, then run devices list again.

silver tendon
#

When I run that it just says not connected.

dusty juniperBOT
#

I want to make sure I give you the right devices command here, because this smells like the CLI is talking to the wrong gateway instance/port.

#

Ah, got it, that means the CLI is talking to the wrong gateway/port, even though the TUI reached ws://127.0.0.1:19789.

Use the gateway explicitly.

1. Get the gateway token

If you’re on the default profile:

openclaw config get gateway.auth.token

If you used a named profile:

openclaw --profile home config get gateway.auth.token
#

2. List devices against the correct gateway

openclaw devices list \
  --url ws://127.0.0.1:19789 \
  --token "PASTE_THE_TOKEN_HERE"

3. Approve the pending request

openclaw devices approve <REQUEST_ID> \
  --url ws://127.0.0.1:19789 \
  --token "PASTE_THE_TOKEN_HERE"

Then reconnect the TUI.

#

Why this is happening

  • the TUI is connecting to 19789
  • the plain CLI command is probably still trying the default path/port
  • so devices list says ā€œnot connectedā€ even though the gateway is actually up

If you want, paste the output of:

openclaw config get gateway.auth.token

and

openclaw devices list --url ws://127.0.0.1:19789 --token "..."
#

with the token redacted, and I’ll check the exact next step.

silver tendon
#

For step 2 the token is redacted.

dusty juniperBOT
#

I want to verify whether there’s a supported CLI way to show the actual gateway token, instead of telling you to dig around blindly.

#

Yep, that’s expected, config get redacts secrets.

So for the real token, do this instead:

1. Find the actual config file

openclaw config file

2. Open that file directly

Look for:

gateway: {
#
  auth: {
    mode: "token",
    token: "THE_REAL_TOKEN_IS_HERE"
  }
}

Copy that real token value.

3. Use it with the explicit gateway URL

openclaw devices list \
  --url ws://127.0.0.1:19789 \
  --token "THE_REAL_TOKEN"
#

Then:

openclaw devices approve <REQUEST_ID> \
  --url ws://127.0.0.1:19789 \
  --token "THE_REAL_TOKEN"

Then reconnect the TUI.

If you don’t see a plaintext token in the config file, tell me, and I’ll give you the cleanest way to set a new known token and continue.

silver tendon
#

It says there is a mismatch between the gateway remote token and the gateway auth token.

dusty juniperBOT
#

Aha, that’s the bug.

You’ve got local gateway auth and remote gateway token mixed together.

For your setup, you want:

  • gateway.mode = local
  • bind = loopback
  • auth = token
  • port = 19789
  • no stale gateway.remote.token in the way

Fastest clean fix

Don’t hand-fight the JSON right now. Re-run just the gateway config wizard:

#
openclaw config --section gateway --section daemon

Choose:

  • Local
  • Loopback
  • Token auth
  • port 19789

Then reinstall the service from that config:

openclaw gateway install --force
openclaw gateway restart
#
openclaw gateway status --deep

Why this happened

gateway.remote.token is for a client connecting to some other gateway.
gateway.auth.token is the token your local gateway expects.

For a same-machine local setup, you generally want the local auth token, not a mismatched remote token path.

If you want, paste the gateway section of your config with secrets redacted and I’ll sanity-check it before you rerun the wizard.

silver tendon
#

Service: LaunchAgent (loaded)
File logs: /tmp/openclaw/openclaw-2026-04-14.10g
Command: /opt/homebrew/opt/node@22/bin/node/opt/homebrew/lib/node_modules/openclaw/dist/index.js gateway -port 19789
Service file: ~/Library/LaunchAgents/ai.openclaw.gateway.plist
Service env: OPENCLAW_GATEWAY_PORT-19789
t
Config (cli): ~/.openclaw/openclaw.json
Config (service): ~/.openclaw/openclaw.json
e
Gateway: bind=loopback (127.0.0.1), port=19789 (service args)
Probe target: ąøžąø£ąø°//127.0.0.1:19789
Dashboard: http://127.0.0.1:19789/
Probe note: Loopback-only gateway; only local clients can connect.
ec
Runtime: running (pid 9402, state active)
Warm-up: launch agents can take a few seconds. Try again shortly.
RPC probe: failed
RPC target: ws://127.0.0.1:19789
gateway closed (1008): unauthorized: gateway token mismatch (provide gateway auth token)
ec
ct
in
Gateway runtime PID does not own the listening port. Other gateway process(es) are listening: 7930
Fix: run openclaw gateway restart and re-check with openclaw gateway status -deep.
Port 19789 is already in use.

  • pid 7930 kate: openclaw-gateway (127.0.0.1:19789)
  • Gateway already running locally. Stop it (openclaw gateway stop) or use a different port.
    Listening: 127.0.0.1:19789
    Troubles: run openclaw status
    Troubleshooting: https://docs.openclaw.ai/troubleshooting
dusty juniperBOT
#

Yep, this finally tells the story.

You have two different gateway processes involved:

  • LaunchAgent started a new one: pid 9402
  • but pid 7930 is the one actually holding port 19789

So the CLI is hitting the old/stale gateway, which is using a different token, hence:

  • gateway token mismatch
  • Runtime PID does not own the listening port
  • Port 19789 is already in use

Fix

Do this in order:

#
openclaw gateway stop
openclaw gateway status --deep

If 19789 is still occupied after that, don’t keep fighting it in-app. Do:

openclaw gateway install --force
openclaw gateway restart
openclaw gateway status --deep

What I want to see after that

In gateway status --deep:

#
  • only one gateway process
  • no ā€œruntime PID does not own the listening portā€
  • RPC probe: ok

If port 19789 is STILL owned after gateway stop

At that point I’d honestly just do a full reboot once, then immediately run:

openclaw gateway status --deep
openclaw gateway restart
openclaw gateway status --deep

That stale pid 7930 process is the real problem now, not your agent setup.

You’re very close, annoying as this is. If you paste the next gateway status --deep, I can tell you whether the stale process is gone.

silver tendon
#

Full reboot of the machine?

dusty juniperBOT
#

Yes, if openclaw gateway stop did not clear the stale process, a full reboot is the safest next move.

I wouldn’t make it the first step, but at this point, with:

  • stale PID still owning 19789
  • token mismatch
  • LaunchAgent not owning the listening port

a reboot is a reasonable reset.

After reboot, run these immediately

openclaw gateway status --deep
openclaw gateway restart
openclaw gateway status --deep
#

What you want after reboot:

  • only one gateway process
  • port 19789 owned by the current runtime
  • RPC probe: ok

If you paste that post-reboot gateway status --deep, I’ll tell you the next exact step.

silver tendon
#

šŸ¦ž OpenClaw 2026.4.14 (323493f) — Running on your hardware, reading your logs, judging nothing (mostly).

│
ā—‡
Service: LaunchAgent (loaded)
File logs: /tmp/openclaw/openclaw-2026-04-14.log
Command: /opt/homebrew/opt/node@22/bin/node /opt/homebrew/lib/node_modules/openclaw/dist/index.js gateway --port 19789
Service file: ~/Library/LaunchAgents/ai.openclaw.gateway.plist
Service env: OPENCLAW_GATEWAY_PORT=19789

Config (cli): ~/.openclaw/openclaw.json
Config (service): ~/.openclaw/openclaw.json

Gateway: bind=loopback (127.0.0.1), port=19789 (service args)
Probe target: ws://127.0.0.1:19789
Dashboard: http://127.0.0.1:19789/
Probe note: Loopback-only gateway; only local clients can connect.

Runtime: running (pid 25880, state active)
Warm-up: launch agents can take a few seconds. Try again shortly.
RPC probe: failed
RPC target: ws://127.0.0.1:19789
gateway closed (1008): unauthorized: gateway token mismatch (provide gateway auth token)

Gateway runtime PID does not own the listening port. Other gateway process(es) are listening: 650
Fix: run openclaw gateway restart and re-check with openclaw gateway status --deep.

Port 19789 is already in use.

  • pid 650 kate: openclaw-gateway (127.0.0.1:19789)
  • Gateway already running locally. Stop it (openclaw gateway stop) or use a different port.
    Listening: 127.0.0.1:19789
    Troubles: run openclaw status
    Troubleshooting: https://docs.openclaw.ai/troubleshooting
dusty juniperBOT
#

I’m going to check the troubleshooting docs for the exact cleanup path here, because after a reboot that lingering openclaw-gateway process means there’s probably an extra service install hanging around.

#

Okay, the reboot result is actually useful.

That means this is not just one stuck process, it’s very likely an extra/legacy gateway service that is auto-starting at boot and reclaiming 19789.

pid 650 kate: openclaw-gateway looks exactly like that kind of stale service.

Next move

Use Doctor’s deep service scan.

Run:

openclaw gateway uninstall
openclaw doctor --deep
#

If Doctor reports extra / legacy gateway-like services, then run the repair path:

openclaw doctor --repair --deep

If it offers to remove stale/legacy gateway services, say yes.

Then reinstall the current service cleanly:

openclaw gateway install --force
openclaw gateway restart
openclaw gateway status --deep

Why I’m suggesting this

#

Your output says:

  • current LaunchAgent pid = 25880
  • but port owner = 650
  • reboot did not clear it

So something is being relaunched automatically, not just hanging around.

What I want to see after this

In openclaw gateway status --deep:

  • only one gateway process
  • no ā€œruntime PID does not own the listening portā€
  • RPC probe: ok

Paste the doctor --deep output if you want, that should show the stale service pretty clearly.

silver tendon
#

The doctor says port 19789 is already in use - pid 29547 Kate: OpenClaw-gateway (127.0.0.1:19789) - gateway already running locally. Stop it or use a different port. It’s asking if I want to install the gateway service now.

dusty juniperBOT
#

Say no for now.

You do not want to install a new service while OpenClaw-gateway is already holding 19789, or you’ll just stack another conflict on top of the current one.

Do this first

Get to zero listeners on 19789.

Run:

openclaw gateway stop
openclaw gateway status --deep

If OpenClaw-gateway is still there after stop

#

That means the old/legacy service is still the real problem.

In that case:

  • if Doctor offers to remove / repair stale gateway services, say yes
  • but still say no to installing the new service until the port is free

Rule of thumb

  • port still occupied → do not install
  • port free → then install/reinstall cleanly

Once gateway status --deep no longer shows OpenClaw-gateway owning 19789, then do:

openclaw gateway install --force
#
openclaw gateway restart
openclaw gateway status --deep

If you want, paste the next gateway status --deep after openclaw gateway stop and I’ll tell you whether you’re clear to install.

silver tendon
#

Same issue. Port already in use.

dusty juniperBOT
#

I’m going to check the macOS service docs for the exact launchd label situation, because if gateway stop still leaves the port occupied, there’s almost certainly a second launchd job or legacy label behind it.

#

I think I see the missing piece now.

If the OpenClaw macOS app / hatch / menu bar companion is still open, it can keep managing the local gateway service on macOS. So you stop it, and it comes right back.

That would explain why the port stays occupied even after reboot and stop attempts.

Try this in this order

  1. Quit the OpenClaw app completely

    • menu bar app
    • hatch / TUI window
    • anything OpenClaw-related that’s still open
  2. Then run:

#
openclaw gateway stop
openclaw gateway uninstall
openclaw gateway status --deep

If the port is finally free

Then reinstall cleanly:

openclaw gateway install --force
openclaw gateway restart
openclaw gateway status --deep

Why I think this matters

#

The macOS docs explicitly say the app can manage/attach to the Gateway locally via launchd. So if the app is open, it may be re-enabling the LaunchAgent while you’re trying to clean it up.

You’re not crazy, this is exactly the kind of loop that feels haunted.

If you quit the app and gateway status --deep still shows port 19789 occupied, paste that output and then we’ll go one level deeper into the launchd label cleanup.

silver tendon
#

I don’t even have the app.

dusty juniperBOT
#

Got it, then this is probably a raw launchd cleanup issue, not the app.

The macOS docs show the current label is:

  • ai.openclaw.gateway

and older installs can leave behind legacy com.openclaw.* labels.

Let’s check what launchd thinks exists

Run:

launchctl list | grep -i openclaw

Then boot out the label(s) you see

#

If you see the current one:

launchctl bootout gui/$UID/ai.openclaw.gateway

If you also see a legacy com.openclaw... label, boot that out too.

After that

Run:

openclaw gateway uninstall
openclaw gateway status --deep
#

If the port is finally free, reinstall cleanly:

openclaw gateway install --force
openclaw gateway restart
openclaw gateway status --deep

Why this is the right level now

You’ve already rebooted, and the same OpenClaw-gateway listener came back.
That means something in launchd is reloading it.

Paste the output of:

#
launchctl list | grep -i openclaw

and I can tell you exactly which label to boot out.

silver tendon
#

2954 0 ai.openclaw.main

dusty juniperBOT
#

There it is.

ai.openclaw.main is the rogue service.

That means you’ve got a profiled LaunchAgent for profile main still loaded, and that’s the one reclaiming the port.

Do this now

launchctl bootout gui/$UID/ai.openclaw.main
launchctl list | grep -i openclaw
openclaw gateway status --deep

If the port is finally free

Reinstall only the service you actually want:

#
openclaw gateway install --force
openclaw gateway restart
openclaw gateway status --deep

Important

Do not use --profile main unless you intentionally want a separate profiled gateway.

For the simpler setup we’ve been aiming for, you want:

  • one default gateway
  • multiple agents inside it

So ai.openclaw.main is exactly the extra service we needed to remove.

#

If you paste the next launchctl list | grep -i openclaw or gateway status --deep, I can tell you if you’re finally clean.

silver tendon
#

šŸ¦ž OpenClaw 2026.4.14 (323493f) — Your .zshrc wishes it could do what I do.

│
ā—‡
Service: LaunchAgent (loaded)
File logs: /tmp/openclaw/openclaw-2026-04-14.log
Command: /opt/homebrew/opt/node@22/bin/node /opt/homebrew/lib/node_modules/openclaw/dist/index.js gateway --port 19789
Service file: ~/Library/LaunchAgents/ai.openclaw.gateway.plist
Service env: OPENCLAW_GATEWAY_PORT=19789

Config (cli): ~/.openclaw/openclaw.json
Config (service): ~/.openclaw/openclaw.json

Gateway: bind=loopback (127.0.0.1), port=19789 (service args)
Probe target: ws://127.0.0.1:19789
Dashboard: http://127.0.0.1:19789/
Probe note: Loopback-only gateway; only local clients can connect.

Runtime: running (pid 31426, state active)
RPC probe: ok

Listening: 127.0.0.1:19789
Troubles: run openclaw status
Troubleshooting: https://docs.openclaw.ai/troubleshooting

dusty juniperBOT
#

Nice, that’s clean now. šŸŽ‰

This is the state we wanted:

  • one gateway
  • correct config + service
  • RPC probe: ok
  • port 19789 stable

What’s next

1. Hatch / pair the main agent

If the TUI asks for pairing again, now this should work:

#
openclaw devices list
openclaw devices approve <REQUEST_ID>

Then reconnect the TUI.


2. If Agent 1’s Telegram bot is not configured yet

openclaw config set channels.telegram.enabled true --strict-json
openclaw config set channels.telegram.defaultAccount default
openclaw config set channels.telegram.accounts.default.botToken "AGENT1_BOT_TOKEN"
openclaw config set channels.telegram.accounts.default.dmPolicy pairing
#

3. Create Agent 2

openclaw agents add agent2 \
  --workspace ~/.openclaw/workspace-agent2 \
  --bind telegram:agent2 \
  --model anthropic/claude-sonnet-4-6

4. Add Agent 2’s Telegram bot

#
openclaw config set channels.telegram.accounts.agent2.botToken "AGENT2_BOT_TOKEN"
openclaw config set channels.telegram.accounts.agent2.dmPolicy pairing
openclaw gateway restart

5. Verify routing

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

#

6. If Agent 2 needs its own credentials

openclaw secrets configure --agent agent2

That gives it its own auth store.

If you want, next I can give you the exact expected final config shape so you can compare it line-by-line before adding Agent 2.

silver tendon
#

I got back gateway connect failed: GatewayClientRequestError: pairing required
ā—‡
Direct scope access failed; using local fallback.

There is one pending request with the role operator; scopes: operator.admin, operator.read, operator.write, operator.approvals, operator.pairing, and operator.talk.secrets; and flags repair and then one paired with roles operator, scopes operator.read.

dusty juniperBOT
#

Perfect, that’s actually the right state now.

What this means:

  • you already have an old paired device with only operator.read
  • the CLI just created a new pending request asking for the full operator scopes it needs
  • local fallback found it successfully

Next step

Approve the pending requestId from that output.

Use the exact ID shown by openclaw devices list:

openclaw devices approve <REQUEST_ID>
#

Important: use the real request ID, not --latest, because --latest only previews.

Why this matters

Right now your paired device only has:

  • operator.read

but the new request wants:

  • operator.admin
  • operator.read
  • operator.write
  • operator.approvals
  • operator.pairing
  • operator.talk.secrets
#

That’s why pairing/admin-ish commands were failing before.

After approval:

  1. reconnect the TUI / hatch
  2. then continue with the Telegram + Agent 2 setup

If you want, paste the requestId line with only the ID redacted except the last few chars, and I can confirm you’re approving the right one.

silver tendon
#

šŸ¦ž OpenClaw 2026.4.14 (323493f) — Deployed locally, trusted globally, debugged eternally.

│
gateway connect failed: GatewayClientRequestError: pairing required
ā—‡
Direct scope access failed; using local fallback.
unknown requestId
kate@Kates-Mac-mini

dusty juniperBOT
#

Yep, that means the pending pairing request ID changed underneath you.

OpenClaw does that when the device retries pairing or changes auth details, it supersedes the old pending request and issues a new requestId.

Do this again, back to back

openclaw devices list

Then immediately copy the current pending requestId from that output and run:

openclaw devices approve <NEW_REQUEST_ID>

Important:

#
  • don’t use the old ID
  • don’t wait too long between list and approve
  • --latest only previews, it does not approve

If you want, paste the exact devices list output with the requestId partially redacted, and I’ll point at the right line.

silver tendon
#

okay got it

dusty juniperBOT
#

Nice. šŸ‘

Once that approval goes through:

  1. reconnect / hatch the main agent
  2. verify it responds
  3. then do Agent 2:
openclaw agents add agent2 \
  --workspace ~/.openclaw/workspace-agent2 \
  --bind telegram:agent2 \
  --model anthropic/claude-sonnet-4-6

Then add Agent 2’s bot:

#
openclaw config set channels.telegram.accounts.agent2.botToken "AGENT2_BOT_TOKEN"
openclaw config set channels.telegram.accounts.agent2.dmPolicy pairing
openclaw gateway restart

If Agent 2 needs its own creds:

openclaw secrets configure --agent agent2

If you hit anything weird on the approval/reconnect step, paste it and I’ll keep going with you.

silver tendon
#

So I don't want this to actually be an agent - I just wanted to create the "shell" instance in my admin profile. Do I need to actually hatch it? Or can I bop over to the first agent's device login and start setting it up now?

dusty juniperBOT
#

Yep, you do not need to hatch main if you’re only using it as the admin/control shell.

That’s a perfectly valid setup.

Recommended structure

  • main = admin shell only
  • agent1 = real Telegram agent
  • agent2 = real Telegram agent

So yes, you can skip chatting with main and go straight to setting up the real agents.

Do this next

Create Agent 1

#
openclaw agents add agent1 \
  --workspace ~/.openclaw/workspace-agent1 \
  --bind telegram:agent1 \
  --model anthropic/claude-sonnet-4-6

Add Agent 1’s Telegram bot:

openclaw config set channels.telegram.enabled true --strict-json
openclaw config set channels.telegram.accounts.agent1.botToken "AGENT1_BOT_TOKEN"
openclaw config set channels.telegram.accounts.agent1.dmPolicy pairing

If Agent 1 has its own creds:

#
openclaw secrets configure --agent agent1

Create Agent 2

openclaw agents add agent2 \
  --workspace ~/.openclaw/workspace-agent2 \
  --bind telegram:agent2 \
  --model anthropic/claude-sonnet-4-6

Add Agent 2’s Telegram bot:

#
openclaw config set channels.telegram.accounts.agent2.botToken "AGENT2_BOT_TOKEN"
openclaw config set channels.telegram.accounts.agent2.dmPolicy pairing

If Agent 2 has its own creds:

openclaw secrets configure --agent agent2

Restart and verify

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

Key point

Leave main unbound if you don’t want it acting as a real chat agent.

So:

  • no need to hatch main
  • go straight to agent1 and agent2

If you want, I can give you the final exact config shape for this ā€œmain as admin shell + agent1/agent2 as Telegram botsā€ setup.

silver tendon
#

Does agent 1 need admin rights on the machine to complete setup?

dusty juniperBOT
#

No, Agent 1 does not need machine admin rights just to complete setup.

For the normal setup you’re doing, Agent 1 only needs:

  • its own workspace
  • its own model/API creds
  • its own Telegram bot/account binding

That’s it.

Good pattern

  • main = admin shell / operator
  • agent1 = normal agent
  • agent2 = normal agent

Keep the heavy admin/operator powers on main, not on the Telegram-facing agents.

#

Only give more access later if needed

You’d only need extra machine-level permissions if that agent is supposed to do things like:

  • run system commands
  • use screen / UI automation
  • touch privileged local tools
  • use other OS-level capabilities

But for ā€œbe a Telegram agent with its own brain + credsā€, no admin rights needed.

That’s actually the safer setup.

silver tendon
#

Select a channel
│ Finished
TypeError: Cannot read properties of undefined (reading 'trim')

dusty juniperBOT
#

I’ve seen that trim error before, but I want to verify whether it’s the stale session-store bug or something more specific to the channel picker.

#

That looks like a real bug in the interactive agents add channel picker.

Good news, you can bypass it completely.

Workaround: skip the wizard, use explicit flags

Because openclaw agents add switches to the non-interactive path as soon as you pass flags, you can avoid the broken ā€œSelect a channelā€ step.

Agent 1

openclaw agents add agent1 \
  --workspace ~/.openclaw/workspace-agent1 \
  --bind telegram:agent1 \
  --model anthropic/claude-sonnet-4-6
#

Then add its bot:

openclaw config set channels.telegram.enabled true --strict-json
openclaw config set channels.telegram.accounts.agent1.botToken "AGENT1_BOT_TOKEN"
openclaw config set channels.telegram.accounts.agent1.dmPolicy pairing

Agent 2

openclaw agents add agent2 \
  --workspace ~/.openclaw/workspace-agent2 \
  --bind telegram:agent2 \
  --model anthropic/claude-sonnet-4-6
#

Then add its bot:

openclaw config set channels.telegram.accounts.agent2.botToken "AGENT2_BOT_TOKEN"
openclaw config set channels.telegram.accounts.agent2.dmPolicy pairing

Then

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

So, short version: don’t use the channel picker UI here. It’s crashing, but the CLI path should still work.

#

If this gets you unblocked, I’d also file a GitHub issue afterward, because Select a channel -> TypeError ... trim is definitely not expected.

silver tendon
#

Okay now that I have the channels set I'd like to hatch agent 1. It doesn't have a gateway config or anything yet. Can you walk me through the steops/

dusty juniperBOT
#

Yep, and the good news is: Agent 1 should not have its own gateway config.

It shares the one working gateway you already fixed.

Mental model

  • gateway config = one per machine/setup
  • agent config/workspace/auth = one per agent

So Agent 1 does not need its own port, bind, auth token, etc.


To hatch Agent 1

You have 2 ways to do it.

#

Option A, easiest: hatch locally in TUI

If you want to bring Agent 1 to life from your Mac first:

openclaw tui --url ws://127.0.0.1:19789 --agent agent1 --session main

That opens a session directly against agent1.

If it asks for pairing again, approve it the same way you did before.


Option B, probably what you really want: just DM Agent 1’s Telegram bot

If Agent 1 already has:

#
  • its own workspace
  • its Telegram bot token configured
  • its binding set to telegram:agent1

then you can just message the bot in Telegram.

Because you set:

openclaw config set channels.telegram.accounts.agent1.dmPolicy pairing

the first DM should create a pairing flow for that Telegram user.

Then approve it:

#
openclaw pairing list telegram
openclaw pairing approve telegram <CODE>

After that, talking to Agent 1’s Telegram bot is effectively its real ā€œhatchā€.


Before you hatch Agent 1, quick checklist

1. Make sure Agent 1 exists

openclaw agents list --bindings
#

You want to see agent1 and its telegram:agent1 binding.

2. Make sure the Telegram account is configured

openclaw channels status --probe

3. If Agent 1 needs its own creds

openclaw secrets configure --agent agent1

Do that before hatching if you want separate model/API/Google auth for Agent 1.


#

Recommended next move

I’d do this order:

  1. openclaw agents list --bindings
  2. openclaw channels status --probe
  3. openclaw secrets configure --agent agent1 if needed
  4. either:
    • openclaw tui --url ws://127.0.0.1:19789 --agent agent1 --session main
    • or DM the Agent 1 Telegram bot directly

So, short answer: no separate gateway config for Agent 1, just hatch it against the existing gateway.

If you want, paste the output of openclaw agents list --bindings and I’ll sanity-check whether Agent 1 is ready to hatch right now.

silver tendon
#

heidi@Kates-Mac-mini ~ % openclaw agents list --bindings

šŸ¦ž OpenClaw 2026.4.14 (323493f) — Running on your hardware, reading your logs, judging nothing (mostly).

Agents:

  • main (default)
    Workspace: ~/.openclaw/workspace
    Agent dir: ~/.openclaw/agents/main/agent
    Routing rules: 0
    Routing: default (no explicit rules)
    Providers:
    • telegram heidi: configured
      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.
dusty juniperBOT
#

Yep, this is the key detail:

Right now you only have one actual agent:

  • main

And your configured Telegram account id is:

  • telegram heidi

So Agent 1 does not exist yet.

Also, because there are 0 routing rules, that Telegram account will currently fall through to main.

What to do now

Create Agent 1 and bind it to the existing Telegram account id heidi:

#
openclaw agents add agent1 \
  --workspace ~/.openclaw/workspace-agent1 \
  --bind telegram:heidi \
  --model anthropic/claude-sonnet-4-6

That should create an explicit routing rule so the heidi Telegram bot goes to agent1 instead of main.

Then verify

openclaw agents list --bindings

You want to see:

#
  • main still existing
  • agent1 existing
  • a routing rule binding telegram:heidi → agent1

Then hatch / use Agent 1

Either locally:

openclaw tui --url ws://127.0.0.1:19789 --agent agent1 --session main

Or just DM the Telegram bot that belongs to account heidi.

If Agent 1 needs its own creds

#
openclaw secrets configure --agent agent1

That’s the missing step. You weren’t blocked on hatching, you were blocked because agent1 wasn’t created yet.

If you want, after you run agents add agent1, paste the new openclaw agents list --bindings output and I’ll confirm it’s routed correctly.

silver tendon
#

When I have it create the workspace it's asking me if I want to configure the model/auth for this agent now.

dusty juniperBOT
#

If you want Agent 1 to have its own separate creds, say yes.

That matches the setup you described earlier:

  • unique API keys
  • unique Google Workspace
  • separate agent identity

My recommendation

For Agent 1, I’d choose yes if you have the credentials ready.

When to choose no

Choose no only if you want to:

  • finish creating the agent first
#
  • get routing/binding working
  • configure creds afterward with:
openclaw secrets configure --agent agent1

Short version

  • want separate auth now? → Yes
  • want to finish agent creation first and do auth later? → No

Given your goal, yes is the cleaner choice.

silver tendon
#

So I already did yes and went through the steps before (when I set up the telegram channel). Why would it not have worked then?

dusty juniperBOT
#

Because earlier you were almost certainly configuring the gateway/default setup, not agent1 specifically.

That’s the subtle but important split:

What you configured before

When you first set things up, OpenClaw had:

  • the gateway
  • the default agent: main
  • the Telegram account: heidi

So the stuff you entered earlier would have applied to:

  • the gateway/channel config, and/or
  • main’s auth/config
#

What did not exist yet

At that point, you did not have:

  • an agent1 entry
  • an agent1 workspace
  • an agent1 auth store
  • an explicit route sending telegram:heidi to agent1

So there was nowhere for ā€œAgent 1 specificā€ setup to actually land.

Short version

Earlier setup worked, but it worked for the existing default agent (main), not for the agent you’re creating now.

That’s why this prompt matters now, this is the first time OpenClaw actually has a real agent1 to attach separate model/auth to.

#

So your intuition is right, it feels repetitive, but this time it’s finally targeting the correct agent.

silver tendon
#

Okay I think I uncovered an issue maybe leading to the trim error from before (I just got it again). Look at my channel status:

Channel status ──────────────────╮
│ │
│ undefined: configured │
│ Feishu: not configured │
│ Nostr: not configured │
│ Microsoft Teams: not configured │
│ Nextcloud Talk: not configured │
│ BlueBubbles: not configured │
│ Zalo: not configured │
│ Zalo Personal: not configured │
│ Discord: not configured │
│ QQ Bot: not configured │
│ WhatsApp: not configured │
│ Feishu: installed │
│ Google Chat: installed │
│ Nostr: installed │
│ Microsoft Teams: installed │
│ Mattermost: installed │
│ Nextcloud Talk: installed │
│ Matrix: installed │
│ BlueBubbles: installed │
│ LINE: installed │
│ Zalo: installed │
│ Zalo Personal: installed │
│ Synology Chat: installed │
│ Tlon: installed │
│ Discord: installed │
│ iMessage: installed │
│ IRC: installed │
│ QQ Bot: installed │
│ Signal: installed │
│ Slack: installed │
│ Twitch: installed │
│ WhatsApp: installed

#

It says "undefined: configured".

dusty juniperBOT
#

Yeah, that does not look normal.

undefined: configured is a big red flag, and yes, I think it’s a very plausible explanation for the trim crash in the channel picker.

A configured channel should look like a real channel name, for example Telegram, not undefined.

What I’d check next

Please paste these:

openclaw config get channels --json
openclaw config get bindings --json
openclaw config validate --json

You can redact tokens, but leave the structure intact.

#

Why I think this matters

The interactive picker is probably expecting a channel id/name string and is getting undefined instead, then trying to do .trim() on it.

So right now I think you have either:

  • a malformed channels entry
  • a broken binding
  • or a partially written account/channel config from the earlier setup chaos

Short version

  • yes, that undefined: configured looks wrong
  • yes, it could absolutely be the root cause of the trim error
  • next best move is to inspect raw channels + bindings

Paste those three outputs and I’ll help you spot the bad entry.

silver tendon
#

When I go to configure telegram it asks if I want to keep the current settings, and if I do it gives that error.

dusty juniperBOT
#

Yep, exactly, that is the suspicious bit.

undefined: configured should not exist.

That strongly suggests there’s a malformed channel entry in your config, and it’s probably what the picker is choking on.

Please run these and paste the output:

openclaw config get channels --json
openclaw config get bindings --json
openclaw config validate --json

Redact tokens if needed, but keep the JSON structure.

Once we see that, we can usually spot the broken undefined entry pretty quickly.

#

Yep, that pretty much confirms it.

If choosing ā€œkeep current settingsā€ causes the crash, then the saved Telegram config is the broken thing.

Short answer

Do not keep the current Telegram settings.
Re-enter / rebuild them from scratch.

Safest workaround

At this point I’d avoid the interactive Telegram config path and rebuild that section cleanly with CLI config commands.

If your Telegram account id is heidi, do:

#
openclaw config unset channels.telegram
openclaw config set channels.telegram.enabled true --strict-json
openclaw config set channels.telegram.accounts.heidi.botToken "YOUR_BOT_TOKEN"
openclaw config set channels.telegram.accounts.heidi.dmPolicy pairing
openclaw gateway restart
openclaw channels status --probe

That should give you a clean channels.telegram block instead of whatever malformed state is causing undefined: configured.

Why I’m recommending this

Because the wizard is trying to reuse bad saved state.
If we wipe just the Telegram section and rebuild it cleanly, the picker should stop tripping over the corrupted entry.

If you want, after you run that, paste:

#
openclaw config get channels --json

and I’ll confirm the Telegram shape looks sane before you continue with agent1.

silver tendon
#

šŸ¦ž OpenClaw 2026.4.14 (323493f) — I'm like tmux: confusing at first, then suddenly you can't live without me.

│
ā—‡
Gateway not reachable: Error: gateway closed (1006 abnormal closure (no close frame)): no close reason
Gateway target: ws://127.0.0.1:18789
Source: local loopback
Config: /Users/heidi/.openclaw/openclaw.json
Bind: loopback
Gateway not reachable; showing config-only status.
Config: /Users/heidi/.openclaw/openclaw.json
Mode: local

  • telegram heidi: enabled, not configured, mode:polling

Tip: status --deep adds gateway health probes to status output (requires a reachable gateway).

dusty juniperBOT
#

Aha, this is the next clue.

Your config has drifted back to 18789 again.

That’s why status is trying:

ws://127.0.0.1:18789

even though the working gateway we fixed earlier was on 19789.

Fix the port first

Run:

#
openclaw config set gateway.port 19789 --strict-json
openclaw gateway install --force
openclaw gateway restart
openclaw gateway status --deep

You want gateway status --deep to show:

  • port 19789
  • RPC probe: ok

Then fix Telegram

Your status also says:

#
telegram heidi: enabled, not configured

So after the gateway is back on 19789, re-add the bot token:

openclaw config set channels.telegram.accounts.heidi.botToken "YOUR_BOT_TOKEN"
openclaw config set channels.telegram.accounts.heidi.dmPolicy pairing
openclaw channels status --probe

What happened

One of the config flows you used likely rewrote part of ~/.openclaw/openclaw.json, and now the CLI is pointing back at the default port.

So right now you have two separate problems:

#
  1. config fell back to 18789
  2. Telegram account heidi is enabled but missing its token/config

Fix the port first, then the Telegram config.

If you paste the next openclaw gateway status --deep, I’ll check that you’re back on the right port before you touch agent1 again.

versed lagoon
#

On the setup after clicking skip for channel I got TypeError: Cannot read properties of undefined (reading 'trim')

silver tendon
#

heidi@Kates-Mac-mini ~ % openclaw gateway status --deep

šŸ¦ž OpenClaw 2026.4.14 (323493f) — Running on your hardware, reading your logs, judging nothing (mostly).

│
ā—‡
Service: LaunchAgent (loaded)
File logs: /var/folders/9v/5sxh2c254w7cq9gqm38n_b8h0000gp/T/openclaw-502/openclaw-2026-04-14.log
Command: /opt/homebrew/opt/node@22/bin/node /opt/homebrew/lib/node_modules/openclaw/dist/index.js gateway --port 19789
Service file: ~/Library/LaunchAgents/ai.openclaw.gateway.plist
Service env: OPENCLAW_GATEWAY_PORT=19789

Config (cli): ~/.openclaw/openclaw.json
Config (service): ~/.openclaw/openclaw.json

Gateway: bind=loopback (127.0.0.1), port=19789 (service args)
Probe target: ws://127.0.0.1:19789
Dashboard: http://127.0.0.1:19789/
Probe note: Loopback-only gateway; only local clients can connect.

Runtime: running (pid 35448, state active)
Warm-up: launch agents can take a few seconds. Try again shortly.
RPC probe: failed
RPC target: ws://127.0.0.1:19789
gateway closed (1006):

Gateway port 19789 is not listening (service appears running).
Last gateway error: 2026-04-14T21:32:39.605-04:00 Gateway start blocked: existing config is missing gateway.mode. Treat this as suspicious or clobbered config. Re-run openclaw onboard --mode local or openclaw setup, set gateway.mode=local manually, or pass --allow-unconfigured.
Logs: ~/.openclaw/logs/gateway.log
Errors: ~/.openclaw/logs/gateway.err.log

Troubles: run openclaw status
Troubleshooting: https://docs.openclaw.ai/troubleshooting

dusty juniperBOT
#

Yep, that looks like a real setup wizard bug, not you.

Can you paste:

openclaw --version

For now, the workaround is to avoid the interactive channel step entirely, finish setup, then configure the channel manually.

For Telegram, for example:

openclaw config set channels.telegram.enabled true --strict-json
openclaw config set channels.telegram.accounts.default.botToken "YOUR_BOT_TOKEN"
openclaw config set channels.telegram.accounts.default.dmPolicy pairing
#
openclaw gateway restart

So, short version:

  • skip the broken channel wizard
  • finish onboarding
  • add the channel with config set

If you want, I can give you the exact command block for whatever channel you’re setting up.

#

Yep, this one is clear.

Your config got clobbered again, and the gateway is refusing to start because:

existing config is missing gateway.mode

So the fix is to put the local gateway settings back manually.

Run this

openclaw config set gateway.mode local
openclaw config set gateway.bind loopback
openclaw config set gateway.port 19789 --strict-json
#
openclaw config set gateway.auth.mode token
openclaw gateway install --force
openclaw gateway restart
openclaw gateway status --deep

What I expect after that

gateway status --deep should go back to:

  • port 19789
  • Runtime: running
  • RPC probe: ok

What happened

#

One of the config flows you used, likely the buggy channel/configure path, rewrote part of ~/.openclaw/openclaw.json and removed gateway.mode.

So right now I would stop using the interactive channel/config wizard until you’re stable again.

Use direct config set commands instead.

If you want, after you run those commands, paste the next openclaw gateway status --deep and I’ll make sure the gateway is actually healthy again before you touch Telegram/agents.

silver tendon
#

šŸ¦ž OpenClaw 2026.4.14 (323493f) — I'll do the boring stuff while you dramatically stare at the logs like it's cinema.

│
ā—‡
Service: LaunchAgent (loaded)
File logs: /var/folders/9v/5sxh2c254w7cq9gqm38n_b8h0000gp/T/openclaw-502/openclaw-2026-04-14.log
Command: /opt/homebrew/opt/node@22/bin/node /opt/homebrew/lib/node_modules/openclaw/dist/index.js gateway --port 19789
Service file: ~/Library/LaunchAgents/ai.openclaw.gateway.plist
Service env: OPENCLAW_GATEWAY_PORT=19789

Config (cli): ~/.openclaw/openclaw.json
Config (service): ~/.openclaw/openclaw.json

Gateway: bind=loopback (127.0.0.1), port=19789 (service args)
Probe target: ws://127.0.0.1:19789
Dashboard: http://127.0.0.1:19789/
Probe note: Loopback-only gateway; only local clients can connect.

Runtime: running (pid 36149, state active)
RPC probe: ok

Listening: 127.0.0.1:19789
Troubles: run openclaw status
Troubleshooting: https://docs.openclaw.ai/troubleshooting

dusty juniperBOT
#

Nice, gateway is healthy again. šŸŽ‰

At this point I would stop touching gateway settings entirely. The boring part is finally stable.

Next move

1. Fix Telegram cleanly, using direct config only

If Telegram is still showing weird undefined / not configured behavior, rebuild just that section:

openclaw config unset channels.telegram
openclaw config set channels.telegram.enabled true --strict-json
openclaw config set channels.telegram.accounts.heidi.botToken "YOUR_BOT_TOKEN"
openclaw config set channels.telegram.accounts.heidi.dmPolicy pairing
openclaw gateway restart
#
openclaw channels status --probe

You want telegram heidi to show up cleanly, not undefined.


2. Create Agent 1 and bind it to the existing Telegram account id heidi

openclaw agents add agent1 \
  --workspace ~/.openclaw/workspace-agent1 \
  --bind telegram:heidi \
  --model anthropic/claude-sonnet-4-6
#

3. Give Agent 1 its own creds if needed

openclaw secrets configure --agent agent1

4. Verify routing

openclaw agents list --bindings
openclaw channels status --probe
#

You want to see:

  • main still there as admin shell
  • agent1 exists
  • telegram:heidi routed to agent1

5. Hatch / test Agent 1

Either locally:

openclaw tui --url ws://127.0.0.1:19789 --agent agent1 --session main

Or just DM the Telegram bot for account heidi.

#

If you want, the next thing I can do is give you the exact Agent 2 command too, so you can add both in one clean pass without touching the broken wizard again.

silver tendon
#

šŸ¦ž OpenClaw 2026.4.14 (323493f) — If it works, it's automation; if it breaks, it's a "learning opportunity."

Agents:

  • main (default)
    Workspace: ~/.openclaw/workspace
    Agent dir: ~/.openclaw/agents/main/agent
    Routing rules: 0
    Routing: default (no explicit rules)
    Providers:
    • telegram heidi: configured
  • heidi
    Workspace: ~/.openclaw/workspace-heidi
    Agent dir: ~/.openclaw/agents/heidi/agent
    Model: anthropic/claude-sonnet-4-6
    Routing rules: 0
    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.
dusty juniperBOT
#

Nice, you’re basically one step away.

Right now:

  • main exists
  • heidi exists
  • but there are still 0 routing rules

So Telegram will still fall through to main unless you bind it explicitly.

Do this now

Bind the Telegram account heidi to the agent heidi:

openclaw agents bind --agent heidi --bind telegram:heidi
#

Then verify

openclaw agents list --bindings

You want to see an explicit rule routing:

  • telegram:heidi → heidi

After that

You can hatch/test the real agent:

openclaw tui --url ws://127.0.0.1:19789 --agent heidi --session main
#

Or just DM the Telegram bot for account heidi.

So the missing piece here is not creation anymore, it’s binding.
Once you add that rule, main can stay your admin shell and heidi becomes the real Telegram-facing agent.

silver tendon
#

šŸ¦ž OpenClaw 2026.4.14 (323493f) — I don't judge, but your missing API keys are absolutely judging you.

Agents:

  • main (default)
    Workspace: ~/.openclaw/workspace
    Agent dir: ~/.openclaw/agents/main/agent
    Routing rules: 0
    Routing: default (no explicit rules)
    Providers:
    • telegram heidi: configured
  • heidi
    Workspace: ~/.openclaw/workspace-heidi
    Agent dir: ~/.openclaw/agents/heidi/agent
    Model: anthropic/claude-sonnet-4-6
    Routing rules: 1
    Routing: telegram heidi
    Providers:
    • telegram heidi: configured
      Routing rules:
    • telegram accountId=heidi
      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.
dusty juniperBOT
#

Nice, that looks right now. šŸŽ‰

You’ve got the important part:

  • heidi exists
  • telegram:heidi is explicitly routed to heidi

So the routing problem is solved.

What the output is telling you now

The joke line about missing API keys is the next blocker.

That means the agent exists and is bound correctly, but heidi still needs its own auth/creds.

Next step

#

Configure creds for the heidi agent:

openclaw secrets configure --agent heidi

Pick the provider/creds you want for that agent, for example Anthropic if that’s what you’re using.

Then test it

Either locally:

openclaw tui --url ws://127.0.0.1:19789 --agent heidi --session main

Or just DM the Telegram bot for account heidi.

#

Optional sanity check

openclaw channels status --probe
openclaw models status

At this point, the missing piece is no longer gateway or routing, it’s just agent-specific auth.

silver tendon
#

heidi@Kates-Mac-mini ~ % openclaw secrets configure --agent heidi

šŸ¦ž OpenClaw 2026.4.14 (323493f) — Shell yeah—I'm here to pinch the toil and leave you the glory.

│
ā—‡ Configure secret providers (only env refs are available until file/exec providers are added)
│ Continue
│
ā—‡ Select credential field
│ profiles.anthropic:default.token (auth profile, agent heidi)
│
ā—‡ Secret source
│ env
│
ā—‡ Provider alias
│ default
│
ā—‡ Secret id
│ ANTHROPIC_OAUTH_TOKEN
SecretRefResolutionError: Environment variable "ANTHROPIC_OAUTH_TOKEN" is missing or empty.
heidi@Kates-Mac-mini ~ %

dusty juniperBOT
#

That error is actually pretty straightforward:

You told OpenClaw to use an env-backed secret named:

ANTHROPIC_OAUTH_TOKEN

but that environment variable does not exist in your shell right now.

What it means

The secrets configure flow is working, it’s just failing the lookup.

Fastest next check

Run:

#
env | grep ANTHROPIC

If nothing relevant shows up, then there’s no Anthropic token/key in your shell environment for it to reference.

Your options

Option 1, if you really want env-backed auth

Set/export the env var first, then rerun secrets configure --agent heidi.

Option 2, if you just want to move forward faster

Don’t use the env-ref path right now. Use whatever auth method you actually have available for Anthropic, rather than pointing at a missing env var.

Short version

This is not another OpenClaw bug.

#

It just means:

  • chosen source = env
  • chosen id = ANTHROPIC_OAUTH_TOKEN
  • actual env var = missing

If you paste the output of:

env | grep ANTHROPIC

with secrets redacted, I can tell you which name to use next.

silver tendon
#

It returns nothing.]

dusty juniperBOT
#

That explains it.

You currently have no Anthropic env vars at all, so the env-backed secret path can’t work.

Also, one more important thing: you chose

profiles.anthropic:default.token

which is an OAuth token-style field.

So there are really 2 possibilities:

1. You actually have an Anthropic API key

Then ANTHROPIC_OAUTH_TOKEN is the wrong thing to use.

#

2. You really do want OAuth token auth

Then you need to actually provide ANTHROPIC_OAUTH_TOKEN somewhere OpenClaw can read it.


Best practical fix on macOS

Because launchd does not reliably inherit your shell env, put the secret in:

~/.openclaw/.env

Then rerun the agent auth setup.

If you have an OAuth token

Put this in ~/.openclaw/.env:

#
ANTHROPIC_OAUTH_TOKEN=your_real_token_here

If you have an API key instead

Put this in ~/.openclaw/.env:

ANTHROPIC_API_KEY=your_real_key_here

But if it’s an API key, don’t keep choosing the OAuth-token field.


Short version

#
  • env | grep ANTHROPIC returning nothing = no env secret exists
  • on macOS, shell env alone is a bad long-term path anyway
  • if you have an API key, you likely picked the wrong auth field
  • if you have an OAuth token, add it to ~/.openclaw/.env

If you want, tell me which one you actually have, Anthropic API key or Anthropic OAuth token, and I’ll tell you the exact next step with no guessing.

silver tendon
#

api key

dusty juniperBOT
#

I want to verify the exact Anthropic API-key field name before I tell you what to pick in secrets configure.

#

Perfect, then don’t use the OAuth token field.

Use the API key path.

Do this

1. Put your Anthropic API key in the OpenClaw env file

Create or edit:

~/.openclaw/.env

Add:

#
ANTHROPIC_API_KEY=your_real_api_key_here

2. Restart the gateway

openclaw gateway restart

3. Rerun agent auth setup

openclaw secrets configure --agent heidi

This time, when it asks for the credential field, pick the Anthropic API key / .key field, not:

#
profiles.anthropic:default.token

In other words, choose the key path, not the token path.

Short version

  • API key → ANTHROPIC_API_KEY
  • OAuth token → ANTHROPIC_OAUTH_TOKEN

You have an API key, so use the first one.

If you want, after you restart and rerun secrets configure --agent heidi, paste the list of credential fields it shows and I’ll tell you exactly which one to select.

silver tendon
#

heidi@Kates-Mac-mini ~ % ~/.openclaw/.env
zsh: no such file or directory: /Users/heidi/.openclaw/.env

#

@dusty juniper

#

I'm bored. How do I hatch her?

dusty juniperBOT
#

Hell yes, let’s hatch her. 🄚🦐

You’ve got 2 easy ways:

Option 1, hatch locally in TUI

openclaw tui --url ws://127.0.0.1:19789 --agent heidi --session main

That opens a session directly as the heidi agent.

Option 2, hatch her on Telegram

Just DM the Telegram bot tied to account heidi.

If you set:

#
dmPolicy pairing

then approve the pairing first:

openclaw pairing list telegram
openclaw pairing approve telegram <CODE>

One important caveat

She still needs valid Anthropic auth first, or she’ll wake up and immediately complain about missing creds.

So the real hatch sequence is:

#
  1. set ANTHROPIC_API_KEY in ~/.openclaw/.env
  2. restart gateway
  3. finish openclaw secrets configure --agent heidi
  4. then use TUI or Telegram

If you want the fastest possible hatch, do the TUI one first. It’s less annoying than Telegram while you’re still wiring auth.

silver tendon
#

What exacy commands do I do to finish this up?

dusty juniperBOT
#

Yep. From where you are right now, this is the shortest finish-the-job path.

1. Put your Anthropic API key where the gateway can read it

mkdir -p ~/.openclaw
nano ~/.openclaw/.env

Add this line, save, exit:

ANTHROPIC_API_KEY=PASTE_YOUR_REAL_KEY_HERE

2. Restart the gateway

#
openclaw gateway restart
openclaw gateway status --deep

You want RPC probe: ok.

3. Attach that API key to agent heidi

openclaw secrets configure --agent heidi

In the prompts:

  • choose the Anthropic API key / .key field
  • do not choose .token
#
  • source = env
  • secret id = ANTHROPIC_API_KEY

4. Verify agent + routing are still correct

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

You want to keep seeing:

  • heidi agent exists
  • telegram:heidi routes to heidi

5. Hatch her locally first

#
openclaw tui --url ws://127.0.0.1:19789 --agent heidi --session main

6. Then hatch her on Telegram

Message the heidi Telegram bot.

If pairing is enabled:

openclaw pairing list telegram
openclaw pairing approve telegram <CODE>

#

If you want the super short version

Run these in order:

nano ~/.openclaw/.env
openclaw gateway restart
openclaw secrets configure --agent heidi
openclaw agents list --bindings
openclaw tui --url ws://127.0.0.1:19789 --agent heidi --session main

If this fixes it, please right-click the solution message → Apps → āœ… Mark Solution so Answer Overflow can index it for the next person.

silver tendon
#

mkdir -p -/.openclaw

dusty juniperBOT
#

Tiny typo, it should be:

mkdir -p ~/.openclaw

not:

mkdir -p -/.openclaw

Then continue with:

nano ~/.openclaw/.env
silver tendon
#

provider source = env, what do I put for provider alias??

dusty juniperBOT
#

Use:

default

So for the prompt:

  • source = env
  • provider alias = default
  • secret id = ANTHROPIC_API_KEY

And make sure you picked the Anthropic .key field, not .token.

silver tendon
#

It's asking for evn allowlist (comma separated, blank for unrestricted)

dusty juniperBOT
#

Put:

ANTHROPIC_API_KEY

That’s better than leaving it unrestricted.

So that prompt should be:

ANTHROPIC_API_KEY

Then continue.

silver tendon
#

CONFIGURE SECRET PROVIDER?

  • Add provider (define a new env/file/exec provider)
  • Edit provider
  • Remove Provider
  • Continu
dusty juniperBOT
#

Choose:

Continue

You’ve already set up the env provider details, so you do not need to add/edit/remove one now.

Just continue and let it finish.

silver tendon
#

Select credential field
│ ā— profiles.anthropic:default.key (auth profile, agent heidi) (auth-profiles.json)
│ ā—‹ profiles.anthropic:default.token (auth profile, agent heidi)
│ ā—‹ channels.telegram.accounts.heidi.botToken
│ ā—‹ gateway.auth.token
│ ā—‹ Create auth profile mapping
│ ā—‹ Show derived targets

dusty juniperBOT
#

Yep, pick the one that’s already selected:

profiles.anthropic:default.key

That’s the correct one for an Anthropic API key for agent heidi.

Do not pick:

profiles.anthropic:default.token

That one is the wrong path for your setup.

silver tendon
#

šŸ¦ž OpenClaw 2026.4.14 (323493f) — I don't have opinions about tabs vs spaces. I have opinions about everything else.

│
ā—‡ Configure secret providers (only env refs are available until file/exec providers are added)
│ Add provider
│
ā—‡ Provider source
│ env
│
ā—‡ Provider alias
│ default
│
ā—‡ Env allowlist (comma-separated, blank for unrestricted)
│ ANTHROPIC_API_KEY
│
ā—‡ Configure secret providers
│ Continue
│
ā—‡ Select credential field
│ profiles.anthropic:default.key (auth profile, agent heidi)
│
ā—‡ Secret source
│ env
│
ā—‡ Provider alias
│ default
│
ā—‡ Secret id
│ ANTHROPIC_OAUTH_TOKEN
SecretRefResolutionError: Environment variable "ANTHROPIC_OAUTH_TOKEN" is not allowlisted in secrets.providers.default.allowlist.

dusty juniperBOT
#

Yep, the problem is just this line:

Secret id
ANTHROPIC_OAUTH_TOKEN

That should be:

ANTHROPIC_API_KEY

You did the allowlist correctly.
Then the wizard still got pointed at the wrong secret id.

Rerun it and use exactly this combo

#
  • credential field: profiles.anthropic:default.key
  • source: env
  • provider alias: default
  • secret id: ANTHROPIC_API_KEY

Why it failed

Because you told it:

  • use the key field
  • but fetch the OAuth token env var

Those don’t match.

So just rerun openclaw secrets configure --agent heidi and when it asks for Secret id, type:

#
ANTHROPIC_API_KEY
silver tendon
#

šŸ¦ž OpenClaw 2026.4.14 (323493f) — I speak fluent bash, mild sarcasm, and aggressive tab-completion energy.

│
ā—† Configure secret providers (only env refs are available until file/exec providers are added)
│ ā— Add provider (Define a new env/file/exec provider)
│ ā—‹ Continue
ā””

dusty juniperBOT
#

If you already added the env provider named default, choose:

Continue

Only choose Add provider if the default env provider is missing and you need to create it again.

Given your last run, it should already exist, so I’d pick Continue.

silver tendon
#

Configure another credentiual?

dusty juniperBOT
#

Choose:

No

You only need the Anthropic API key for this step.

After that, finish out of the wizard and then test with:

openclaw tui --url ws://127.0.0.1:19789 --agent heidi --session main

or message the Telegram bot.

silver tendon
#

heidi@Kates-Mac-mini ~ % openclaw tui --url ws://127.0.0.1:19789 --agent heidi --session main
error: unknown option '--agent'

dusty juniperBOT
#

Let me verify the exact openclaw tui flags so I don’t make you fight another bogus option.

#

Yep, that one was on me, sorry. tui uses --session, not --agent.

Use this instead:

openclaw tui --url ws://127.0.0.1:19789 --session agent:heidi:main

If you want the workspace-auto-detect version, this should also work:

cd ~/.openclaw/workspace-heidi
openclaw tui --url ws://127.0.0.1:19789

But the safest explicit one is:

#
openclaw tui --url ws://127.0.0.1:19789 --session agent:heidi:main
silver tendon
#

Okay she's live.

#

Now can we try the next agent?

dusty juniperBOT
#

Hell yes, nice work. šŸŽ‰

That means the hard part is over:

  • gateway is stable on 19789
  • main stays admin-only
  • heidi is a real Telegram-facing agent
  • routing/auth are working

Important rule now

Do not touch the gateway setup again unless you actually want a separate gateway architecture.

For the next agent, just repeat the agent + bind + secrets pattern, not onboarding/setup.

If you want, I can give you the exact Agent 2 command block next.

#

And if this fixed it, please right-click the solution message → Apps → āœ… Mark Solution so Answer Overflow can index it for the next poor soul.

silver tendon
#

Yes the exact command block, please

dusty juniperBOT
#

Yep, let’s do it, same pattern, no new gateway.

I’d use agent2 as both the agent id and Telegram account id to keep it clean.

Exact commands

1. Create Agent 2

openclaw agents add agent2 \
  --workspace ~/.openclaw/workspace-agent2 \
  --bind telegram:agent2 \
  --model anthropic/claude-sonnet-4-6

2. Add the second Telegram bot

#
openclaw config set channels.telegram.accounts.agent2.botToken "AGENT2_BOT_TOKEN"
openclaw config set channels.telegram.accounts.agent2.dmPolicy pairing

3. Add a separate Anthropic key for Agent 2

Edit:

nano ~/.openclaw/.env

Add a second line like:

#
ANTHROPIC_API_KEY_AGENT2=PASTE_AGENT2_KEY_HERE

4. Restart gateway

openclaw gateway restart

5. Configure Agent 2 secrets

openclaw secrets configure --agent agent2

In that wizard, use:

#
  • credential field: profiles.anthropic:default.key
  • source: env
  • provider alias: use a new one like agent2 if it asks you to add/edit provider
  • env allowlist: ANTHROPIC_API_KEY_AGENT2
  • secret id: ANTHROPIC_API_KEY_AGENT2

6. Verify everything

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

You want to end up with:

  • telegram:heidi → heidi
  • telegram:agent2 → agent2
#

Important

Do not run openclaw setup or create another gateway.
Just repeat the agent / bind / secret flow.

If you want, paste the next screen/output and I’ll walk you through Agent 2 the same way.

#

Yep, here’s the exact block.

Replace the two placeholders first:

  • PASTE_AGENT2_BOT_TOKEN_HERE
  • PASTE_AGENT2_ANTHROPIC_API_KEY_HERE
openclaw agents add agent2 \
  --workspace ~/.openclaw/workspace-agent2 \
  --bind telegram:agent2 \
  --model anthropic/claude-sonnet-4-6

openclaw config set channels.telegram.accounts.agent2.botToken "PASTE_AGENT2_BOT_TOKEN_HERE"
openclaw config set channels.telegram.accounts.agent2.dmPolicy pairing
#
cat >> ~/.openclaw/.env <<'EOF'
ANTHROPIC_API_KEY_AGENT2=PASTE_AGENT2_ANTHROPIC_API_KEY_HERE
EOF

openclaw gateway restart

openclaw secrets configure --agent agent2

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

In openclaw secrets configure --agent agent2, choose:

  • credential field → profiles.anthropic:default.key
  • secret source → env
#
  • provider alias → agent2
  • if it asks to add provider:
    • source = env
    • alias = agent2
    • allowlist = ANTHROPIC_API_KEY_AGENT2
  • secret id → ANTHROPIC_API_KEY_AGENT2
  • configure another credential? → No

Then hatch Agent 2

openclaw tui --url ws://127.0.0.1:19789 --session agent:agent2:main

Or DM the second Telegram bot.

If pairing is required:

#
openclaw pairing list telegram
openclaw pairing approve telegram <CODE>

If you paste the next screen/output, I’ll sanity-check Agent 2 too.

silver tendon
#

How do I configure access to gmail and Apple Reminders.

dusty juniperBOT
#

Let me verify the exact docs for Gmail and Apple Reminders support before I point you the wrong way.

#

I found the Gmail docs, and I’m checking the FAQ plus whether Apple Reminders has a first-class OpenClaw integration or not.

#

Short version:

Gmail

Yes, supported.

The built-in OpenClaw path is Gmail via gog and, if you want push-style inbox monitoring, Gmail Pub/Sub hooks.

Start here:

openclaw webhooks gmail setup --account you@example.com

Then run or let the gateway manage it:

#

My recommendation

  • for Gmail, use the built-in Gmail path
  • for Reminders, don’t fight Apple Reminders right away, use OpenClaw cron/heartbeat unless you specifically need the Apple app

If you want, I can give you the exact Gmail setup commands next, or sketch the cleanest Apple Reminders workaround on macOS.

silver tendon
#

sage@Kates-Mac-mini ~ % openclaw gateway restart

šŸ¦ž OpenClaw 2026.4.14 (323493f) — I'm not AI-powered, I'm AI-possessed. Big difference.

Restarted LaunchAgent: gui/503/ai.openclaw.gateway
Timed out after 60s waiting for gateway port 18789 to become healthy.
Gateway process is running but port 18789 is still free (startup hang/crash loop or very slow VM startup).
Service runtime: status=running, state=active, pid=38981
Gateway port 18789 status: free.
Gateway restart timed out after 60s waiting for health checks.
Tip: openclaw gateway status --deep
Tip: openclaw doctor

dusty juniperBOT
#

Aha, we caught it.

You’re now in sage@Kates-Mac-mini, not heidi@Kates-Mac-mini.

That means you’re using a different macOS user, so OpenClaw is reading a different:

  • ~/.openclaw
  • LaunchAgent
  • gateway config
  • default port

That’s why it snapped back to 18789.

What this means

OpenClaw state is effectively per macOS user here.

#

So sage is not continuing the working heidi setup.
It’s a separate runtime.

Your 2 real options

Option 1, recommended right now

Go back to the same macOS user that has the working setup, meaning heidi, and keep building agents there.

This is the cleanest path if you want to continue the shared-gateway setup we just fixed.

Option 2, hard isolation

Use separate macOS users like heidi and sage, each with their own OpenClaw state and own gateway port.

That actually matches your ā€œtotally sandboxedā€ goal better, but it is a different architecture.

My recommendation

#

For this thread, stick with Option 1 and go back to heidi.

If you want, later, we can deliberately set up sage as a fully separate isolated agent user on its own port.

If you want to do that, say ā€œset up sage as isolatedā€ and I’ll give you the exact commands.

silver tendon
#

copy auth profiles from main?

dusty juniperBOT
#

You can, but I wouldn’t if your goal is true isolation.

My recommendation

If you want separate agents with separate creds

Do not copy auth-profiles.json from main.

Configure each agent separately with:

openclaw secrets configure --agent <agent-id>

and use a different env var / key per agent.

If you just want a fast smoke test

You can temporarily reuse the same auth as main, but that means:

#
  • same provider creds
  • not truly isolated
  • harder to reason about later

So I’d only do that to confirm routing works, then replace it.

Short version

  • production / isolated setup → no, don’t copy
  • quick temporary test → okay, but only as a shortcut

Given what you said earlier, I think you want the first one.

silver tendon
#

šŸ¦ž OpenClaw 2026.4.14 (323493f) — I don't have opinions about tabs vs spaces. I have opinions about everything else.

Restarted LaunchAgent: gui/502/ai.openclaw.gateway
Timed out after 60s waiting for gateway port 19789 to become healthy.
Gateway process is running but port 19789 is still free (startup hang/crash loop or very slow VM startup).
Service runtime: status=running, state=active, pid=53647
Gateway port 19789 status: free.
Gateway restart timed out after 60s waiting for health checks.
Tip: openclaw gateway status --deep
Tip: openclaw doctor

dusty juniperBOT
#

That restart output by itself isn’t enough, but it does mean the gateway is failing during startup, not just slow.

Given what you just changed, my guess is the new agent2 secret/provider config introduced something the gateway doesn’t like.

Next 3 commands

Please paste these:

openclaw gateway status --deep
tail -50 ~/.openclaw/logs/gateway.err.log
tail -50 ~/.openclaw/logs/gateway.log

Why

gateway restart only tells us:

#
  • service process exists
  • port never bound

The real cause will be in either:

  • Last gateway error from status --deep
  • ~/.openclaw/logs/gateway.err.log

My suspicion

Most likely one of these:

  • bad secret provider config
  • bad secret ref / allowlist mismatch
  • malformed config written during the second-agent setup

Paste those 3 outputs and I’ll help you pinpoint the exact bad line.

silver tendon
#

šŸ¦ž OpenClaw 2026.4.14 (323493f) — I read logs so you can keep pretending you don't have to.

│
ā—‡
Service: LaunchAgent (loaded)
File logs: /var/folders/9v/5sxh2c254w7cq9gqm38n_b8h0000gp/T/openclaw-502/openclaw-2026-04-14.log
Command: /opt/homebrew/opt/node@22/bin/node /opt/homebrew/lib/node_modules/openclaw/dist/index.js gateway --port 19789
Service file: ~/Library/LaunchAgents/ai.openclaw.gateway.plist
Service env: OPENCLAW_GATEWAY_PORT=19789

Config (cli): ~/.openclaw/openclaw.json
Config (service): ~/.openclaw/openclaw.json

Gateway: bind=loopback (127.0.0.1), port=19789 (service args)
Probe target: ws://127.0.0.1:19789
Dashboard: http://127.0.0.1:19789/
Probe note: Loopback-only gateway; only local clients can connect.

Runtime: running (pid 55097, state active)
Warm-up: launch agents can take a few seconds. Try again shortly.
RPC probe: failed
RPC target: ws://127.0.0.1:19789
gateway closed (1006):

Gateway port 19789 is not listening (service appears running).
Last gateway error: 2026-04-14T21:34:31.608-04:00 Gateway start blocked: existing config is missing gateway.mode. Treat this as suspicious or clobbered config. Re-run openclaw onboard --mode local or openclaw setup, set gateway.mode=local manually, or pass --allow-unconfigured.

dusty juniperBOT
#

Yep, same exact issue again:

existing config is missing gateway.mode

So the config got clobbered again.

Fix it

Run this exact block:

openclaw config set gateway.mode local
openclaw config set gateway.bind loopback
openclaw config set gateway.port 19789 --strict-json
#
openclaw config set gateway.auth.mode token
openclaw gateway restart
openclaw gateway status --deep

You want RPC probe: ok again.

Important

Something in the flow you’re using is still stripping out gateway.mode.

So for now:

  • do not run openclaw setup again
  • do not use the buggy interactive path if it touches gateway config
  • stick to direct config set commands
#

After it comes back

I’d also make a backup of the working config:

cp ~/.openclaw/openclaw.json ~/.openclaw/openclaw.json.working-backup

I’m pretty convinced now there’s a real bug in the current config flow, not just operator error.

silver tendon
#

šŸ¦ž OpenClaw 2026.4.14 (323493f) — Your .env is showing; don't worry, I'll pretend I didn't see it.

│
ā—‡
Service: LaunchAgent (loaded)
File logs: /var/folders/9v/5sxh2c254w7cq9gqm38n_b8h0000gp/T/openclaw-502/openclaw-2026-04-14.log
Command: /opt/homebrew/opt/node@22/bin/node /opt/homebrew/lib/node_modules/openclaw/dist/index.js gateway --port 19789
Service file: ~/Library/LaunchAgents/ai.openclaw.gateway.plist
Service env: OPENCLAW_GATEWAY_PORT=19789

Config (cli): ~/.openclaw/openclaw.json
Config (service): ~/.openclaw/openclaw.json

Gateway: bind=loopback (127.0.0.1), port=19789 (service args)
Probe target: ws://127.0.0.1:19789
Dashboard: http://127.0.0.1:19789/
Probe note: Loopback-only gateway; only local clients can connect.

Runtime: running (pid 59957, state active)
Warm-up: launch agents can take a few seconds. Try again shortly.
RPC probe: failed
RPC target: ws://127.0.0.1:19789
gateway closed (1006):

Gateway port 19789 is not listening (service appears running).
Last gateway error: 2026-04-14T21:34:31.608-04:00 Gateway start blocked: existing config is missing gateway.mode. Treat this as suspicious or clobbered config. Re-run openclaw onboard --mode local or openclaw setup, set gateway.mode=local manually, or pass --allow-unconfigured.
Logs: ~/.openclaw/logs/gateway.log
Errors: ~/.openclaw/logs/gateway.err.log

dusty juniperBOT
#

This still shows the same problem, which means gateway.mode is still not actually present in config.

Let’s verify the raw gateway section directly.

Run this

openclaw config get gateway --json

If mode is missing, then immediately run:

openclaw config set gateway.mode local
openclaw config set gateway.bind loopback
openclaw config set gateway.port 19789 --strict-json
#
openclaw config set gateway.auth.mode token
openclaw config get gateway --json
openclaw gateway restart
openclaw gateway status --deep

What I want to see

In openclaw config get gateway --json, there should be a real field like:

"mode": "local"

Right now, the status output is telling us that field is still absent, so I want to catch whether:

#
  • the config set never stuck
  • or something is deleting it immediately afterward

Paste the openclaw config get gateway --json output first, that’s the cleanest next clue.

silver tendon
#

heidi@Kates-Mac-mini ~ % openclaw config get gateway --json
{
"port": 19789,
"mode": "local",
"bind": "loopback",
"auth": {
"mode": "token",
"token": "OPENCLAW_REDACTED"
}
}

dusty juniperBOT
#

Good, that changes the diagnosis.

Your gateway config is actually correct now:

  • mode: local
  • bind: loopback
  • port: 19789
  • auth.mode: token

So that missing gateway.mode line is probably a stale last-error message, not the current root cause.

Next step: get the real current crash

Please paste these:

#
tail -100 ~/.openclaw/logs/gateway.err.log
tail -100 ~/.openclaw/logs/gateway.log

Why

Now we know:

  • config is fine
  • service starts
  • port never binds

So the real problem is almost certainly in startup logs, for example:

  • bad secret/provider config
  • malformed .env
#
  • agent auth/profile parse failure
  • some other runtime crash after config load

We’re past the gateway-mode problem.
Now we need the actual live error from the logs.

silver tendon
#

heidi@Kates-Mac-mini ~ % tail -100 ~/.openclaw/logs/gateway.err.log
(node:61340) [DEP0040] DeprecationWarning: The punycode module is deprecated. Please use a userland alternative instead.
(Use node --trace-deprecation ... to show where the warning was created)
2026-04-14T23:36:57.715-04:00 [secrets] [SECRETS_RELOADER_DEGRADED] SecretRefResolutionError: Environment variable "ANTHROPIC_API_KEY" is missing or empty.
2026-04-14T23:36:57.718-04:00 Gateway failed to start: Error: Startup failed: required secrets are unavailable. SecretRefResolutionError: Environment variable "ANTHROPIC_API_KEY" is missing or empty.
(node:61364) [DEP0040] DeprecationWarning: The punycode module is deprecated. Please use a userland alternative instead.
(Use node --trace-deprecation ... to show where the warning was created)
2026-04-14T23:36:59.468-04:00 [secrets] [SECRETS_RELOADER_DEGRADED] SecretRefResolutionError: Environment variable "ANTHROPIC_API_KEY" is missing or empty.
2026-04-14T23:36:59.469-04:00 Gateway failed to start: Error: Startup failed: required secrets are unavailable. SecretRefResolutionError: Environment variable "ANTHROPIC_API_KEY" is missing or empty.
(node:61388) [DEP0040] DeprecationWarning: The punycode module is deprecated. Please use a userland alternative instead.
(Use node --trace-deprecation ... to show where the warning was created)
2026-04-14T23:37:01.208-04:00 [secrets] [SECRETS_RELOADER_DEGRADED] SecretRefResolutionError: Environment variable "ANTHROPIC_API_KEY" is missing or empty.
2026-04-14T23:37:01.209-04:00 Gateway failed to start: Error: Startup failed: required secrets are unavailable. SecretRefResolutionError: Environment variable "ANTHROPIC_API_KEY" is missing or empty.
(node:61412) [DEP0040] DeprecationWarning: The punycode module is deprecated. Please use a userland alternative instead.
(Use node --trace-deprecation ... to show where the warning was created)

dusty juniperBOT
#

There it is.

The gateway is failing because Agent 1 (heidi) still depends on:

ANTHROPIC_API_KEY

and that env var is now missing/empty.

What happened

You likely added ANTHROPIC_API_KEY_AGENT2, but heidi is still wired to the original:

ANTHROPIC_API_KEY
#

So startup fails before the gateway can bind the port.

Fix

Edit:

nano ~/.openclaw/.env

Make sure it contains both of these, if both agents should work:

ANTHROPIC_API_KEY=PASTE_HEIDI_KEY_HERE
ANTHROPIC_API_KEY_AGENT2=PASTE_AGENT2_KEY_HERE
#

Then restart:

openclaw gateway restart
openclaw gateway status --deep

Short version

  • heidi still needs ANTHROPIC_API_KEY
  • agent2 can use ANTHROPIC_API_KEY_AGENT2
  • right now the first one is missing, so the whole gateway won’t start

Honestly, this is good news, because now it’s a concrete config problem, not ghost chaos.

silver tendon
#

I don't have Heidi's api key anymore. If I generate a new one will it mess everything up?

dusty juniperBOT
#

No, generating a new one is totally fine, and honestly it’s the right move here.

It won’t mess up your agent setup as long as you put the new key back under the same env var name:

ANTHROPIC_API_KEY=NEW_HEIDI_KEY_HERE

What to do

Edit:

nano ~/.openclaw/.env

Make sure it has:

#
ANTHROPIC_API_KEY=NEW_HEIDI_KEY_HERE
ANTHROPIC_API_KEY_AGENT2=YOUR_AGENT2_KEY_HERE

Then restart:

openclaw gateway restart
openclaw gateway status --deep

Important

You do not need to recreate:

  • the heidi agent
#
  • bindings
  • Telegram config

You’re just restoring the secret that heidi already points to.

Short version

  • new Heidi key? safe
  • put it back in ANTHROPIC_API_KEY
  • restart gateway
  • done

If you want, once you’ve generated it, I can give you the exact final sanity-check commands.

silver tendon
#

šŸ¦ž OpenClaw 2026.4.14 (323493f) — Your terminal just grew claws—type something and let the bot pinch the busywork.

Restarted LaunchAgent: gui/502/ai.openclaw.gateway
Timed out after 60s waiting for gateway port 19789 to become healthy.
Gateway process is running but port 19789 is still free (startup hang/crash loop or very slow VM startup).
Service runtime: status=running, state=active, pid=69217
Gateway port 19789 status: free.
Gateway restart timed out after 60s waiting for health checks.
Tip: openclaw gateway status --deep
Tip: openclaw doctor
heidi@Kates-Mac-mini ~ %

dusty juniperBOT
#

We need the new error now, because gateway restart still only tells us ā€œdidn’t bindā€, not why.

Please run these 2 and paste them:

tail -30 ~/.openclaw/logs/gateway.err.log
grep -n '^ANTHROPIC' ~/.openclaw/.env | sed 's/=.*$/=REDACTED/'

Why these

  • gateway.err.log tells us the actual current startup failure
  • the redacted grep confirms the env vars are really present in the file the gateway loads

I’m guessing one of these is true:

  1. ANTHROPIC_API_KEY still isn’t in ~/.openclaw/.env
#
  1. it’s there but malformed
  2. there’s now a second missing secret for another agent

Paste those two outputs and we’ll pin it down fast.

silver tendon
#

tail -30 ~/.openclaw/logs/gateway.err.log

dusty juniperBOT
#

Yep, run that command and paste the output, plus this one too:

grep -n '^ANTHROPIC' ~/.openclaw/.env | sed 's/=.*$/=REDACTED/'

I need the results, not just the command, so I can see whether it’s still:

  • missing ANTHROPIC_API_KEY
  • malformed .env
  • or a different secret failing now
silver tendon
#

2026-04-14T23:49:03.892-04:00 [secrets] [SECRETS_RELOADER_DEGRADED] SecretRefResolutionError: Environment variable "ANTHROPIC_API_KEY" is missing or empty.
2026-04-14T23:49:03.893-04:00 Gateway failed to start: Error: Startup failed: required secrets are unavailable. SecretRefResolutionError: Environment variable "ANTHROPIC_API_KEY" is missing or empty.
(node:71905) [DEP0040] DeprecationWarning: The punycode module is deprecated. Please use a userland alternative instead.
(Use node --trace-deprecation ... to show where the warning was created)
2026-04-14T23:49:05.633-04:00 [secrets] [SECRETS_RELOADER_DEGRADED] SecretRefResolutionError: Environment variable "ANTHROPIC_API_KEY" is missing or empty.
2026-04-14T23:49:05.636-04:00 Gateway failed to start: Error: Startup failed: required secrets are unavailable. SecretRefResolutionError: Environment variable "ANTHROPIC_API_KEY" is missing or empty.
(node:71929) [DEP0040] DeprecationWarning: The punycode module is deprecated. Please use a userland alternative instead.
(Use node --trace-deprecation ... to show where the warning was created)
2026-04-14T23:49:07.388-04:00 [secrets] [SECRETS_RELOADER_DEGRADED] SecretRefResolutionError: Environment variable "ANTHROPIC_API_KEY" is missing or empty.
2026-04-14T23:49:07.391-04:00 Gateway failed to start: Error: Startup failed: required secrets are unavailable. SecretRefResolutionError: Environment variable "ANTHROPIC_API_KEY" is missing or empty.
(node:71953) [DEP0040] DeprecationWarning: The punycode module is deprecated. Please use a userland alternative instead.
(Use node --trace-deprecation ... to show where the warning was created)
2026-04-14T23:49:09.155-04:00 [secrets] [SECRETS_RELOADER_DEGRADED] SecretRefResolutionError: Environment variable "ANTHROPIC_API_KEY" is missing or empty.
2026-04-14T23:49:09.156-04:00 Gateway failed to start: Error: Startup failed: required secrets are unavailable. SecretRefResolutionError: Environment variable "

dusty juniperBOT
#

Yep, that confirms it, no ambiguity now:

ANTHROPIC_API_KEY is still missing or empty.

So the gateway will keep failing until that exact env var exists with a real value.

Do this now

1. Edit the env file

nano ~/.openclaw/.env

Make sure this line exists and has a real key after the =:

#
ANTHROPIC_API_KEY=PASTE_HEIDI_NEW_KEY_HERE

If you also want Agent 2 later, keep that too:

ANTHROPIC_API_KEY_AGENT2=PASTE_AGENT2_KEY_HERE

2. Verify the lines exist

grep -n '^ANTHROPIC' ~/.openclaw/.env | sed 's/=.*$/=REDACTED/'

You should see at least:

#
ANTHROPIC_API_KEY=REDACTED

3. Restart gateway

openclaw gateway restart
openclaw gateway status --deep

Important

It’s not enough to have ā€œsome Anthropic key somewhereā€.

heidi is specifically wired to:

#
ANTHROPIC_API_KEY

So that exact variable name must exist and must not be blank.

silver tendon
#

heidi@Kates-Mac-mini ~ % grep -n '^ANTHROPIC' ~/.openclaw/.env | sed 's/=.*$/=REDACTED/'
1:ANTHROPIC_API_KEY_heidi=REDACTED
2:ANTHROPIC_API_KEY_sage=REDACTED

dusty juniperBOT
#

Aha, there’s the mismatch.

Your env file has:

  • ANTHROPIC_API_KEY_heidi
  • ANTHROPIC_API_KEY_sage

But heidi is currently configured to look for the exact name:

  • ANTHROPIC_API_KEY

Fastest fix

Add an alias line that points Heidi’s existing key to the exact name OpenClaw expects.

Run this:

#
printf 'ANTHROPIC_API_KEY=%s\n' "$(awk -F= '/^ANTHROPIC_API_KEY_heidi=/{sub(/^ANTHROPIC_API_KEY_heidi=/,""); print; exit}' ~/.openclaw/.env)" >> ~/.openclaw/.env

Then verify:

grep -n '^ANTHROPIC' ~/.openclaw/.env | sed 's/=.*$/=REDACTED/'

You should now see:

  • ANTHROPIC_API_KEY
  • ANTHROPIC_API_KEY_heidi
  • ANTHROPIC_API_KEY_sage

Then restart:

#
openclaw gateway restart
openclaw gateway status --deep

Cleaner long-term fix

Later, you can rewire heidi to use ANTHROPIC_API_KEY_heidi directly.

But right now, the fastest path is just to add the missing generic alias and get the gateway healthy again.

silver tendon
#

šŸ¦ž OpenClaw 2026.4.14 (323493f) — I don't judge, but your missing API keys are absolutely judging you.

│
ā—‡
Service: LaunchAgent (loaded)
File logs: /var/folders/9v/5sxh2c254w7cq9gqm38n_b8h0000gp/T/openclaw-502/openclaw-2026-04-14.log
Command: /opt/homebrew/opt/node@22/bin/node /opt/homebrew/lib/node_modules/openclaw/dist/index.js gateway --port 19789
Service file: ~/Library/LaunchAgents/ai.openclaw.gateway.plist
Service env: OPENCLAW_GATEWAY_PORT=19789

Config (cli): ~/.openclaw/openclaw.json
Config (service): ~/.openclaw/openclaw.json

Gateway: bind=loopback (127.0.0.1), port=19789 (service args)
Probe target: ws://127.0.0.1:19789
Dashboard: http://127.0.0.1:19789/
Probe note: Loopback-only gateway; only local clients can connect.

Runtime: running (pid 74227, state active)
RPC probe: ok

Listening: 127.0.0.1:19789
Troubles: run openclaw status
Troubleshooting: https://docs.openclaw.ai/troubleshooting

dusty juniperBOT
#

Nice, that’s it. Gateway is healthy again. šŸŽ‰

You’re back to:

  • RPC probe: ok
  • listening on 127.0.0.1:19789

I’d do 2 things right now

1. Back up the working config

cp ~/.openclaw/openclaw.json ~/.openclaw/openclaw.json.working-backup
cp ~/.openclaw/.env ~/.openclaw/.env.working-backup

2. Stop changing gateway-level stuff

#

From here on out, only do:

  • agent creation
  • bindings
  • per-agent secrets

Not setup, not gateway re-onboarding.

One cleanup note

Right now heidi is booting because of the fallback alias:

  • ANTHROPIC_API_KEY

Later, if you want it cleaner, reconfigure heidi to use ANTHROPIC_API_KEY_heidi directly.

But don’t touch that now unless you want more excitement.

#

If you want, next I can help you finish sage / Agent 2 without knocking over the gateway again.

And if this solved the main issue, please right-click the solution message → Apps → āœ… Mark Solution so Answer Overflow can index it.

silver tendon
#

Now I'm getting the Telegram error: Missing API key for provider "openai". Configure on gateway auth for that provider, then try again. This is in the sage (agent2) profile. She isconfigured for Anthropic onlyl.

dusty juniperBOT
#

That usually means one of 2 things:

  1. sage is not actually using the Anthropic model you think it is
  2. Telegram is not actually routed to sage, so the message is hitting some other agent/default session that wants OpenAI

So I would not add an OpenAI key. That’s probably the wrong fix.

Please paste these

openclaw models status --agent sage
openclaw agents list --bindings

What I’m expecting

We want to confirm both of these are true:

#
  • sage model = anthropic/claude-sonnet-4-6
  • telegram:<your-sage-account-id> routes to sage

If either of those is wrong, OpenClaw can fall back into a default/OpenAI path and you get exactly this error.

Short version: this smells like model/routing drift, not ā€œyou need OpenAI now.ā€

silver tendon
#

šŸ¦ž OpenClaw 2026.4.14 (323493f) — Give me a workspace and I'll give you fewer tabs, fewer toggles, and more oxygen.

Approved telegram sender 8660138479.
heidi@Kates-Mac-mini ~ % openclaw models status --agent sage

šŸ¦ž OpenClaw 2026.4.14 (323493f) — I'm the reason your shell history looks like a hacker-movie montage.

Config : ~/.openclaw/openclaw.json
Agent dir : ~/.openclaw/agents/sage/agent
Default (agent): anthropic/claude-sonnet-4-6
Fallbacks (0) (defaults): -
Image model (defaults): -
Image fallbacks (0) (defaults): -
Aliases (0) : -
Configured models (0): all

Auth overview
Auth store : ~/.openclaw/agents/sage/agent/auth-profiles.json
Shell env : off
Providers w/ OAuth/tokens (0): -

  • anthropic effective=profiles:~/.openclaw/agents/main/agent/auth-profiles.json | profiles=1 (oauth=0, token=0, api_key=1) | anthropic:default=sk-ant-a...QHohUAAA | env=sk-ant-a...9X4BlQAA | source=env: ANTHROPIC_API_KEY
  • anthropic-openai effective=env:sk-ant-a...9X4BlQAA | env=sk-ant-a...9X4BlQAA | source=env: ANTHROPIC_API_KEY

OAuth/token status

  • none

šŸ¦ž OpenClaw 2026.4.14 (323493f) — Automation with claws: minimal fuss, maximal pinch.

Agents:

  • main (default)
    Workspace: ~/.openclaw/workspace
    Agent dir: ~/.openclaw/agents/main/agent
    Routing rules: 0
    Routing: default (no explicit rules)
    Providers:
    • telegram heidi: configured
    • telegram sage: configured
  • heidi
    Workspace: ~/.openclaw/workspace-heidi
    Agent dir: ~/.openclaw/agents/heidi/agent
    Model: anthropic/claude-sonnet-4-6
    Routing rules: 1
    Routing: telegram heidi
    Providers:
    • telegram heidi: configured
      Routing rules:
    • telegram accountId=heidi
  • sage
    Workspace: ~/.openclaw/workspace-sage
    Agent dir: ~/.openclaw/agents/sage/agent
    Model: anthropic/claude-sonnet-4-6
    Routing rules: 0
    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.
dusty juniperBOT
#

Yep, found it.

sage has 0 routing rules, so Telegram sage is still falling through to main.

That’s why you’re getting weird provider behavior.

Fix the routing

Run:

openclaw agents bind --agent sage --bind telegram:sage
openclaw agents list --bindings

You want to see an explicit rule for:

#
  • telegram:sage → sage

One more important thing

Your models status --agent sage also shows sage is not truly isolated yet on auth.

It’s currently resolving Anthropic from the shared/default path:

  • source=env: ANTHROPIC_API_KEY
  • and even main’s auth store shows up in the effective path

So there are really 2 issues:

  1. Routing is wrong → fix with agents bind
  2. Auth is still shared → fix later by rewiring sage to ANTHROPIC_API_KEY_sage

Do this first

#
openclaw agents bind --agent sage --bind telegram:sage

That should stop Telegram sage from landing on main.

silver tendon
#

Both agents were successfully up and running on Telegram last night and this morning neither are responsive.

dusty juniperBOT
#

If both died at the same time, I’d start by assuming this is a gateway/channel-level problem, not two separate agent failures.

Please paste this bundle:

openclaw --version
whoami
openclaw gateway status --deep
openclaw channels status --probe
openclaw agents list --bindings
tail -50 ~/.openclaw/logs/gateway.err.log

Why these first

  • gateway status --deep tells us if the gateway itself is alive
  • channels status --probe tells us if Telegram is connected/configured
#
  • agents list --bindings confirms the routing rules didn’t drift
  • gateway.err.log catches the real startup/runtime error
  • whoami matters here because earlier you were bouncing between different macOS users

My guess

Most likely one of these:

  1. gateway didn’t come back cleanly after reboot/sleep
  2. Telegram channel config/pairing drifted
  3. you’re in the wrong macOS user again
  4. a required secret/env var is missing, so gateway started badly

Docs if you want them handy:

#

Paste that bundle and I’ll narrow it fast.

silver tendon
#

Okay they both responded as soon as I "woke up" the computer they're living on. It's powered on at all times, but it seems like I need to login a user in order for them to be responsive and functional?

dusty juniperBOT
#

Yep, that’s very likely what you’re seeing.

On macOS, the normal OpenClaw service install is a LaunchAgent, which is user-session scoped. So:

  • machine powered on ≠ enough
  • logged-in macOS user session = what the agent actually lives inside

That means after sleep / logout / some wake states, things can look ā€œonā€ but not actually be responsive until that user session is active again.

Short version

For your current setup, yes, a logged-in user is effectively required.

If you want it reliable 24/7

You’ve got 2 good options:

#

Option 1, easiest on the Mac mini

Use a dedicated macOS user for OpenClaw and keep it:

  • auto-login enabled
  • display allowed to sleep if you want
  • system sleep disabled

Option 2, more robust

Move the always-on gateway/runtime to a Linux box / VPS / dedicated headless host.

That’s the cleaner ā€œagents stay alive no matter whatā€ architecture.

My recommendation

Since you’re already deep into this Mac mini setup:

  • create or keep a dedicated OpenClaw macOS user
#
  • let that user stay logged in
  • disable system sleep

If you want, I can give you the exact macOS settings checklist for making this box behave like an always-on agent host.

silver tendon
#

Yes please!

dusty juniperBOT
#

Yep, here’s the practical Mac mini checklist.

Best setup for an always-on OpenClaw Mac mini

1. Use one dedicated macOS user for OpenClaw

  • keep both agents under that same logged-in user if you’re using the shared-gateway setup
  • don’t bounce between macOS users unless you intentionally want separate runtimes

2. Enable automatic login for that user

In System Settings → Users & Groups → Automatic login
Set it to the dedicated OpenClaw user.

That way after reboot, the user session actually starts.

3. Disable system sleep

You want:

#
  • display can sleep
  • computer/system should not sleep

On a Mac mini, look in System Settings → Lock Screen / Energy and make sure the machine itself stays awake.

If you use terminal, this is the behavior you want:

  • no idle system sleep
  • wake for network access on
  • restart automatically after power failure on

4. It’s okay to lock the screen

The important part is:

  • logged in = good
  • logged out / sitting at login window = bad for this setup
#

So locked is usually fine, logged out is not.

5. Keep it on power and prevent surprise sleep

  • plugged into power full time
  • disable aggressive energy-saving stuff
  • if it’s a ā€œheadlessā€ Mac mini, consider a dummy HDMI plug if display/wake behavior gets weird

6. Test it like a server

After you set this up, do a real test:

  • reboot the Mac
  • wait for auto-login
  • do not manually open anything
  • then check:
    openclaw gateway status --deep
    
#
  openclaw channels status --probe

My recommendation

For your current situation:

  • one dedicated macOS user
  • auto-login enabled
  • system sleep off
  • shared gateway on that user

If you eventually want true ā€œnobody logs in everā€ server behavior, I’d move the gateway to Linux/VPS instead.

If you want, I can give you the exact terminal commands to make the Mac mini stay awake like a little crustacean server.

silver tendon
#

whats a dummy hdmi

#

?

dusty juniperBOT
#

A dummy HDMI is a tiny plug you stick into the Mac’s HDMI port that pretends a monitor is connected.

People also call it:

  • HDMI emulator
  • headless display adapter
  • ghost display plug

Why people use it

On headless Macs, it can help with weird behavior around:

  • wake/sleep
  • display detection
  • remote access
  • apps/services that behave better when macOS thinks a screen exists
#

In your case

You probably don’t need it unless the Mac mini is running with no real monitor and gets weird after sleep/wake.

So it’s more of a stability hack for headless Macs, not an OpenClaw requirement.

#

Sorry, super simply:

A dummy HDMI is a little fake monitor plug.

You put it in the Mac mini’s HDMI port so the Mac thinks a screen is attached, even when there isn’t one.

People use it for headless Macs because sometimes macOS behaves more reliably that way after sleep/wake or remote access.

So:

  • Mac mini with real monitor attached → probably don’t need it
  • Mac mini with no monitor attached → sometimes helpful

If you want, I can stop talking about dummy HDMI and give you the exact always-on Mac mini settings instead.

silver tendon
#

I am getting an error from Heidi in Telegram: HTTP 401: authentication_error: invalid x-api-key

dusty juniperBOT
#

That’s actually a cleaner error than before.

It means Heidi is reaching the provider, but the key being used is invalid.

So this is no longer a gateway/routing problem, it’s just bad Anthropic key material.

Most likely cause

heidi is still using:

ANTHROPIC_API_KEY

and that value is either:

  • old
#
  • mistyped
  • revoked
  • or not the same as your new valid Heidi key

Fix

Edit:

nano ~/.openclaw/.env

Make sure Heidi’s lines both contain the same current valid key:

ANTHROPIC_API_KEY=YOUR_NEW_VALID_HEIDI_KEY
#
ANTHROPIC_API_KEY_heidi=YOUR_NEW_VALID_HEIDI_KEY

Then restart:

openclaw gateway restart
openclaw gateway status --deep

Important

Because Heidi is currently wired to the generic alias, updating only ANTHROPIC_API_KEY_heidi is not enough if ANTHROPIC_API_KEY still points at an old/bad key.

So for now, keep them identical.

#

If you want, after that I can help you do the clean final cleanup so Heidi uses ANTHROPIC_API_KEY_heidi directly and Sage uses ANTHROPIC_API_KEY_sage directly.