CLEMA protocol

Bots

A bot is an account a program runs. Its owner makes it, and it is a user like any other: a Mandarin ID, a profile, the conversations it is in, everybody's privacy and blocks as people have them. What sets it apart is how it is reached: it signs in with a token rather than a phone, and it hears of what happens through a queue of its own rather than connections, over the Bot API (HTTP).

Bots are made and managed through the system bot, in a conversation with it, which works in every client and changes with the server rather than with the clients' releases.

Bot Accounts

What a Bot Hears

A bot follows the streams its user would — its account stream and the stream of every conversation it is in, from when it joined — and is told of:

Event When
message.created, message.edited, message.deleted What is said, and done to what is said
message.reacted A reaction to a message
member.added, member.removed Who comes and goes
conversation.created, conversation.deleted The bot comes to be in a conversation — saying by whom it was added, as a person is told — or is out of it, and why
button.pressed Somebody pressed one of its buttons

Reads, deliveries, pins, drafts and the like are for people's devices and never reach a bot. A bot is not told of what it did itself: a message it wrote or edited, deleted, or reacted to.

All of a direct conversation is addressed to the bot. Of a group, the bot hears what its owner chose, publicly, on its profile, as it was when the bot joined — what those who added it saw. Changed later, it holds in the groups the bot joins after; where it is already, it is to be added again to take it up.

The Queue

Every event a bot is to hear of is noted in its queue in the same transaction that writes the event, so nothing written is ever missing from it. A program takes the queue over the Bot API, and what it confirms goes; confirming a conversation's messages is as far as a bot reads them, so the people it talks with see them read. An update not confirmed within 24 hours of its event goes, and so does one with nothing left to tell.

Buttons

A bot's text message may carry buttons under it, as keyboard: rows of buttons, each with the text it shows, up to 64 characters on one line, and either data — 1 to 64 bytes of text the bot is told when somebody presses it — or a url — an http or https address of up to 2048 characters of printable ASCII, a name in another script given in punycode, and without a user before its host — which a client opens once the person agrees. A row has up to 8 buttons, a keyboard up to 100, taking up to 16 KB as JSON. Only a bot sends them, in message.send and message.edit; anybody else's are not_authorized. An edit carries the keyboard the message is to have: none, when it is left out.

{"id":"poll","type":"message.send","data":{"operation_id":"poll-1","conversation_id":"c_38a2","kind":"text","payload":{"text":"Lunch at noon?"},"keyboard":[[{"text":"Yes","data":"lunch:yes"},{"text":"No","data":"lunch:no"}],[{"text":"Menu","url":"https://example.com/menu"}]]}}

Returned messages carry their keyboard as it is sent. A client shows it under the message and, when a button with data is pressed, tells the server so, showing it waits until the press is answered:

{"id":"press-1","type":"button.press","data":{"msg_id":"512","data":"lunch:yes"}}

A press is of a button the message has, in a message the presser sees, of a bot still in the conversation, and is not_found otherwise. The bot is told of it as button.pressed, in its account stream: press_id, who it is from, the conversation_id, the message as the bot sees it, and the button's data:

{"type":"button.pressed","seq":"77","data":{"press_id":"p_6f1c2a9e","from":67890,"conversation_id":"c_38a2","message":{"msg_id":"512","conversation_id":"c_38a2","from":12345,"kind":"text","payload":{"text":"Lunch at noon?"},"time":"2026-10-13T09:00:00Z","revision":1,"reactions":[]},"data":"lunch:yes"}}

The bot answers with button.answer: the press_id, and what the person is shown, a text of up to 200 characters, alert to be dismissed rather than shown briefly. That answers the press:

{"id":"answer-1","type":"button.answer","data":{"press_id":"p_6f1c2a9e","text":"Counted","alert":false}}
{"id":"press-1","type":"button.press","ok":true,"data":{"text":"Counted","alert":false}}

A press the bot does not answer within 10 seconds is answered with nothing, and the client stops waiting; answered later, or by any other bot, button.answer is not_found. A press is the bot's and the presser's alone: it goes into no history, and nobody else learns of it. ICQ clients show no buttons.

Commands

A bot says which commands it takes: lists of a command, 1 to 32 Latin lower-case letters, digits and underscores written after /, and its description, up to 256 characters on one line, up to 100 a list. One list is for everywhere, and others may take its place in direct conversations and in groups. A bot's profile carries the lists that hold, as commands:

{"commands":{"direct":[{"command":"start","description":"Begin"},{"command":"forecast","description":"The weather where you are"}],"groups":[{"command":"forecast","description":"The weather where you are"}]}}

A client offers them as / is typed, in a conversation with the bot or a group it is in, from the bot's profile as it fetches it. In a group, a command chosen is written /command@name, the bot's name, mentioning the bot, so that a bot hearing only what is addressed to it hears it too. Whoever follows the bot's profile is told when they change, which they do ten times a minute at most: more is rate_limited.

The System Bot

The server runs a bot of its own, which makes and keeps people's bots: the system bot, Bots, by the name bots — shorter than any name a bot may be given, so that nobody else has it. It is a bot as any other to whoever writes to it, in a direct conversation, from any client, ICQ's included, and it is in no group. Its owner is the server; it signs in nowhere, and nobody manages it.

It is told what to do with commands, a message each — they are its profile's commands — and what a command asks for comes in the messages that follow, a step each, until it is done:

Command Steps Does
/newbot the bot's name as people see it (its nick), then its public name Makes a bot, and tells its link, ID and token
/mybots — Lists the sender's bots
/token the bot Replaces the bot's token, and tells the new one
/setname the bot, then its name Changes the nick the bot goes by
/setdescription the bot, then the text, or /empty Changes what the bot says about itself, its about
/setuserpic the bot, then a picture, or /empty Changes or removes the bot's avatar
/setreads the bot, then all or addressed Changes what the bot hears of the groups it joins after
/setjoingroups the bot, then enable or disable Lets everybody add the bot to groups, or nobody: its group_invites privacy
/cancel — Gives up the command under way
/help, /start — Tells what it can do

A bot is chosen by its public name, with or without @. Where a step has choices — which bot, which value — they are buttons under what it asks as well: a press is as the words it stands for, and counts under what it asked last alone — a press of any button above that is answered that it is over. A picture is sent as a photo of up to 10 MB, which the server makes an avatar of as it makes a preview, aside, telling once it is done — a picture that won't do ends the command; a server that makes no previews takes a JPEG or PNG of up to 512 KB as it is. A step answered wrongly is asked again; another command gives up the one under way, and so does an hour without an answer, or the server's restart. The system bot answers at a bot's pace, like any other: past it, a flood goes unanswered.

Mandarin

The server runs a second account of its own, Mandarin, which tells people of their accounts, as the chat «Telegram» does there. It has an ID of its own, 1, below where the server's IDs start, so that nobody else ever has it, and the name mandarin, which no invitation may take. It is a bot owned by nobody, whom nobody adds to a group; its profile and its conversation say official as the system bot's do.

It writes to anybody, whatever they let others write to them, unless they block it, and takes no messages: its conversation has no message.send among its capabilities, and writing to it returns not_authorized. Over a transport it is a contact like any other, ID 1, whose messages arrive and whose buttons do not.

It writes, in the language of the account's session used last that said one (Russian to whoever reads it, English to everybody else):

When What
A code to sign in is asked for and goes to the app The code, and the address that asked; marked sign_in_code, it goes to no transport
An account is made A welcome, with a link to the service's news where the server has one
A session signs in with a code, or a QR code lets one in How it got in, its device and address, and buttons that own it or end it
A transport's client signs on from an address it did not sign on from for a month That it did, and from where
The account's number changes That it changed, not to what: transports show it too
A transport's password is set, changed or removed That it was
A wrong password is given at a transport five times within an hour How many, and the last address; once an hour at most
A new session takes the place of a CLEMA client's session Which one ended
An operator queues a notice (mandarin-server notice <text>) The notice, to everybody, within a minute; a server that stops while writing it leaves the people it had taken in hand without it

A sign-in's notice has two buttons: "It's me" and "End session". A press of "End session" ends that session, if it is still there, and the notice is edited to say it was ended; a press of "It's me" leaves it, and the notice is edited to say it was the account's own. Either way both buttons go.

Bot API

A program drives a bot over HTTP, the Bot API, on the server's own address: POST /bot/<token>/<method> with JSON parameters, answered {"ok": true, "result": ...} or {"ok": false, "error": {...}} with the codes of Error Codes. What a bot does is done as the CLEMA command a client would make, and fails as that would. Its methods, the updates and how they are confirmed, webhooks and the pace a bot keeps are described for bot developers in the Bot API guide.