Channels/Config — Config Presence

Focus Deep-Dive

Auto-Detection of Configured Channels from Config, Env & OAuth

The config presence module scans three sources — config file entries, environment variable prefixes, and OAuth credential files — to build a list of potentially configured channel IDs. This enables the system to auto-discover which channels are ready to use without requiring explicit activation.

Config Scan Env Detection OAuth Check 13 Prefixes

📚 What is this & why does it matter?

Users configure channels in different ways: some edit openclaw.config.json, others set environment variables, and WhatsApp users go through an OAuth flow that stores credentials on disk. The presence detection system unifies all these methods into a single list of active channels.

💡 Real-world analogy

Think of a smart home hub that auto-discovers connected devices. It checks its config file for known devices, scans the network for Bluetooth signals (environment variables), and checks if any devices have paired certificates stored locally (OAuth credentials). The result is a unified list of “available devices” regardless of how they were set up.

Contents

Detection Sources

flowchart TD
    subgraph ConfigFile["Config File Scan"]
        CF["openclaw.config.json"]
        KEYS["Extract channel keys"]
        FILTER["Filter ignored keys
(defaults, modelByChannel)"]
        MEANINGFUL["hasMeaningfulChannelConfig()"]
    end
    subgraph EnvScan["Environment Scan"]
        ENV["process.env"]
        PREFIX["Match 13 prefixes"]
        NONBLANK["hasNonEmptyString()"]
    end
    subgraph OAuthScan["OAuth Credential Scan"]
        OAUTH["resolveOAuthDir()"]
        LEGACY["Check creds.json"]
        ACCOUNTS["Scan account dirs"]
    end
    subgraph Result["Final List"]
        MERGE["Set<string>"]
        LIST["configuredChannelIds[]"]
    end

    CF --> KEYS --> FILTER --> MEANINGFUL
    MEANINGFUL --> MERGE
    ENV --> PREFIX --> NONBLANK
    NONBLANK --> MERGE
    OAUTH --> LEGACY --> MERGE
    OAUTH --> ACCOUNTS --> MERGE
    MERGE --> LIST

Config File Scanning

Meaningful Config Detection

const IGNORED_CHANNEL_CONFIG_KEYS = new Set(["defaults", "modelByChannel"]);

export function hasMeaningfulChannelConfig(value: unknown): boolean {
  if (!isRecord(value)) return false;
  return Object.keys(value).some((key) => key !== "enabled");
}

A channel config is “meaningful” if it has any key beyond just enabled. Keys in the ignore set (defaults, modelByChannel) are skipped entirely as they apply globally.

Environment Variable Scanning

The system checks for 13 known prefixes. If any environment variable with a matching prefix has a non-empty value, the corresponding channel is considered configured:

const CHANNEL_ENV_PREFIXES = [
  ["BLUEBUBBLES_", "bluebubbles"],
  ["DISCORD_", "discord"],
  ["GOOGLECHAT_", "googlechat"],
  ["IRC_", "irc"],
  ["LINE_", "line"],
  ["MATRIX_", "matrix"],
  ["MSTEAMS_", "msteams"],
  ["SIGNAL_", "signal"],
  ["SLACK_", "slack"],
  ["TELEGRAM_", "telegram"],
  ["WHATSAPP_", "whatsapp"],
  ["ZALOUSER_", "zalouser"],
  ["ZALO_", "zalo"],
] as const;

WhatsApp OAuth Detection

WhatsApp has a special credential check that scans for creds.json files:

flowchart TD
    START["hasWhatsAppAuthState()"]
    START --> LEGACY{"Legacy creds.json
exists?"}
    LEGACY -->|Yes| FOUND["return true"]
    LEGACY -->|No| DEFAULT{"Default account
creds.json?"}
    DEFAULT -->|Yes| FOUND
    DEFAULT -->|No| SCAN["Scan account dirs"]
    SCAN --> ANY{"Any dir has
creds.json?"}
    ANY -->|Yes| FOUND
    ANY -->|No| NOTFOUND["return false"]

Main Function

export function listPotentialConfiguredChannelIds(
  cfg: OpenClawConfig,
  env: NodeJS.ProcessEnv = process.env,
): string[]

Returns a deduplicated array of channel IDs that appear to be configured via any detection source.

Edge Cases

ScenarioBehavior
Config has { telegram: { enabled: true } }Not meaningful (only enabled key)
Config has { telegram: { enabled: true, token: "..." } }Meaningful (has token)
TELEGRAM_BOT_TOKEN="" in envNot detected (empty string)
TELEGRAM_BOT_TOKEN="abc" in envDetected as telegram
WhatsApp OAuth dir missingSilently returns false (try/catch)