Signal Channel Setup for OpenClaw via signal-cli
Covers Signal support through signal-cli, including the native daemon and bbernhard container setup paths plus the number model. Useful for operators connecting a bot to Signal.
Read this when
- Setting up Signal support
- Debugging Signal send/receive
Signal ships as a channel plugin you can download (@openclaw/signal). Communication between the gateway and signal-cli happens over HTTP: you can use either the native daemon (JSON-RPC + SSE) or the bbernhard/signal-cli-rest-api container (REST + WebSocket). libsignal is not embedded in OpenClaw.
The number model (read this first)
- The gateway links up with a Signal device, namely the
signal-cliaccount. - If the bot runs on your personal Signal account, messages you send yourself get ignored (loop protection).
- To get "I text the bot and it replies," give the bot a separate bot number.
Install
openclaw plugins install @openclaw/signal
By default, @openclaw/signal is installed from ClawHub. Installing straight from npm is done with npm:@openclaw/signal. The plugin gets registered and enabled by plugins install; you do not need a separate enable step. General install rules live in Plugins.
Quick setup
Pick a number
Give the bot a separate Signal number (recommended).
Install the plugin
openclaw plugins install @openclaw/signal
Run the guided setup
openclaw channels add
The wizard checks whether signal-cli exists on PATH and, if it is missing, offers to install it: on Linux x86-64 it downloads the official native GraalVM build, while on macOS and other architectures it installs through Homebrew. Next it asks for the bot number and the signal-cli path.
When setting up non-interactively, openclaw channels add --channel signal also takes --signal-number <e164> for the bot phone number, along with --http-host <host> and --http-port <port> for the Signal daemon endpoint (default 127.0.0.1:8080).
Link or register the account
- QR link (fastest): run
signal-cli link -n "OpenClaw", then scan with Signal. See Path A. - SMS registration: a dedicated number with captcha + SMS verification. See Path B.
Verify and pair
openclaw channels status --probe
Send an initial DM, then approve pairing: openclaw pairing approve signal <CODE>.
Minimal config:
{
channels: {
signal: {
enabled: true,
account: "+15551234567",
transport: {
kind: "managed-native",
cliPath: "signal-cli",
},
dmPolicy: "pairing",
allowFrom: ["+15557654321"],
},
},
}
| Field | Description |
|---|---|
account | Bot phone number in E.164 format (+15551234567) |
transport | Account-owned Signal connection and process mode |
dmPolicy | DM access policy (pairing recommended) |
allowFrom | Phone numbers or uuid:<id> values allowed to DM |
Multi-account support: configure channels.signal.accounts with per-account settings and an optional name. Every named account owns its own transport; the top-level transport is not inherited. Only the implicit default account uses the top-level transport. The shared pattern is described in Multi-account channels.
Account keys rely on the normalized IDs that status displays. For instance, Work Phone with its own account number runs as work-phone and applies its authored settings without running Doctor. When several keys normalize to the same ID, the exact key takes precedence and Doctor reports the collision. Deletion will not remove that account if another stored key would then select a different identity; the error names both keys so you can fix the collision first. Legacy aliases that lack their own number keep the inherited behavior they already have. Doctor can clean up unambiguous keys, yet it refuses to rename an alias when doing so would activate settings that were previously ignored.
If account dmPolicy and groupPolicy are omitted, they inherit from the channel root; explicit account policies take precedence. When neither scope sets them, DMs use pairing and groups use allowlist.
What it is
- Signal is always the destination for replies.
- DMs use the agent's main session; with the default
session.groupScope: "per-group", groups stay isolated (agent:<agentId>:signal:group:<groupId>). - By default, Signal can write config updates that
/config set|unsettriggers (requirescommands.config: true). Turn this off withchannels.signal.configWrites: false.
Setup path A: link existing Signal account (QR)
- Install
signal-cli(JVM or native build), or haveopenclaw channels addhandle the installation for you. - Connect a bot account:
signal-cli link -n "OpenClaw", then scan the QR code inside Signal. - Set up Signal and launch the gateway.
Setup path B: register dedicated bot number (SMS, Linux)
Choose this route when you want a dedicated bot number rather than linking an existing Signal app account. The steps below have been verified on Ubuntu 24.
- Obtain a number capable of receiving SMS (landlines can use voice verification). Using a dedicated bot number prevents account and session conflicts.
- On the gateway host, install
signal-cli:
VERSION=$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/AsamK/signal-cli/releases/latest | sed -e 's/^.*\/v//')
curl -L -O "https://github.com/AsamK/signal-cli/releases/download/v${VERSION}/signal-cli-${VERSION}-Linux-native.tar.gz"
sudo tar xf "signal-cli-${VERSION}-Linux-native.tar.gz" -C /opt
sudo ln -sf /opt/signal-cli /usr/local/bin/
signal-cli --version
When running the JVM build (signal-cli-${VERSION}.tar.gz), a JRE must be installed first. Keep signal-cli current; upstream documentation warns that older releases may stop working as Signal server APIs evolve.
A managed signal-cli daemon receives only an allowlisted environment; refer to Managed daemon environment.
- Register the number and verify it:
signal-cli -a +<BOT_PHONE_NUMBER> register
Continuing within step 3, when a captcha is required (completing it needs browser access):
- Navigate to
https://signalcaptchas.org/registration/generate.html. - Solve the captcha, then copy the
signalcaptcha://...link target from "Open Signal". - Where possible, run this from the same external IP as the browser session, since captcha tokens expire fast.
- Register and verify right away:
signal-cli -a +<BOT_PHONE_NUMBER> register --captcha '<SIGNALCAPTCHA_URL>'
signal-cli -a +<BOT_PHONE_NUMBER> verify <VERIFICATION_CODE>
- Set up OpenClaw and confirm the channel works. Configuration edits take effect via hot reload; bring the Gateway up if it is not running. Should you have modified the service's
PATHin order to locatesignal-cli, restart it.
openclaw doctor
openclaw channels status --probe
- Pair the sender of your DMs:
- Send any message to the bot number.
- On the server, approve it:
openclaw pairing approve signal <PAIRING_CODE>. - Add the bot number to your phone's contacts so it does not show as "Unknown contact".
Warning
If you register a phone number account with
signal-cli, the main Signal app session for that number may be de-authenticated. A dedicated bot number is preferable, or keep your existing phone app setup by using QR link mode.
Upstream references:
signal-cliREADME:https://github.com/AsamK/signal-cli- Captcha flow:
https://github.com/AsamK/signal-cli/wiki/Registration-with-captcha - Linking flow:
https://github.com/AsamK/signal-cli/wiki/Linking-other-devices-(Provisioning)
External native daemon mode
If you would rather manage signal-cli on your own terms (slow JVM cold starts, container init, shared CPUs), run the daemon as a separate process and have OpenClaw point to it:
For non-interactive setups, specify the endpoint kind explicitly when it is needed:
openclaw channels add --channel signal --signal-number +15551234567 \
--http-url http://127.0.0.1:8080 --signal-transport external-native
{
channels: {
signal: {
transport: {
kind: "external-native",
url: "http://127.0.0.1:8080",
},
},
},
}
Auto-spawn and OpenClaw's startup wait are both skipped this way. When a managed daemon starts slowly, set channels.signal.transport.startupTimeoutMs.
Managed daemon environment
From the Gateway environment, a managed signal-cli daemon receives only process essentials: PATH, HOME, user, locale (LANG, LC_*), TZ, temp directories, XDG_*, the Java launcher inputs (JAVA_HOME, JAVA_OPTS, JAVA_TOOL_OPTIONS, JDK_JAVA_OPTIONS, _JAVA_OPTIONS, SIGNAL_CLI_OPTS), signal-cli's own SIGNAL_CLI_CONFIG and SIGNAL_CLI_USER_AGENT, the native library path (LD_LIBRARY_PATH, DYLD_LIBRARY_PATH, DYLD_FALLBACK_LIBRARY_PATH), and common Windows system variables. Provider keys, Gateway tokens and other secrets held in the Gateway environment never reach it.
Proxy and trust-store variables (HTTP_PROXY, HTTPS_PROXY, NO_PROXY, ALL_PROXY in either case, SSL_CERT_FILE, SSL_CERT_DIR, REQUESTS_CA_BUNDLE, CURL_CA_BUNDLE, NODE_EXTRA_CA_CERTS) are not inherited. If any of them is set, the Gateway emits a one-time warning that names them (names only, never values) when starting the daemon, and openclaw doctor reports the same.
signal-cli runs on the JVM, which reads proxy and trust-store settings from Java system properties. Choose one approach:
-
Pass Java properties via
JAVA_TOOL_OPTIONS, which the daemon inherits:JAVA_TOOL_OPTIONS="-Dhttps.proxyHost=proxy.example -Dhttps.proxyPort=3128 -Dhttp.nonProxyHosts=localhost|127.0.0.1"For a private CA, add
-Djavax.net.ssl.trustStore=/path/to/truststore.p12 -Djavax.net.ssl.trustStoreType=PKCS12. -
Point
channels.signal.transport.cliPathat a wrapper script that sets what it needs (for example, turns your proxy variables into Java properties), then runssignal-cli "$@". -
Run the daemon yourself and use external native daemon mode.
Container mode (bbernhard/signal-cli-rest-api)
Rather than running signal-cli natively, you can deploy the bbernhard/signal-cli-rest-api Docker container, which puts a REST + WebSocket interface in front of signal-cli.
openclaw channels add --channel signal --signal-number +15551234567 \
--http-url http://signal-cli:8080 --signal-transport container
Requirements:
- Real-time message receiving requires the container to run with
MODE=json-rpc. - Your Signal account must be registered or linked inside the container before OpenClaw connects.
Example docker-compose.yml service:
signal-cli:
image: bbernhard/signal-cli-rest-api:latest
environment:
MODE: json-rpc
ports:
- "8080:8080"
volumes:
- signal-cli-data:/home/.local/share/signal-cli
OpenClaw config:
{
channels: {
signal: {
enabled: true,
account: "+15551234567",
transport: {
kind: "container",
url: "http://signal-cli:8080",
},
},
},
}
The protocol and process lifecycle OpenClaw uses are selected by transport.kind:
| Value | Behavior |
|---|---|
"managed-native" | Launches native signal-cli and uses JSON-RPC at /api/v1/rpc plus SSE at /api/v1/events; url may select a connection endpoint distinct from the daemon bind |
"external-native" | Connects to a native signal-cli daemon that is already running |
"container" | Connects to bbernhard REST at /v2/send and WebSocket at /v1/receive/{account} |
During setup and openclaw doctor --fix, an existing endpoint may be checked once to determine its concrete kind. At runtime, protocols are neither auto-detected nor switched.
Where the container exposes matching APIs, container mode supports the same Signal operations as native mode: sends, receives, attachments, typing indicators, read/viewed receipts, reactions, groups, and styled text. Native Signal RPC calls are translated by OpenClaw into the container's REST payloads, including group.{base64(internal_id)} group IDs and text_mode: "styled" for formatted text.
Operational notes:
- Receiving requires
MODE=json-rpc.MODE=normalcan make/v1/aboutappear healthy, yet/v1/receive/{account}will not upgrade to WebSocket, so the container receive streaming check fails. - For the bbernhard REST API set
kind: "container"; for nativesignal-cliJSON-RPC/SSE setkind: "external-native". - Container attachment downloads obey the same media byte limits as native mode. When the server sends
Content-Length, oversized responses are rejected before being fully buffered; otherwise they are rejected while streaming. - Health and missing-attachment results do not wait for an unused response body's cancellation to finish.
Opt-in private UNIX socket
A managed native daemon on POSIX systems can listen on a UNIX socket rather than an HTTP listener. This helps on shared hosts where other OS users must not be able to control the Signal daemon. Give transport.socketPath an absolute path (no more than 103 UTF-8 bytes, and without . or .. path segments):
{
channels: {
signal: {
enabled: true,
account: "+15555550123",
transport: {
kind: "managed-native",
socketPath: "/home/user/.local/state/signal-private/daemon.sock",
},
},
},
}
The socket's immediate directory must be owned by the Gateway OS user and carry mode 0700 (no group or other access). If that directory is missing and its parent already exists, OpenClaw creates it; permissions on directories that already exist are not repaired. Paths that are symlinks are rejected. Beyond the BSD mode bits, OpenClaw on macOS also inspects ACLs and rejects access-granting ACL entries for non-owners, inheritable entries included. POSIX ACLs are not inspected on Linux, so operators should pick a parent hierarchy with no access-granting ACLs. Each account needs its own socket path. This opt-in is not supported on Windows.
socketPath works only together with kind: "managed-native" and cannot be combined with url, httpHost, or httpPort. Leave receiveMode out, or set it to "manual"; receive subscriptions are managed by OpenClaw over the socket. Should the socket connection or permissions fail, this transport stops, and no HTTP fallback exists.
Existing managed HTTP defaults, external native daemons, and container setups are unaffected. Opting out leaves the existing HTTP exposure unchanged: a loopback bind does not stop another local OS user from reaching an unauthenticated daemon. The private directory separates OS users, not processes running as the same user or administrators. signal-cli does not authorize a connecting peer's UID, so this isolation guarantee rests on filesystem authorization. Signal sender pairing and allowlists remain separate message-access controls.
Access control (DMs + groups)
DMs:
- Default:
channels.signal.dmPolicy = "pairing". - Senders who are unknown receive a pairing code; their messages are ignored until approval (codes expire after 1 hour).
- Approve with
openclaw pairing list signalandopenclaw pairing approve signal <CODE>. - For Signal DMs, pairing is the default token exchange. Details: Pairing
- Senders identified only by UUID (from
sourceUuid) are stored asuuid:<id>inchannels.signal.allowFrom.
Groups:
channels.signal.groupPolicy = open | allowlist | disabled.- When
allowlistis set,channels.signal.groupAllowFromdecides which senders or groups are allowed to trigger group replies. Entries may be Signal group IDs (raw,group:<id>, orsignal:group:<id>), sender phone numbers,uuid:<id>values, or*. - Group behavior can be overridden through
requireMention,tools, andtoolsBySenderonchannels.signal.groups["<group-id>" | "*"]. - For multi-account setups, per-account overrides go in
channels.signal.accounts.<id>.groups. - Adding a Signal group to the allowlist via
groupAllowFromdoes not by itself turn off mention gating. Every group message is processed by an explicitly configuredchannels.signal.groups["<group-id>"]entry unlessrequireMention=trueis set. - Under
requireMention=true, Signal native @mentions are matched from structured mention metadata against the bot account phone oraccountUuid. For plain-text matching,agents.entries.*.groupChat.mentionPatternsis tried first, thenmessages.groupChat.mentionPatterns; if neither is set, patterns are derived from the routed agent'sidentity.nameandidentity.emoji. Setting an explicitmentionPatterns: []at the chosen level turns off this text fallback while native @mentions keep working. - Runtime note: when
channels.signalis entirely absent, group checks at runtime fall back togroupPolicy="allowlist"(even whenchannels.defaults.groupPolicyis set).
Mention-gated group with bounded context:
{
channels: {
signal: {
account: "+15551234567",
accountUuid: "bot-signal-uuid",
groupPolicy: "allowlist",
groupAllowFrom: ["group:<signal-group-id>"],
historyLimit: 8,
groups: {
"<signal-group-id>": { requireMention: true },
},
},
},
messages: {
groupChat: {
mentionPatterns: ["\\bopenclaw\\b"],
},
},
}
Allowed group messages that do not mention the bot produce no reply and are retained only inside the bounded pending history window. If a later native @mention or fallback text mention triggers the bot, OpenClaw pulls in that recent context and answers in the same group. Skipped attachment bodies are never downloaded; at most they show up as compact media placeholders within the pending context.
How it works (behavior)
- Native mode:
signal-cliruns as a daemon, and the gateway reads events over SSE. - Container mode: REST API is used by the gateway to send, and WebSocket to receive.
- Inbound messages get normalized into the shared channel envelope.
- Replies are always routed back to the same number or group.
- When the backend accepts the inbound timestamp and author, replies to inbound messages carry native Signal quote metadata; if that metadata is missing or rejected, OpenClaw delivers the reply as a normal message.
- Canceling the originating delivery halts further send attempts, including attachments still being prepared and the native-quote fallback. A request already submitted to Signal is permitted to complete, and its accepted result is kept; cancellation cannot recall that message.
- Native quote use is configured with
channels.signal.replyToMode = off | first | all | batched, or withchannels.signal.replyToModeByChatType.direct/groupfor per-chat-type overrides. Values set at account level underchannels.signal.accounts.<id>win.
Media + limits
- Outbound text is split into chunks of
channels.signal.textChunkLimit(default 4000). - Optional newline chunking: setting
channels.signal.streaming.chunkMode="newline"splits on blank lines (paragraph boundaries) ahead of length chunking. - Attachments are supported (base64 fetched from
signal-cli). - For voice-note attachments, the
signal-clifilename serves as a MIME fallback whencontentTypeis absent, so audio transcription can still classify AAC voice memos. - Default media cap:
channels.signal.mediaMaxMb(default 8). channels.signal.ignoreAttachmentsskips media downloads for any transport.- Group history context is sized by
channels.signal.historyLimit(orchannels.signal.accounts.*.historyLimit), withmessages.groupChat.historyLimitas the fallback. To turn it off, set0(default 50).
Typing + read receipts
- Typing indicators: typing signals go out through
signal-cli sendTypingand are refreshed by OpenClaw for as long as a reply is running. - Read receipts: with
channels.signal.sendReadReceiptsset to true, read receipts for allowed DMs are forwarded by OpenClaw. - Groups get no read receipts from
signal-cli.
Lifecycle status reactions
Setting messages.statusReactions.enabled: true lets Signal display the shared queued/thinking/tool/compaction/done/error reaction lifecycle on inbound turns. The inbound message timestamp is what Signal uses as the reaction target; for groups, reactions are sent with the Signal group ID plus the original sender as target author.
Status reactions additionally need an ack reaction and a matching messages.ackReactionScope (direct, group-all, group-mentions, or all). To turn off Signal status reactions, set channels.signal.reactionLevel: "off".
After the final done/error state, Signal puts the initial ack reaction back.
Reactions (message tool)
Use message action=react together with channel=signal.
- Targets: an E.164 sender or a UUID (take
uuid:<id>from the pairing output; a bare UUID works too). messageIdholds the Signal timestamp of the message being reacted to.- Reactions in groups need either
targetAuthorortargetAuthorUuid.
message action=react channel=signal target=uuid:123e4567-e89b-12d3-a456-426614174000 messageId=1737630212345 emoji=๐ฅ
message action=react channel=signal target=+15551234567 messageId=1737630212345 emoji=๐ฅ remove=true
message action=react channel=signal target=signal:group:<groupId> targetAuthor=uuid:<sender-uuid> messageId=1737630212345 emoji=โ
Config:
channels.signal.actions.reactions: turns reaction actions on or off (default true).channels.signal.reactionLevel:off | ack | minimal | extensive(defaultminimal).- With
off/ack, agent reactions are disabled (the message toolreactreturns errors). - With
minimal/extensive, agent reactions are enabled and the guidance level is set.
- With
- Per-account overrides:
channels.signal.accounts.<id>.actions.reactions,channels.signal.accounts.<id>.reactionLevel.
Approval reactions
Approval prompts for Signal exec and plugins are routed by the top-level approvals.exec and approvals.plugin blocks. No channels.signal.execApprovals block exists for Signal.
๐grants a single approval.๐rejects the request.- Where a request allows persistent approval, use
/approve <id> allow-always.
Resolving approval reactions needs explicit Signal approvers, taken from channels.signal.allowFrom, channels.signal.defaultTo, or the corresponding account-level fields. Direct same-chat exec approval prompts can still hide the duplicate local /approve fallback even without explicit approvers; in group approvals with no approvers, the local fallback stays visible.
Agent questions
The ask_user tool is not exposed by Signal. To request your input, the agent sends an ordinary message, and you answer in plain text. Numbered reactions cannot answer questions. The approval reactions covered above behave as described.
Delivery targets (CLI/cron)
- DMs:
signal:+15551234567(or plain E.164). - UUID DMs:
uuid:<id>(or bare UUID). - Groups:
signal:group:<groupId>. - Usernames:
username:<name>(when your Signal account supports them).
Aliases
Set up aliases to give recurring Signal targets stable names. Aliases exist only in OpenClaw config; they neither create nor edit Signal contacts.
{
channels: {
signal: {
aliases: {
me: "+15557654321",
jane: "uuid:123e4567-e89b-12d3-a456-426614174000",
ops: "group:<groupId>",
},
defaultTo: "signal:me",
},
},
}
Aliases work anywhere a Signal delivery target is accepted:
openclaw message send --channel signal --target signal:ops --message "Deployment is complete"
Per-account aliases inherit the top-level aliases, and can add names or override them:
{
channels: {
signal: {
aliases: {
me: "+15557654321",
},
accounts: {
work: {
aliases: {
ops: "group:<workGroupId>",
},
},
},
},
},
}
Configured aliases are listed by openclaw directory peers list --channel signal and openclaw directory groups list --channel signal. The Signal directory is backed by config; it never queries Signal contacts live and never modifies the Signal account.
Troubleshooting
Start with this ladder:
openclaw status
openclaw gateway status
openclaw logs --follow
openclaw doctor
openclaw channels status --probe
Then, if needed, check DM pairing state:
openclaw pairing list signal
Common failures:
- The daemon is reachable but nothing comes back: check
account,transport.kind, the transport URL, and the receive mode. - The event stream keeps closing: look at the daemon or proxy. A healthy idle stream stays open, so an unexpected close shows up as a lost connection in logs and channel status.
- DMs are ignored: the sender is still waiting for pairing approval.
- Group messages are ignored: group sender/mention gating is blocking delivery.
- Config validation errors after edits: run
openclaw doctor --fix. - Signal absent from diagnostics: verify
channels.signal.enabled: true.
Extra checks:
openclaw pairing list signal
pgrep -af signal-cli
openclaw logs --plain --limit 500 | grep -i "signal" | tail -20
For the triage flow, see Channels Troubleshooting.
Security notes
- Account keys are stored locally by
signal-cli(usually~/.local/share/signal-cli/data/). - Before migrating or rebuilding the server, back up Signal account state.
- Leave
channels.signal.dmPolicy: "pairing"in place unless you deliberately want wider DM access. - SMS verification is needed only for registration or recovery, though losing control of the number/account can make re-registration harder.
Configuration reference (Signal)
Full configuration: Configuration
Provider options:
channels.signal.enabled: turns channel startup on or off.channels.signal.account: the bot account's E.164 number.channels.signal.accountUuid: optional UUID for the bot account, used to detect native @mentions and guard against loops.channels.signal.transport: transport owned by the account. Leave it out to use the managed native defaults.channels.signal.transport.kind:managed-native | external-native | container.channels.signal.transport.url: needed byexternal-nativeandcontainer; formanaged-nativeit is optional, and only when that connection endpoint is not the same as the daemon bind.channels.signal.transport.cliPath: the managed-native route tosignal-cli.channels.signal.transport.configPath: optionalsignal-cli --configdirectory for managed-native mode.channels.signal.transport.httpHost,channels.signal.transport.httpPort: the managed-native daemon bind (defaults to127.0.0.1:8080).channels.signal.transport.startupTimeoutMs: how long managed-native startup waits, in ms (minimum 1000, maximum 120000; default 30000).channels.signal.transport.receiveMode: managed-nativeon-start | manual.channels.signal.ignoreAttachments: do not download inbound attachments for this account.channels.signal.transport.ignoreStories: managed-native toggle for stories.channels.signal.sendReadReceipts: pass read receipts along.channels.signal.dmPolicy:pairing | allowlist | open | disabled(default: pairing).channels.signal.allowFrom: DM allowlist (E.164 oruuid:<id>).openneeds"*". Since Signal has no usernames, use phone or UUID IDs.channels.signal.aliases: aliases on the OpenClaw side for DM and group delivery targets.channels.signal.groupPolicy:open | allowlist | disabled(default: allowlist).channels.signal.groupAllowFrom: group allowlist; takes Signal group IDs (raw,group:<id>, orsignal:group:<id>), sender E.164 numbers, oruuid:<id>values.channels.signal.groups: overrides for individual groups, keyed by Signal group ID (or"*"). Fields supported:requireMention,tools,toolsBySender.channels.signal.accounts.<id>.groups: a per-account form ofchannels.signal.groupsfor setups with multiple accounts.channels.signal.accounts.<id>.aliases: per-account aliases, merged with the top-level aliases.channels.signal.replyToMode: native reply quote mode,off | first | all | batched(default:all).channels.signal.replyToModeByChatType.direct,channels.signal.replyToModeByChatType.group: native reply quote overrides for each chat type.channels.signal.accounts.<id>.replyToMode,channels.signal.accounts.<id>.replyToModeByChatType.direct,channels.signal.accounts.<id>.replyToModeByChatType.group: reply quote overrides at the account level.channels.signal.historyLimit: maximum number of group messages pulled in as context (0 turns this off).channels.signal.dmHistoryLimit: DM history limit, counted in user turns. Per-user overrides:channels.signal.dms["<phone_or_uuid>"].historyLimit.channels.signal.textChunkLimit: character count for outbound chunks (default 4000).channels.signal.markdown.tables: the Markdown table rendering mode,off | bullets | code(defaultbullets);blockfalls back tocode(Signal has no native block tables).channels.signal.streaming.chunkMode:length(default) ornewlineto split on blank lines (paragraph boundaries) before length chunking.channels.signal.mediaMaxMb: inbound/outbound media cap in MB (default 8).channels.signal.reactionLevel:off | ack | minimal | extensive(defaultminimal). See Reactions.channels.signal.reactionNotifications:off | own | all | allowlist(defaultown) - when the agent is notified of incoming reactions from others.channels.signal.reactionAllowlist: senders whose reactions notify the agent whenreactionNotifications: "allowlist".channels.signal.streaming.block.enabled,channels.signal.streaming.block.coalesce: block-mode streaming controls shared across channels. See Streaming.
Related global options:
agents.entries.*.groupChat.mentionPatterns(plain-text fallback; Signal native @mentions are detected from structured metadata when the bot account identity is configured).messages.groupChat.mentionPatterns(global fallback).channels.signal.responsePrefixor an account-levelresponsePrefix.
Related
- Channels Overview - all supported channels
- Pairing - DM authentication and pairing flow
- Groups - group chat behavior and mention gating
- Channel routing - session routing for messages
- Reactions - emoji reaction semantics for the
messagetool - RPC adapters - the signal-cli JSON-RPC-over-HTTP daemon pattern behind this channel
- Security - access model and hardening