# The /menu control panel

`/menu` opens the bot's settings card directly in Telegram: three feature doors, an Extra Features page, and the group picker behind `allowedGroups`. `/options` and `/help` are exact aliases for the same command.

## Opening the menu

Send `/menu`, `/options`, or `/help` in any chat the bot is in — three exact aliases for one command. Matching is case-insensitive, the leading slash is optional, and an `@<botusername>` suffix is accepted: `/menu`, `menu`, `/MENU@yourbot` all open it.

#### Who may open it — is\_owner\_or\_admin (any one is enough)

| Setting | Value |
| --- | --- |
| By user id | The sender's Telegram user id matches the id pinned from the bot owner's first `/start`. |
| By owner username | The sender's username matches the bot's configured owner username. |
| By platform admin | The sender's username is on Memescale's platform-admin username set. |

> **Telegram group-admin rights don't count**
>
> There is no call to Telegram's `getChatMember` anywhere in this check. A Telegram group's own admins — anyone promoted inside that group, however senior — cannot open `/menu` unless they also match one of the three conditions above. Anyone who doesn't gets no reply from this route at all: no denial message, no error.

This check is independent of whether the chat itself is authorized for the bot — the owner or a platform admin can open `/menu` in any chat the bot is a member of, authorized or not. See Groups and access for what "authorized" means.

* [Groups and access](#menu-access-groups)

## Command suggestions in unauthorized chats

Distinct from the settings card itself: Telegram also lets a bot push a per-chat list of suggested slash commands — the list under the `/` icon next to the message box. The bot recomputes that list on every incoming message.

When `is_authorized` — owner/staff, a DM-authorized username, or the chat's own presence in the allowed-groups set, see Groups and access — fails for the sender and chat a message came from, the bot deliberately pushes an **empty** list for that chat: `menu_plan` marks the scope `none`, and `sync_menu` calls Telegram's `setMyCommands` with an empty array. Nothing is suggested there — on purpose, not a bug.

This is separate from whether `/menu` itself works. `/menu` is gated purely on `is_owner_or_admin` (see Opening the menu above) and still runs when typed, suggested or not.

* [Groups and access](#menu-access-groups)

## The three doors

The root card's text is exactly `View the menu below.` Up to three doors follow, one per row top to bottom, then a `Manage Groups` / `Close` row at the bottom.

| Door | Opens | Always shown? |
| --- | --- | --- |
| 🎨 Image Generation Settings | The Image Generation Settings page (below) | No — only when the bot has at least one generation trigger. See The generation gate. |
| 💹 Buy Bot Menu | The buy bot's own settings card, replacing this card in place | Yes — injected on every bot, unconditionally. |
| ✨ Extra Features | The Extra Features page (below) | Yes |

> **Beta**
>
> The buy bot is currently in beta, served from the dashboard's beta tab.

Buy Bot Menu is a hand-off, not a settings page of its own here: the tap replaces the settings card with the buy bot's own card. If that card happens to be riding on a media message at the time (a buy-bot layout with an image or video attached), Telegram can't edit media back into plain text, so the bot drops that card and sends the settings page as a fresh message instead of editing in place.

* [The settings card](#buybot-commands-card)

`Manage Groups` opens the group picker described later in this chapter. `Close` deletes both the settings card and the original `/menu` command message that opened it.

> **Icon fallback**
>
> Menu buttons carry small Telegram custom-emoji icons by default. If Telegram ever rejects an icon for this bot, the bot immediately retries the same render as plain-text buttons and remembers not to try icons again — every later menu render for that bot stays plain text from then on.

Every settings-page button carries an `ms:` callback prefix; every group-picker button carries `om:`. Both are gated the same way as the command itself — a tap from anyone but the owner or a platform admin gets the alert `Owner / admins only` and changes nothing.

## The generation gate

The Image Generation Settings door renders only when the bot has at least one generation trigger. A bot configured with `packageType` `custom` — an edit-only / utility bot with no character and no trigger — yields no triggers at all, so the door never appears for it.

> **Note**
>
> A stale link or a hand-crafted callback that points straight at the Image Generation Settings page on a bot with no trigger is silently rewritten back to the root menu, instead of opening or erroring.

## Image Generation Settings

Header text: `🎨 Image Generation Settings`. Two switches, in this order, each a label row followed by an On / Off button pair; the page ends with `Back` / `Close`.

| Label | Writes | Default |
| --- | --- | --- |
| ✍️ Image Captions | `gallery_links_enabled` **and** `captions_enabled` — both, together | Off |
| ⌨️ Require Forward Slash | `slash_required` | Off |

> **One switch, two flags**
>
> Image Captions writes two separate config flags at once from a single switch: the gallery-link button under a generation (`gallery_links_enabled`) and the caption text under a generation (`captions_enabled`). The switch itself reads as On whenever either flag alone is On, and tapping it writes the same new value to both.

> **Require Forward Slash also gates edits**
>
> This switch isn't limited to generations. When it's on, the bot's edit-prompt extraction refuses to recognize an edit at all — a reply to a photo with a prompt, or a photo sent with a prompt caption — unless the text starts with `/`. Turning it on silences bare-word image edits exactly the way it silences bare-word generations.

> **Same flag, the dashboard's wording**
>
> The dashboard's equivalent switch (Settings → Features → Slash Required For Generation) carries this tooltip: "When this is on, generating or editing an image in your group only works with a forward slash in front of the command. If your command is `generate`, people have to type `/generate` — typing the bare word does nothing. Turn it on when a trigger word also comes up in normal chat, so an ordinary message never fires an unintended generation." Same `slash_required` flag either way.

## Extra Features

Header text: `✨ Extra Features`. Four switches, in this order, same label-then-On/Off shape; the page ends with `Back` / `Close`.

| Label | Writes | Default | Write path |
| --- | --- | --- | --- |
| 🎵 MP3 Downloader | `mp3_enabled` | On | Bot state — instant, in-process. |
| 😀 Emoji Packs in Groups | `emoji_packs_enabled` | On | Bot state — instant, in-process; also re-registers this bot's Telegram command menus. |
| 🐦 X Automation | `twitter_automation_enabled` | Off | Bot state — instant, in-process. |
| 🔎 Multi-Chain Scanner | `scanner.enabled` | Off | `memebot.json` — see below. |

> **Beta**
>
> X automations are currently in beta.

The first three switches write straight to the bot's own state file and take effect immediately, with no round trip anywhere. Multi-Chain Scanner is different: it lives in `memebot.json`, so the tap dispatches to memescale.ai, which writes the config, pushes it to the bot, and reloads the bot before the tap gets its answer.

*What the bot replies on tap*

| Situation | Reply |
| --- | --- |
| Already in that state | `Already on` / `Already off` |
| Toggled successfully | `Updated` |
| Multi-Chain Scanner only: the dashboard couldn't be reached | `Couldn't reach memescale.ai — try again` |

* [What an automation is, and the master switch](#xauto-what-it-is)
* [Turning the scanner on and off](#calls-toggle)
* [MP3 downloader](#tools-mp3-downloader)

## The Manage Groups picker

`Manage Groups` opens the same group-picker implementation the buy bot uses for its own target list (see Groups and access) — pointed at `allowedGroups` instead. Prompt text, with rows to show: `Which group should I generate and edit images in? Tap to add or remove.`

With no admin groups to show yet, the card reads instead: `Promote me to admin in whichever group you'd like me to generate images in, then tap Add Groups.`

* One row per group the bot is currently an admin in — rechecked live, capped at scanning 40 groups — where the tapping user is also a member: `✅ Title` when authorized, `❌ Title` when not. Tapping a row flips it and the card redraws in place.
* Any group still in `allowedGroups` that the live admin check can no longer vouch for — the bot was removed or demoted since — still gets a `✅` row, so it can still be removed even though it can't be re-added by tapping.
* Group titles on each row are capped at 48 characters.

#### Add a group

1. Tap `Add Groups`.
2. The card is replaced with: `Let's add a group. Make sure I am in the group as an admin first, and then send me either the link to the group, or the group ID which you can get by typing /getid.`
3. Send a public group link, an `@handle`, a `t.me/c/…` message link, or the numeric chat id from `/getid` as your very next message in that chat.
4. The bot checks the chat and replies with the outcome below.

*What you can paste*

| You send | Read as |
| --- | --- |
| A number, 5+ digits, with or without a leading `-` | Chat id |
| `@handle` | Public handle |
| `t.me/…`, `telegram.me/…`, `telegram.dog/…` public link | Public handle |
| `t.me/c/<id>/…` message link | Chat id |
| `tg://resolve?domain=…` | Public handle |
| `t.me/+…`, `/joinchat/…`, `tg://join?invite=…` — a private invite link | Refused, see below |

`{what}` in the replies below becomes "link" or "group ID", matching whichever form you sent.

*What the bot replies*

| Situation | Reply |
| --- | --- |
| Not a recognizable link or id | `That doesn't look like a group link or ID.`, then the Add Groups prompt again |
| A private invite link | `That's a private invite link, and Telegram doesn't let bots look those up. Send /getid inside the group and paste the group ID here.` |
| The bot isn't in that chat | `I'm not in this group yet, add me first and repaste the {what}.` |
| The bot is in the chat but not an admin | `I'm in the group but not an admin yet, once I am admin repaste the {what}.` |
| The chat is a channel, not a group | `That's not a group. Send the {what} of a group I'm an admin in.` |
| Already authorized | The picker redraws with `<title> is already authorized ✅` on top. Nothing is written. |
| Otherwise | The group is authorized. The picker redraws with `Added <title> ✅` on top. |

> **Limit**
>
> This picker enforces no maximum group count. Every row above is the only thing standing between a tap and a newly authorized group.

* [Manage Groups — buy bot's picker](#buybot-commands-groups)
* [Groups and access](#menu-access-groups)
