openclaw-quiubo
v2.6.69
Published
OpenClaw Quiubo channel plugin — chat with AI assistants through Quiubo
Maintainers
Readme
openclaw-quiubo
OpenClaw channel plugin for Quiubo — chat with AI assistants through Quiubo's SDK API.
Installation
npm install openclaw-quiuboUpdating
openclaw plugins update openclaw-quiuboSetup
openclaw channels addThe interactive wizard will:
- Prompt for your SDK API Key (starts with
qub_) - Authenticate against the Quiubo API
- List existing bot identities or create a new one
- Save the configuration
Prerequisites
| Item | Where to get it | |------|----------------| | SDK API Key | Quiubo app > Settings > Developer > API Keys | | Bot Identity | Created during setup wizard, or pre-create in Developer console |
Quick Start: Talking to your agent
Once setup completes, your agent is ready to chat:
- Open Quiubo — your agent appears as a contact with its own chat
- Send a message — the agent receives it and responds automatically
- Add to groups — invite the agent to any group, then @mention it to get its attention
How agents receive messages
| Context | How to trigger the agent |
|---------|------------------------|
| 1:1 chat (agent channel) | Just send a message — the agent always responds |
| Group (agent is a member) | @mention the agent: @BotName do something |
| Group (agent-only) | Every message triggers all agents (auto-broadcast) |
| Group (directory agent) | @mention required — agents with triggerMode: "mention" only respond when mentioned |
@team shortcut
In groups with 2+ agents, type @Team to mention all agents at once. The @Team mention expands to individual agent mentions before delivery.
Scheduled messages
Agents can send messages on a schedule using cron jobs:
# Default agent — announce mode works
openclaw cron add --name "daily-report" --every 24h \
--channel quiubo --to <group-uuid> --announce \
--message "Generate and post the daily report."
# Named agent — use --no-deliver (agent sends the message itself)
openclaw cron add --name "standup" --agent my-agent --every 24h \
--no-deliver --to <group-uuid> \
--message "Post the daily standup to the group chat."See Cron delivery for details on delivery modes.
Configuration
channels:
quiubo:
accounts:
default:
enabled: true
apiUrl: https://api.quiubo.io
apiKey: qub_...
botIdentityId: <uuid>
pollIntervalMs: 5000| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| apiKey | Yes | — | SDK API key (starts with qub_) |
| botIdentityId | Yes | — | UUID of the bot's service identity |
| enabled | No | true | Enable/disable this account |
| apiUrl | No | https://api.quiubo.io | API base URL |
| pollIntervalMs | No | 5000 | Polling fallback interval in ms |
Group context injection
The plugin injects group metadata (name, members, E2EE status, scopes) into agent prompts via the before_prompt_build hook. This lets agents know who's in the conversation without being told.
Required config — OpenClaw classifies before_prompt_build as a prompt injection hook and blocks it by default. You must explicitly allow it:
openclaw config set plugins.entries.openclaw-quiubo.hooks.allowPromptInjection true
openclaw gateway restartWithout this, the hook silently doesn't register — no error, no warning.
Multiple accounts
Run the setup wizard again and enter a different Account ID when prompted (e.g., support-bot, sales-bot). Each account gets its own gateway instance, cursor file, and bot config cache. For full multi-agent isolation (separate workspaces, models, cron jobs), see the Multi-Agent Setup guide.
Architecture
Message delivery
The plugin uses a dual-mode real-time gateway:
Pusher WebSocket (primary) ─┐
├──→ dedup ──→ onMessage() ──→ OpenClaw agent pipeline
Polling fallback (safety) ─┘- Pusher WebSocket: Real-time push delivery via
private-user-{botIdentityId}channel - Polling: Runs concurrently as a safety net (catches messages Pusher may silently miss)
- Dedup: Both paths pass through cursor + in-memory dedup — no double-processing
Outbound messages are sent via the Quiubo SDK REST API.
Replay prevention
Four layers prevent old messages from being reprocessed on restart:
- Cursor persistence: Per-account cursor files at
~/.openclaw/cron/quiubo-cursors-{accountId}.jsonsurvive restarts - seekToLatest(): On cold start (no cursor for a group), paginates to the latest message without processing — only subsequent messages are treated as new
- FIFO dedup set: In-memory
dispatchedset (capped at 500 entries with FIFO eviction) catches duplicates across Pusher and poll paths within a session - Dedup guard on all delivery paths: Pusher plaintext, Pusher E2EE, and poll paths all check the dedup set before dispatching
Resilience
- Exponential backoff: Poll failures increase delay (5s > 10s > 20s > 40s > 60s cap), resets on success
- Poll concurrency limiter: Groups polled in batches of 5 via
Promise.allSettledto avoid API burst - Gateway lifecycle safety:
startAccount()stops any existing gateway before creating a new one (prevents orphaned timers on config reload) - Pusher timeout management: 15s connection timeout is properly cancelled on stop/restart
End-to-end encryption (E2EE)
The plugin supports Quiubo's E2EE protocol for groups that require it:
- Key generation: Deterministic Ed25519 + X25519 keypairs derived from a 32-byte seed (persisted to
~/.openclaw/cron/quiubo-keys-{accountId}.json) - Auto-enrollment: On first startup, generates keypair and enrolls via challenge-response (
requestKeyChallenge>signChallenge>verifyKeyChallenge) - Inbound decryption: GroupEnvelopeV2 messages decrypted using XChaCha20-Poly1305 with epoch keys
- Outbound encryption: Plaintext encrypted before sending when E2EE is granted for the group
- Epoch key management: Dual-layer cache (active key + historical keys per epoch) with 30-min TTL and automatic refresh
- Pusher events: Handles
e2ee-granted,e2ee-revoked,epoch-rotatedfor real-time key lifecycle
Directory agents
Agents can be listed in Quiubo's public agent directory, allowing any group to add them:
- Auto-registration: If no agent record exists for the bot identity, one is created automatically on startup
- Directory groups: Discovered via
listAgentGroups()(refreshed every 60s) and polled alongside partner groups - Mention filtering: In directory groups, polled messages are only processed if they contain an
@mentionof the agent (Pusher path is pre-filtered server-side bytriggerMode) - Scope enforcement: Outbound messages check
grantedScopes— agent won't attempt to send ifsend_messagesisn't granted - Real-time membership: Pusher events
agent:group-addedandagent:group-removedupdate the cache immediately
Bot-enabled gating
Every incoming message passes through a multi-step gating pipeline:
- Self-echo skip — Bot's own messages ignored
- Agent channel bypass —
agent_channelgroups always process (1:1 bot channels) - Cache miss resolution — Unknown groups fetched via API with 5s timeout (fail-closed)
- Bot-enabled check —
settings.bot.enabledmust betrue - Security mode check —
PLAINTEXT_SDKor E2EE-granted groups only - Owner takeover — Owner sends a message > bot suppressed for
suppressionMinutes - Suppression check — Skipped while suppressed (stale entries evicted after 1 hour)
Inbound routing
Messages are routed through OpenClaw's agent pipeline:
finalizeInboundContext() → dispatchReplyWithBufferedBlockDispatcher()Session keys: quiubo:{groupId} for the main agent, agent:{agentId}:quiubo:{groupId} for non-main agents.
Auto-provisioning
On first gateway startup, if the bot has no groups, the plugin automatically creates a welcome agent_channel group, adds the bot as a member, and sends a welcome message.
Multi-Agent Setup
Run multiple agents on a single gateway — each with its own chat, model, workspace, and cron jobs.
openclaw channels add— create a new bot identity- Add the agent and binding to
~/.openclaw/openclaw.json - Create the agent's workspace
openclaw gateway restart
All agents share one SDK API key (and its quota). Each gets fully isolated conversations, cursors, and session keys.
Full guide — architecture, config examples, cron setup, and troubleshooting.
Markdown Attachments
Agents can send .md file attachments alongside messages. Attachments appear as tappable cards in the Quiubo app with a full markdown viewer.
OpenClaw's MEDIA: token protocol is used: when an agent writes a file and includes MEDIA: /path/to/file.md in its response, the plugin reads the file and sends it as a structured attachment.
Supported: .md files (max 1MB) and images — .jpg, .jpeg, .png, .webp (max 5MB, uploaded via S3 presign). Source tracking distinguishes agent vs subagent attachments.
Add this to your agent's AGENTS.md:
## Sending File Attachments
When you want to attach a markdown file to your reply:
1. Write the file to disk (e.g. `/tmp/report.md`)
2. Include a `MEDIA:` token in your response text pointing to the file path
Example response:
Here's your daily report:
MEDIA: /tmp/daily-report.md
The file will be delivered as a tappable attachment card in the chat.
Supported: `.md` (max 1MB) and images `.jpg`/`.png`/`.webp` (max 5MB).Operational Notes
Per-account state files
Each account persists its own state files under ~/.openclaw/cron/:
| File | Purpose | Safe to delete? |
|------|---------|-----------------|
| quiubo-cursors-{accountId}.json | Message cursor positions | Yes — gateway will seekToLatest() on next start (no replay) |
| quiubo-keys-{accountId}.json | E2EE key seed (32 bytes) | No — deleting forces re-enrollment, may break E2EE for existing conversations |
Heartbeat
If an agent is registered, the gateway sends a heartbeat every 60s to report connectionStatus: online. Heartbeat stops on Pusher disconnect and resumes on reconnect.
Typing indicators
A typing indicator is sent immediately when processing begins, then repeated every 4s until the response is delivered.
Scheduled messages / Cron delivery
Cron jobs that deliver to Quiubo groups must include --to <groupId>:
openclaw cron add --name "team-checkin" --every 30m --channel quiubo --to 7868cc21-... "Check in with the team"Without --to, the extension cannot determine which group to deliver to. Unlike 1:1 sessions (which have a single bound chat), group sessions are multi-tenant — the target must be explicit.
Note: The
--tovalue is the Quiubo group UUID, visible in the group detail screen or conversation URL.
Named agent crons
The --announce delivery mode does not work reliably with --agent <id> (see openclaw/openclaw#32432). The workaround is --no-deliver — the agent sends the message itself using the message tool:
openclaw cron add --name "giskard-standup" --agent giskard --every 24h \
--no-deliver \
--to 7868cc21-... \
--message 'Post the daily standup summary to the Quiubo group chat.'With --no-deliver, the cron skips the announce pipeline entirely. The agent receives the prompt and sends messages through its own account binding, which correctly resolves identity and group routing.
Why this works: Announce delivery resolves targets using a different code path that lacks proper account resolution for named agents. With --no-deliver, the agent uses the standard message tool path, which goes through the agent's own channel binding (quiubo:accountId).
Delivery mode comparison
| Mode | Flag | How it works | Named agent support |
|------|------|-------------|-------------------|
| Announce | --announce (default) | Cron delivers output via channel adapter | ❌ Fails for --agent |
| No deliver | --no-deliver | Agent sends messages itself via message tool | ✅ Works |
| Webhook | --webhook --to <url> | Cron POSTs to your endpoint | ✅ Works |
See #84 for a planned improvement to auto-resolve the target from the session bound group.
Managing Accounts
openclaw channels disable --channel quiubo # Disable
openclaw channels add # Re-configureDevelopment
npm run build # Compile TypeScript
npm run typecheck # Type-check without emitting
npm run release # Bump version + publishProject structure
index.ts # Entry point + exports
src/
api.ts # REST API client (QuiuboApiClient)
channel.ts # Channel plugin (config, setup, onboarding, outbound, gateway)
realtime-gateway.ts # Pusher WebSocket + polling fallback + replay prevention
crypto.ts # E2EE: key generation, envelope decrypt/encrypt, Ed25519 signing
key-manager.ts # Dual-layer epoch key cache with auto-fetch
runtime.ts # Plugin runtime singleton
types.ts # TypeScript type definitionsAPI coverage
| Category | Methods |
|----------|---------|
| Auth | authenticate() |
| Messages | sendMessage(), listMessages(), sendTypingIndicator() |
| Groups | createGroup(), listGroups(), getGroup(), addMembers(), removeMembers(), listGroupMembers(), updateGroupSettings() |
| Identities | createIdentity(), listIdentities(), deleteIdentity() |
| Join Tokens | createJoinToken(), listJoinTokens(), deleteJoinToken() |
| Agents | listAgents(), createAgent(), updateAgent(), sendHeartbeat(), listAgentGroups(), getGroupAgent() |
| E2EE | requestKeyChallenge(), verifyKeyChallenge(), getEpochKey(), getEpochKeys() |
| Pusher | pusherAuth() |
| OpenClaw | sendOpenclawResponse() |
| Webhooks | configureWebhook() |
Known Security Scanner Warnings
When installing, OpenClaw's plugin scanner may flag two patterns. Both are false positives:
- "Shell command execution detected (child_process)" — From
pusher-js's bundled XMLHttpRequest polyfill. This sync code path is never executed by the plugin. - "Environment variable access combined with network send" — The plugin reads
process.env.HOMEto locate~/.openclaw/cron/for persisting cursors and keys. No credentials flow through environment variables.
To suppress the auto-load warning, add the plugin to your allowlist in ~/.openclaw/openclaw.json:
{
"plugins": {
"allow": ["openclaw-quiubo"]
}
}License
MIT
