Skip to main content

Architecture

NanoClaw Pro uses a skill-based channel system where each communication channel (WhatsApp, Telegram, Slack, Discord, Gmail) is installed as a separate skill. The core ships with no channels built in — you choose which channels to install.

Self-Registration Pattern

Channels use a self-registration pattern at startup:
  1. Each channel skill adds implementation code to src/channels/
  2. The channel registers itself by calling registerChannel() at module load time
  3. At startup, NanoClaw loops through registered channels and connects those with valid credentials
  4. Channels without credentials are automatically skipped
// Example: How channels self-register
import { registerChannel, ChannelOpts } from './registry.js';

registerChannel('whatsapp', (opts: ChannelOpts) => {
  // Return null if credentials are missing
  if (!existsSync(authPath)) return null;
  return new WhatsAppChannel(opts);
});

Channel Interface

Every channel implements a standard interface:
interface Channel {
  name: string;
  connect(): Promise<void>;
  sendMessage(jid: string, text: string): Promise<void>;
  isConnected(): boolean;
  ownsJid(jid: string): boolean;
  disconnect(): Promise<void>;
  setTyping?(jid: string, isTyping: boolean): Promise<void>;
  syncGroups?(force: boolean): Promise<void>;
}

Available Channels

WhatsApp

Personal or dedicated number with QR/pairing code auth

Telegram

Bot-based with simple token authentication

Slack

Socket Mode integration (no public URL needed)

Discord

Bot integration with Gateway Intents

Gmail

Email integration with OAuth authentication

How Channels Work

Message Flow

  1. Incoming Message → Channel receives message from platform API
  2. Store in SQLite → Message is stored with metadata
  3. Polling Loop → Main loop polls for new messages every 2 seconds
  4. Routing Check → Router verifies chat is registered and checks trigger pattern
  5. Agent Invocation → Message is processed by Claude in an isolated container
  6. Response → Router sends response back through the owning channel

Multi-Channel Support

NanoClaw Pro can run multiple channels simultaneously:
  • Each channel auto-enables when its credentials are present
  • Channels operate independently and in parallel
  • Messages are routed to the correct channel based on JID prefix (whatsapp:, tg:, slack:, etc.)
  • No conflicts — you can have WhatsApp, Telegram, and Slack all running together

Adding a New Channel

To create a custom channel integration:
1

Create Channel Implementation

Add a new file to src/channels/<name>.ts that implements the Channel interface.
2

Self-Register

Call registerChannel(name, factory) at module load time:
registerChannel('mychannel', (opts: ChannelOpts) => {
  const credentials = readEnvFile(['MY_CHANNEL_TOKEN']);
  if (!credentials.MY_CHANNEL_TOKEN) return null;
  return new MyChannel(credentials.MY_CHANNEL_TOKEN, opts);
});
3

Add to Barrel Import

Add an import line to src/channels/index.ts:
import './mychannel.js';
4

Handle Messages

Call opts.onMessage() when messages arrive and opts.onChatMetadata() for chat discovery.
See existing channel implementations in .claude/skills/add-*/add/src/channels/ for reference patterns.

Channel Registry

The channel system is built on a factory registry in src/channels/registry.ts:
export type ChannelFactory = (opts: ChannelOpts) => Channel | null;

const registry = new Map<string, ChannelFactory>();

export function registerChannel(name: string, factory: ChannelFactory): void {
  registry.set(name, factory);
}

export function getChannelFactory(name: string): ChannelFactory | undefined {
  return registry.get(name);
}

export function getRegisteredChannelNames(): string[] {
  return [...registry.keys()];
}
Each factory receives ChannelOpts (callbacks for onMessage, onChatMetadata, and registeredGroups) and returns either a Channel instance or null if credentials are not configured.

Key Files

FilePurpose
src/channels/registry.tsChannel factory registry
src/channels/index.tsBarrel imports that trigger channel self-registration
src/types.tsChannel interface, ChannelOpts, message types
src/index.tsOrchestrator — instantiates channels, runs message loop
src/router.tsFinds owning channel for a JID, formats messages

Next Steps

Install WhatsApp

Set up WhatsApp with QR code or pairing code

Install Telegram

Create a Telegram bot and connect

Build docs developers (and LLMs) love