Bot installs
A ClickClack bot install is three things:
- A
kind=botuser inside one workspace. - One scoped
ccb_...bearer token for that bot. - A runtime config that stores the token and knows which workspace/channel to
watch.
The token is the install secret. The bot user is the visible chat identity. The runtime is whatever process uses the token: OpenClaw, CI, a small SDK script, or a service daemon.
#Pick the bot shape
Use a service bot for shared automation that does not belong to one human: deploy notifiers, triage agents, infrastructure bots, and shared OpenClaw workers.
Use a user-owned bot when the bot should be visibly attached to a person: personal OpenClaw agents, delegated assistants, or automation that should lose access if the owner leaves the workspace.
Both are normal ClickClack users with kind=bot. A service bot has no owner_user_id; a user-owned bot has owner_user_id=<human user id>. Bot tokens always authenticate as the bot user, never as the owner.
#Create a service bot
Run this on the ClickClack host, against the same data directory as the server:
clickclack admin bot create \
--data /var/lib/clickclack \
--workspace wsp_... \
--name "OpenClaw Service" \
--handle openclaw-service \
--scopes bot:write \
--token-name openclaw-prod \
--plain
Docker deployment:
docker exec clickclack clickclack admin bot create \
--data /app/data \
--workspace wsp_... \
--name "OpenClaw Service" \
--handle openclaw-service \
--scopes bot:write \
--token-name openclaw-prod \
--plain
--plain prints only the raw ccb_... token. Capture it once, move it into the target runtime secret store, and do not paste it into docs, tickets, chat, or logs.
#Create a user-owned bot
Pass the human owner's user ID:
clickclack admin bot create \
--data /var/lib/clickclack \
--workspace wsp_... \
--owner usr_peter \
--name "Peter's OpenClaw" \
--handle peter-openclaw \
--scopes bot:write \
--token-name openclaw-personal \
--plain
The owner must be a human workspace member. A bot cannot own another bot. The server also checks that the owner is still a workspace member when a user-owned bot token is used.
#Scopes
Start with the smallest useful bundle:
bot:read: read workspace/channel/message/thread/DM state and realtimebot:write:bot:readplus posting messages, replies, DMs, and uploads.bot:admin:bot:writeplus channel creation/update.
events.
Use explicit comma-separated scopes when a runtime needs less than a bundle:
--scopes workspaces:read,channels:read,messages:read,realtime:read
Current MVP scopes are documented in features/bots.md.
#Install into OpenClaw
OpenClaw's ClickClack extension reads ClickClack accounts from channels.clickclack. Keep tokens in env-backed secret refs:
{
"channels": {
"clickclack": {
"enabled": true,
"baseUrl": "https:
"clickclack",
"service",
{
{
"OpenClaw Service",
{ "env", "default", "CLICKCLACK_SERVICE_TOKEN" },
"usr_...",
"channel:general",
["*"]
},
{
"Peter's OpenClaw",
{ "env", "default", "CLICKCLACK_PETER_TOKEN" },
"usr_...",
"channel:general",
"model",
"openai/gpt-5.4-mini",
"senderIsOwner": true
}
}
}
}
}
Then set the environment on the OpenClaw process:
export CLICKCLACK_SERVICE_TOKEN=ccb_...
export CLICKCLACK_PETER_TOKEN=ccb_...
workspace may be the workspace ID (wsp_...) or slug. Targets are channel:<name-or-id>, thread:<message-id>, or dm:<user-id>.
#Install into a small SDK bot
For a one-shot bot:
CLICKCLACK_URL=https://app.clickclack.chat \
CLICKCLACK_TOKEN=ccb_... \
CLICKCLACK_CHANNEL_ID=chn_... \
CLICKCLACK_TEXT="clack from bot" \
pnpm --filter @clickclack/example-bot start
For a long-running bot, use ClickClackBot from the TypeScript SDK. Persist the latest event cursor after each handled event, reconnect with that cursor, and ignore messages authored by the bot's own botUserId.
#Verify the install
Check identity:
curl -fsS \
-H "Authorization: Bearer $CLICKCLACK_BOT_TOKEN" \
https://app.clickclack.chat/api/me
Check workspace access:
curl -fsS \
-H "Authorization: Bearer $CLICKCLACK_BOT_TOKEN" \
https://app.clickclack.chat/api/workspaces
Post a smoke message with the SDK example or the OpenClaw extension. In the UI, the message author should show the bot display name and a bot badge. A user-owned bot profile should also show that it belongs to its owner.
#Rotate or remove
The MVP has CLI creation and bearer-token auth. Revocation API/UI is planned; until that lands, rotate by creating a new bot token, moving the runtime to the new secret, and deleting or revoking the old token directly in the database during a maintenance window.
Keep these rules:
- Never commit raw
ccb_...tokens. - Store production tokens in env files, 1Password, or the hosting provider's
- Use one token per runtime so rotation has a small blast radius.
- Use service bots for shared infrastructure and user-owned bots for delegated
secret store.
personal automation.