Channels/Config — Config Presence
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
| Scenario | Behavior |
|---|---|
Config has { telegram: { enabled: true } } | Not meaningful (only enabled key) |
Config has { telegram: { enabled: true, token: "..." } } | Meaningful (has token) |
TELEGRAM_BOT_TOKEN="" in env | Not detected (empty string) |
TELEGRAM_BOT_TOKEN="abc" in env | Detected as telegram |
| WhatsApp OAuth dir missing | Silently returns false (try/catch) |