tg-operator-cards
Installation
SKILL.md
tg-operator-cards
Input: the facts of one event. Output: a short sendMessage text in parse_mode: HTML for the operator of the bot. Three shapes share one layout: the review card (waits for a decision), the receipt (the bot already acted), and the decision footer (records who decided and when).
Not for messages to customers, digests of many events (tg-rich-digest), tables (tg-rich-messages), or rewriting agent prose (tg-reply-rewrite). Write in the operator's language.
Rules
- First line: outcome and person. It must make sense alone in a notification preview:
✅ Enrolled: Ada (@ada). Bold the outcome and the name. A review card starts with the thing to decide:🧾 Order #482. - One fact per line. Each line starts with one emoji that names the kind of fact: 🧾 order or application, 💳 money, ✉️ delivery to the person. The same emoji means the same kind of fact in every card of the bot. No blank lines inside a block.
- Label first, value second. Bold only the values the operator checks against another system: the amount, the order number. Put values the operator copies in
<code>: product code, ticket code, ID. - A problem takes the place of the normal line. Where the card would say what went fine, put ⚠️, what failed, and the next step in one sentence. The card keeps its shape, so the warning line is the one that looks different.
- Say what the bot did.
Confirmation sent, notsent him the confirmation. In languages with grammatical gender this keeps the card correct for every person. - Format numbers for reading.
19 000 ₽, not19000. Name the moment a date refers to:Paid … on 08.11, not a bare date. - No filler. No "successfully", no "please note", no closing period on a one-fact line.
- Escape
&,<,>in every dynamic value. Names come from users. One unescaped<and Telegram rejects the whole message with400 can't parse entities: the action happened, and the operator saw nothing. - The decision edits the card. When the operator presses a button, edit the same message with
editMessageText: the same card text, a footer line, and no decision buttons. One event stays one message in the chat. - What the bot knows about the person is a second block. After one blank line: a count line, then past orders oldest first, each with its period and amount. Name where the knowledge ends (
in the bot), so an empty history is not read as a new customer. Leave the current order out of the list. When the history cannot be read, omit the block:noneis a claim, not a fallback. - In a private chat the person block can be a widget. Send the person, the current order and their history as an HTML widget (
tg-widgets). The caption carries the first line and only the facts the widget does not show: a client that draws widgets puts the caption right under the widget, and a repeated fact is read twice. A client without widget support shows only the caption, so its first line still names the outcome and the person. Give the widget a button only for an action the operator takes: no copy button for a value nobody pastes. Groups refuse widgets today, see the delivery table in tg-widgets: there the card stays text. When the server refuses the widget, send the full text card instead.