$cmdThe line
/$command
-$option $value
Hover any term for what it is. An entity is not a third kind of thing — it is an option whose type resolves to a person, chat or file, so it also stays in mentions or attachments.
$tagiAnatomy of a tag
What one option looks like in the composer, empty and filled.
$attach
attaching
a file
$attach
attaching
๐ฌ
composer-crash.mp4
×
- iconicon, image or emoji — the same three the dropdown row allows
- keygrey, always readable, never clipped
- valueaccent, sized to its text, with its thumbnail once picked
| Part | Limit | Past it |
| key | 14 characters | never clipped — the tag wraps to the next row instead |
| placeholder | 24 characters | clipped, the tag keeps its width |
| value | 230px, about 28 characters | clipped with an ellipsis, full text on hover |
| tags per line | 5 | they flow onto a second row, never scroll |
$fileDeclaration
// added to the command; without it nothing changes
{
"name": "$command",
"options": [
{ "name": "$option", "type": "text", "required": true },
{ "name": "$option", "type": "password" },
{ "name": "$option", "type": "dropdown", "choices": [] },
{ "name": "$option", "type": "dropdown" }, // no choices: the suggestion handler fills it
{ "name": "$option", "type": "date" },
{ "name": "$entity", "type": "user" }
]
}
$listOption types
The same vocabulary Cliq forms already use, so an option reads like a form field.
Typeparams returns
$font
text
string
$chev
pattern — a regular expression the whole value must matchmin / max — length in characters, counted after trimming- Leading and trailing space is dropped before any check runs
$lock
password
string
$chev
- Same
pattern, min and max as text - Never echoed in the sent line, the card, or
arguments - Not carried in the chat history — the handler is the only thing that sees it
$flash
number
int
$chev
min / max — a ceiling only where one is declared, so a percentage caps at 100 and a sum of money does not- Whole numbers only unless the option is declared decimal
- Grouping separators are refused:
1,250 won't do, 1250 will
$list
dropdown
string
$chev
- With
choices: the value must be one of them - Without: a typed value that isn't in the fetched list is offered back rather than refused — the list is advisory
- The label is what you read; the
value is what the handler receives
$cal
date
date
$chev
- Must be a real date — 31 Feb is refused at the picker
min / max as ISO dates, so a leave request cannot start in the past- Sent as ISO, read back as a date
$clock
time
time
$chev
- 24-hour, in 30-minute steps unless the option declares its own
min / max bound it to working hours where that matters- Paired with a
date option, the two are checked together
$phone
phone
string
$chev
- The country comes from the list — the code is never typed
- Digits, spaces and hyphens only after the code
- Length is checked against the country, so a 9-digit Indian number is refused
$cash
currency
string, int
$chev
- The currency comes from the list, never free text
- Amount of 0 or more, at most two decimal places
- Handler receives the code and the amount apart, never a formatted string
$mail
email
string
$chev
- One address per option — no comma-separated lists
- Shape is checked, delivery is not: a typo that parses still sends
- Display names are stripped:
Riya <riya@…> keeps only the address
$user
user
the person
$chev
- Must resolve to somebody in the org
- Refused with a reason when they are outside the chat the command ran in
- Deactivated accounts do not appear in the list
$team
chat
the chat
$chev
- Only chats the caller can already see — a command cannot be used to discover a private channel
- Restricted rows show as restricted rather than being hidden, so the refusal is legible
- Archived channels are excluded
$attach
file
the file
$chev
- The caller must be able to open it — access is checked at pick time, not at send
- Type and size limits are the chat's own
- A link to a file is resolved to the file, not the URL
A value that fails is refused in the composer, with the reason under its tag — the handler is never called with it.
$layersOptions that depend on others
A line is not a fixed set of tags. Two rules change what is on it, both read from what is already filled.
// a tag that only exists in some cases
{ "name": "room", "type": "dropdown", "required": true,
"showWhen": { "mode": "f2f" } }
// a tag that repeats as many times as a count says
{ "name": "count", "type": "stepper", "min": 2, "max": 5 },
{ "name": "choice", "type": "text", "repeat": "count" }
| Rule | What happens |
| showWhen | The tag appears only when the named option holds one of the listed values. Hidden means absent, not empty — params has no key for it, and a hidden option is never required. |
| repeat | The tag is drawn once per unit of the option it names, arriving as choice1…choiceN. Lowering the count drops the last tags and their values. |
| stepper | A number set with − and +, bounded by min and max. Use it where the count itself is the question, so the row grows as you answer. |
Try it: /schedule-meeting asks for a room only when the meeting is face to face, and /poll grows a tag per option as you step the count.
$listAnatomy of a dropdown row
Three parts, the same shape Cliq's suggestion rows already use.
๐ช๐บ
EUR · Euro
€
Available
open to interruptions
D
#TKT-00892 Payment gateway timeout
critical
Jeri
Product Manager
#3939 Issue: Can't view visitor
#SalesIQ-issues
Same three parts every time — a status, a ticket, a person, a currency. What changes is only which of the three thumbnail forms the row sends.
The thumbnail takes any one of three forms. What you send on the left, what the row draws on the right.
| You send | Renders as |
"icon": "e102" |
$cash a Cliq glyph, in the row's own colour |
"imageurl": "…/eu.png" |
the image, cropped to the square |
"emoji": "๐ช๐บ" |
๐ช๐บ the emoji, at the same size |
- thumbnailan icon code like
e102, an imageurl, or one emoji — one of the three, never two
- titlethe label, and what typing matches against
- descriptionmeta text, right-aligned, safe to lose
| Part | Limit | Past it |
| title | 60 characters | clipped with an ellipsis |
| description | 60 characters | clipped, then dropped on a narrow composer |
| imageurl | 500 characters | row renders without a thumbnail |
| icon | 4 characters, e100–e999 | unknown codes draw nothing |
| emoji | 1 character | only the first is drawn |
| rows | 25 per fetch | the rest are not sent |
The row limits are the composer's, not the handler's — a longer title is accepted and then clipped, so a fetch is never rejected for cosmetics.
$rocketExecution handler
Everything delivered today is unchanged. params is added.
// Deluge
value = params.get("$option");
who = params.get("$entity");
response = Map();
response.put("text", "Done: " + value);
return response;
| Attribute | Contents |
| arguments | The raw string after the command name. Still delivered, so a handler can migrate one option at a time. |
| options | The -key value pairs, as strings. Unchanged. |
| selection | What you picked from the suggestion handler's list, as maps of title, description, imageurl. Unchanged. |
mentions attachments | The entities on the message. Unchanged. |
chat, user, location | Unchanged. |
| paramsnew | Keyed by option name, typed per the declaration. An absent optional option is an absent key. |
$searchA command with no options
Declaring options is not required. A command can keep exactly today's shape: no tags, and the suggestion handler opening the moment you pick the command.
/gif search GIFs
- The list opens on pick, not on a tag — there is nothing to fill first.
- What you choose is the whole input, and arrives in
selection, exactly as it does today.
params is empty, because nothing was declared. A handler written for today keeps working untouched.
- Try
/gif or /oncall.
$searchSuggestion handler
Already in Cliq, unchanged. A dropdown declared without choices is filled by it, so there is no second lookup handler to write.
$linkBack-linking
Declared per option, fired after the handler returns. Off by default — a linked entity is usually enough, and a second message in the referenced chat is noise.
$layersCompatibility
- No declared
options means the command behaves exactly as it does today.
- Filling a command shows no typing indicator in the chat. The composer is local until you send — the other side learns nothing from you picking a ticket and changing your mind.
arguments is still delivered to declared commands.
- Adding an optional option is backward compatible. Making one required, or narrowing a type, is not.