Files
moltbot/docs/cli/channels.md
Sliverp 2db4d779db Feat/channels list show all and drop auth (#78456)
* feat(channels list): drop auth providers, add --all, surface installed/configured/enabled

`openclaw channels list` used to conflate two very different surfaces: chat
channels and OAuth/API-key auth providers for model routing. The auth
section was the first and most visible block in the output even for
operators who only cared about chat channels, and its JSON `auth` key
leaked model-provider identities into a command whose top-level help
describes it as channel management. Worse, the command silently hid
every channel that had no configured account, so users could not tell
from `channels list` which bundled or catalog channels were even
available to configure.

Split the surface cleanly around channels only:

1. Remove the `Auth providers (OAuth + API keys)` text section and the
   `auth` field from the JSON payload. Model-provider auth profiles
   remain reachable via `openclaw models auth list`, which is where
   they conceptually belong.

2. Add a `--all` flag to surface every channel an operator could
   configure: bundled channel plugins that have no account yet and
   catalog-listed external channels whose plugin package is not even
   installed on disk. Without `--all` the output still shows only
   channels with at least one configured account, matching the
   previous default behavior so existing scripts keep working. The
   "empty" default path now prints a hint pointing at `--all`.

3. Render three explicit status tags per row — `installed` /
   `not installed`, `configured` / `not configured`, `enabled` /
   `disabled` — so bundled-but-unconfigured plugins and installable
   catalog channels both render with accurate state instead of being
   invisible. Installed state comes from the same
   `isCatalogChannelInstalled` probe the setup flow uses, so it stays
   consistent with `openclaw onboard` and `channels add`.

4. JSON payload now carries an `origin` per channel (`configured`,
   `available`, `installable`) alongside `installed: boolean`, which
   lets tooling distinguish "user has set this up" from "user could
   set this up" without second-guessing.

Register `--all` on both the Commander CLI and the fast-path route-arg
parser so the flag works in both code paths, update the one routes
test that asserted the parsed args shape, and rewrite the old auth
profiles surface test as a broader `channels list` behavior spec
covering default output, `--all` output, JSON shape (no `auth`), and
the bundled-unconfigured + catalog-not-installed cases.

Docs: call out that `channels list` is chat-channel only now, mention
`--all`, and point at `openclaw models auth list` for what used to be
the auth providers block.

* fix(channels list): surface catalog channels that are installed on disk but not yet configured

The previous `--all` path filtered catalog entries with
`!installedByChannelId.get(entry.id)` before rendering them as
catalog-only rows. That assumed "catalog entry not already rendered
as a plugin row" implied "not installed", which is wrong: an external
channel plugin package can be installed on disk (`isCatalogChannelInstalled`
returns true) while the read-only channel loader still declines to
surface a plugin object for it — the loader only activates channels
that appear in user config, so a plugin that is installed but never
configured ended up in neither bucket and silently dropped out of
`channels list --all`.

Operator-facing symptom: `pnpm openclaw channels list --all` omitted
WeCom (and any other catalog channel in the same state) even though
its npm package was present on disk and its catalog entry existed,
while rendering every other uninstalled catalog channel as expected.

Fix: drop the `installed` filter from `catalogOnlyLines` so every
catalog entry that is not already represented by a plugin row is
rendered, and let the row itself carry the real installed/not-installed
tag. Two renderings now land in the catalog-only bucket:

- Not installed — rendered as `not installed, not configured, disabled`
  (installable row).
- Installed but unconfigured — rendered as `installed, not configured,
  disabled` (ready-to-configure row). The JSON `origin` for this case
  becomes `available`, matching the existing origin for bundled
  plugins that are installed but unconfigured, so downstream tooling
  sees a consistent "you could configure this now" signal regardless
  of whether the plugin came from bundled sources or from the catalog.

Regression test added under the WeCom scenario.

* refactor(channels list): drop model-provider usage surface, make the command channel-only

`openclaw channels list` used to append a model-provider usage/quota
snapshot (Anthropic, OpenRouter, OpenAI Codex, Gemini, Zai, Minimax,
etc.) under every invocation. That was a leftover from the days when
`channels list` was the only "operator overview" command; the same
data is now owned by `openclaw status` (overview) and
`openclaw models list` (per-provider), which handle timeouts, probe
errors, and output shape consistently for that class of data. Keeping
the snapshot wired into `channels list` meant:

- Every default invocation made one blocking `loadProviderUsageSummary`
  call that fanned out to every configured provider billing/auth
  endpoint, adding seconds of latency to a command that otherwise
  just reads local config.
- `channels list --no-usage` was the escape hatch, but the flag was
  itself a self-sustaining bug: it only existed because the command
  did work that did not belong to it.
- JSON consumers had an optional `usage` key whose shape was owned by
  the provider-usage module, not by the channels module, so any
  change upstream silently reshaped `channels list --json` output.
- Failed provider fetches printed provider-side errors on a command
  that never advertised itself as a provider-health surface.

Scope this PR tightens, in one move:

1. Remove `loadProviderUsageSummary` / `formatUsageReportLines` usage
   from `src/commands/channels/list.ts`. The command now only reads
   config, the read-only channel plugin registry, and the trusted
   catalog — matching its name.
2. Drop `--no-usage` from the Commander CLI registration, from the
   fast-path route-arg parser (`parseChannelsListRouteArgs`), and
   from `ChannelsListOptions`. The flag is gone, not silently
   ignored, so anyone depending on it will get a clear
   "unknown option" from Commander and from the fast-path router.
3. Drop the `usage` key from `channels list --json` payloads. Shape
   of the `chat` record and the new `origin` / `installed` tags
   introduced earlier in this branch are unchanged.
4. Print a single-line migration pointer at the bottom of the text
   output so operators who expected usage know where it went
   (`openclaw status` / `openclaw models list`). This replaces what
   used to be a block of fetched provider data with one static line,
   so it cannot fail or add latency.
5. Update `docs/cli/channels.md` troubleshooting to remove the
   `--no-usage` mention and point at the two new entry points.
6. Update tests: drop the `loadProviderUsageSummary` mock and the
   `"keeps JSON output valid when usage loading fails"` case,
   replace it with a positive assertion that `payload.usage` is
   undefined (locking in the narrower contract), and remove `usage`
   from every `channelsListCommand(...)` call to match the narrowed
   `ChannelsListOptions` type. The route-args test is updated to
   expect `{ json, all }` without `usage`.

No other command changes. `openclaw status` and `openclaw models list`
already render usage; they are the documented replacements.

Breaking-ish surface:

- CLI: `channels list --no-usage` now fails with "unknown option".
  Tooling should drop the flag — there is nothing left to opt out of.
- JSON: `channels list --json` no longer carries a top-level `usage`
  key. Tooling that read it must migrate to
  `openclaw status --json` or `openclaw models list --json`.

* fix(channels.list.test): widen isCatalogChannelInstalled mock signature to accept entry param

CI typecheck failed because the mock was declared with a zero-arg signature while one test called mockImplementation(({ entry }) => …). Tighten the generic so vitest's mock accepts the same params the real helper does.

* changelog: record channels list channel-only rework (#78456)
2026-05-07 11:28:52 +01:00

8.8 KiB

summary, read_when, title
summary read_when title
CLI reference for `openclaw channels` (accounts, status, login/logout, logs)
You want to add/remove channel accounts (WhatsApp/Telegram/Discord/Google Chat/Slack/Mattermost (plugin)/Signal/iMessage/Matrix)
You want to check channel status or tail channel logs
Channels

openclaw channels

Manage chat channel accounts and their runtime status on the Gateway.

Related docs:

Common commands

openclaw channels list
openclaw channels list --all
openclaw channels status
openclaw channels capabilities
openclaw channels capabilities --channel discord --target channel:123
openclaw channels capabilities --channel discord --target channel:<voice-channel-id>
openclaw channels resolve --channel slack "#general" "@jane"
openclaw channels logs --channel all

channels list shows chat channels only: configured accounts by default, with installed, configured, and enabled status tags per account. Pass --all to also surface bundled channels that have no configured account yet and installable catalog channels that are not yet on disk. Auth providers (OAuth + API keys) and model-provider usage/quota snapshots are no longer printed here; use openclaw models auth list for provider auth profiles and openclaw status or openclaw models list for usage.

Status / capabilities / resolve / logs

  • channels status: --probe, --timeout <ms>, --json
  • channels capabilities: --channel <name>, --account <id> (only with --channel), --target <dest>, --timeout <ms>, --json
  • channels resolve: <entries...>, --channel <name>, --account <id>, --kind <auto|user|group>, --json
  • channels logs: --channel <name|all>, --lines <n>, --json

channels status --probe is the live path: on a reachable gateway it runs per-account probeAccount and optional auditAccount checks, so output can include transport state plus probe results such as works, probe failed, audit ok, or audit failed. If the gateway is unreachable, channels status falls back to config-only summaries instead of live probe output.

Do not use openclaw sessions, Gateway sessions.list, or the agent sessions_list tool as a channel socket-health signal. Those surfaces report stored conversation rows, not provider runtime state. After a Discord provider restart, a connected but quiet account may be healthy while no Discord session row appears until the next inbound or outbound conversation event.

Add / remove accounts

openclaw channels add --channel telegram --token <bot-token>
openclaw channels add --channel nostr --private-key "$NOSTR_PRIVATE_KEY"
openclaw channels remove --channel telegram --delete
`openclaw channels add --help` shows per-channel flags (token, private key, app token, signal-cli paths, etc).

channels remove only operates on installed/configured channel plugins. Use channels add first for installable catalog channels. For runtime-backed channel plugins, channels remove also asks the running Gateway to stop the selected account before it updates config, so disabling or deleting an account does not leave the old listener active until restart.

Common non-interactive add surfaces include:

  • bot-token channels: --token, --bot-token, --app-token, --token-file
  • Signal/iMessage transport fields: --signal-number, --cli-path, --http-url, --http-host, --http-port, --db-path, --service, --region
  • Google Chat fields: --webhook-path, --webhook-url, --audience-type, --audience
  • Matrix fields: --homeserver, --user-id, --access-token, --password, --device-name, --initial-sync-limit
  • Nostr fields: --private-key, --relay-urls
  • Tlon fields: --ship, --url, --code, --group-channels, --dm-allowlist, --auto-discover-channels
  • --use-env for default-account env-backed auth where supported

If a channel plugin needs to be installed during a flag-driven add command, OpenClaw uses the channel's default install source without opening the interactive plugin install prompt.

When you run openclaw channels add without flags, the interactive wizard can prompt:

  • account ids per selected channel
  • optional display names for those accounts
  • Bind configured channel accounts to agents now?

If you confirm bind now, the wizard asks which agent should own each configured channel account and writes account-scoped routing bindings.

You can also manage the same routing rules later with openclaw agents bindings, openclaw agents bind, and openclaw agents unbind (see agents).

When you add a non-default account to a channel that is still using single-account top-level settings, OpenClaw promotes account-scoped top-level values into the channel's account map before writing the new account. Most channels land those values in channels.<channel>.accounts.default, but bundled channels can preserve an existing matching promoted account instead. Matrix is the current example: if one named account already exists, or defaultAccount points at an existing named account, promotion preserves that account instead of creating a new accounts.default.

Routing behavior stays consistent:

  • Existing channel-only bindings (no accountId) continue to match the default account.
  • channels add does not auto-create or rewrite bindings in non-interactive mode.
  • Interactive setup can optionally add account-scoped bindings.

If your config was already in a mixed state (named accounts present and top-level single-account values still set), run openclaw doctor --fix to move account-scoped values into the promoted account chosen for that channel. Most channels promote into accounts.default; Matrix can preserve an existing named/default target instead.

Login and logout (interactive)

openclaw channels login --channel whatsapp
openclaw channels logout --channel whatsapp
  • channels login supports --verbose.
  • channels login and logout can infer the channel when only one supported login target is configured.
  • channels logout prefers the live Gateway path when reachable, so logout stops any active listener before clearing channel auth state. If a local Gateway is not reachable, it falls back to local auth cleanup.
  • Run channels login from a terminal on the gateway host. Agent exec blocks this interactive login flow; channel-native agent login tools, such as whatsapp_login, should be used from chat when available.

Troubleshooting

  • Run openclaw status --deep for a broad probe.
  • Use openclaw doctor for guided fixes.
  • openclaw channels list no longer prints model provider usage/quota snapshots. For those, use openclaw status (overview) or openclaw models list (per-provider).
  • openclaw channels status falls back to config-only summaries when the gateway is unreachable. If a supported channel credential is configured via SecretRef but unavailable in the current command path, it reports that account as configured with degraded notes instead of showing it as not configured.

Capabilities probe

Fetch provider capability hints (intents/scopes where available) plus static feature support:

openclaw channels capabilities
openclaw channels capabilities --channel discord --target channel:123

Notes:

  • --channel is optional; omit it to list every channel (including extensions).
  • --account is only valid with --channel.
  • --target accepts channel:<id> or a raw numeric channel id and only applies to Discord. For Discord voice channels, the permission check flags missing ViewChannel, Connect, Speak, SendMessages, and ReadMessageHistory.
  • Probes are provider-specific: Discord intents + optional channel permissions; Slack bot + user scopes; Telegram bot flags + webhook; Signal daemon version; Microsoft Teams app token + Graph roles/scopes (annotated where known). Channels without probes report Probe: unavailable.

Resolve names to IDs

Resolve channel/user names to IDs using the provider directory:

openclaw channels resolve --channel slack "#general" "@jane"
openclaw channels resolve --channel discord "My Server/#support" "@someone"
openclaw channels resolve --channel matrix "Project Room"

Notes:

  • Use --kind user|group|auto to force the target type.
  • Resolution prefers active matches when multiple entries share the same name.
  • channels resolve is read-only. If a selected account is configured via SecretRef but that credential is unavailable in the current command path, the command returns degraded unresolved results with notes instead of aborting the entire run.
  • channels resolve does not install channel plugins. Use channels add --channel <name> before resolving names for an installable catalog channel.