replies - WireCatLabs/tg-cli GitHub Wiki
This page is about answering Telegram messages automatically when you cannot answer yourself — for example, a short "I will answer in the morning" to people who write after working hours. By the end you have a working auto-reply: a rule with your reply text, a choice of who may get it, a way to check what it would answer before it sends anything, and ready-made texts from Drafts and reply templates.
A few words used below:
- A rule says which incoming messages to answer and what to do: reply, open a task, or both.
- A template is the reply text. It can include the sender's name and the time.
- The audience is the list of people and chats that may get a reply at all, whatever a rule says.
-
tg personal serveis the background process that receives new messages and applies the rules.
Who gets a reply, and when anything is sent:
-
Replies go to everyone your rules match, unless you limit the audience. Answer only selected
people with
tg personal replies audience --reply listed --allow-people …, or leave some out with--deny-peopleand--deny-chats. -
Nothing is sent until you turn sending on.
permissions.replies.sendmust beallow.askcounts as no, because a background server has nobody to ask. A new rule is also off until you turn it on.
The full option lists are in the auto-reply commands.
tg personal replies add away
tg personal replies edit away --template 'Thanks, {{ sender.firstName | default: "there" }}! I will answer in the morning.'
tg personal replies edit away --outside 09:00-19:00 --days mon-fri --timezone Europe/Madrid
tg personal replies edit away --per-chat 1/12h --per-person 1/1dadd creates a rule that is off, with every setting written out. The rules live in
<profile>.replies.json, in the same folder as the configFile that tg config show --json names.
By default the rules answer everyone they match. To answer only selected people, list their Telegram
ids, comma-separated; tg personal contacts show <name> --json prints a person's id as id:
tg personal replies audience --reply listed --allow-people 1000001To answer everyone except some people or chats, keep --reply all and deny them:
tg personal replies audience --deny-people 1000002 --deny-chats -1002000002After the first command the file holds:
{
"audience": {
"reply": "listed",
"allow": { "people": ["1000001"], "chats": [] },
"deny": { "people": [], "chats": [] }
},
"rules": [ … ]
}Rule ids are lower-case letters, digits and -, and each is unique. A rule that replies cannot be
turned on with an empty template.
Then look at what it would have answered, turn it on, and start the server:
tg personal replies test --since-time 7d
tg personal replies on away
tg config set permissions.replies.send allow
tg personal servereplies test reads only messages already in your local store. It sends nothing, changes nothing
and never connects. tg personal replies off away turns one rule off.
replies edit changes only the fields you name. A comma-separated list replaces the whole list; an
empty string clears it.
| What | Options |
|---|---|
| Action |
--do reply,task — a reply, a task, or both |
| Chats |
--kinds dialog,group, --allow-chats, --deny-chats
|
| Conditions |
--words, --question / --no-question, --mentions-me / --no-mentions-me
|
| Senders |
--allow-people, --deny-people, --contacts-only / --no-contacts-only
|
| Reply |
--template, --as-reply / --no-as-reply
|
| Limits |
--per-chat, --per-person, such as 1/12h
|
| Working hours |
--outside, --days, --timezone, --no-hours
|
The first time you set working hours, give the window, the days and the time zone together; after that you can change one. A wrong edit does not overwrite the file, and the other rules, the audience and the record of what was answered stay as they were.
tg personal replies audience shows who the whole file may answer. A new file is --reply all: it answers
anyone a rule matches. --reply listed answers only the allowed people and chats. --allow-people, --allow-chats, --deny-people and --deny-chats
replace those lists, and a denial wins over an allowance. A task action opens a task on this computer
and is not limited by the audience.
Examples of reply texts for common cases, and when to keep a draft instead, are on Drafts and reply templates.
A template can use sender.firstName, sender.name, chat.title, chat.kind and now (in the
rule's time zone, or UTC without working hours), with filters such as {{ now | date: "%H:%M" }}. The
incoming message's text is not a template variable. Unknown variables and filters are refused.
A model may write only the ai block; everything outside it is your text:
Thanks, {{ sender.firstName | default: "there" }}!
{% ai %}Briefly confirm you got the message; I will answer tomorrow.{% else %}I will answer tomorrow.{% endai %}The block's body is an instruction to the model. The incoming text goes to the model separately, as
data. When no model is set up, there is no consent, or the call fails, the else text is sent; without
an else, the message gets no reply and the reason is recorded.
Choose the model with models.replies.provider (openai or anthropic), models.replies.model and,
for your own server, models.replies.base_url; models.default fills what is not set. Keep the key with
tg personal models text key set.
Using a model needs its own consent, separate from the right to send:
tg personal replies consents show
tg personal replies consents grant
tg personal replies consents revoke
tg personal replies consents deny -1002000002
tg personal replies consents allow -1002000002grant lets incoming message data go to the chosen provider for the whole profile. deny keeps one
chat's messages away from the model; allow removes that, without granting consent. A new provider
or endpoint needs consent again. tg personal replies test --ai sends stored messages to the model so you can
see its text; it still sends nothing to Telegram.
- Anyone the audience does not allow.
- Your own messages, channels, bots, and messages sent on behalf of a chat.
- An edited message, a message already handled, and anything that arrived before
servestarted. - In a group, a message that neither mentions you nor replies to you, unless the rule names that group
in
chats.
perChat and perPerson limits are required on every rule, so two auto-repliers that answer each
other stop at the first limit.
tg personal replies pause
tg personal replies resume
tg personal replies status
tg personal sends listpause stops every rule at once, a running serve included, without a restart; resume undoes it.
status says whether sending is allowed, which rules are on and who they may answer. sends list
shows each reply with the rule that sent it.