openclaw-quiubo
v2.4.0
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-quiuboSetup
Quiubo is configured with:
openclaw channels add --channel quiuboThis launches the interactive setup wizard which will:
- Prompt for your SDK API Key (starts with
qub_) - Authenticate against the Quiubo API
- List your existing bot identities or create a new one
- Save the configuration
Prerequisites
You need a Quiubo SDK app with an API key. Get one from the Developer section in the Quiubo app settings.
What you'll need
| 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 |
Configuration
After running channels add, your OpenClaw config will contain:
channels:
quiubo:
accounts:
default:
enabled: true
apiUrl: https://api.quiubo.io
apiKey: qub_...
botIdentityId: <uuid>
pollIntervalMs: 5000Config fields
| 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 |
Multiple accounts
You can configure multiple accounts by running the setup wizard again:
openclaw channels add --channel quiuboWhen prompted for Account ID, enter a new name (e.g., support-bot, sales-bot).
Multi-Agent Setup
Run multiple AI agents on a single OpenClaw gateway — each with their own Quiubo chat, workspace, model, and cron jobs. For example: a personal assistant on Opus and an autonomous project manager on Sonnet, each in their own chat.
Step 1: Add the agent
In ~/.openclaw/openclaw.json, add a new agent to the list:
{
"agents": {
"list": [
{ "id": "main" },
{
"id": "project-manager",
"model": "anthropic/claude-sonnet-4-5",
"workspace": "~/.openclaw/workspace-project-manager"
}
]
}
}Each agent can use a different model — useful for cost control when running autonomous agents.
Step 2: Add a Quiubo account for the agent
Add a second account under the Quiubo plugin config. You can reuse the same SDK API key — each account just needs its own bot identity:
{
"plugins": {
"quiubo": {
"accounts": {
"default": {
"sdkApiKey": "qub_...",
"botIdentityId": "<main-bot-uuid>"
},
"pm": {
"sdkApiKey": "qub_...",
"botIdentityId": "<pm-bot-uuid>"
}
}
}
}
}Create additional bot identities through the Quiubo developer console or the setup wizard.
Step 3: Bind accounts to agents
Bindings tell OpenClaw which Quiubo account routes to which agent:
{
"bindings": [
{
"match": { "channel": "quiubo", "accountId": "default" },
"agentId": "main"
},
{
"match": { "channel": "quiubo", "accountId": "pm" },
"agentId": "project-manager"
}
]
}Without bindings, all messages route to the first agent. This is the most common setup issue — don't skip this step.
Step 4: Create the agent's workspace
mkdir -p ~/.openclaw/workspace-project-manager/memorySeed it with the standard OpenClaw agent files:
SOUL.md— personality and purposeAGENTS.md— operating instructionsUSER.md— info about the humanIDENTITY.md— name, emoji, avatarMEMORY.md— long-term memory (starts empty)
Step 5: Copy auth profiles (optional)
If the new agent needs access to the same services (web search, APIs, etc.):
mkdir -p ~/.openclaw/agents/project-manager/agent/
cp ~/.openclaw/agents/main/agent/auth-profiles.json ~/.openclaw/agents/project-manager/agent/Step 6: Restart
openclaw gateway restartThe new agent is live. Messages to the PM bot identity route to project-manager, use Sonnet, and read from its own workspace.
How routing works
Quiubo Chat (You + Main Bot) → account: default → binding → agent: main
Quiubo Chat (You + PM Bot) → account: pm → binding → agent: project-manager- Messages: The plugin passes
AccountIdto OpenClaw, which resolves the agent from bindings - Cron jobs: Filtered by
agentId— each agent's chat only shows its own jobs - Sessions: Each agent gets its own session namespace, no cross-talk
- Workspaces: Fully isolated — agents can't see or edit each other's files
Full config example
{
"agents": {
"list": [
{ "id": "main" },
{
"id": "project-manager",
"model": "anthropic/claude-sonnet-4-5",
"workspace": "~/.openclaw/workspace-project-manager"
}
]
},
"bindings": [
{
"match": { "channel": "quiubo", "accountId": "default" },
"agentId": "main"
},
{
"match": { "channel": "quiubo", "accountId": "pm" },
"agentId": "project-manager"
}
],
"plugins": {
"quiubo": {
"accounts": {
"default": {
"sdkApiKey": "qub_...",
"botIdentityId": "<main-bot-uuid>"
},
"pm": {
"sdkApiKey": "qub_...",
"botIdentityId": "<pm-bot-uuid>"
}
}
}
}
}Tips
- Cost control: Use cheaper models for autonomous agents that run frequently
- Workspace isolation: Agents should never edit each other's files — enforce this in their
AGENTS.md - Permissions: Add rules about what agents can/can't do (e.g., "ask before spending money")
- Scaling: Same pattern for any number of agents — new ID, new bot identity, new binding, new workspace
Markdown Attachments
Agents can send .md file attachments alongside their messages. Attachments appear as tappable cards in the Quiubo app with a full markdown viewer.
How it works
OpenClaw uses the MEDIA: token protocol. When an agent writes a file and includes a MEDIA: /path/to/file.md line in its response text, the dispatcher extracts it and passes the path to the plugin. The plugin reads the file from disk and sends it as an attachment via the Quiubo API.
Supported: .md files only, max 1MB each, max 5 per message.
Agent instructions
Add this to your agent's AGENTS.md so it knows how to send attachments:
## 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.
Only `.md` files are supported. Files over 1MB are skipped.Cron job attachments
Cron jobs with delivery.channel already target the correct group. To send attachments from a cron job, the cron agent just needs to follow the same MEDIA: token protocol — write the .md file, then include the MEDIA: line in the output.
What the user sees
- In chat: A compact card below the message text showing the filename, size, and source badge (agent/subagent/cron)
- On tap: Full-screen markdown viewer with rendered content
- In group details: A "Documents" tab listing all attachments in the group, filterable by source
How it works
Message delivery
The plugin uses a dual-mode gateway for receiving messages:
- Primary: Pusher WebSocket — real-time push delivery
- Fallback: Polling — automatic fallback when Pusher is unavailable
Outbound messages are sent via the Quiubo SDK REST API.
Auto-provisioning
On first gateway startup, if the bot has no groups, the plugin automatically:
- Creates a welcome group (type:
agent_channel) - Adds the bot as a member
- Sends a welcome message
This means users can start chatting immediately after setup — no manual group creation needed.
Inbound routing
Messages are routed through OpenClaw's agent pipeline using the standard finalizeInboundContext() → dispatchReplyWithBufferedBlockDispatcher() pattern (same as openclaw-mqtt).
Session keys use the format quiubo:<groupId>. The AccountId field in the context payload tells OpenClaw which agent to route to via the bindings config.
Bot-Enabled Gating
The extension implements a multi-step gating pipeline to determine whether to respond to a message. This runs for every incoming message (both Pusher and polling paths).
Gating Pipeline
- Self-echo skip — Messages from the bot's own identity are ignored
- Agent channel bypass —
agent_channelgroups always process messages (1:1 bot channels) - Security mode check — Only
PLAINTEXT_SDKgroups are processed; E2EE groups are skipped - Bot-enabled check —
settings.bot.enabledmust betrue(with cache-miss fallback) - Owner takeover — If the sender is the group owner, suppress bot for
suppressionMinutes - Suppression check — If currently suppressed, skip the message
Bot Config Cache
The extension maintains an in-memory cache of bot configuration per group:
interface BotConfig {
enabled: boolean;
suppressionMinutes: number;
ownerIdentityId: string;
groupType: string; // 'standard' | 'agent_channel'
}- Populated at startup from
listGroups()+listGroupMembers()for each group - Updated on cache miss via
onCacheMisscallback (5s timeout, fail-closed) - Hydrated from polls when Pusher is unavailable
Suppression Map
Owner takeover suppression uses a Map<groupId, suppressedUntil>:
- When the group owner sends a message,
suppressedUntilis set tonow + suppressionMinutes * 60_000 - Entries older than 1 hour are periodically evicted via
clearStaleSuppression()
Cache-Miss Strategy
When a message arrives for a group not in the cache (e.g., newly created):
- Extension calls
onCacheMiss(groupId)which fetches group details + members from the API - 5-second timeout — if the fetch fails or times out, the message is skipped (fail-closed)
- This is safer than fail-open: better to miss a message than respond incorrectly
Managing accounts
Disable an account
openclaw channels disable --channel quiuboRemove an account
Delete the account entry from your OpenClaw config, or use the config editor.
Development
npm run build # Compile TypeScript
npm run typecheck # Type-check without emittingProject structure
src/
api.ts # REST API client (QuiuboApiClient)
channel.ts # Channel plugin (config, setup, onboarding, outbound, gateway)
realtime-gateway.ts # Pusher WebSocket + polling fallback
polling-gateway.ts # Polling-only gateway
webhook-handler.ts # HTTP webhook server (alternative inbound)
runtime.ts # Plugin runtime singleton
types.ts # TypeScript type definitionsAPI coverage
The QuiuboApiClient wraps these SDK endpoints:
| Category | Methods |
|----------|---------|
| Auth | authenticate() |
| Messages | sendMessage(), listMessages() |
| Groups | createGroup(), listGroups(), getGroup(), addMembers(), removeMembers(), listGroupMembers(), updateGroupSettings() |
| Identities | createIdentity(), listIdentities(), deleteIdentity() |
| Join Tokens | createJoinToken(), listJoinTokens(), deleteJoinToken() |
| Webhooks | configureWebhook() |
| Pusher | pusherAuth() |
License
MIT
