Clawq communicates with the outside world through channels --- modular communication backends that implement a common interface. Several integrations ship today, including chat channels such as Telegram, Discord, and Slack plus webhook-driven integrations such as GitHub and MS Teams.

Interrupting a running turn

In chat channels, prefix a message with ! to interrupt the current turn for that same session and then send the rest as a normal message. For example, !stop interrupts the in-flight turn and sends stop next. A bare ! becomes [interrupted].

If a shell_exec tool call is running when interrupted, the process is moved to a background shell instead of being killed. Use bg_shell_status, bg_shell_wait, and bg_shell_result tools to track it.

The Channel.S Module Type

Every channel implements the Channel.S OCaml module signature:

module type S = sig
  val name : string
  val start :
    config:Runtime_config.t ->
    session_manager:Session.t ->
    unit Lwt.t
end

The contract is intentionally narrow. A channel receives the global runtime configuration and a session manager, then runs as a long-lived Lwt promise. The daemon supervisor (daemon.ml) starts all enabled channels in parallel and monitors them for failures.

Channel Overview

ChannelProtocolTransportStatus
TelegramBot API (long polling)HTTPSImplemented
DiscordGateway v10 (WebSocket)WSS + RESTImplemented
SlackSocket ModeWSSImplemented
Slack (Events API)HTTP pushHTTPSImplemented
GitHubWebhooks + API repliesHTTPSImplemented
WebHTTP gatewayRESTImplemented
CLIstdin/stdoutLocalImplemented
MS TeamsBot Framework webhookHTTPSImplemented
IRCIRC protocol (RFC 2812)TCP/TLSImplemented
MatrixClient-Server APIHTTPSImplemented
MattermostWebSocket + RESTWSS + RESTImplemented
EmailIMAP/SMTPTCP/TLSImplemented
DingTalkStream ModeHTTPSImplemented
Lark/FeishuBot Event CallbackHTTPSImplemented
LINEMessaging APIHTTPSImplemented
NostrNIP-01 relay + NIP-04 DMsWSSImplemented
OneBotOneBot v11WS + HTTPImplemented
WhatsAppCloud APIHTTPSImplemented
iMessageAppleScript + SQLiteLocalImplemented
Signalsignal-cli RESTHTTPSImplemented

Telegram

Telegram is the fastest channel to set up. Clawq connects via the Telegram Bot API using long polling --- no webhooks, no public IP required.

Configuration

{
  "channels": {
    "telegram": {
      "accounts": {
        "main": {
          "bot_token": "123456:ABC-DEF...",
          "allow_from": ["*"]
        }
      }
    }
  }
}

Or via the CLI:

clawq config set channels.telegram.accounts.main.bot_token "123456:ABC-DEF..."
clawq config set channels.telegram.accounts.main.allow_from '["*"]'

Setup

The fastest path is the interactive wizard:

clawq setup telegram

Or manually:

  1. Create a bot with @BotFather on Telegram.
  2. Copy the bot token into your config.
  3. Start the daemon with clawq agent.
  4. Send your bot a message to verify the connection.

Key Features

  • Long polling with configurable timeout (default 30s) --- no inbound firewall rules needed.
  • Rate limiting via the shared Rate_limiter token bucket.
  • Media support --- voice messages, photos, and documents are received and routed to the agent. Voice messages are automatically transcribed when an STT provider is configured: a “Transcribing…” progress message is sent, updated to “Transcribing… Done!” on completion, and the transcribed text is forwarded to the agent as [Voice]: <text>. Validation enforces limits (under 25 MB, under 1 hour) and skips likely music files.
  • Token redaction --- bot tokens are automatically redacted in log output via the redact_token helper.
  • Silent notifications --- messages are sent with notification disabled by default, so users are not constantly pinged by bot responses.
  • Thinking format --- when show_thinking is enabled, thinking blocks are rendered as blockquote + italic (> _thinking..._) for a clean Telegram display.

How It Works

telegram.ml calls getUpdates in a loop, parsing each update into an internal update record with chat ID, user ID, text, and optional media fields. Each update is dispatched to the session manager, which routes it to the appropriate agent session. Responses are sent back via sendMessage.

Discord

Clawq connects to Discord using the Gateway v10 WebSocket protocol for receiving events and the REST API for sending messages. The implementation includes full connection lifecycle management: Hello, Identify, Heartbeat, Resume, and Reconnect.

Configuration

{
  "channels": {
    "discord": {
      "enabled": true,
      "bot_token": "MTIzNDU2Nzg5...",
      "allow_guilds": ["*"],
      "allow_users": ["*"]
    }
  }
}

Setup

The fastest path is the interactive wizard:

clawq setup discord

The wizard walks through setting the bot token, allowed guilds/users, and gateway intents. Or manually:

  1. Create a Discord application at the Discord Developer Portal.
  2. Add a Bot to the application and copy its token.
  3. Invite the bot to your server with the applications.commands and bot scopes, plus Send Messages and Read Message History permissions.
  4. Configure the token and start clawq agent.

Key Features

  • WebSocket gateway with automatic heartbeat, session resume, and reconnect on disconnect.
  • Group chat filtering --- in guild channels, the bot only responds when explicitly @mentioned, addressed by name (e.g. “clawq, …”), or sent a slash command. DMs are always processed.
  • Guild and user allowlists --- restrict which servers and users can interact with the bot.
  • REST rate limit tracking --- server-driven rate limits are parsed from response headers (X-RateLimit-Remaining, X-RateLimit-Reset) with per-route bucket tracking and global rate limit handling.
  • Message chunking --- responses longer than 2000 characters are automatically split into multiple messages.
  • Voice transcription --- audio attachments (.ogg, .opus, .webm, etc.) are automatically transcribed via the configured STT provider. A “Transcribing…” progress message is sent and updated to “Transcribing… Done!” on completion. Music files are skipped unless the filename contains “voice” or “recording”. Size limit: 25 MB.

Architecture

The Discord channel is split across two modules:

  • discord_gateway.ml --- the Gateway protocol state machine. Manages the WebSocket connection, heartbeat loop, sequence tracking, identify/resume handshakes, and dispatch event routing.
  • discord.ml --- the channel implementation. Handles message parsing, access control, REST API calls (with rate limit buckets), and session routing.

Both modules use the shared ws_client.ml WebSocket client, which provides TLS connections with proper certificate verification via ca-certs.

Slack

Clawq supports two Slack integration modes: Socket Mode (recommended) and the Events API (requires a public endpoint).

Socket Mode uses a WebSocket connection initiated by the bot, so no public URL is needed --- similar to Telegram’s long polling approach.

{
  "channels": {
    "slack": {
      "enabled": true,
      "mode": "socket",
      "bot_token": "xoxb-...",
      "app_token": "xapp-...",
      "allow_channels": ["*"],
      "allow_users": ["*"]
    }
  }
}

Setup:

Use the interactive wizard (clawq setup slack) or follow the manual steps:

  1. Create a Slack app at api.slack.com/apps.
  2. Enable Socket Mode in the app settings.
  3. Generate an App-Level Token (xapp-...) with the connections:write scope.
  4. Install the app to your workspace and copy the Bot Token (xoxb-...).
  5. Subscribe to message.channels and message.im events.
  6. Configure both tokens and start clawq agent.

slack_socket.ml calls apps.connections.open to obtain a WSS URL, then connects and listens for envelope-wrapped events. Each envelope is acknowledged by sending back the envelope_id, and the contained event is forwarded to the standard Slack event parser.

Events API Mode

The Events API mode uses HTTP push --- Slack sends events to your gateway’s /slack/events endpoint.

{
  "channels": {
    "slack": {
      "enabled": true,
      "mode": "events_api",
      "bot_token": "xoxb-...",
      "signing_secret": "abc123...",
      "allow_channels": ["*"],
      "allow_users": ["*"]
    }
  }
}

This mode requires a publicly reachable endpoint. The http_server.ml gateway handles the /slack/events route, and slack.ml verifies every request using HMAC-SHA256 signature verification with the signing secret and a 5-minute timestamp window.

Key Features (Both Modes)

  • Channel and user allowlists --- control which Slack channels and users can interact with the bot.
  • HMAC signature verification (Events API) --- every incoming request is cryptographically verified.
  • Envelope acknowledgement (Socket Mode) --- ensures Slack does not redeliver events.
  • Voice transcription --- audio file attachments are automatically transcribed via the configured STT provider with progress messages. Music files are skipped; size limit: 25 MB.

GitHub

GitHub uses per-repo webhook endpoints on the clawq gateway. It supports both the original /clawq comment flow for pull requests and a generalized hook system for broader automation such as failed CI investigation.

Configuration

{
  "channels": {
    "github": {
      "auth": {
        "type": "pat",
        "token": "ghp_..."
      },
      "repos": [
        {
          "name": "acme/backend",
          "webhook_secret": "super-secret-value",
          "webhook_path": "/github/webhook/backend",
          "allow_users": ["octocat"],
          "react_to": ["issue_comment", "pull_request", "workflow_job"],
          "include_pr_files": true
        }
      ]
    }
  }
}

Hook Files

Generalized automations are loaded from ~/.clawq/workspace/gh-hooks/.

---
name: investigate-ci-failure
repo: acme/backend
event: workflow_job
match:
  status: completed
  conclusion: failure
---
Investigate the failed CI job for {{repo}} on {{branch}}.
Payload snapshot: {{payload_path}}

Verified webhook deliveries are snapshotted under ~/.clawq/workspace/tmp/github-deliveries/, and old snapshots are cleaned up opportunistically when new deliveries arrive.

Setup

Use the interactive wizard (clawq setup github) or follow the manual steps:

  1. Create a GitHub Personal Access Token and store it under channels.github.auth.token.
  2. Configure one repo entry per GitHub repository with a unique webhook_path, a webhook_secret, and the canonical owner/repo in name.
  3. In GitHub, create a webhook pointing at your public clawq URL plus that path, for example https://your-host/github/webhook/backend.
  4. Subscribe the webhook to the events you want clawq to process.
  5. Add any hook files to ~/.clawq/workspace/gh-hooks/ and start clawq agent.

Session Keys

Each GitHub thread maps to a stable clawq session key so that follow-up /clawq interactions resume the same conversation context:

Thread surfaceSession key format
PR event or comment on a PRgithub:{owner}/{repo}:pr:{number}
Issue comment (non-PR)github:{owner}/{repo}:issue:{number}
PR review commentgithub:{owner}/{repo}:pr:{number}

Review comments on the same PR share a session with the PR timeline, so the agent has full PR context regardless of which comment surface invoked it. Replies are routed back to the correct GitHub API surface: issue/PR comments use the Issues API, while review comments reply in-thread via the Pull Reviews API.

Comment/Reply Lifecycle

When a /clawq command is detected in a GitHub comment, clawq follows a defined lifecycle to provide clear feedback:

  1. Acknowledge --- an “eyes” reaction is added to the triggering comment so the user knows the command was received.
  2. Placeholder --- a placeholder comment is posted with a spinner (> /clawq ...\n\n⏳ Working on it...) for issue and PR comments. Review comments skip this step since replies are threaded differently.
  3. Process --- the webhook returns HTTP 200 immediately; the agent turn runs asynchronously via Lwt.async.
  4. Finalize --- the placeholder comment is edited with the final response (or a new comment/reply is posted if no placeholder exists). All bot replies include a <!-- clawq-reply --> marker.
  5. Notify --- a channel notifier is registered for the session so that autonomous or deferred agent responses are posted to the same GitHub thread.

Bot self-loop protection: incoming comments containing the <!-- clawq-reply --> marker are silently ignored, preventing the bot from reacting to its own replies.

Delivery deduplication: the X-GitHub-Delivery header is tracked in an in-memory LRU set (capacity 500). Duplicate deliveries are rejected before any processing occurs.

Key Features

  • Signature verification --- deliveries must pass GitHub HMAC validation with the configured webhook_secret.
  • Repo identity enforcement --- the payload repo must match the configured channels.github.repos[].name for that webhook path.
  • Unique webhook paths --- duplicate webhook_path bindings are rejected as ambiguous.
  • Stable sessions --- repeated /clawq interactions on the same issue or PR resume the same session context (see Session Keys above).
  • Async processing --- the webhook returns HTTP 200 immediately; agent processing happens asynchronously with acknowledgment, placeholder, and edit lifecycle (see Comment/Reply Lifecycle above).
  • Delivery deduplication --- duplicate webhook deliveries are suppressed via an in-memory LRU set keyed by the X-GitHub-Delivery header.
  • Bot self-loop protection --- replies include an HTML comment marker; incoming comments with that marker are silently ignored.
  • File-backed hooks --- non-comment events such as workflow_job can route prompts into sessions using repo-scoped markdown hook files.
  • Trust gating --- allow_users gates arbitrary-content events such as push; only a small system-event subset (workflow_job, workflow_run, check_run, check_suite, ping) bypasses that allowlist.

MS Teams

MS Teams uses the Microsoft Bot Framework webhook protocol. Teams POSTs activity JSON to your configured webhook path; clawq replies via the Bot Framework REST API using OAuth 2.0 bearer tokens.

What you'll need

  • An Azure account with permission to register apps and create Bot resources
  • A publicly reachable HTTPS URL for your clawq instance (use a tunnel — see below)
  • About 20–30 minutes for Azure portal setup

How It Works

  1. Teams sends a POST to your webhook path with a JSON Activity payload.
  2. clawq responds 202 Accepted immediately.
  3. Asynchronously, clawq verifies JWT claims, extracts the message text (stripping <at> mention tags), looks up or creates a session keyed as teams:<team_id>:<conversation_id>, and runs the agent turn. Sessions are shared per-channel; sender identity is passed via context headers.
  4. The reply is posted back via {serviceUrl}/v3/conversations/{conversation_id}/activities/{activity_id}. In group chats, the bot only responds when explicitly @mentioned, addressed by name, or sent a slash command. When it does reply, the sender is @mentioned so they receive a notification.

Configuration

{
  "channels": {
    "teams": {
      "app_id": "your-azure-app-id",
      "app_secret": "your-azure-client-secret",
      "tenant_id": "your-azure-tenant-id",
      "webhook_path": "/teams/webhook",
      "allow_teams": ["*"],
      "allow_users": ["*"]
    }
  }
}

Setup

Use the interactive wizard (clawq setup teams) to configure the clawq-side credentials, then follow the Azure setup below.

Get your public HTTPS URL first

You need a publicly reachable HTTPS URL before entering anything into Azure. HTTP will be rejected. Start here before opening the Azure portal.

Step 0 — Get your public URL

Start clawq with a tunnel to obtain a stable HTTPS URL:

clawq config set tunnel.enabled true
clawq config set tunnel.provider cloudflare   # or ngrok, tailscale
clawq agent

Note the tunnel URL printed at startup (e.g. https://abc123.trycloudflare.com). Your Messaging Endpoint will be https://abc123.trycloudflare.com/teams/webhook.

Step 1 — Register an Azure AD application

  1. Open Azure App registrationsNew registration.
  2. Give it a name (e.g. “clawq-bot”). Leave redirect URIs blank. Register.
  3. Note the Application (client) ID — this is your app_id.
  4. Note the Directory (tenant) ID — this is your tenant_id.
  5. Go to Certificates & secretsNew client secret. Copy the secret value immediately — it is only shown once. This is your app_secret.

Client secret expiry

Azure client secrets expire after 12–24 months by default. Set a calendar reminder to rotate it before expiry. When it expires, clawq will log Teams: token fetch failed and outbound replies will stop.

Step 2 — Create an Azure Bot

  1. Open Azure Bot ServiceCreate.
  2. Set Messaging endpoint to your URL from Step 0: https://your-tunnel-url/teams/webhook
  3. Under Microsoft App ID, select Use existing app registration and enter the Application ID from Step 1.
  4. Finish creation. In the Bot resource, open the Channels blade and add Microsoft Teams.

Step 3 — Create a Teams App Manifest

This step is required. Without it, the bot is registered in Azure but completely invisible inside Teams — you will not be able to find or message it.

  1. Open the Teams Developer PortalAppsNew app.
  2. Fill in the App name, description, and developer info.
  3. Under App featuresBot, click Enter a bot ID and enter your Application (client) ID from Step 1.
  4. Under Scope, check Personal and/or Team depending on use.
  5. Go to PublishPublish to your org (or sideload for testing).
  6. If publishing to your org, an admin must approve the app in the Teams Admin Center.
  7. In Teams, go to Apps → search for your bot by name → Add. When installing to an org, searching by name is the easiest way to find your bot.

Step 4 — Configure clawq

clawq config set channels.teams.app_id "your-application-id"
clawq config set channels.teams.app_secret "your-client-secret"
clawq config set channels.teams.tenant_id "your-tenant-id"

Step 5 — Verify and start

clawq channel test teams   # verifies OAuth credentials against Azure AD
clawq agent
clawq channel              # confirm teams shows as configured

Common Mistakes

  • Forgot the Teams App Manifest (Step 3): The bot will be registered in Azure but invisible in Teams. You cannot message a bot that has no Teams app.
  • Using http:// instead of https://: Azure rejects non-HTTPS endpoints. Always use https:// for the Messaging Endpoint.
  • Entered the Messaging Endpoint before having a tunnel URL: Go back into the Azure Bot resource and update the Messaging Endpoint after you have your real URL.
  • Copied app_id instead of the client secret into app_secret: The client secret is the value shown under Certificates & secrets, not the Application ID.
  • Client secret expired: Secrets expire. Rotate via Azure Portal → Certificates & secrets → New client secret.

Key Features

  • JWT claim validation --- inbound requests carry a Bot Framework JWT; clawq verifies aud, iss, exp, and nbf claims. RS256 signature verification is not performed (known limitation).
  • OAuth 2.0 outbound auth --- clawq fetches a client_credentials bearer token from Azure AD, cached with a 60 s safety margin before expiry.
  • Message splitting --- replies longer than 28,672 characters are split at whitespace boundaries and sent as multiple activities.
  • Async processing --- the webhook returns HTTP 202 immediately; agent processing happens asynchronously.
  • Team and user allowlists --- restrict which Teams and users can interact with the bot via allow_teams and allow_users.
  • Activity deduplication --- duplicate Bot Framework deliveries are suppressed via an in-memory LRU set.
  • Group chat filtering --- in group conversations, the bot only responds when explicitly @mentioned, addressed by name (e.g. “clawq, …”), or sent a slash command. 1:1 chats always receive a response.
  • @mention in group chats --- when the bot does respond in group conversations, it automatically @mentions the sender using Bot Framework mention entities, ensuring they receive a notification.
  • Native markdown tables --- slash commands like /status, /costs, and /usage render with native markdown tables in Teams for clean formatting.
  • Voice transcription --- audio attachments are automatically transcribed via the configured STT provider with progress messages. Music files are skipped; size limit: 25 MB.
  • Interactive menus --- menu subcommands (/model menu, /thinking menu, /config menu, /skills, /costs menu, /bg menu) render as Adaptive Cards with clickable buttons on Teams. On other channels they render as text-formatted lists. Paginated menus show 9 items per page with nav buttons.
  • File uploads --- /debug_dump_chat sends session state as a JSON file. In personal chats with file_consent_cards enabled, a file consent card is sent alongside a temporary download link as a fallback. In group chats (or when consent cards are disabled), only the download link is used (requires tunnel.url). If no public URL is configured, falls back to sending the first 25 KB as truncated text.
  • Notification suppression --- tool status messages (thinking indicators, tool call updates) do not trigger Teams notifications; only final replies do.

See the Microsoft Teams bot documentation and the Bot Framework authentication guide for full details.

Web Gateway

The HTTP gateway (http_server.ml) exposes a REST API and serves the embedded web chat UI. It is always active when the daemon runs and also handles the Slack Events API integration.

Endpoints

POST /chat

Send a message to the agent.

Body:    { "message": "...", "session_key": "..." }
Headers: Authorization: Bearer <auth_token>
      OR x-api-key: <auth_token>

When gateway.require_pairing is enabled, browser clients must first pair via /pair. API clients with a valid auth_token bypass pairing entirely.

GET /chat/stream

SSE streaming endpoint. Emits events as the agent processes a turn:

EventPayload
messageText chunk from the model
thinkingModel reasoning block (when thinking is enabled)
tool_callTool invocation update
doneTurn complete
errorError during the turn

GET /health

Health check. Returns {"status":"ok"} when the daemon is running.

GET /commands

Returns slash command metadata used for autocomplete in the web UI.

GET /ui-version

Returns the current embedded UI version hash. The web UI polls this to detect when a reload is needed after a daemon update.

POST /pair

Browser pairing endpoint. Takes a 6-digit OTP code (shown by clawq otp-show) and returns a session token on success.

Body:    { "code": "123456" }
Returns: { "token": "..." }

GET /

Serves the embedded web chat UI.

Auth vs Pairing

There are two ways to authenticate with the gateway:

  • auth_token — a static bearer token configured in gateway.auth_token. Suitable for programmatic API access (scripts, integrations). Bypasses pairing.
  • Browser pairing — used by the web UI. The user obtains a 6-digit OTP via clawq otp-show or a Telegram /pair command, submits it to POST /pair, and receives a session token valid for the configured pairing TTL.

Set gateway.require_pairing = true to require browser clients to pair before chatting. This does not affect clients that provide a valid auth_token.

Matrix

Clawq connects to Matrix homeservers via the Client-Server API, using long-polling /sync to receive events and the room send endpoint for replies.

Configuration

{
  "channels": {
    "matrix": {
      "homeserver_url": "https://matrix.example.com",
      "access_token": "syt_...",
      "user_id": "@clawq:example.com",
      "allow_rooms": ["*"],
      "allow_users": ["*"]
    }
  }
}

Setup

clawq setup matrix

Or manually: create a Matrix account for your bot, generate an access token, and configure the homeserver URL and credentials.

Key Features

  • Sync-based polling --- uses the /sync endpoint with a since token for incremental event retrieval.
  • Room and user allowlists --- restrict which rooms and users can interact with the bot.
  • Message editing --- supports editing previous messages in-place.
  • Markdown rendering --- messages support standard Markdown formatting.

IRC

Clawq connects to IRC servers via raw TCP or TLS sockets, implementing the core IRC protocol (RFC 2812) for sending and receiving messages.

Configuration

{
  "channels": {
    "irc": {
      "host": "irc.libera.chat",
      "port": 6697,
      "tls": true,
      "nick": "clawq-bot",
      "password": null,
      "sasl": false,
      "channels": ["#mychannel"],
      "allow_from": ["*"]
    }
  }
}

Setup

clawq setup irc

Or manually: configure the IRC server host, port, TLS setting, bot nickname, and channel list.

Key Features

  • TCP/TLS connections --- supports both plaintext and TLS-encrypted connections.
  • SASL authentication --- optional SASL PLAIN authentication for registered nicks.
  • PING/PONG keepalive --- responds to server PINGs to maintain the connection.
  • Channel and DM support --- handles both channel messages and private messages.
  • Message chunking --- responses are split at the 512-byte IRC message limit.
  • User allowlist --- restrict which IRC users can trigger the bot.

Mattermost

Clawq connects to Mattermost servers using the WebSocket API for receiving events and the REST API v4 for sending messages.

Configuration

{
  "channels": {
    "mattermost": {
      "url": "https://mattermost.example.com",
      "access_token": "your-personal-access-token",
      "team_id": "team-id-here",
      "channel_ids": ["channel-id-1"],
      "allow_users": ["*"]
    }
  }
}

Setup

clawq setup mattermost

Or manually: create a personal access token in Mattermost, find your team and channel IDs, and configure the connection.

Key Features

  • WebSocket event stream --- real-time message delivery via the Mattermost WebSocket API.
  • Markdown support --- responses are formatted with standard Markdown, which Mattermost renders natively.
  • Message editing --- supports editing previous messages in-place.
  • Channel and user allowlists --- restrict which channels and users the bot responds to.

Email

Clawq monitors an email inbox via IMAP and replies via SMTP, enabling email-based agent interactions.

Configuration

{
  "channels": {
    "email": {
      "imap_host": "imap.gmail.com",
      "imap_port": 993,
      "smtp_host": "smtp.gmail.com",
      "smtp_port": 587,
      "username": "bot@example.com",
      "password": "app-password",
      "from_address": "bot@example.com",
      "allow_from": ["*"],
      "poll_interval_s": 30.0
    }
  }
}

Setup

clawq setup email

Or manually: configure IMAP and SMTP credentials for the bot’s email account. For Gmail, use an App Password.

Key Features

  • IMAP polling --- periodically checks for new messages with configurable poll interval.
  • SMTP replies --- sends responses as email replies with proper threading headers (In-Reply-To, References).
  • Sender allowlist --- restrict which email addresses can trigger the bot.
  • Subject threading --- replies preserve the email subject with Re: prefix for clean threading in email clients.

DingTalk

Clawq connects to DingTalk (aka DingDing) using the Stream Mode protocol for receiving robot messages and the REST API for sending replies.

Configuration

{
  "channels": {
    "dingtalk": {
      "app_key": "your-app-key",
      "app_secret": "your-app-secret",
      "agent_id": "your-agent-id",
      "allow_from": ["*"],
      "webhook_url": null
    }
  }
}

Setup

clawq setup dingtalk

Or manually: create a DingTalk robot in the developer console, enable Stream Mode, and configure the app credentials.

Key Features

  • Stream Mode --- receives messages via the DingTalk stream protocol, no public URL required.
  • Conversation replies --- sends replies to the originating conversation using the openConversationId.
  • Group and DM support --- handles both group chat and 1-on-1 conversations.
  • User allowlist --- restrict which DingTalk users can interact with the bot.

Lark/Feishu

Clawq integrates with Lark (Feishu) using the Event Callback mechanism for receiving messages and the REST API for sending replies.

Configuration

{
  "channels": {
    "lark": {
      "enabled": true,
      "app_id": "cli_...",
      "app_secret": "your-app-secret",
      "verification_token": "your-verification-token",
      "endpoint": "/lark/webhook",
      "mode": "webhook",
      "allow_users": ["*"]
    }
  }
}

Setup

clawq setup lark

Or manually: create a Lark app in the developer console, configure event subscriptions, and set the webhook URL to your clawq gateway endpoint.

Key Features

  • Event callbacks --- receives messages via Lark’s event subscription system.
  • Tenant access token --- authenticates API calls using auto-refreshed tenant tokens.
  • Group and P2P support --- handles both group chat and peer-to-peer conversations.
  • User allowlist --- restrict which Lark users can interact with the bot.

LINE

Clawq connects to LINE using the Messaging API with webhook-based event delivery and both reply and push message endpoints for responses.

Configuration

{
  "channels": {
    "line": {
      "channel_access_token": "your-channel-access-token",
      "channel_secret": "your-channel-secret",
      "allow_from": ["*"]
    }
  }
}

Setup

clawq setup line

Or manually: create a LINE Messaging API channel in the LINE Developers Console, configure the webhook URL to your clawq gateway, and copy the channel access token and secret.

Key Features

  • Webhook events --- receives messages via LINE’s webhook push mechanism.
  • Reply tokens --- uses one-time reply tokens for immediate responses; falls back to push messages for delayed replies.
  • Signature verification --- validates webhook payloads using HMAC-SHA256 with the channel secret.
  • User allowlist --- restrict which LINE users can interact with the bot.

Nostr

Clawq connects to Nostr relays via WebSocket, using NIP-04 encrypted direct messages for private agent conversations.

Configuration

{
  "channels": {
    "nostr": {
      "relays": ["wss://relay.damus.io", "wss://nos.lol"],
      "private_key": "nsec1...",
      "pubkey": "npub1...",
      "nak_path": "/usr/local/bin/nak",
      "allow_from": ["*"]
    }
  }
}

Setup

clawq setup nostr

Or manually: generate a Nostr keypair, configure relay URLs, and install the nak CLI tool for event signing and encryption.

Key Features

  • Multi-relay support --- connects to multiple relays simultaneously for redundancy.
  • NIP-04 encrypted DMs --- messages are encrypted end-to-end using the NIP-04 standard.
  • Event signing --- all outgoing events are signed with the bot’s private key via the nak tool.
  • Subscription filters --- subscribes to DM events addressed to the bot’s public key.
  • User allowlist --- restrict which Nostr pubkeys can interact with the bot.

OneBot

Clawq connects to QQ and other Chinese IM platforms via the OneBot v11 protocol, supporting both WebSocket and HTTP transports.

Configuration

{
  "channels": {
    "onebot": {
      "ws_url": "ws://127.0.0.1:6700",
      "http_url": "http://127.0.0.1:5700",
      "access_token": null,
      "allow_from": ["*"],
      "allow_groups": ["*"]
    }
  }
}

Setup

clawq setup onebot

Or manually: install a OneBot-compatible bot framework (e.g., go-cqhttp, Lagrange), configure the WebSocket and HTTP endpoints, and optionally set an access token for authentication.

Key Features

  • WebSocket event stream --- receives events via the OneBot v11 WebSocket forward connection.
  • HTTP API --- sends messages via the OneBot HTTP API (send_private_msg, send_group_msg).
  • Group and private chat --- handles both private messages and group conversations.
  • Message recall --- supports deleting (recalling) messages via the API.
  • User and group allowlists --- restrict which users and groups can interact with the bot.

WhatsApp

Clawq integrates with WhatsApp using the Cloud API (Meta Business Platform) for sending and receiving messages.

Configuration

{
  "channels": {
    "whatsapp": {
      "phone_number_id": "123456789",
      "access_token": "EAAx...",
      "verify_token": "my-verify-token",
      "allow_from": ["*"]
    }
  }
}

Setup

clawq setup whatsapp

Or manually: create a WhatsApp Business app in the Meta Developer Portal, configure the webhook URL to your clawq gateway, set the verify token for the webhook handshake, and copy the access token.

Key Features

  • Cloud API --- sends and receives messages through Meta’s WhatsApp Cloud API.
  • Webhook verification --- handles the GET challenge/response handshake required by Meta.
  • Webhook events --- receives incoming messages via POST webhook delivery.
  • Phone number allowlist --- restrict which phone numbers can interact with the bot.

iMessage

Clawq integrates with iMessage on macOS using AppleScript for sending messages and SQLite for reading incoming messages from the Messages database.

Configuration

{
  "channels": {
    "imessage": {
      "poll_interval_s": 2.0,
      "allow_from": ["*"]
    }
  }
}

Setup

clawq setup imessage

This channel only works on macOS. Grant clawq Full Disk Access in System Preferences to allow reading the Messages SQLite database.

Key Features

  • SQLite polling --- monitors ~/Library/Messages/chat.db for new incoming messages at a configurable poll interval.
  • AppleScript sending --- sends replies via osascript using the Messages AppleScript interface.
  • Handle-based sessions --- each contact (phone number or email) maps to a stable session key.
  • Contact allowlist --- restrict which iMessage handles can interact with the bot.

macOS only

This channel requires macOS with Full Disk Access permissions. It will not work on Linux or Windows.

Signal

Clawq connects to Signal via the signal-cli REST API, which runs as a separate service that bridges Signal’s protocol to HTTP.

Configuration

{
  "channels": {
    "signal": {
      "base_url": "http://127.0.0.1:8080",
      "account": "+1234567890",
      "api_mode": "json-rpc",
      "allow_from": ["*"],
      "max_chunk_bytes": 6000
    }
  }
}

Setup

clawq setup signal

Or manually: install and configure signal-cli-rest-api, register or link a phone number, and point clawq at the REST API endpoint.

Key Features

  • signal-cli REST bridge --- communicates with Signal through the signal-cli REST API service.
  • Group and DM support --- handles both group messages and direct messages.
  • Message chunking --- long responses are split at configurable byte boundaries (max_chunk_bytes).
  • Reactions --- supports sending emoji reactions to messages.
  • Contact allowlist --- restrict which Signal numbers can interact with the bot.

Web Channel

The web channel provides a simple HTTP REST API for programmatic access to clawq sessions, separate from the main web gateway.

Configuration

{
  "web_channel": {
    "enabled": true,
    "path_prefix": "/web",
    "totp_secret": null,
    "token_ttl_hours": 24
  }
}

Setup

Enable the web channel in your config and optionally configure TOTP authentication. The channel is served by the main HTTP gateway.

Key Features

  • REST API --- simple JSON request/response interface for sending messages and receiving replies.
  • Session management --- supports custom session IDs for maintaining conversation context.
  • Optional TOTP auth --- can require TOTP-based authentication for access.
  • CORS support --- includes CORS headers for browser-based access.

Adding a New Channel

To add a new channel:

  1. Create a new module that satisfies Channel.S.
  2. Add the corresponding config type to runtime_config.ml.
  3. Wire it into daemon.ml alongside the existing channels.
  4. Place it in clawq_runtime_integrations (not core) per the runtime split rules.

The narrow Channel.S interface means most of the work is in the protocol-specific implementation --- the integration point with the rest of clawq is minimal.