docs: complete channels rename sweep
This commit is contained in:
@@ -80,7 +80,7 @@ Key behaviors:
|
||||
- Prompt is prefixed with `[cron:<jobId> <job name>]` for traceability.
|
||||
- A summary is posted to the main session (prefix `Cron`, configurable).
|
||||
- `wakeMode: "now"` triggers an immediate heartbeat after posting the summary.
|
||||
- If `payload.deliver: true`, output is delivered to a provider; otherwise it stays internal.
|
||||
- If `payload.deliver: true`, output is delivered to a channel; otherwise it stays internal.
|
||||
|
||||
Use isolated jobs for noisy, frequent, or "background chores" that shouldn't spam
|
||||
your main chat history.
|
||||
@@ -94,9 +94,9 @@ Common `agentTurn` fields:
|
||||
- `message`: required text prompt.
|
||||
- `model` / `thinking`: optional overrides (see below).
|
||||
- `timeoutSeconds`: optional timeout override.
|
||||
- `deliver`: `true` to send output to a provider target.
|
||||
- `provider`: `last` or a specific provider.
|
||||
- `to`: provider-specific target (phone/chat/channel id).
|
||||
- `deliver`: `true` to send output to a channel target.
|
||||
- `channel`: `last` or a specific channel.
|
||||
- `to`: channel-specific target (phone/chat/channel id).
|
||||
- `bestEffortDeliver`: avoid failing the job if delivery fails.
|
||||
|
||||
Isolation options (only for `session=isolated`):
|
||||
@@ -116,12 +116,12 @@ Resolution priority:
|
||||
2. Hook-specific defaults (e.g., `hooks.gmail.model`)
|
||||
3. Agent config default
|
||||
|
||||
### Delivery (provider + target)
|
||||
Isolated jobs can deliver output to a provider. The job payload can specify:
|
||||
- `provider`: `whatsapp` / `telegram` / `discord` / `slack` / `signal` / `imessage` / `last`
|
||||
- `to`: provider-specific recipient target
|
||||
### Delivery (channel + target)
|
||||
Isolated jobs can deliver output to a channel. The job payload can specify:
|
||||
- `channel`: `whatsapp` / `telegram` / `discord` / `slack` / `signal` / `imessage` / `last`
|
||||
- `to`: channel-specific recipient target
|
||||
|
||||
If `provider` or `to` is omitted, cron can fall back to the main session’s “last route”
|
||||
If `channel` or `to` is omitted, cron can fall back to the main session’s “last route”
|
||||
(the last place the agent replied).
|
||||
|
||||
Target format reminders:
|
||||
|
||||
@@ -32,7 +32,7 @@ Example hook config (enable Gmail preset mapping):
|
||||
```
|
||||
|
||||
To deliver the Gmail summary to a chat surface, override the preset with a mapping
|
||||
that sets `deliver` + optional `provider`/`to`:
|
||||
that sets `deliver` + optional `channel`/`to`:
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -51,7 +51,7 @@ that sets `deliver` + optional `provider`/`to`:
|
||||
"New email from {{messages[0].from}}\nSubject: {{messages[0].subject}}\n{{messages[0].snippet}}\n{{messages[0].body}}",
|
||||
model: "openai/gpt-5.2-mini",
|
||||
deliver: true,
|
||||
provider: "last"
|
||||
channel: "last"
|
||||
// to: "+15551234567"
|
||||
}
|
||||
]
|
||||
@@ -59,7 +59,7 @@ that sets `deliver` + optional `provider`/`to`:
|
||||
}
|
||||
```
|
||||
|
||||
If you want a fixed channel, set `provider` + `to`. Otherwise `provider: "last"`
|
||||
If you want a fixed channel, set `channel` + `to`. Otherwise `channel: "last"`
|
||||
uses the last delivery route (falls back to WhatsApp).
|
||||
|
||||
To force a cheaper model for Gmail runs, set `model` in the mapping
|
||||
|
||||
@@ -15,9 +15,9 @@ status: experimental
|
||||
|
||||
Broadcast Groups enable multiple agents to process and respond to the same message simultaneously. This allows you to create specialized agent teams that work together in a single WhatsApp group or DM — all using one phone number.
|
||||
|
||||
Current scope: **WhatsApp only** (web provider).
|
||||
Current scope: **WhatsApp only** (web channel).
|
||||
|
||||
Broadcast groups are evaluated after provider allowlists and group activation rules. In WhatsApp groups, this means broadcasts happen when Clawdbot would normally reply (for example: on mention, depending on your group settings).
|
||||
Broadcast groups are evaluated after channel allowlists and group activation rules. In WhatsApp groups, this means broadcasts happen when Clawdbot would normally reply (for example: on mention, depending on your group settings).
|
||||
|
||||
## Use Cases
|
||||
|
||||
@@ -152,7 +152,7 @@ Agents process in order (one waits for previous to finish):
|
||||
4. **If not in broadcast list**:
|
||||
- Normal routing applies (first matching binding)
|
||||
|
||||
Note: broadcast groups do not bypass provider allowlists or group activation rules (mentions/commands/etc). They only change *which agents run* when a message is eligible for processing.
|
||||
Note: broadcast groups do not bypass channel allowlists or group activation rules (mentions/commands/etc). They only change *which agents run* when a message is eligible for processing.
|
||||
|
||||
### Session Isolation
|
||||
|
||||
@@ -272,7 +272,7 @@ Broadcast groups work alongside existing routing:
|
||||
```json
|
||||
{
|
||||
"bindings": [
|
||||
{ "match": { "provider": "whatsapp", "peer": { "kind": "group", "id": "GROUP_A" } }, "agentId": "alfred" }
|
||||
{ "match": { "channel": "whatsapp", "peer": { "kind": "group", "id": "GROUP_A" } }, "agentId": "alfred" }
|
||||
],
|
||||
"broadcast": {
|
||||
"GROUP_B": ["agent1", "agent2"]
|
||||
|
||||
@@ -8,7 +8,7 @@ read_when:
|
||||
|
||||
# Gateway CLI
|
||||
|
||||
The Gateway is Clawdbot’s WebSocket server (providers, nodes, sessions, hooks).
|
||||
The Gateway is Clawdbot’s WebSocket server (channels, nodes, sessions, hooks).
|
||||
|
||||
Subcommands in this page live under `clawdbot gateway …`.
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ This page describes the current CLI behavior. If commands change, update this do
|
||||
|
||||
Clawdbot uses a lobster palette for CLI output.
|
||||
|
||||
- `accent` (#FF5A2D): headings, provider labels, primary highlights.
|
||||
- `accent` (#FF5A2D): headings, labels, primary highlights.
|
||||
- `accentBright` (#FF7A3D): command names, emphasis.
|
||||
- `accentDim` (#D14A22): secondary highlight text.
|
||||
- `info` (#FF8A5B): informational values.
|
||||
|
||||
@@ -92,7 +92,7 @@ Tune the boundary via `agents.defaults.blockStreamingBreak` (`text_end` vs `mess
|
||||
Control soft block chunking with `agents.defaults.blockStreamingChunk` (defaults to
|
||||
800–1200 chars; prefers paragraph breaks, then newlines; sentences last).
|
||||
Coalesce streamed chunks with `agents.defaults.blockStreamingCoalesce` to reduce
|
||||
single-line spam (idle-based merging before send). Non-Telegram providers require
|
||||
single-line spam (idle-based merging before send). Non-Telegram channels require
|
||||
explicit `*.blockStreaming: true` to enable block replies.
|
||||
Verbose tool summaries are emitted at tool start (no debounce); Control UI
|
||||
streams tool output via agent events when available.
|
||||
|
||||
@@ -3,7 +3,7 @@ summary: "Behavior and config for WhatsApp group message handling (mentionPatter
|
||||
read_when:
|
||||
- Changing group message rules or mentions
|
||||
---
|
||||
# Group messages (web provider)
|
||||
# Group messages (WhatsApp web channel)
|
||||
|
||||
Goal: let Clawd sit in WhatsApp groups, wake up only when pinged, and keep that thread separate from the personal DM session.
|
||||
|
||||
@@ -18,27 +18,27 @@ Note: `agents.list[].groupChat.mentionPatterns` is now used by Telegram/Discord/
|
||||
- Ephemeral/view-once: we unwrap those before extracting text/mentions, so pings inside them still trigger.
|
||||
- Group system prompt: on the first turn of a group session (and whenever `/activation` changes the mode) we inject a short blurb into the system prompt like `You are replying inside the WhatsApp group "<subject>". Group members: Alice (+44...), Bob (+43...), … Activation: trigger-only … Address the specific sender noted in the message context.` If metadata isn’t available we still tell the agent it’s a group chat.
|
||||
|
||||
## Config for Clawd UK (+447700900123)
|
||||
## Config example (WhatsApp)
|
||||
Add a `groupChat` block to `~/.clawdbot/clawdbot.json` so display-name pings work even when WhatsApp strips the visual `@` in the text body:
|
||||
|
||||
```json5
|
||||
{
|
||||
"whatsapp": {
|
||||
"groups": {
|
||||
"*": { "requireMention": true }
|
||||
channels: {
|
||||
whatsapp: {
|
||||
groups: {
|
||||
"*": { requireMention: true }
|
||||
}
|
||||
}
|
||||
},
|
||||
"agents": {
|
||||
"list": [
|
||||
agents: {
|
||||
list: [
|
||||
{
|
||||
"id": "main",
|
||||
"groupChat": {
|
||||
"historyLimit": 50,
|
||||
"mentionPatterns": [
|
||||
"@?clawd",
|
||||
"@?clawd\\s*uk",
|
||||
id: "main",
|
||||
groupChat: {
|
||||
historyLimit: 50,
|
||||
mentionPatterns: [
|
||||
"@?clawdbot",
|
||||
"\\+?447700900123"
|
||||
"\\+?15555550123"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -48,8 +48,8 @@ Add a `groupChat` block to `~/.clawdbot/clawdbot.json` so display-name pings wor
|
||||
```
|
||||
|
||||
Notes:
|
||||
- The regexes are case-insensitive; they cover `@clawd`, `@clawd uk`, `clawdbot`, and the raw number with or without `+`/spaces.
|
||||
- WhatsApp still sends canonical mentions via `mentionedJids` when someone taps the contact, so the number fallback is rarely needed but is a good safety net.
|
||||
- The regexes are case-insensitive; they cover a display-name ping like `@clawdbot` and the raw number with or without `+`/spaces.
|
||||
- WhatsApp still sends canonical mentions via `mentionedJids` when someone taps the contact, so the number fallback is rarely needed but is a useful safety net.
|
||||
|
||||
### Activation command (owner-only)
|
||||
|
||||
@@ -60,8 +60,8 @@ Use the group chat command:
|
||||
Only the owner number (from `channels.whatsapp.allowFrom`, or the bot’s own E.164 when unset) can change this. Send `/status` as a standalone message in the group to see the current activation mode.
|
||||
|
||||
## How to use
|
||||
1) Add Clawd UK (`+447700900123`) to the group.
|
||||
2) Say `@clawd …` (or `@clawd uk`, `@clawdbot`, or include the number). Only allowlisted senders can trigger it unless you set `groupPolicy: "open"`.
|
||||
1) Add your WhatsApp account (the one running Clawdbot) to the group.
|
||||
2) Say `@clawdbot …` (or include the number). Only allowlisted senders can trigger it unless you set `groupPolicy: "open"`.
|
||||
3) The agent prompt will include recent group context plus the trailing `[from: …]` marker so it can address the right person.
|
||||
4) Session-level directives (`/verbose on`, `/think high`, `/new` or `/reset`, `/compact`) apply only to that group’s session; send them as standalone messages so they register. Your personal DM session remains independent.
|
||||
|
||||
|
||||
@@ -41,17 +41,17 @@ If you want...
|
||||
| Only you can trigger in groups | `groupPolicy: "allowlist"`, `groupAllowFrom: ["+1555..."]` |
|
||||
|
||||
## Session keys
|
||||
- Group sessions use `agent:<agentId>:<provider>:group:<id>` session keys (rooms/channels use `agent:<agentId>:<provider>:channel:<id>`).
|
||||
- Group sessions use `agent:<agentId>:<channel>:group:<id>` session keys (rooms/channels use `agent:<agentId>:<channel>:channel:<id>`).
|
||||
- Telegram forum topics add `:topic:<threadId>` to the group id so each topic has its own session.
|
||||
- Direct chats use the main session (or per-sender if configured).
|
||||
- Heartbeats are skipped for group sessions.
|
||||
|
||||
## Display labels
|
||||
- UI labels use `displayName` when available, formatted as `<provider>:<token>`.
|
||||
- UI labels use `displayName` when available, formatted as `<channel>:<token>`.
|
||||
- `#room` is reserved for rooms/channels; group chats use `g-<slug>` (lowercase, spaces -> `-`, keep `#@+._-`).
|
||||
|
||||
## Group policy
|
||||
Control how group/room messages are handled per provider:
|
||||
Control how group/room messages are handled per channel:
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -107,7 +107,7 @@ Notes:
|
||||
|
||||
Quick mental model (evaluation order for group messages):
|
||||
1) `groupPolicy` (open/disabled/allowlist)
|
||||
2) group allowlists (`*.groups`, `*.groupAllowFrom`, provider-specific allowlist)
|
||||
2) group allowlists (`*.groups`, `*.groupAllowFrom`, channel-specific allowlist)
|
||||
3) mention gating (`requireMention`, `/activation`)
|
||||
|
||||
## Mention gating (default)
|
||||
@@ -155,7 +155,7 @@ Notes:
|
||||
- Per-agent override: `agents.list[].groupChat.mentionPatterns` (useful when multiple agents share a group).
|
||||
- Mention gating is only enforced when mention detection is possible (native mentions or `mentionPatterns` are configured).
|
||||
- Discord defaults live in `channels.discord.guilds."*"` (overridable per guild/channel).
|
||||
- Group history context is wrapped uniformly across providers; use `messages.groupChat.historyLimit` for the global default and `<provider>.historyLimit` (or `<provider>.accounts.*.historyLimit`) for overrides. Set `0` to disable.
|
||||
- Group history context is wrapped uniformly across channels; use `messages.groupChat.historyLimit` for the global default and `channels.<channel>.historyLimit` (or `channels.<channel>.accounts.*.historyLimit`) for overrides. Set `0` to disable.
|
||||
|
||||
## Group allowlists
|
||||
When `channels.whatsapp.groups`, `channels.telegram.groups`, or `channels.imessage.groups` is configured, the keys act as a group allowlist. Use `"*"` to allow all groups while still setting default mention behavior.
|
||||
|
||||
@@ -17,20 +17,20 @@ Inbound message
|
||||
-> routing/bindings -> session key
|
||||
-> queue (if a run is active)
|
||||
-> agent run (streaming + tools)
|
||||
-> outbound replies (provider limits + chunking)
|
||||
-> outbound replies (channel limits + chunking)
|
||||
```
|
||||
|
||||
Key knobs live in configuration:
|
||||
- `messages.*` for prefixes, queueing, and group behavior.
|
||||
- `agents.defaults.*` for block streaming and chunking defaults.
|
||||
- Provider overrides (`channels.whatsapp.*`, `channels.telegram.*`, etc.) for caps and streaming toggles.
|
||||
- Channel overrides (`channels.whatsapp.*`, `channels.telegram.*`, etc.) for caps and streaming toggles.
|
||||
|
||||
See [Configuration](/gateway/configuration) for full schema.
|
||||
|
||||
## Inbound dedupe
|
||||
|
||||
Providers can redeliver the same message after reconnects. Clawdbot keeps a
|
||||
short-lived cache keyed by provider/account/peer/session/message id so duplicate
|
||||
Channels can redeliver the same message after reconnects. Clawdbot keeps a
|
||||
short-lived cache keyed by channel/account/peer/session/message id so duplicate
|
||||
deliveries do not trigger another agent run.
|
||||
|
||||
## Sessions and devices
|
||||
@@ -40,7 +40,7 @@ Sessions are owned by the gateway, not by clients.
|
||||
- Groups/channels get their own session keys.
|
||||
- The session store and transcripts live on the gateway host.
|
||||
|
||||
Multiple devices/providers can map to the same session, but history is not fully
|
||||
Multiple devices/channels can map to the same session, but history is not fully
|
||||
synced back to every client. Recommendation: use one primary device for long
|
||||
conversations to avoid divergent context. The Control UI and TUI always show the
|
||||
gateway-backed session transcript, so they are the source of truth.
|
||||
@@ -50,20 +50,20 @@ Details: [Session management](/concepts/session).
|
||||
## Inbound bodies and history context
|
||||
|
||||
Clawdbot separates the **prompt body** from the **command body**:
|
||||
- `Body`: prompt text sent to the agent. This may include provider envelopes and
|
||||
- `Body`: prompt text sent to the agent. This may include channel envelopes and
|
||||
optional history wrappers.
|
||||
- `CommandBody`: raw user text for directive/command parsing.
|
||||
- `RawBody`: legacy alias for `CommandBody` (kept for compatibility).
|
||||
|
||||
When a provider supplies history, it uses a shared wrapper:
|
||||
When a channel supplies history, it uses a shared wrapper:
|
||||
- `[Chat messages since your last reply - for context]`
|
||||
- `[Current message - respond to this]`
|
||||
|
||||
Directive stripping only applies to the **current message** section so history
|
||||
remains intact. Providers that wrap history should set `CommandBody` (or
|
||||
remains intact. Channels that wrap history should set `CommandBody` (or
|
||||
`RawBody`) to the original message text and keep `Body` as the combined prompt.
|
||||
History buffers are configurable via `messages.groupChat.historyLimit` (global
|
||||
default) and per-provider overrides like `channels.slack.historyLimit` or
|
||||
default) and per-channel overrides like `channels.slack.historyLimit` or
|
||||
`channels.telegram.accounts.<id>.historyLimit` (set `0` to disable).
|
||||
|
||||
## Queueing and followups
|
||||
@@ -71,7 +71,7 @@ default) and per-provider overrides like `channels.slack.historyLimit` or
|
||||
If a run is already active, inbound messages can be queued, steered into the
|
||||
current run, or collected for a followup turn.
|
||||
|
||||
- Configure via `messages.queue` (and `messages.queue.byProvider`).
|
||||
- Configure via `messages.queue` (and `messages.queue.byChannel`).
|
||||
- Modes: `interrupt`, `steer`, `followup`, `collect`, plus backlog variants.
|
||||
|
||||
Details: [Queueing](/concepts/queue).
|
||||
@@ -79,7 +79,7 @@ Details: [Queueing](/concepts/queue).
|
||||
## Streaming, chunking, and batching
|
||||
|
||||
Block streaming sends partial replies as the model produces text blocks.
|
||||
Chunking respects provider text limits and avoids splitting fenced code.
|
||||
Chunking respects channel text limits and avoids splitting fenced code.
|
||||
|
||||
Key settings:
|
||||
- `agents.defaults.blockStreamingDefault` (`on|off`, default off)
|
||||
@@ -87,7 +87,7 @@ Key settings:
|
||||
- `agents.defaults.blockStreamingChunk` (`minChars|maxChars|breakPreference`)
|
||||
- `agents.defaults.blockStreamingCoalesce` (idle-based batching)
|
||||
- `agents.defaults.humanDelay` (human-like pause between block replies)
|
||||
- Provider overrides: `*.blockStreaming` and `*.blockStreamingCoalesce` (non-Telegram providers require explicit `*.blockStreaming: true`)
|
||||
- Channel overrides: `*.blockStreaming` and `*.blockStreamingCoalesce` (non-Telegram channels require explicit `*.blockStreaming: true`)
|
||||
|
||||
Details: [Streaming + chunking](/concepts/streaming).
|
||||
|
||||
@@ -104,6 +104,6 @@ Details: [Thinking + reasoning directives](/tools/thinking) and [Token use](/tok
|
||||
|
||||
Outbound message formatting is centralized in `messages`:
|
||||
- `messages.responsePrefix` (outbound prefix) and `channels.whatsapp.messagePrefix` (WhatsApp inbound prefix)
|
||||
- Reply threading via `replyToMode` and per-provider defaults
|
||||
- Reply threading via `replyToMode` and per-channel defaults
|
||||
|
||||
Details: [Configuration](/gateway/configuration#messages) and provider docs.
|
||||
Details: [Configuration](/gateway/configuration#messages) and channel docs.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
summary: "Multi-agent routing: isolated agents, provider accounts, and bindings"
|
||||
summary: "Multi-agent routing: isolated agents, channel accounts, and bindings"
|
||||
title: Multi-Agent Routing
|
||||
read_when: "You want multiple isolated agents (workspaces + auth) in one gateway process."
|
||||
status: active
|
||||
@@ -7,7 +7,7 @@ status: active
|
||||
|
||||
# Multi-Agent Routing
|
||||
|
||||
Goal: multiple *isolated* agents (separate workspace + `agentDir` + sessions), plus multiple provider accounts (e.g. two WhatsApps) in one running Gateway. Inbound is routed to an agent via bindings.
|
||||
Goal: multiple *isolated* agents (separate workspace + `agentDir` + sessions), plus multiple channel accounts (e.g. two WhatsApps) in one running Gateway. Inbound is routed to an agent via bindings.
|
||||
|
||||
## What is “one agent”?
|
||||
|
||||
@@ -64,7 +64,7 @@ clawdbot agents list --bindings
|
||||
|
||||
With **multiple agents**, each `agentId` becomes a **fully isolated persona**:
|
||||
|
||||
- **Different phone numbers/accounts** (per provider `accountId`).
|
||||
- **Different phone numbers/accounts** (per channel `accountId`).
|
||||
- **Different personalities** (per-agent workspace files like `AGENTS.md` and `SOUL.md`).
|
||||
- **Separate auth + sessions** (no cross-talk unless explicitly enabled).
|
||||
|
||||
@@ -87,8 +87,8 @@ Example:
|
||||
]
|
||||
},
|
||||
bindings: [
|
||||
{ agentId: "alex", match: { provider: "whatsapp", peer: { kind: "dm", id: "+15551230001" } } },
|
||||
{ agentId: "mia", match: { provider: "whatsapp", peer: { kind: "dm", id: "+15551230002" } } }
|
||||
{ agentId: "alex", match: { channel: "whatsapp", peer: { kind: "dm", id: "+15551230001" } } },
|
||||
{ agentId: "mia", match: { channel: "whatsapp", peer: { kind: "dm", id: "+15551230002" } } }
|
||||
],
|
||||
channels: {
|
||||
whatsapp: {
|
||||
@@ -110,21 +110,21 @@ Bindings are **deterministic** and **most-specific wins**:
|
||||
1. `peer` match (exact DM/group/channel id)
|
||||
2. `guildId` (Discord)
|
||||
3. `teamId` (Slack)
|
||||
4. `accountId` match for a provider
|
||||
5. provider-level match (`accountId: "*"`)
|
||||
4. `accountId` match for a channel
|
||||
5. channel-level match (`accountId: "*"`)
|
||||
6. fallback to default agent (`agents.list[].default`, else first list entry, default: `main`)
|
||||
|
||||
## Multiple accounts / phone numbers
|
||||
|
||||
Providers that support **multiple accounts** (e.g. WhatsApp) use `accountId` to identify
|
||||
Channels that support **multiple accounts** (e.g. WhatsApp) use `accountId` to identify
|
||||
each login. Each `accountId` can be routed to a different agent, so one server can host
|
||||
multiple phone numbers without mixing sessions.
|
||||
|
||||
## Concepts
|
||||
|
||||
- `agentId`: one “brain” (workspace, per-agent auth, per-agent session store).
|
||||
- `accountId`: one provider account instance (e.g. WhatsApp account `"personal"` vs `"biz"`).
|
||||
- `binding`: routes inbound messages to an `agentId` by `(provider, accountId, peer)` and optionally guild/team ids.
|
||||
- `accountId`: one channel account instance (e.g. WhatsApp account `"personal"` vs `"biz"`).
|
||||
- `binding`: routes inbound messages to an `agentId` by `(channel, accountId, peer)` and optionally guild/team ids.
|
||||
- Direct chats collapse to `agent:<agentId>:<mainKey>` (per-agent “main”; `session.mainKey`).
|
||||
|
||||
## Example: two WhatsApps → two agents
|
||||
@@ -153,14 +153,14 @@ multiple phone numbers without mixing sessions.
|
||||
|
||||
// Deterministic routing: first match wins (most-specific first).
|
||||
bindings: [
|
||||
{ agentId: "home", match: { provider: "whatsapp", accountId: "personal" } },
|
||||
{ agentId: "work", match: { provider: "whatsapp", accountId: "biz" } },
|
||||
{ agentId: "home", match: { channel: "whatsapp", accountId: "personal" } },
|
||||
{ agentId: "work", match: { channel: "whatsapp", accountId: "biz" } },
|
||||
|
||||
// Optional per-peer override (example: send a specific group to work agent).
|
||||
{
|
||||
agentId: "work",
|
||||
match: {
|
||||
provider: "whatsapp",
|
||||
channel: "whatsapp",
|
||||
accountId: "personal",
|
||||
peer: { kind: "group", id: "1203630...@g.us" },
|
||||
},
|
||||
@@ -194,7 +194,7 @@ multiple phone numbers without mixing sessions.
|
||||
|
||||
## Example: WhatsApp daily chat + Telegram deep work
|
||||
|
||||
Split by provider: route WhatsApp to a fast everyday agent and Telegram to an Opus agent.
|
||||
Split by channel: route WhatsApp to a fast everyday agent and Telegram to an Opus agent.
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -215,17 +215,17 @@ Split by provider: route WhatsApp to a fast everyday agent and Telegram to an Op
|
||||
]
|
||||
},
|
||||
bindings: [
|
||||
{ agentId: "chat", match: { provider: "whatsapp" } },
|
||||
{ agentId: "opus", match: { provider: "telegram" } }
|
||||
{ agentId: "chat", match: { channel: "whatsapp" } },
|
||||
{ agentId: "opus", match: { channel: "telegram" } }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
- If you have multiple accounts for a provider, add `accountId` to the binding (for example `{ provider: "whatsapp", accountId: "personal" }`).
|
||||
- To route a single DM/group to Opus while keeping the rest on chat, add a `match.peer` binding for that peer; peer matches always win over provider-wide rules.
|
||||
- If you have multiple accounts for a channel, add `accountId` to the binding (for example `{ channel: "whatsapp", accountId: "personal" }`).
|
||||
- To route a single DM/group to Opus while keeping the rest on chat, add a `match.peer` binding for that peer; peer matches always win over channel-wide rules.
|
||||
|
||||
## Example: same provider, one peer to Opus
|
||||
## Example: same channel, one peer to Opus
|
||||
|
||||
Keep WhatsApp on the fast agent, but route one DM to Opus:
|
||||
|
||||
@@ -238,13 +238,13 @@ Keep WhatsApp on the fast agent, but route one DM to Opus:
|
||||
]
|
||||
},
|
||||
bindings: [
|
||||
{ agentId: "opus", match: { provider: "whatsapp", peer: { kind: "dm", id: "+15551234567" } } },
|
||||
{ agentId: "chat", match: { provider: "whatsapp" } }
|
||||
{ agentId: "opus", match: { channel: "whatsapp", peer: { kind: "dm", id: "+15551234567" } } },
|
||||
{ agentId: "chat", match: { channel: "whatsapp" } }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Peer bindings always win, so keep them above the provider-wide rule.
|
||||
Peer bindings always win, so keep them above the channel-wide rule.
|
||||
|
||||
## Per-Agent Sandbox and Tool Configuration
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ We now serialize command-based auto-replies (WhatsApp Web listener) through a ti
|
||||
- When verbose logging is enabled, queued commands emit a short notice if they waited more than ~2s before starting.
|
||||
- Typing indicators (`onReplyStart`) still fire immediately on enqueue so user experience is unchanged while we wait our turn.
|
||||
|
||||
## Queue modes (per provider)
|
||||
## Queue modes (per channel)
|
||||
Inbound messages can steer the current run, wait for a followup turn, or do both:
|
||||
- `steer`: inject immediately into the current run (cancels pending tool calls after the next tool boundary). If not streaming, falls back to followup.
|
||||
- `followup`: enqueue for the next agent turn after the current run ends.
|
||||
@@ -30,12 +30,12 @@ Inbound messages can steer the current run, wait for a followup turn, or do both
|
||||
Steer-backlog means you can get a followup response after the steered run, so
|
||||
streaming surfaces can look like duplicates. Prefer `collect`/`steer` if you want
|
||||
one response per inbound message.
|
||||
Send `/queue collect` as a standalone command (per-session) or set `messages.queue.byProvider.discord: "collect"`.
|
||||
Send `/queue collect` as a standalone command (per-session) or set `messages.queue.byChannel.discord: "collect"`.
|
||||
|
||||
Defaults (when unset in config):
|
||||
- All surfaces → `collect`
|
||||
|
||||
Configure globally or per provider via `messages.queue`:
|
||||
Configure globally or per channel via `messages.queue`:
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -45,7 +45,7 @@ Configure globally or per provider via `messages.queue`:
|
||||
debounceMs: 1000,
|
||||
cap: 20,
|
||||
drop: "summarize",
|
||||
byProvider: { discord: "collect" }
|
||||
byChannel: { discord: "collect" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ Goal: small, hard-to-misuse tool set so agents can list sessions, fetch history,
|
||||
|
||||
## Key Model
|
||||
- Main direct chat bucket is always the literal key `"main"` (resolved to the current agent’s main key).
|
||||
- Group chats use `agent:<agentId>:<provider>:group:<id>` or `agent:<agentId>:<provider>:channel:<id>` (pass the full key).
|
||||
- Group chats use `agent:<agentId>:<channel>:group:<id>` or `agent:<agentId>:<channel>:channel:<id>` (pass the full key).
|
||||
- Cron jobs use `cron:<job.id>`.
|
||||
- Hooks use `hook:<uuid>` unless explicitly set.
|
||||
- Node bridge uses `node-<nodeId>` unless explicitly set.
|
||||
@@ -40,14 +40,14 @@ Behavior:
|
||||
Row shape (JSON):
|
||||
- `key`: session key (string)
|
||||
- `kind`: `main | group | cron | hook | node | other`
|
||||
- `provider`: `whatsapp | telegram | discord | signal | imessage | webchat | internal | unknown`
|
||||
- `channel`: `whatsapp | telegram | discord | signal | imessage | webchat | internal | unknown`
|
||||
- `displayName` (group display label if available)
|
||||
- `updatedAt` (ms)
|
||||
- `sessionId`
|
||||
- `model`, `contextTokens`, `totalTokens`
|
||||
- `thinkingLevel`, `verboseLevel`, `systemSent`, `abortedLastRun`
|
||||
- `sendPolicy` (session override if set)
|
||||
- `lastProvider`, `lastTo`
|
||||
- `lastChannel`, `lastTo`
|
||||
- `transcriptPath` (best-effort path derived from store dir + sessionId)
|
||||
- `messages?` (only when `messageLimit > 0`)
|
||||
|
||||
@@ -85,17 +85,17 @@ Behavior:
|
||||
- Max turns is `session.agentToAgent.maxPingPongTurns` (0–5, default 5).
|
||||
- Once the loop ends, Clawdbot runs the **agent‑to‑agent announce step** (target agent only):
|
||||
- Reply exactly `ANNOUNCE_SKIP` to stay silent.
|
||||
- Any other reply is sent to the target provider.
|
||||
- Any other reply is sent to the target channel.
|
||||
- Announce step includes the original request + round‑1 reply + latest ping‑pong reply.
|
||||
|
||||
## Provider Field
|
||||
- For groups, `provider` is the provider recorded on the session entry.
|
||||
- For direct chats, `provider` maps from `lastProvider`.
|
||||
- For cron/hook/node, `provider` is `internal`.
|
||||
- If missing, `provider` is `unknown`.
|
||||
## Channel Field
|
||||
- For groups, `channel` is the channel recorded on the session entry.
|
||||
- For direct chats, `channel` maps from `lastChannel`.
|
||||
- For cron/hook/node, `channel` is `internal`.
|
||||
- If missing, `channel` is `unknown`.
|
||||
|
||||
## Security / Send Policy
|
||||
Policy-based blocking by provider/chat type (not per session id).
|
||||
Policy-based blocking by channel/chat type (not per session id).
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -103,7 +103,7 @@ Policy-based blocking by provider/chat type (not per session id).
|
||||
"sendPolicy": {
|
||||
"rules": [
|
||||
{
|
||||
"match": { "provider": "discord", "chatType": "group" },
|
||||
"match": { "channel": "discord", "chatType": "group" },
|
||||
"action": "deny"
|
||||
}
|
||||
],
|
||||
@@ -122,7 +122,7 @@ Enforcement points:
|
||||
- auto-reply delivery logic
|
||||
|
||||
## sessions_spawn
|
||||
Spawn a sub-agent run in an isolated session and announce the result back to the requester chat provider.
|
||||
Spawn a sub-agent run in an isolated session and announce the result back to the requester chat channel.
|
||||
|
||||
Parameters:
|
||||
- `task` (required)
|
||||
@@ -143,7 +143,7 @@ Behavior:
|
||||
- Sub-agents default to the full tool set **minus session tools** (configurable via `tools.subagents.tools`).
|
||||
- Sub-agents are not allowed to call `sessions_spawn` (no sub-agent → sub-agent spawning).
|
||||
- Always non-blocking: returns `{ status: "accepted", runId, childSessionKey }` immediately.
|
||||
- After completion, Clawdbot runs a sub-agent **announce step** and posts the result to the requester chat provider.
|
||||
- After completion, Clawdbot runs a sub-agent **announce step** and posts the result to the requester chat channel.
|
||||
- Reply exactly `ANNOUNCE_SKIP` during the announce step to stay silent.
|
||||
- Sub-agent sessions are auto-archived after `agents.defaults.subagents.archiveAfterMinutes` (default: 60).
|
||||
- Announce replies include a stats line (runtime, tokens, sessionKey/sessionId, transcript path, and optional cost).
|
||||
|
||||
@@ -18,7 +18,7 @@ All session state is **owned by the gateway** (the “master” Clawdbot). UI cl
|
||||
- Store file: `~/.clawdbot/agents/<agentId>/sessions/sessions.json` (per agent).
|
||||
- Transcripts: `~/.clawdbot/agents/<agentId>/sessions/<SessionId>.jsonl` (Telegram topic sessions use `.../<SessionId>-topic-<threadId>.jsonl`).
|
||||
- The store is a map `sessionKey -> { sessionId, updatedAt, ... }`. Deleting entries is safe; they are recreated on demand.
|
||||
- Group entries may include `displayName`, `provider`, `subject`, `room`, and `space` to label sessions in UIs.
|
||||
- Group entries may include `displayName`, `channel`, `subject`, `room`, and `space` to label sessions in UIs.
|
||||
- Clawdbot does **not** read legacy Pi/Tau session folders.
|
||||
|
||||
## Session pruning
|
||||
@@ -33,11 +33,11 @@ the workspace is writable. See [Memory](/concepts/memory) and
|
||||
|
||||
## Mapping transports → session keys
|
||||
- Direct chats collapse to the per-agent primary key: `agent:<agentId>:<mainKey>`.
|
||||
- Multiple phone numbers and providers can map to the same agent main key; they act as transports into one conversation.
|
||||
- Group chats isolate state: `agent:<agentId>:<provider>:group:<id>` (rooms/channels use `agent:<agentId>:<provider>:channel:<id>`).
|
||||
- Multiple phone numbers and channels can map to the same agent main key; they act as transports into one conversation.
|
||||
- Group chats isolate state: `agent:<agentId>:<channel>:group:<id>` (rooms/channels use `agent:<agentId>:<channel>:channel:<id>`).
|
||||
- Telegram forum topics append `:topic:<threadId>` to the group id for isolation.
|
||||
- Legacy `group:<id>` keys are still recognized for migration.
|
||||
- Inbound contexts may still use `group:<id>`; the provider is inferred from `Provider` and normalized to the canonical `agent:<agentId>:<provider>:group:<id>` form.
|
||||
- Inbound contexts may still use `group:<id>`; the channel is inferred from `Provider` and normalized to the canonical `agent:<agentId>:<channel>:group:<id>` form.
|
||||
- Other sources:
|
||||
- Cron jobs: `cron:<job.id>`
|
||||
- Webhooks: `hook:<uuid>` (unless explicitly set by the hook)
|
||||
@@ -56,7 +56,7 @@ Block delivery for specific session types without listing individual ids.
|
||||
session: {
|
||||
sendPolicy: {
|
||||
rules: [
|
||||
{ action: "deny", match: { provider: "discord", chatType: "group" } },
|
||||
{ action: "deny", match: { channel: "discord", chatType: "group" } },
|
||||
{ action: "deny", match: { keyPrefix: "cron:" } }
|
||||
],
|
||||
default: "allow"
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
---
|
||||
summary: "Streaming + chunking behavior (block replies, draft streaming, limits)"
|
||||
read_when:
|
||||
- Explaining how streaming or chunking works on providers
|
||||
- Changing block streaming or provider chunking behavior
|
||||
- Explaining how streaming or chunking works on channels
|
||||
- Changing block streaming or channel chunking behavior
|
||||
- Debugging duplicate/early block replies or draft streaming
|
||||
---
|
||||
# Streaming + chunking
|
||||
|
||||
Clawdbot has two separate “streaming” layers:
|
||||
- **Block streaming (providers):** emit completed **blocks** as the assistant writes. These are normal provider messages (not token deltas).
|
||||
- **Block streaming (channels):** emit completed **blocks** as the assistant writes. These are normal channel messages (not token deltas).
|
||||
- **Token-ish streaming (Telegram only):** update a **draft bubble** with partial text while generating; final message is sent at the end.
|
||||
|
||||
There is **no real token streaming** to external provider messages today. Telegram draft streaming is the only partial-stream surface.
|
||||
There is **no real token streaming** to external channel messages today. Telegram draft streaming is the only partial-stream surface.
|
||||
|
||||
## Block streaming (provider messages)
|
||||
## Block streaming (channel messages)
|
||||
|
||||
Block streaming sends assistant output in coarse chunks as it becomes available.
|
||||
|
||||
@@ -24,20 +24,20 @@ Model output
|
||||
│ └─ chunker emits blocks as buffer grows
|
||||
└─ (blockStreamingBreak=message_end)
|
||||
└─ chunker flushes at message_end
|
||||
└─ provider send (block replies)
|
||||
└─ channel send (block replies)
|
||||
```
|
||||
Legend:
|
||||
- `text_delta/events`: model stream events (may be sparse for non-streaming models).
|
||||
- `chunker`: `EmbeddedBlockChunker` applying min/max bounds + break preference.
|
||||
- `provider send`: actual outbound messages (block replies).
|
||||
- `channel send`: actual outbound messages (block replies).
|
||||
|
||||
**Controls:**
|
||||
- `agents.defaults.blockStreamingDefault`: `"on"`/`"off"` (default off).
|
||||
- Provider overrides: `*.blockStreaming` (and per-account variants) to force `"on"`/`"off"` per provider.
|
||||
- Channel overrides: `*.blockStreaming` (and per-account variants) to force `"on"`/`"off"` per channel.
|
||||
- `agents.defaults.blockStreamingBreak`: `"text_end"` or `"message_end"`.
|
||||
- `agents.defaults.blockStreamingChunk`: `{ minChars, maxChars, breakPreference? }`.
|
||||
- `agents.defaults.blockStreamingCoalesce`: `{ minChars?, maxChars?, idleMs? }` (merge streamed blocks before send).
|
||||
- Provider hard cap: `*.textChunkLimit` (e.g., `channels.whatsapp.textChunkLimit`).
|
||||
- Channel hard cap: `*.textChunkLimit` (e.g., `channels.whatsapp.textChunkLimit`).
|
||||
- Discord soft cap: `channels.discord.maxLinesPerMessage` (default 17) splits tall replies to avoid UI clipping.
|
||||
|
||||
**Boundary semantics:**
|
||||
@@ -54,7 +54,7 @@ Block chunking is implemented by `EmbeddedBlockChunker`:
|
||||
- **Break preference:** `paragraph` → `newline` → `sentence` → `whitespace` → hard break.
|
||||
- **Code fences:** never split inside fences; when forced at `maxChars`, close + reopen the fence to keep Markdown valid.
|
||||
|
||||
`maxChars` is clamped to the provider `textChunkLimit`, so you can’t exceed per-provider caps.
|
||||
`maxChars` is clamped to the channel `textChunkLimit`, so you can’t exceed per-channel caps.
|
||||
|
||||
## Coalescing (merge streamed blocks)
|
||||
|
||||
@@ -68,7 +68,7 @@ progressive output.
|
||||
(final flush always sends remaining text).
|
||||
- Joiner is derived from `blockStreamingChunk.breakPreference`
|
||||
(`paragraph` → `\n\n`, `newline` → `\n`, `sentence` → space).
|
||||
- Provider overrides are available via `*.blockStreamingCoalesce` (including per-account configs).
|
||||
- Channel overrides are available via `*.blockStreamingCoalesce` (including per-account configs).
|
||||
- Default coalesce `minChars` is bumped to 1500 for Signal/Slack/Discord unless overridden.
|
||||
|
||||
## Human-like pacing between blocks
|
||||
@@ -84,11 +84,11 @@ more natural.
|
||||
## “Stream chunks or everything”
|
||||
|
||||
This maps to:
|
||||
- **Stream chunks:** `blockStreamingDefault: "on"` + `blockStreamingBreak: "text_end"` (emit as you go). Non-Telegram providers also need `*.blockStreaming: true`.
|
||||
- **Stream chunks:** `blockStreamingDefault: "on"` + `blockStreamingBreak: "text_end"` (emit as you go). Non-Telegram channels also need `*.blockStreaming: true`.
|
||||
- **Stream everything at end:** `blockStreamingBreak: "message_end"` (flush once, possibly multiple chunks if very long).
|
||||
- **No block streaming:** `blockStreamingDefault: "off"` (only final reply).
|
||||
|
||||
**Provider note:** For non-Telegram providers, block streaming is **off unless**
|
||||
**Channel note:** For non-Telegram channels, block streaming is **off unless**
|
||||
`*.blockStreaming` is explicitly set to `true`. Telegram can stream drafts
|
||||
(`channels.telegram.streamMode`) without block replies.
|
||||
|
||||
@@ -97,14 +97,14 @@ Config location reminder: the `blockStreaming*` defaults live under
|
||||
|
||||
## Telegram draft streaming (token-ish)
|
||||
|
||||
Telegram is the only provider with draft streaming:
|
||||
Telegram is the only channel with draft streaming:
|
||||
- Uses Bot API `sendMessageDraft` in **private chats with topics**.
|
||||
- `channels.telegram.streamMode: "partial" | "block" | "off"`.
|
||||
- `partial`: draft updates with the latest stream text.
|
||||
- `block`: draft updates in chunked blocks (same chunker rules).
|
||||
- `off`: no draft streaming.
|
||||
- Draft chunk config (only for `streamMode: "block"`): `channels.telegram.draftChunk` (defaults: `minChars: 200`, `maxChars: 800`).
|
||||
- Draft streaming is separate from block streaming; block replies are off by default and only enabled by `*.blockStreaming: true` on non-Telegram providers.
|
||||
- Draft streaming is separate from block streaming; block replies are off by default and only enabled by `*.blockStreaming: true` on non-Telegram channels.
|
||||
- Final reply is still a normal message.
|
||||
- `/reasoning stream` writes reasoning into the draft bubble (Telegram only).
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ read_when:
|
||||
---
|
||||
# Typing indicators
|
||||
|
||||
Typing indicators are sent to the chat provider while a run is active. Use
|
||||
Typing indicators are sent to the chat channel while a run is active. Use
|
||||
`agents.defaults.typingMode` to control **when** typing starts and `typingIntervalSeconds`
|
||||
to control **how often** it refreshes.
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ Save to `~/.clawdbot/clawdbot.json` and you can DM the bot from that number.
|
||||
debounceMs: 1000,
|
||||
cap: 20,
|
||||
drop: "summarize",
|
||||
byProvider: {
|
||||
byChannel: {
|
||||
whatsapp: "collect",
|
||||
telegram: "collect",
|
||||
discord: "collect",
|
||||
@@ -143,12 +143,12 @@ Save to `~/.clawdbot/clawdbot.json` and you can DM the bot from that number.
|
||||
sendPolicy: {
|
||||
default: "allow",
|
||||
rules: [
|
||||
{ action: "deny", match: { provider: "discord", chatType: "group" } }
|
||||
{ action: "deny", match: { channel: "discord", chatType: "group" } }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
// Providers
|
||||
// Channels
|
||||
channels: {
|
||||
whatsapp: {
|
||||
dmPolicy: "pairing",
|
||||
@@ -345,7 +345,7 @@ Save to `~/.clawdbot/clawdbot.json` and you can DM the bot from that number.
|
||||
messageTemplate: "From: {{messages[0].from}}\nSubject: {{messages[0].subject}}",
|
||||
textTemplate: "{{messages[0].snippet}}",
|
||||
deliver: true,
|
||||
provider: "last",
|
||||
channel: "last",
|
||||
to: "+15555550123",
|
||||
thinking: "low",
|
||||
timeoutSeconds: 300,
|
||||
|
||||
@@ -376,7 +376,7 @@ Controls how WhatsApp direct chats (DMs) are handled:
|
||||
- `"open"`: allow all inbound DMs (**requires** `channels.whatsapp.allowFrom` to include `"*"`)
|
||||
- `"disabled"`: ignore all inbound DMs
|
||||
|
||||
Pairing codes expire after 1 hour; the bot only sends a pairing code when a new request is created. Pending DM pairing requests are capped at **3 per provider** by default.
|
||||
Pairing codes expire after 1 hour; the bot only sends a pairing code when a new request is created. Pending DM pairing requests are capped at **3 per channel** by default.
|
||||
|
||||
Pairing approvals:
|
||||
- `clawdbot pairing list whatsapp`
|
||||
@@ -428,7 +428,7 @@ Notes:
|
||||
|
||||
### `channels.telegram.accounts` / `channels.discord.accounts` / `channels.slack.accounts` / `channels.signal.accounts` / `channels.imessage.accounts`
|
||||
|
||||
Run multiple accounts per provider (each account has its own `accountId` and optional `name`):
|
||||
Run multiple accounts per channel (each account has its own `accountId` and optional `name`):
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -452,7 +452,7 @@ Run multiple accounts per provider (each account has its own `accountId` and opt
|
||||
Notes:
|
||||
- `default` is used when `accountId` is omitted (CLI + routing).
|
||||
- Env tokens only apply to the **default** account.
|
||||
- Base provider settings (group policy, mention gating, etc.) apply to all accounts unless overridden per account.
|
||||
- Base channel settings (group policy, mention gating, etc.) apply to all accounts unless overridden per account.
|
||||
- Use `bindings[].match.accountId` to route each account to a different agents.defaults.
|
||||
|
||||
### Group chat mention gating (`agents.list[].groupChat` + `messages.groupChat`)
|
||||
@@ -477,7 +477,7 @@ Group messages default to **require mention** (either metadata mention or regex
|
||||
}
|
||||
```
|
||||
|
||||
`messages.groupChat.historyLimit` sets the global default for group history context. Providers can override with `channels.<provider>.historyLimit` (or `channels.<provider>.accounts.*.historyLimit` for multi-account). Set `0` to disable history wrapping.
|
||||
`messages.groupChat.historyLimit` sets the global default for group history context. Channels can override with `channels.<channel>.historyLimit` (or `channels.<channel>.accounts.*.historyLimit` for multi-account). Set `0` to disable history wrapping.
|
||||
|
||||
Per-agent override (takes precedence when set, even `[]`):
|
||||
```json5
|
||||
@@ -491,7 +491,7 @@ Per-agent override (takes precedence when set, even `[]`):
|
||||
}
|
||||
```
|
||||
|
||||
Mention gating defaults live per provider (`channels.whatsapp.groups`, `channels.telegram.groups`, `channels.imessage.groups`, `channels.discord.guilds`). When `*.groups` is set, it also acts as a group allowlist; include `"*"` to allow all groups.
|
||||
Mention gating defaults live per channel (`channels.whatsapp.groups`, `channels.telegram.groups`, `channels.imessage.groups`, `channels.discord.guilds`). When `*.groups` is set, it also acts as a group allowlist; include `"*"` to allow all groups.
|
||||
|
||||
To respond **only** to specific text triggers (ignoring native @-mentions):
|
||||
```json5
|
||||
@@ -517,7 +517,7 @@ To respond **only** to specific text triggers (ignoring native @-mentions):
|
||||
}
|
||||
```
|
||||
|
||||
### Group policy (per provider)
|
||||
### Group policy (per channel)
|
||||
|
||||
Use `channels.*.groupPolicy` to control whether group/room messages are accepted at all:
|
||||
|
||||
@@ -602,17 +602,17 @@ Inbound messages are routed to an agent via bindings.
|
||||
- `deny`: array of denied tool names (deny wins)
|
||||
- `agents.defaults`: shared agent defaults (model, workspace, sandbox, etc.).
|
||||
- `bindings[]`: routes inbound messages to an `agentId`.
|
||||
- `match.provider` (required)
|
||||
- `match.channel` (required)
|
||||
- `match.accountId` (optional; `*` = any account; omitted = default account)
|
||||
- `match.peer` (optional; `{ kind: dm|group|channel, id }`)
|
||||
- `match.guildId` / `match.teamId` (optional; provider-specific)
|
||||
- `match.guildId` / `match.teamId` (optional; channel-specific)
|
||||
|
||||
Deterministic match order:
|
||||
1) `match.peer`
|
||||
2) `match.guildId`
|
||||
3) `match.teamId`
|
||||
4) `match.accountId` (exact, no peer/guild/team)
|
||||
5) `match.accountId: "*"` (provider-wide, no peer/guild/team)
|
||||
5) `match.accountId: "*"` (channel-wide, no peer/guild/team)
|
||||
6) default agent (`agents.list[].default`, else first list entry, else `"main"`)
|
||||
|
||||
Within each match tier, the first matching entry in `bindings` wins.
|
||||
@@ -700,8 +700,8 @@ Example: two WhatsApp accounts → two agents:
|
||||
]
|
||||
},
|
||||
bindings: [
|
||||
{ agentId: "home", match: { provider: "whatsapp", accountId: "personal" } },
|
||||
{ agentId: "work", match: { provider: "whatsapp", accountId: "biz" } }
|
||||
{ agentId: "home", match: { channel: "whatsapp", accountId: "personal" } },
|
||||
{ agentId: "work", match: { channel: "whatsapp", accountId: "biz" } }
|
||||
],
|
||||
channels: {
|
||||
whatsapp: {
|
||||
@@ -741,7 +741,7 @@ Controls how inbound messages behave when an agent run is already active.
|
||||
debounceMs: 1000,
|
||||
cap: 20,
|
||||
drop: "summarize", // old | new | summarize
|
||||
byProvider: {
|
||||
byChannel: {
|
||||
whatsapp: "collect",
|
||||
telegram: "collect",
|
||||
discord: "collect",
|
||||
@@ -784,9 +784,9 @@ Notes:
|
||||
- `commands.restart: true` enables `/restart` and the gateway tool restart action.
|
||||
- `commands.useAccessGroups: false` allows commands to bypass access-group allowlists/policies.
|
||||
|
||||
### `web` (WhatsApp web provider)
|
||||
### `web` (WhatsApp web channel runtime)
|
||||
|
||||
WhatsApp runs through the gateway’s web provider. It starts automatically when a linked session exists.
|
||||
WhatsApp runs through the gateway’s web channel (Baileys Web). It starts automatically when a linked session exists.
|
||||
Set `web.enabled: false` to keep it off by default.
|
||||
|
||||
```json5
|
||||
@@ -1483,8 +1483,8 @@ Example (tuned):
|
||||
|
||||
Block streaming:
|
||||
- `agents.defaults.blockStreamingDefault`: `"on"`/`"off"` (default off).
|
||||
- Provider overrides: `*.blockStreaming` (and per-account variants) to force block streaming on/off.
|
||||
Non-Telegram providers require an explicit `*.blockStreaming: true` to enable block replies.
|
||||
- Channel overrides: `*.blockStreaming` (and per-account variants) to force block streaming on/off.
|
||||
Non-Telegram channels require an explicit `*.blockStreaming: true` to enable block replies.
|
||||
- `agents.defaults.blockStreamingBreak`: `"text_end"` or `"message_end"` (default: text_end).
|
||||
- `agents.defaults.blockStreamingChunk`: soft chunking for streamed blocks. Defaults to
|
||||
800–1200 chars, prefers paragraph breaks (`\n\n`), then newlines, then sentences.
|
||||
@@ -1496,9 +1496,9 @@ Block streaming:
|
||||
```
|
||||
- `agents.defaults.blockStreamingCoalesce`: merge streamed blocks before sending.
|
||||
Defaults to `{ idleMs: 1000 }` and inherits `minChars` from `blockStreamingChunk`
|
||||
with `maxChars` capped to the provider text limit. Signal/Slack/Discord default
|
||||
with `maxChars` capped to the channel text limit. Signal/Slack/Discord default
|
||||
to `minChars: 1500` unless overridden.
|
||||
Provider overrides: `channels.whatsapp.blockStreamingCoalesce`, `channels.telegram.blockStreamingCoalesce`,
|
||||
Channel overrides: `channels.whatsapp.blockStreamingCoalesce`, `channels.telegram.blockStreamingCoalesce`,
|
||||
`channels.discord.blockStreamingCoalesce`, `channels.slack.blockStreamingCoalesce`, `channels.signal.blockStreamingCoalesce`,
|
||||
`channels.imessage.blockStreamingCoalesce`, `channels.msteams.blockStreamingCoalesce` (and per-account variants).
|
||||
- `agents.defaults.humanDelay`: randomized pause between **block replies** after the first.
|
||||
@@ -1532,8 +1532,8 @@ Z.AI models are available as `zai/<model>` (e.g. `zai/glm-4.7`) and require
|
||||
`30m`. Set `0m` to disable.
|
||||
- `model`: optional override model for heartbeat runs (`provider/model`).
|
||||
- `includeReasoning`: when `true`, heartbeats will also deliver the separate `Reasoning:` message when available (same shape as `/reasoning on`). Default: `false`.
|
||||
- `target`: optional delivery provider (`last`, `whatsapp`, `telegram`, `discord`, `slack`, `signal`, `imessage`, `none`). Default: `last`.
|
||||
- `to`: optional recipient override (provider-specific id, e.g. E.164 for WhatsApp, chat id for Telegram).
|
||||
- `target`: optional delivery channel (`last`, `whatsapp`, `telegram`, `discord`, `slack`, `signal`, `imessage`, `none`). Default: `last`.
|
||||
- `to`: optional recipient override (channel-specific id, e.g. E.164 for WhatsApp, chat id for Telegram).
|
||||
- `prompt`: optional override for the heartbeat body (default: `Read HEARTBEAT.md if exists. Consider outstanding tasks. Checkup sometimes on your human during (user local) day time.`). Overrides are sent verbatim; include a `Read HEARTBEAT.md if exists` line if you still want the file read.
|
||||
- `ackMaxChars`: max chars allowed after `HEARTBEAT_OK` before delivery (default: 300).
|
||||
|
||||
@@ -1606,7 +1606,7 @@ Tool groups (shorthands) work in **global** and **per-agent** tool policies:
|
||||
|
||||
`tools.elevated` controls elevated (host) exec access:
|
||||
- `enabled`: allow elevated mode (default true)
|
||||
- `allowFrom`: per-provider allowlists (empty = disabled)
|
||||
- `allowFrom`: per-channel allowlists (empty = disabled)
|
||||
- `whatsapp`: E.164 numbers
|
||||
- `telegram`: chat ids or usernames
|
||||
- `discord`: user ids or usernames (falls back to `channels.discord.dm.allowFrom` if omitted)
|
||||
@@ -2082,12 +2082,12 @@ Controls session scoping, idle expiry, reset triggers, and where the session sto
|
||||
// Max ping-pong reply turns between requester/target (0–5).
|
||||
maxPingPongTurns: 5
|
||||
},
|
||||
sendPolicy: {
|
||||
rules: [
|
||||
{ action: "deny", match: { provider: "discord", chatType: "group" } }
|
||||
],
|
||||
default: "allow"
|
||||
}
|
||||
sendPolicy: {
|
||||
rules: [
|
||||
{ action: "deny", match: { channel: "discord", chatType: "group" } }
|
||||
],
|
||||
default: "allow"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -2097,7 +2097,7 @@ Fields:
|
||||
- Sandbox note: `agents.defaults.sandbox.mode: "non-main"` uses this key to detect the main session. Any session key that does not match `mainKey` (groups/channels) is sandboxed.
|
||||
- `agentToAgent.maxPingPongTurns`: max reply-back turns between requester/target (0–5, default 5).
|
||||
- `sendPolicy.default`: `allow` or `deny` fallback when no rule matches.
|
||||
- `sendPolicy.rules[]`: match by `provider`, `chatType` (`direct|group|room`), or `keyPrefix` (e.g. `cron:`). First deny wins; otherwise allow.
|
||||
- `sendPolicy.rules[]`: match by `channel`, `chatType` (`direct|group|room`), or `keyPrefix` (e.g. `cron:`). First deny wins; otherwise allow.
|
||||
|
||||
### `skills` (skills config)
|
||||
|
||||
@@ -2349,8 +2349,8 @@ Hot-applied (no full gateway restart):
|
||||
- `browser` (browser control server restart)
|
||||
- `cron` (cron service restart + concurrency update)
|
||||
- `agents.defaults.heartbeat` (heartbeat runner restart)
|
||||
- `web` (WhatsApp web provider restart)
|
||||
- `telegram`, `discord`, `signal`, `imessage` (provider restarts)
|
||||
- `web` (WhatsApp web channel restart)
|
||||
- `telegram`, `discord`, `signal`, `imessage` (channel restarts)
|
||||
- `agent`, `models`, `routing`, `messages`, `session`, `whatsapp`, `logging`, `skills`, `ui`, `talk`, `identity`, `wizard` (dynamic reads)
|
||||
|
||||
Requires full Gateway restart:
|
||||
@@ -2409,7 +2409,7 @@ Defaults:
|
||||
messageTemplate:
|
||||
"From: {{messages[0].from}}\nSubject: {{messages[0].subject}}\n{{messages[0].snippet}}",
|
||||
deliver: true,
|
||||
provider: "last",
|
||||
channel: "last",
|
||||
model: "openai/gpt-5.2-mini",
|
||||
},
|
||||
],
|
||||
@@ -2424,7 +2424,7 @@ Requests must include the hook token:
|
||||
|
||||
Endpoints:
|
||||
- `POST /hooks/wake` → `{ text, mode?: "now"|"next-heartbeat" }`
|
||||
- `POST /hooks/agent` → `{ message, name?, sessionKey?, wakeMode?, deliver?, provider?, to?, model?, thinking?, timeoutSeconds? }`
|
||||
- `POST /hooks/agent` → `{ message, name?, sessionKey?, wakeMode?, deliver?, channel?, to?, model?, thinking?, timeoutSeconds? }`
|
||||
- `POST /hooks/<name>` → resolved via `hooks.mappings`
|
||||
|
||||
`/hooks/agent` always posts a summary into the main session (and can optionally trigger an immediate heartbeat via `wakeMode: "now"`).
|
||||
@@ -2434,8 +2434,8 @@ Mapping notes:
|
||||
- `match.source` matches a payload field (e.g. `{ source: "gmail" }`) so you can use a generic `/hooks/ingest` path.
|
||||
- Templates like `{{messages[0].subject}}` read from the payload.
|
||||
- `transform` can point to a JS/TS module that returns a hook action.
|
||||
- `deliver: true` sends the final reply to a provider; `provider` defaults to `last` (falls back to WhatsApp).
|
||||
- If there is no prior delivery route, set `provider` + `to` explicitly (required for Telegram/Discord/Slack/Signal/iMessage/MS Teams).
|
||||
- `deliver: true` sends the final reply to a channel; `channel` defaults to `last` (falls back to WhatsApp).
|
||||
- If there is no prior delivery route, set `channel` + `to` explicitly (required for Telegram/Discord/Slack/Signal/iMessage/MS Teams).
|
||||
- `model` overrides the LLM for this hook run (`provider/model` or alias; must be allowed if `agents.defaults.models` is set).
|
||||
|
||||
Gmail helper config (used by `clawdbot hooks gmail setup` / `run`):
|
||||
@@ -2574,9 +2574,9 @@ Template placeholders are expanded in `tools.audio.transcription.args` (and any
|
||||
| `{{Body}}` | Full inbound message body |
|
||||
| `{{RawBody}}` | Raw inbound message body (no history/sender wrappers; best for command parsing) |
|
||||
| `{{BodyStripped}}` | Body with group mentions stripped (best default for agents) |
|
||||
| `{{From}}` | Sender identifier (E.164 for WhatsApp; may differ per provider) |
|
||||
| `{{From}}` | Sender identifier (E.164 for WhatsApp; may differ per channel) |
|
||||
| `{{To}}` | Destination identifier |
|
||||
| `{{MessageSid}}` | Provider message id (when available) |
|
||||
| `{{MessageSid}}` | Channel message id (when available) |
|
||||
| `{{SessionId}}` | Current session UUID |
|
||||
| `{{IsNewSession}}` | `"true"` when a new session was created |
|
||||
| `{{MediaUrl}}` | Inbound media pseudo-URL (if present) |
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
---
|
||||
summary: "Health check steps for provider connectivity"
|
||||
summary: "Health check steps for channel connectivity"
|
||||
read_when:
|
||||
- Diagnosing web provider health
|
||||
- Diagnosing WhatsApp channel health
|
||||
---
|
||||
# Health Checks (CLI)
|
||||
|
||||
Short guide to verify provider connectivity without guessing.
|
||||
Short guide to verify channel connectivity without guessing.
|
||||
|
||||
## Quick checks
|
||||
- `clawdbot status` — local summary: gateway reachability/mode, update hint, link provider auth age, sessions + recent activity.
|
||||
- `clawdbot status` — local summary: gateway reachability/mode, update hint, linked channel auth age, sessions + recent activity.
|
||||
- `clawdbot status --all` — full local diagnosis (read-only, color, safe to paste for debugging).
|
||||
- `clawdbot status --deep` — also probes the running Gateway (per-provider probes when supported).
|
||||
- `clawdbot status --deep` — also probes the running Gateway (per-channel probes when supported).
|
||||
- `clawdbot health --json` — asks the running Gateway for a full health snapshot (WS-only; no direct Baileys socket).
|
||||
- Send `/status` as a standalone message in WhatsApp/WebChat to get a status reply without invoking the agent.
|
||||
- Logs: tail `/tmp/clawdbot/clawdbot-*.log` and filter for `web-heartbeat`, `web-reconnect`, `web-auto-reply`, `web-inbound`.
|
||||
@@ -26,4 +26,4 @@ Short guide to verify provider connectivity without guessing.
|
||||
- No inbound messages → confirm linked phone is online and the sender is allowed (`channels.whatsapp.allowFrom`); for group chats, ensure allowlist + mention rules match (`channels.whatsapp.groups`, `agents.list[].groupChat.mentionPatterns`).
|
||||
|
||||
## Dedicated "health" command
|
||||
`clawdbot health --json` asks the running Gateway for its health snapshot (no direct provider sockets from the CLI). It reports linked creds/auth age when available, per-provider probe summaries, session-store summary, and a probe duration. It exits non-zero if the Gateway is unreachable or the probe fails/timeouts. Use `--timeout <ms>` to override the 10s default.
|
||||
`clawdbot health --json` asks the running Gateway for its health snapshot (no direct channel sockets from the CLI). It reports linked creds/auth age when available, per-channel probe summaries, session-store summary, and a probe duration. It exits non-zero if the Gateway is unreachable or the probe fails/timeouts. Use `--timeout <ms>` to override the 10s default.
|
||||
|
||||
@@ -76,7 +76,7 @@ and logged; a message that is only `HEARTBEAT_OK` is dropped.
|
||||
model: "anthropic/claude-opus-4-5",
|
||||
includeReasoning: false, // default: false (deliver separate Reasoning: message when available)
|
||||
target: "last", // last | whatsapp | telegram | discord | slack | signal | imessage | none
|
||||
to: "+15551234567", // optional provider-specific override
|
||||
to: "+15551234567", // optional channel-specific override
|
||||
prompt: "Read HEARTBEAT.md if exists. Consider outstanding tasks. Checkup sometimes on your human during (user local) day time.",
|
||||
ackMaxChars: 300 // max chars allowed after HEARTBEAT_OK
|
||||
}
|
||||
@@ -91,8 +91,8 @@ and logged; a message that is only `HEARTBEAT_OK` is dropped.
|
||||
- `model`: optional model override for heartbeat runs (`provider/model`).
|
||||
- `includeReasoning`: when enabled, also deliver the separate `Reasoning:` message when available (same shape as `/reasoning on`).
|
||||
- `target`:
|
||||
- `last` (default): deliver to the last used external provider.
|
||||
- explicit provider: `whatsapp` / `telegram` / `discord` / `slack` / `signal` / `imessage`.
|
||||
- `last` (default): deliver to the last used external channel.
|
||||
- explicit channel: `whatsapp` / `telegram` / `discord` / `slack` / `signal` / `imessage`.
|
||||
- `none`: run the heartbeat but **do not deliver** externally.
|
||||
- `to`: optional recipient override (E.164 for WhatsApp, chat id for Telegram, etc.).
|
||||
- `prompt`: overrides the default prompt body (not merged).
|
||||
|
||||
@@ -125,7 +125,7 @@ CLAWDBOT_CONFIG_PATH=~/.clawdbot/b.json CLAWDBOT_STATE_DIR=~/.clawdbot-b clawdbo
|
||||
- `status` — short summary.
|
||||
- `system-presence` — current presence list.
|
||||
- `system-event` — post a presence/system note (structured).
|
||||
- `send` — send a message via the active provider(s).
|
||||
- `send` — send a message via the active channel(s).
|
||||
- `agent` — run an agent turn (streams events back on same connection).
|
||||
- `node.list` — list paired + currently-connected bridge nodes (includes `caps`, `deviceFamily`, `modelIdentifier`, `paired`, `connected`, and advertised `commands`).
|
||||
- `node.describe` — describe a node (capabilities + supported `node.invoke` commands; works for paired nodes and for currently-connected unpaired nodes).
|
||||
@@ -268,7 +268,7 @@ Windows installs should use **WSL2** and follow the Linux systemd section above.
|
||||
|
||||
## Operational checks
|
||||
- Liveness: open WS and send `req:connect` → expect `res` with `payload.type="hello-ok"` (with snapshot).
|
||||
- Readiness: call `health` → expect `ok: true` and a linked provider in the `providers` payload (when applicable).
|
||||
- Readiness: call `health` → expect `ok: true` and a linked channel in `linkChannel` (when applicable).
|
||||
- Debug: subscribe to `tick` and `presence` events; ensure `status` shows linked/auth age; presence entries show Gateway host and connected clients.
|
||||
|
||||
## Safety guarantees
|
||||
|
||||
@@ -45,18 +45,18 @@ Plugins run **in-process** with the Gateway. Treat them as trusted code:
|
||||
|
||||
## DM access model (pairing / allowlist / open / disabled)
|
||||
|
||||
All current DM-capable providers support a DM policy (`dmPolicy` or `*.dm.policy`) that gates inbound DMs **before** the message is processed:
|
||||
All current DM-capable channels support a DM policy (`dmPolicy` or `*.dm.policy`) that gates inbound DMs **before** the message is processed:
|
||||
|
||||
- `pairing` (default): unknown senders receive a short pairing code and the bot ignores their message until approved. Codes expire after 1 hour; repeated DMs won’t resend a code until a new request is created. Pending requests are capped at **3 per provider** by default.
|
||||
- `pairing` (default): unknown senders receive a short pairing code and the bot ignores their message until approved. Codes expire after 1 hour; repeated DMs won’t resend a code until a new request is created. Pending requests are capped at **3 per channel** by default.
|
||||
- `allowlist`: unknown senders are blocked (no pairing handshake).
|
||||
- `open`: allow anyone to DM (public). **Requires** the provider allowlist to include `"*"` (explicit opt-in).
|
||||
- `open`: allow anyone to DM (public). **Requires** the channel allowlist to include `"*"` (explicit opt-in).
|
||||
- `disabled`: ignore inbound DMs entirely.
|
||||
|
||||
Approve via CLI:
|
||||
|
||||
```bash
|
||||
clawdbot pairing list <provider>
|
||||
clawdbot pairing approve <provider> <code>
|
||||
clawdbot pairing list <channel>
|
||||
clawdbot pairing approve <channel> <code>
|
||||
```
|
||||
|
||||
Details + files on disk: [Pairing](/start/pairing)
|
||||
@@ -66,8 +66,8 @@ Details + files on disk: [Pairing](/start/pairing)
|
||||
Clawdbot has two separate “who can trigger me?” layers:
|
||||
|
||||
- **DM allowlist** (`allowFrom` / `channels.discord.dm.allowFrom` / `channels.slack.dm.allowFrom`): who is allowed to talk to the bot in direct messages.
|
||||
- When `dmPolicy="pairing"`, approvals are written to `~/.clawdbot/credentials/<provider>-allowFrom.json` (merged with config allowlists).
|
||||
- **Group allowlist** (provider-specific): which groups/channels/guilds the bot will accept messages from at all.
|
||||
- When `dmPolicy="pairing"`, approvals are written to `~/.clawdbot/credentials/<channel>-allowFrom.json` (merged with config allowlists).
|
||||
- **Group allowlist** (channel-specific): which groups/channels/guilds the bot will accept messages from at all.
|
||||
- Common patterns:
|
||||
- `channels.whatsapp.groups`, `channels.telegram.groups`, `channels.imessage.groups`: per-group defaults like `requireMention`; when set, it also acts as a group allowlist (include `"*"` to keep allow-all behavior).
|
||||
- `groupPolicy="allowlist"` + `groupAllowFrom`: restrict who can trigger the bot *inside* a group session (WhatsApp/Telegram/Signal/iMessage/Microsoft Teams).
|
||||
|
||||
@@ -75,7 +75,7 @@ managers (pnpm/npm) because the daemon does not load your shell init. Runtime
|
||||
variables like `DISPLAY` should live in `~/.clawdbot/.env` (loaded early by the
|
||||
gateway).
|
||||
|
||||
WhatsApp + Telegram providers require **Node**; Bun is unsupported. If your
|
||||
WhatsApp + Telegram channels require **Node**; Bun is unsupported. If your
|
||||
service was installed with Bun or a version-managed Node path, run `clawdbot doctor`
|
||||
to migrate to a system Node install.
|
||||
|
||||
@@ -174,7 +174,7 @@ Look for `AllowFrom: ...` in the output.
|
||||
|
||||
**Check 2:** For group chats, is mention required?
|
||||
```bash
|
||||
# The message must match mentionPatterns or explicit mentions; defaults live in provider groups/guilds.
|
||||
# The message must match mentionPatterns or explicit mentions; defaults live in channel groups/guilds.
|
||||
# Multi-agent: `agents.list[].groupChat.mentionPatterns` overrides global patterns.
|
||||
grep -n "agents\\|groupChat\\|mentionPatterns\\|channels\\.whatsapp\\.groups\\|channels\\.telegram\\.groups\\|channels\\.imessage\\.groups\\|channels\\.discord\\.guilds" \
|
||||
"${CLAWDBOT_CONFIG_PATH:-$HOME/.clawdbot/clawdbot.json}"
|
||||
@@ -193,17 +193,17 @@ If `dmPolicy` is `pairing`, unknown senders should receive a code and their mess
|
||||
|
||||
**Check 1:** Is a pending request already waiting?
|
||||
```bash
|
||||
clawdbot pairing list <provider>
|
||||
clawdbot pairing list <channel>
|
||||
```
|
||||
|
||||
Pending DM pairing requests are capped at **3 per provider** by default. If the list is full, new requests won’t generate a code until one is approved or expires.
|
||||
Pending DM pairing requests are capped at **3 per channel** by default. If the list is full, new requests won’t generate a code until one is approved or expires.
|
||||
|
||||
**Check 2:** Did the request get created but no reply was sent?
|
||||
```bash
|
||||
clawdbot logs --follow | grep "pairing request"
|
||||
```
|
||||
|
||||
**Check 3:** Confirm `dmPolicy` isn’t `open`/`allowlist` for that provider.
|
||||
**Check 3:** Confirm `dmPolicy` isn’t `open`/`allowlist` for that channel.
|
||||
|
||||
### Image + Mention Not Working
|
||||
|
||||
@@ -250,7 +250,7 @@ Or use the `process` tool to background long commands.
|
||||
```bash
|
||||
# Check local status (creds, sessions, queued events)
|
||||
clawdbot status
|
||||
# Probe the running gateway + providers (WA connect + Telegram + Discord APIs)
|
||||
# Probe the running gateway + channels (WA connect + Telegram + Discord APIs)
|
||||
clawdbot status --deep
|
||||
|
||||
# View recent connection events
|
||||
|
||||
@@ -62,7 +62,7 @@ WhatsApp / Telegram / Discord
|
||||
└─ Android node via Bridge + pairing
|
||||
```
|
||||
|
||||
Most operations flow through the **Gateway** (`clawdbot gateway`), a single long-running process that owns provider connections and the WebSocket control plane.
|
||||
Most operations flow through the **Gateway** (`clawdbot gateway`), a single long-running process that owns channel connections and the WebSocket control plane.
|
||||
|
||||
## Network model
|
||||
|
||||
|
||||
@@ -68,9 +68,9 @@ clawdbot doctor
|
||||
The Control UI’s **Logs** tab tails the same file using `logs.tail`.
|
||||
See [/web/control-ui](/web/control-ui) for how to open it.
|
||||
|
||||
### Provider-only logs
|
||||
### Channel-only logs
|
||||
|
||||
To filter provider activity (WhatsApp/Telegram/etc), use:
|
||||
To filter channel activity (WhatsApp/Telegram/etc), use:
|
||||
|
||||
```bash
|
||||
clawdbot channels logs --channel whatsapp
|
||||
|
||||
@@ -5,7 +5,7 @@ read_when:
|
||||
---
|
||||
# Image & Media Support — 2025-12-05
|
||||
|
||||
Clawdbot is now **web-only** (Baileys). This document captures the current media handling rules for send, gateway, and agent replies.
|
||||
The WhatsApp channel runs via **Baileys Web**. This document captures the current media handling rules for send, gateway, and agent replies.
|
||||
|
||||
## Goals
|
||||
- Send media with optional captions via `clawdbot message send --media`.
|
||||
@@ -15,9 +15,9 @@ Clawdbot is now **web-only** (Baileys). This document captures the current media
|
||||
## CLI Surface
|
||||
- `clawdbot message send --media <path-or-url> [--message <caption>]`
|
||||
- `--media` optional; caption can be empty for media-only sends.
|
||||
- `--dry-run` prints the resolved payload; `--json` emits `{ provider, to, messageId, mediaUrl, caption }`.
|
||||
- `--dry-run` prints the resolved payload; `--json` emits `{ channel, to, messageId, mediaUrl, caption }`.
|
||||
|
||||
## Web Provider Behavior
|
||||
## WhatsApp Web channel behavior
|
||||
- Input: local file path **or** HTTP(S) URL.
|
||||
- Flow: load into a Buffer, detect media kind, and build the correct payload:
|
||||
- **Images:** resize & recompress to JPEG (max side 2048px) targeting `agents.defaults.mediaMaxMb` (default 5 MB), capped at 6 MB.
|
||||
|
||||
@@ -96,7 +96,7 @@ It can set up:
|
||||
- `~/clawd` workspace bootstrap
|
||||
- `~/.clawdbot/clawdbot.json` config
|
||||
- model auth profiles
|
||||
- provider config/login
|
||||
- model provider config/login
|
||||
- Linux systemd **user** service (daemon)
|
||||
|
||||
If you’re doing OAuth on a headless VM: do OAuth on a normal machine first, then copy the auth profile to the VM (see [FAQ](/start/faq)).
|
||||
|
||||
@@ -42,8 +42,8 @@ export PEEKABOO_BRIDGE_SOCKET=/path/to/bridge.sock
|
||||
|
||||
## Security & permissions
|
||||
|
||||
- The bridge validates **caller code signatures**; TeamID `Y5PE65HELJ` is
|
||||
allowed by default (Peekaboo’s signing team), plus the Clawdbot app’s TeamID.
|
||||
- The bridge validates **caller code signatures**; an allowlist of TeamIDs is
|
||||
enforced (Peekaboo host TeamID + Clawdbot app TeamID).
|
||||
- Requests time out after ~10 seconds.
|
||||
- If required permissions are missing, the bridge returns a clear error message
|
||||
rather than launching System Settings.
|
||||
|
||||
@@ -10,8 +10,8 @@ read_when:
|
||||
This app now ships Sparkle auto-updates. Release builds must be Developer ID–signed, zipped, and published with a signed appcast entry.
|
||||
|
||||
## Prereqs
|
||||
- Developer ID Application cert installed (`Developer ID Application: Peter Steinberger (Y5PE65HELJ)` is expected).
|
||||
- Sparkle private key path set in the environment as `SPARKLE_PRIVATE_KEY_FILE`; key lives in `/Users/steipete/Library/CloudStorage/Dropbox/Backup/Sparkle` (same key as Trimmy; public key baked into Info.plist).
|
||||
- Developer ID Application cert installed (example: `Developer ID Application: <Developer Name> (<TEAMID>)`).
|
||||
- Sparkle private key path set in the environment as `SPARKLE_PRIVATE_KEY_FILE` (path to your Sparkle ed25519 private key; public key baked into Info.plist).
|
||||
- Notary credentials (keychain profile or API key) for `xcrun notarytool` if you want Gatekeeper-safe DMG/zip distribution.
|
||||
- We use a Keychain profile named `clawdbot-notary`, created from App Store Connect API key env vars in your shell profile:
|
||||
- `APP_STORE_CONNECT_API_KEY_P8`, `APP_STORE_CONNECT_KEY_ID`, `APP_STORE_CONNECT_ISSUER_ID`
|
||||
@@ -32,7 +32,7 @@ BUNDLE_ID=com.clawdbot.mac \
|
||||
APP_VERSION=2026.1.11-4 \
|
||||
APP_BUILD="$(git rev-list --count HEAD)" \
|
||||
BUILD_CONFIG=release \
|
||||
SIGN_IDENTITY="Developer ID Application: Peter Steinberger (Y5PE65HELJ)" \
|
||||
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
|
||||
scripts/package-mac-app.sh
|
||||
|
||||
# Zip for distribution (includes resource forks for Sparkle delta support)
|
||||
@@ -50,7 +50,7 @@ BUNDLE_ID=com.clawdbot.mac \
|
||||
APP_VERSION=2026.1.11-4 \
|
||||
APP_BUILD="$(git rev-list --count HEAD)" \
|
||||
BUILD_CONFIG=release \
|
||||
SIGN_IDENTITY="Developer ID Application: Peter Steinberger (Y5PE65HELJ)" \
|
||||
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
|
||||
scripts/package-mac-dist.sh
|
||||
|
||||
# Optional: ship dSYM alongside the release
|
||||
@@ -60,7 +60,7 @@ ditto -c -k --keepParent apps/macos/.build/release/Clawdbot.app.dSYM dist/Clawdb
|
||||
## Appcast entry
|
||||
Use the release note generator so Sparkle renders formatted HTML notes:
|
||||
```bash
|
||||
SPARKLE_PRIVATE_KEY_FILE=/Users/steipete/Library/CloudStorage/Dropbox/Backup/Sparkle/ed25519-private-key scripts/make_appcast.sh dist/Clawdbot-2026.1.11-4.zip https://raw.githubusercontent.com/clawdbot/clawdbot/main/appcast.xml
|
||||
SPARKLE_PRIVATE_KEY_FILE=/path/to/ed25519-private-key scripts/make_appcast.sh dist/Clawdbot-2026.1.11-4.zip https://raw.githubusercontent.com/clawdbot/clawdbot/main/appcast.xml
|
||||
```
|
||||
Generates HTML release notes from `CHANGELOG.md` (via [`scripts/changelog-to-html.sh`](https://github.com/clawdbot/clawdbot/blob/main/scripts/changelog-to-html.sh)) and embeds them in the appcast entry.
|
||||
Commit the updated `appcast.xml` alongside the release assets (zip + dSYM) when publishing.
|
||||
|
||||
@@ -20,14 +20,14 @@ read_when:
|
||||
### PeekabooBridge (UI automation)
|
||||
- UI automation uses a separate UNIX socket named `bridge.sock` and the PeekabooBridge JSON protocol.
|
||||
- Host preference order (client-side): Peekaboo.app → Claude.app → Clawdbot.app → local execution.
|
||||
- Security: bridge hosts require TeamID `Y5PE65HELJ`; DEBUG-only same-UID escape hatch is guarded by `PEEKABOO_ALLOW_UNSIGNED_SOCKET_CLIENTS=1` (Peekaboo convention).
|
||||
- Security: bridge hosts require an allowed TeamID; DEBUG-only same-UID escape hatch is guarded by `PEEKABOO_ALLOW_UNSIGNED_SOCKET_CLIENTS=1` (Peekaboo convention).
|
||||
- See: [PeekabooBridge usage](/platforms/mac/peekaboo) for details.
|
||||
|
||||
### Mach/XPC
|
||||
- Not required for automation; `node.invoke` + PeekabooBridge cover current needs.
|
||||
|
||||
## Operational flows
|
||||
- Restart/rebuild: `SIGN_IDENTITY="Apple Development: Peter Steinberger (2ZAC4GM7GD)" scripts/restart-mac.sh`
|
||||
- Restart/rebuild: `SIGN_IDENTITY="Apple Development: <Developer Name> (<TEAMID>)" scripts/restart-mac.sh`
|
||||
- Kills existing instances
|
||||
- Swift build + package
|
||||
- Writes/bootstraps/kickstarts the LaunchAgent
|
||||
|
||||
@@ -70,7 +70,7 @@ Query parameters:
|
||||
- `message` (required)
|
||||
- `sessionKey` (optional)
|
||||
- `thinking` (optional)
|
||||
- `deliver` / `to` / `provider` (optional)
|
||||
- `deliver` / `to` / `channel` (optional)
|
||||
- `timeoutSeconds` (optional)
|
||||
- `key` (optional unattended mode key)
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Each `ChannelPlugin` bundles:
|
||||
- `status`: defaultRuntime + probe/audit/buildAccountSnapshot + buildChannelSummary + logSelfId + collectStatusIssues.
|
||||
- `gateway`: startAccount/stopAccount with runtime context (`getStatus`/`setStatus`), plus optional `loginWithQrStart/loginWithQrWait` for gateway-owned QR login flows.
|
||||
- `security`: dmPolicy + allowFrom hints used by `doctor security`.
|
||||
- `heartbeat`: optional readiness checks + heartbeat recipient resolution when providers own targeting.
|
||||
- `heartbeat`: optional readiness checks + heartbeat recipient resolution when channels own targeting.
|
||||
- `auth`: optional login hook used by `clawdbot channels login`.
|
||||
- `reload`: `configPrefixes` that map to hot restarts.
|
||||
- `onboarding`: optional CLI onboarding adapter (wizard UI hooks per channel).
|
||||
@@ -58,7 +58,7 @@ Each `ChannelPlugin` bundles:
|
||||
- `channels.status` summary objects come from `status.buildChannelSummary` (no per-channel branching in the handler).
|
||||
- `channels.status` warnings flow through `status.collectStatusIssues` per plugin.
|
||||
- CLI list uses `meta.showConfigured` to decide whether to show configured state.
|
||||
- CLI provider options and prompt provider lists are generated from `listProviderPlugins()` (avoid hardcoded arrays).
|
||||
- CLI channel options and prompt channel lists are generated from `listChannelPlugins()` (avoid hardcoded arrays).
|
||||
- Channel selection (`resolveMessageChannelSelection`) inspects `config.isEnabled` + `config.isConfigured` per plugin instead of hardcoded checks.
|
||||
- Pairing flows (CLI + store) use `plugin.pairing` (`idLabel`, `normalizeAllowEntry`, `notifyApproval`) via `src/channels/plugins/pairing.ts`.
|
||||
- CLI channel remove/disable delegates to `config.setAccountEnabled` + `config.deleteAccount` per plugin.
|
||||
@@ -72,39 +72,39 @@ Each `ChannelPlugin` bundles:
|
||||
- Outbound delivery results accept `meta` for channel-specific fields to avoid core type churn in new plugins.
|
||||
- Agent gateway routing sets `deliveryTargetMode` and uses `resolveOutboundTarget` for implicit fallback targets when `to` is missing.
|
||||
- Elevated tool allowlists (`tools.elevated.allowFrom`) are a record keyed by channel id (no schema update needed when adding channels).
|
||||
- Block streaming defaults live on the plugin (`capabilities.blockStreaming`, `streaming.blockStreamingCoalesceDefaults`) instead of hardcoded provider checks.
|
||||
- Block streaming defaults live on the plugin (`capabilities.blockStreaming`, `streaming.blockStreamingCoalesceDefaults`) instead of hardcoded channel checks.
|
||||
- Channel logout routes through `channels.logout` using `gateway.logoutAccount` on each plugin (clients should call the generic method).
|
||||
- Gateway message-channel normalization uses `src/channels/registry.ts` for cheap validation/normalization without plugin init cycles.
|
||||
- Group mention gating now flows through `plugin.groups.resolveRequireMention` (Discord/Slack/Telegram/WhatsApp/iMessage) instead of branching in reply handlers.
|
||||
- Command authorization uses `config.resolveAllowFrom` + `config.formatAllowFrom`, with `commands.enforceOwnerForCommands` and `commands.skipWhenConfigEmpty` driving provider-specific behavior.
|
||||
- Command authorization uses `config.resolveAllowFrom` + `config.formatAllowFrom`, with `commands.enforceOwnerForCommands` and `commands.skipWhenConfigEmpty` driving channel-specific behavior.
|
||||
- Security warnings (`doctor security`) use `plugin.security.resolveDmPolicy` + `plugin.security.collectWarnings`; supply `policyPath` + `allowFromPath` for accurate config hints.
|
||||
- Reply threading uses `plugin.threading.resolveReplyToMode` and `plugin.threading.allowTagsWhenOff` rather than provider switches in reply helpers.
|
||||
- Reply threading uses `plugin.threading.resolveReplyToMode` and `plugin.threading.allowTagsWhenOff` rather than channel switches in reply helpers.
|
||||
- Tool auto-threading context flows through `plugin.threading.buildToolContext` (e.g., Slack threadTs injection).
|
||||
- Messaging tool dedupe now relies on `plugin.messaging.normalizeTarget` for provider-specific target normalization.
|
||||
- Messaging tool dedupe now relies on `plugin.messaging.normalizeTarget` for channel-specific target normalization.
|
||||
- Message tool + CLI action dispatch now use `plugin.actions.listActions` + `plugin.actions.handleAction`; use `plugin.actions.supportsAction` for dispatch-only gating when you still want fallback send/poll.
|
||||
- Session announce targets can opt into `meta.preferSessionLookupForAnnounceTarget` when session keys are insufficient (e.g., WhatsApp).
|
||||
- Onboarding provider setup is delegated to adapter modules under `src/providers/plugins/onboarding/*`, keeping `setupProviders` provider-agnostic.
|
||||
- Onboarding registry now reads `plugin.onboarding` from each provider (no standalone onboarding map).
|
||||
- Onboarding channel setup is delegated to adapter modules under `src/channels/plugins/onboarding/*`, keeping `setupChannels` channel-agnostic.
|
||||
- Onboarding registry now reads `plugin.onboarding` from each channel (no standalone onboarding map).
|
||||
- Channel login flows (`clawdbot channels login`) route through `plugin.auth.login` when available.
|
||||
- `clawdbot status` reports `linkProvider` (derived from `status.buildProviderSummary().linked`) instead of a hardcoded `web` provider field.
|
||||
- Gateway `web.login.*` methods use `plugin.gatewayMethods` ownership to pick the provider (no hardcoded `normalizeProviderId("web")` in the handler).
|
||||
- `clawdbot status` reports `linkChannel` (derived from `status.buildChannelSummary().linked`) instead of a hardcoded `web` field.
|
||||
- Gateway `web.login.*` methods use `plugin.gatewayMethods` ownership to pick the channel (no hardcoded `normalizeChannelId("web")` in the handler).
|
||||
|
||||
## CLI Commands (inline references)
|
||||
- Add/remove channels: `clawdbot channels add <channel>` / `clawdbot channels remove <channel>`.
|
||||
- Inspect channel state: `clawdbot channels list`, `clawdbot channels status`.
|
||||
- Link/unlink channels: `clawdbot channels login --channel <channel>` / `clawdbot channels logout --channel <channel>`.
|
||||
- Pairing approvals: `clawdbot pairing list <provider>`, `clawdbot pairing approve <provider> <code>`.
|
||||
- Pairing approvals: `clawdbot pairing list <channel>`, `clawdbot pairing approve <channel> <code>`.
|
||||
|
||||
## Adding a Provider (checklist)
|
||||
1) Create `src/providers/plugins/<id>.ts` exporting `ProviderPlugin`.
|
||||
2) Register in `src/providers/plugins/index.ts` and update `src/providers/registry.ts` (ids/aliases/meta) if needed.
|
||||
3) Add a dock entry in `src/providers/dock.ts` for any shared behavior (capabilities, allowFrom format/resolve, mention stripping, threading, streaming chunk defaults).
|
||||
## Adding a Channel (checklist)
|
||||
1) Create `src/channels/plugins/<id>.ts` exporting `ChannelPlugin`.
|
||||
2) Register in `src/channels/plugins/index.ts` and update `src/channels/registry.ts` (ids/aliases/meta) if needed.
|
||||
3) Add a dock entry in `src/channels/dock.ts` for any shared behavior (capabilities, allowFrom format/resolve, mention stripping, threading, streaming chunk defaults).
|
||||
4) Add `reload.configPrefixes` for hot reload when config changes.
|
||||
5) Delegate to existing provider modules (send/probe/monitor) or create them.
|
||||
5) Delegate to existing channel modules (send/probe/monitor) or create them.
|
||||
6) If you changed the gateway protocol: run `pnpm protocol:check` (updates `dist/protocol.schema.json` + `apps/macos/Sources/ClawdbotProtocol/GatewayModels.swift`).
|
||||
7) Update docs/tests for any behavior changes.
|
||||
|
||||
## Cleanup Expectations
|
||||
- Keep plugin files small; move heavy logic into provider modules.
|
||||
- Keep plugin files small; move heavy logic into channel modules.
|
||||
- Prefer shared helpers over V2 copies.
|
||||
- Update docs when behavior/inputs change.
|
||||
|
||||
@@ -81,7 +81,7 @@ git commit -m "Add Clawd workspace"
|
||||
## What Clawdbot Does
|
||||
- Runs WhatsApp gateway + Pi coding agent so the assistant can read/write chats, fetch context, and run skills via the host Mac.
|
||||
- macOS app manages permissions (screen recording, notifications, microphone) and exposes the `clawdbot` CLI via its bundled binary.
|
||||
- Direct chats collapse into the agent's `main` session by default; groups stay isolated as `agent:<agentId>:<provider>:group:<id>` (rooms/channels: `agent:<agentId>:<provider>:channel:<id>`); heartbeats keep background tasks alive.
|
||||
- Direct chats collapse into the agent's `main` session by default; groups stay isolated as `agent:<agentId>:<channel>:group:<id>` (rooms/channels: `agent:<agentId>:<channel>:channel:<id>`); heartbeats keep background tasks alive.
|
||||
|
||||
## Core Skills (enable in Settings → Skills)
|
||||
- **mcporter** — Tool server runtime/CLI for managing external skill backends.
|
||||
|
||||
@@ -67,8 +67,8 @@ A `sessionKey` identifies *which conversation bucket* you’re in (routing + iso
|
||||
Common patterns:
|
||||
|
||||
- Main/direct chat (per agent): `agent:<agentId>:<mainKey>` (default `main`)
|
||||
- Group: `agent:<agentId>:<provider>:group:<id>`
|
||||
- Room/channel (Discord/Slack): `agent:<agentId>:<provider>:channel:<id>` or `...:room:<id>`
|
||||
- Group: `agent:<agentId>:<channel>:group:<id>`
|
||||
- Room/channel (Discord/Slack): `agent:<agentId>:<channel>:channel:<id>` or `...:room:<id>`
|
||||
- Cron: `cron:<job.id>`
|
||||
- Webhook: `hook:<uuid>` (unless overridden)
|
||||
|
||||
|
||||
@@ -1256,7 +1256,7 @@ If you run the gateway manually, `clawdbot gateway --force` can reclaim the port
|
||||
|
||||
### What’s the fastest way to get more details when something fails?
|
||||
|
||||
Start the Gateway with `--verbose` to get more console detail. Then inspect the log file for provider auth, model routing, and RPC errors.
|
||||
Start the Gateway with `--verbose` to get more console detail. Then inspect the log file for channel auth, model routing, and RPC errors.
|
||||
|
||||
## Media & attachments
|
||||
|
||||
@@ -1280,8 +1280,8 @@ Treat inbound DMs as untrusted input. Defaults are designed to reduce risk:
|
||||
|
||||
- Default behavior on DM‑capable channels is **pairing**:
|
||||
- Unknown senders receive a pairing code; the bot does not process their message.
|
||||
- Approve with: `clawdbot pairing approve <provider> <code>`
|
||||
- Pending requests are capped at **3 per provider**; check `clawdbot pairing list <provider>` if a code didn’t arrive.
|
||||
- Approve with: `clawdbot pairing approve <channel> <code>`
|
||||
- Pending requests are capped at **3 per channel**; check `clawdbot pairing list <channel>` if a code didn’t arrive.
|
||||
- Opening DMs publicly requires explicit opt‑in (`dmPolicy: "open"` and allowlist `"*"`).
|
||||
|
||||
Run `clawdbot doctor` to surface risky DM policies.
|
||||
|
||||
@@ -18,14 +18,14 @@ Security context: [Security](/gateway/security)
|
||||
|
||||
## 1) DM pairing (inbound chat access)
|
||||
|
||||
When a provider is configured with DM policy `pairing`, unknown senders get a short code and their message is **not processed** until you approve.
|
||||
When a channel is configured with DM policy `pairing`, unknown senders get a short code and their message is **not processed** until you approve.
|
||||
|
||||
Default DM policies are documented in: [Security](/gateway/security)
|
||||
|
||||
Pairing codes:
|
||||
- 8 characters, uppercase, no ambiguous chars (`0O1I`).
|
||||
- **Expire after 1 hour**. The bot only sends the pairing message when a new request is created (roughly once per hour per sender).
|
||||
- Pending DM pairing requests are capped at **3 per provider** by default; additional requests are ignored until one expires or is approved.
|
||||
- Pending DM pairing requests are capped at **3 per channel** by default; additional requests are ignored until one expires or is approved.
|
||||
|
||||
### Approve a sender
|
||||
|
||||
@@ -39,8 +39,8 @@ Supported channels: `telegram`, `whatsapp`, `signal`, `imessage`, `discord`, `sl
|
||||
### Where the state lives
|
||||
|
||||
Stored under `~/.clawdbot/credentials/`:
|
||||
- Pending requests: `<provider>-pairing.json`
|
||||
- Approved allowlist store: `<provider>-allowFrom.json`
|
||||
- Pending requests: `<channel>-pairing.json`
|
||||
- Approved allowlist store: `<channel>-allowFrom.json`
|
||||
|
||||
Treat these as sensitive (they gate access to your assistant).
|
||||
|
||||
@@ -72,7 +72,7 @@ Full protocol + design notes: [Gateway pairing](/gateway/pairing)
|
||||
|
||||
- Security model + prompt injection: [Security](/gateway/security)
|
||||
- Updating safely (run doctor): [Updating](/install/updating)
|
||||
- Provider configs:
|
||||
- Channel configs:
|
||||
- Telegram: [Telegram](/channels/telegram)
|
||||
- WhatsApp: [WhatsApp](/channels/whatsapp)
|
||||
- Signal: [Signal](/channels/signal)
|
||||
|
||||
@@ -105,13 +105,13 @@ Tip: `--json` does **not** imply non-interactive mode. Use `--non-interactive` (
|
||||
- Disable auth only if you fully trust every local process.
|
||||
- Non‑loopback binds still require auth.
|
||||
|
||||
5) **Providers**
|
||||
5) **Channels**
|
||||
- WhatsApp: optional QR login.
|
||||
- Telegram: bot token.
|
||||
- Discord: bot token.
|
||||
- Signal: optional `signal-cli` install + account config.
|
||||
- iMessage: local `imsg` CLI path + DB access.
|
||||
- DM security: default is pairing. First DM sends a code; approve via `clawdbot pairing approve <provider> <code>` or use allowlists.
|
||||
- DM security: default is pairing. First DM sends a code; approve via `clawdbot pairing approve <channel> <code>` or use allowlists.
|
||||
|
||||
6) **Daemon install**
|
||||
- macOS: LaunchAgent
|
||||
|
||||
@@ -14,7 +14,7 @@ and the agent should rely on them directly.
|
||||
## Disabling tools
|
||||
|
||||
You can globally allow/deny tools via `tools.allow` / `tools.deny` in `clawdbot.json`
|
||||
(deny wins). This prevents disallowed tools from being sent to providers.
|
||||
(deny wins). This prevents disallowed tools from being sent to model providers.
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -228,7 +228,7 @@ Notes:
|
||||
- Uses the image model directly (independent of the main chat model).
|
||||
|
||||
### `message`
|
||||
Send messages and provider actions across Discord/Slack/Telegram/WhatsApp/Signal/iMessage/MS Teams.
|
||||
Send messages and channel actions across Discord/Slack/Telegram/WhatsApp/Signal/iMessage/MS Teams.
|
||||
|
||||
Core actions:
|
||||
- `send` (text + optional media)
|
||||
@@ -248,7 +248,7 @@ Core actions:
|
||||
- `timeout` / `kick` / `ban`
|
||||
|
||||
Notes:
|
||||
- `send` routes WhatsApp via the Gateway; other providers go direct.
|
||||
- `send` routes WhatsApp via the Gateway; other channels go direct.
|
||||
- `poll` uses the Gateway for WhatsApp and MS Teams; Discord polls go direct.
|
||||
- When a message tool call is bound to an active chat session, sends are constrained to that session’s target to avoid cross-context leaks.
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
---
|
||||
summary: "Reaction semantics shared across providers"
|
||||
summary: "Reaction semantics shared across channels"
|
||||
read_when:
|
||||
- Working on reactions in any provider
|
||||
- Working on reactions in any channel
|
||||
---
|
||||
# Reaction tooling
|
||||
|
||||
Shared reaction semantics across providers:
|
||||
Shared reaction semantics across channels:
|
||||
|
||||
- `emoji` is required when adding a reaction.
|
||||
- `emoji=""` removes the bot's reaction(s) when supported.
|
||||
- `remove: true` removes the specified emoji when supported (requires `emoji`).
|
||||
|
||||
Provider notes:
|
||||
Channel notes:
|
||||
|
||||
- **Discord/Slack**: empty `emoji` removes all of the bot's reactions on the message; `remove: true` removes just that emoji.
|
||||
- **Telegram**: empty `emoji` removes the bot's reactions; `remove: true` also removes reactions but still requires a non-empty `emoji` for tool validation.
|
||||
|
||||
@@ -7,7 +7,7 @@ read_when:
|
||||
|
||||
# Sub-agents
|
||||
|
||||
Sub-agents are background agent runs spawned from an existing agent run. They run in their own session (`agent:<agentId>:subagent:<uuid>`) and, when finished, **announce** their result back to the requester chat provider.
|
||||
Sub-agents are background agent runs spawned from an existing agent run. They run in their own session (`agent:<agentId>:subagent:<uuid>`) and, when finished, **announce** their result back to the requester chat channel.
|
||||
|
||||
Primary goals:
|
||||
- Parallelize “research / long task / slow tool” work without blocking the main run.
|
||||
@@ -19,7 +19,7 @@ Primary goals:
|
||||
|
||||
Use `sessions_spawn`:
|
||||
- Starts a sub-agent run (`deliver: false`, global lane: `subagent`)
|
||||
- Then runs an announce step and posts the announce reply to the requester chat provider
|
||||
- Then runs an announce step and posts the announce reply to the requester chat channel
|
||||
- Default model: inherits the caller unless you set `agents.defaults.subagents.model` (or per-agent `agents.list[].subagents.model`); an explicit `sessions_spawn.model` still wins.
|
||||
|
||||
Tool params:
|
||||
@@ -48,7 +48,7 @@ Auto-archive:
|
||||
Sub-agents report back via an announce step:
|
||||
- The announce step runs inside the sub-agent session (not the requester session).
|
||||
- If the sub-agent replies exactly `ANNOUNCE_SKIP`, nothing is posted.
|
||||
- Otherwise the announce reply is posted to the requester chat provider via the gateway `send` method.
|
||||
- Otherwise the announce reply is posted to the requester chat channel via the gateway `send` method.
|
||||
|
||||
Announce payloads include a stats line at the end:
|
||||
- Runtime (e.g., `runtime 5m12s`)
|
||||
|
||||
@@ -30,7 +30,7 @@ The onboarding wizard generates a gateway token by default, so paste it here on
|
||||
## What it can do (today)
|
||||
- Chat with the model via Gateway WS (`chat.history`, `chat.send`, `chat.abort`)
|
||||
- Stream tool calls + live tool output cards in Chat (agent events)
|
||||
- Connections: WhatsApp/Telegram status + QR login + Telegram config (`providers.status`, `web.login.*`, `config.set`)
|
||||
- Connections: WhatsApp/Telegram status + QR login + Telegram config (`channels.status`, `web.login.*`, `config.set`)
|
||||
- Instances: presence list + refresh (`system-presence`)
|
||||
- Sessions: list + per-session thinking/verbose overrides (`sessions.list`, `sessions.patch`)
|
||||
- Cron jobs: list/add/run/enable/disable + run history (`cron.*`)
|
||||
|
||||
@@ -28,7 +28,7 @@ Use SSH tunneling or Tailscale to reach the Gateway WS.
|
||||
- `--token <token>`: Gateway token (if required).
|
||||
- `--password <password>`: Gateway password (if required).
|
||||
- `--session <key>`: Session key (default: `main`, or `global` when scope is global).
|
||||
- `--deliver`: Deliver assistant replies to the provider (default off).
|
||||
- `--deliver`: Deliver assistant replies to the channel (default off).
|
||||
- `--thinking <level>`: Override thinking level for sends.
|
||||
- `--timeout-ms <ms>`: Agent timeout in ms (defaults to `agents.defaults.timeoutSeconds`).
|
||||
- `--history-limit <n>`: History entries to load (default 200).
|
||||
|
||||
@@ -10,7 +10,7 @@ Status: the macOS/iOS SwiftUI chat UI talks directly to the Gateway WebSocket.
|
||||
|
||||
## What it is
|
||||
- A native chat UI for the gateway (no embedded browser and no local static server).
|
||||
- Uses the same sessions and routing rules as other providers.
|
||||
- Uses the same sessions and routing rules as other channels.
|
||||
- Deterministic routing: replies always go back to WebChat.
|
||||
|
||||
## Quick start
|
||||
@@ -30,7 +30,7 @@ Status: the macOS/iOS SwiftUI chat UI talks directly to the Gateway WebSocket.
|
||||
## Configuration reference (WebChat)
|
||||
Full configuration: [Configuration](/gateway/configuration)
|
||||
|
||||
Provider options:
|
||||
Channel options:
|
||||
- No dedicated `webchat.*` block. WebChat uses the gateway endpoint + auth settings below.
|
||||
|
||||
Related global options:
|
||||
|
||||
Reference in New Issue
Block a user