Conversation
The bot never registered its commands, so Telegram's in-app "/" menu button
had nothing to show and the commands were only discoverable by reading
/mp_help. Register the list with setMyCommands so commands are tappable.
Lists are scoped to mirror the role model in _process_cmd rather than
exposing the whole admin surface to every user:
- default scope -> 5 public self-service commands
- admin/superadmin chats via admins.conf -> 18 command control plane
- root chat and superadmin admins -> those 18 plus the four commands
gated on the superadmin role (/mp_remove, /mp_restart, /mp_update,
/mp_lockdown)
The command tables live once, in the manager. The generated bot daemon
re-runs `mtproxymax telegram sync-commands` on boot instead of carrying its
own copy, so the menu self-heals and picks up newly added admins. Syncing is
best-effort throughout: a Telegram outage must never break setup or the poll
loop, and revoking an admin calls deleteMyCommands so a stale admin menu is
not left behind.
Also add an explicit `telegram sync-commands` subcommand for manual re-sync.
rvalitov
marked this pull request as ready for review
September 18, 2026 08:05
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #136
Related PR list:
feat(telegram): register the bot command menu with
setMyCommandsThe problem
The bot has 27 commands, but nothing tells a user they exist. The client-side
/menu button shows an empty list, so the only way to discover a command is to
already know it — or to read
/mp_help, which itself has to be known.That is a poor fit for the public self-service tier in particular, where the
whole point is that an end user with a secret label can check their quota
without an admin walking them through it.
What this does
Registers command lists with Telegram via
setMyCommands, scoped so each rolesees only what it may run:
TG_CMDS_PUBLIC—/start,/my_status,/redeem,/voucher,/supportsuperadmininadmins.confTG_CMDS_SUPERADMIN— the admin plane plus/mp_remove,/mp_restart,/mp_update,/mp_lockdownresellerinadmins.confTG_CMDS_ADMIN— the admin plane, minus the superadmin-only fourThe scope mirrors the gates
_process_cmdalready applies, so the menu neveradvertises something a role cannot actually run.
Three tables (
TG_CMDS_PUBLIC,TG_CMDS_ADMIN,TG_CMDS_SUPERADMIN) are thesingle source of truth. The bot daemon does not duplicate them — it re-runs
mtproxymax telegram sync-commandson boot instead.When it re-syncs
sync-commandsbefore the poll loop)admin_add) or has one revoked (admin_remove) — revocation callsdeleteMyCommandsfor that chat so a demoted admin stops seeing the admin planemtproxymax telegram sync-commandstelegram setupEvery call is best-effort. A Telegram outage must never abort setup or stall the
poll loop, so failures are logged and swallowed.
Defensive details
stripped, quotes and backslashes escaped). Telegram rejects the entire list
if any single entry is malformed, so one stray character would blank the whole
menu.
_tg_api_postkeeps the bot token out of the process list by writing the URLinto a
curl -Kconfig file rather than passing it as an argument.Testing
tests/test_telegram_commands.sh— 28 assertions, 0 failures.It stubs
curlto capturemethod | chat_id | commandsinto a TSV and asserts:scoping per role, no duplicate commands across scopes, that the emitted bodies
are valid JSON, and that a network failure is survivable rather than fatal.
Files
mtproxymax.sh— command tables, JSON rendering, sync/clear, CLIsync-commands, wizard and boot hookstests/test_telegram_commands.sh— newREADME.md— documents the/menu andtelegram sync-commands