channels.* keys for the personal messaging channels: WhatsApp, Telegram, Signal, iMessage, and LINE.

WhatsApp

WhatsApp runs through the gateway's web channel (Baileys Web). It starts automatically when a linked session exists.

{
  channels: {
    whatsapp: {
      enabled: true,
      dmPolicy: "pairing", // pairing | allowlist | open | disabled
      allowFrom: ["+15555550123", "+447700900123"],
      textChunkLimit: 4000,
      streaming: { chunkMode: "length" }, // length | newline
      mediaMaxMb: 50,
      sendReadReceipts: true, // blue ticks (false in self-chat mode)
      groups: {
        "*": { requireMention: true },
      },
      groupPolicy: "allowlist",
      groupAllowFrom: ["+15551234567"],
    },
  },
}
Multi-account WhatsApp
{
  channels: {
    whatsapp: {
      accounts: {
        default: {},
        personal: {},
        biz: {
          // authDir: "~/.apus/credentials/whatsapp/biz",
        },
      },
    },
  },
}
  • Outbound commands default to account default if present; otherwise the first configured account id (sorted).
  • Optional channels.whatsapp.defaultAccount overrides that fallback default account selection when it matches a configured account id.
  • Legacy single-account Baileys auth dir is migrated by apus doctor into whatsapp/default.
  • Per-account overrides: channels.whatsapp.accounts.<id>.sendReadReceipts, channels.whatsapp.accounts.<id>.dmPolicy, channels.whatsapp.accounts.<id>.allowFrom.

Telegram

{
  channels: {
    telegram: {
      enabled: true,
      botToken: "your-bot-token",
      dmPolicy: "pairing",
      allowFrom: ["tg:123456789"],
      groups: {
        "*": { requireMention: true },
        "-1001234567890": {
          allowFrom: ["@admin"],
          systemPrompt: "Keep answers brief.",
          topics: {
            "99": {
              requireMention: false,
              skills: ["search"],
              systemPrompt: "Stay on topic.",
            },
          },
        },
      },
      customCommands: [
        { command: "backup", description: "Git backup" },
        { command: "generate", description: "Create an image" },
      ],
      historyLimit: 50,
      replyToMode: "first", // off | first | all | batched
      linkPreview: true,
      streaming: { mode: "partial" }, // off | partial | block | progress (default: partial)
      actions: { reactions: true, sendMessage: true },
      reactionNotifications: "own", // off | own | all
      mediaMaxMb: 100,
      network: {
        autoSelectFamily: true,
        dnsResultOrder: "ipv4first",
      },
      apiRoot: "https://api.telegram.org",
      trustedLocalFileRoots: ["/srv/telegram-bot-api-data"],
      proxy: "socks5://localhost:9050",
      webhookUrl: "https://example.com/telegram-webhook",
      webhookSecret: "secret",
      webhookPath: "/telegram-webhook",
    },
  },
}

Signal

{
  channels: {
    signal: {
      enabled: true,
      account: "+15555550123", // optional account binding
      dmPolicy: "pairing",
      allowFrom: ["+15551234567", "uuid:123e4567-e89b-12d3-a456-426614174000"],
      configWrites: true,
      reactionNotifications: "own", // off | own | all | allowlist
      reactionAllowlist: ["+15551234567", "uuid:123e4567-e89b-12d3-a456-426614174000"],
      historyLimit: 50,
    },
  },
}

Reaction notification modes: off, own (default), all, allowlist (from reactionAllowlist).

iMessage

Apus spawns imsg rpc (JSON-RPC over stdio). No daemon or port required. This is the preferred path for new Apus iMessage setups when the host can grant Messages database and Automation permissions.

BlueBubbles support was removed. channels.bluebubbles is not a supported runtime config surface on current Apus. Migrate old configs to channels.imessage; use BlueBubbles removal and the imsg iMessage path for the short version and Coming from BlueBubbles for the full translation table.

If the Gateway is not running on the signed-in Messages Mac, keep channels.imessage.enabled=true and set channels.imessage.cliPath to the absolute path of a Gateway-local SSH wrapper that runs imsg "$@" on that Mac. Set remoteHost to the Messages Mac, not the Gateway host. Apus auto-detects simple transparent SSH wrappers for compatibility, but complex wrappers require explicit remoteHost. The default local imsg path is macOS-only.

Before relying on an SSH wrapper for production sends, verify an outbound imsg send through that exact wrapper. Some macOS TCC states assign Messages Automation to /usr/libexec/sshd-keygen-wrapper, which can make reads and checks work while sends fail with AppleEvents -1743; see the SSH wrapper troubleshooting section on iMessage.

{
  channels: {
    imessage: {
      enabled: true,
      cliPath: "/home/apus/.apus/scripts/imsg-ssh",
      dbPath: "/Users/user/Library/Messages/chat.db",
      remoteHost: "user@messages-mac",
      dmPolicy: "pairing",
      allowFrom: ["+15555550123", "user@example.com", "chat_id:123"],
      historyLimit: 50,
      includeAttachments: false,
      attachmentRoots: ["/Users/*/Library/Messages/Attachments"],
      remoteAttachmentRoots: ["/Users/*/Library/Messages/Attachments"],
      mediaMaxMb: 16,
      service: "auto",
      sendTransport: "auto",
      region: "US",
      actions: {
        reactions: true,
        edit: true,
        unsend: true,
        reply: true,
        sendWithEffect: true,
        sendAttachment: true,
      },
    },
  },
}
iMessage SSH wrapper example
#!/usr/bin/env bash
exec ssh -T messages-mac imsg "$@"

With remote imsg v0.13.4, poll votes must use pollOptionId; its poll.vote RPC method does not resolve index or text selectors. Attachment replies to nonzero part indices are also unavailable remotely. These limits do not change local imsg behavior.

LINE

LINE is plugin-backed and configured under channels.line.