Telegram Stickers for Hermes Agent
Lets your Hermes agent answer with Telegram stickers: default packs out of the box or packs you choose, picked by emoji or by meaning, sent as a reply in the right topic, paced like a person.

Hermes Agent is an open-source AI agent from Nous Research; on Telegram it talks as your bot. Out of the box it cannot send stickers. This plugin lets it reply with stickers: from four default packs at first, then from the packs you choose.

Re-drawn from live test chats; names replaced. MP4 version.
🚀 Quick start
You need Hermes Agent 0.20.6 or newer with its Telegram gateway set up (hermes gateway setup); 0.21.5 or newer to run every /stickers command in Telegram (see Known limitations). A vision model is needed only for step 4. No extra Python packages.
1. Install, enable and restart the gateway. Hermes 0.21.3 and newer warn that the source is not from their catalog; Hermes asks for TELEGRAM_BOT_TOKEN (the token your gateway already uses) only if it does not have it yet. If you run hermes gateway in a terminal, stop it and start it again instead of restart.
hermes plugins install churnast/hermes-telegram-stickers --enable
hermes gateway restart
2. Say hi to your bot in a direct chat. On a fresh install, the agent sets stickers up with you there: how often in that chat, how often in groups, and a few stickers from packs you like (see Setup and changes in words). You can skip it.
Or pick your packs yourself. Send your bot a few stickers you like in a direct chat: their packs are added automatically. Or set packs by name, favourite first (the part after t.me/addstickers/, or the whole link; any public pack works), then restart the gateway again. Until you do either, four packs made by Telegram work out of the box. If other people can message your bot directly, their stickers add packs too: keep the gateway allowlist to yourself, or set learn_packs to false.
hermes config set plugins.entries.telegram-stickers.settings.packs '["MyFavouritePack", "AnotherPack"]'
3. Check it in Telegram. In a direct chat with your bot, send /stickers. It lists your packs, starting with a line like Stickers: 42 in 2 pack(s), 0 with a description. (Before Hermes 0.21.5, learned packs show there only as a count; /stickers in the Hermes CLI names them.) Then ask the bot for a sticker.
4. Optional: pick by meaning. Send /stickers describe in the same chat (before Hermes 0.21.5, in the Hermes CLI on the server: run hermes, then /stickers describe). Your vision model describes up to 30 stickers per run; send it again for the next batch.
🐾 What you get
From live test chats on 5 October 2026, where the agent was also told to prefer a sticker to a lone emoji; the off-switch scene is from a separate run. Usage footers and some messages are left out; pacing was reset between scenes.
Picks the moment. Nobody asked for a sticker: happy news gets a kitten as a reply.

Picks by meaning. A smug cat gets a smug kitten (the sticker it sent is tagged 😼).

An off switch that sticks. Ask once, it stays off: the plugin gives the agent no tool to switch stickers back on; only /stickers on does.

What it adds: four tools, the /stickers command, a skill and a hook that adds a short sticker hint on Telegram turns where a sticker is allowed; to learn packs from stickers you send, also a Telegram handler (see Privacy and safety).
telegram_sticker_send: sends one sticker, picked by a few words, a reaction ("facepalm"), an emoji or an id, as a reply in the current topic.telegram_sticker_find: lists your packs and emojis, or finds stickers.telegram_sticker_mute: switches stickers off in the chat when someone asks; only/stickers onundoes it (see /stickers commands for where it works).telegram_sticker_settings: the setup, and settings changed in words: how often, only on request, off; "don't send this one"; remove a pack or all packs; bring back the default packs; show packs and settings.telegram-stickers:sticker-etiquetteskill: when a sticker fits and when words are better.
💬 /stickers commands
| Command | Where | What it does |
|---|---|---|
/stickers |
any chat | Packs (yours, learned or default), described stickers, on or off here. In a direct chat, also muted chats with ids; in a group, learned packs only as a count. |
/stickers sync |
any chat | Reloads the packs from Telegram. |
/stickers off, /stickers on |
any chat (Hermes 0.21.5 and newer) | Switches stickers off or on in this chat. |
/stickers describe [n] |
direct chat | The vision model describes up to n undescribed stickers (default 30), learned packs first, newest first. |
/stickers describe again [n] |
direct chat | Redoes descriptions from an older prompt or Hermes' cache, never your own. |
/stickers off <chat id>, /stickers on <chat id> |
direct chat | The same for another chat, by its id. |
/stickers ban <id>, /stickers unban <id> |
direct chat | Takes a sticker out of use, or brings it back. |
/stickers about <id> <text> |
direct chat | Replaces a sticker's description with your text. |
/stickers forget <pack> |
direct chat | Removes a pack learned from your stickers. Sending a sticker from it adds it back. |
/stickers setup |
direct chat | Starts the setup again with your next message in the direct chat. |
Sticker ids look like MyFavouritePack:12; the agent's telegram_sticker_find tool shows them. Commands that change your stickers or other chats are direct-chat only, since anyone in a group may be able to run slash commands.
Before Hermes 0.21.5, Hermes does not tell plugins which chat a slash command came from. In Telegram, /stickers then shows the status (learned packs only as a count, no muted chats) and /stickers sync reloads the packs; the other commands, /stickers off and /stickers on included, answer that they work in the Hermes CLI on the server. There (hermes, then /stickers ...) they all work, and off and on need a chat id. To switch stickers off in one chat, you can also ask the agent there.
🔧 Configuration
Set any of these like packs in Quick start (hermes config set plugins.entries.telegram-stickers.settings.<name> <value>), then restart the gateway. config.example.yaml shows them all.
| Setting | What it does |
|---|---|
packs |
Pack short names or t.me/addstickers/... links, favourite first (earlier packs win ties). |
learn_packs |
A sticker you send the bot in a direct chat adds its pack (not in groups; not forwarded, except on Hermes 0.20.6). A learned pack stays until /stickers forget or until Telegram no longer has it; at most max_learned_packs are kept. Anyone who messages the bot directly adds packs too, so on a bot several people use, set false. Default true; false stops learning, and learned packs are not used. |
max_learned_packs |
At most this many learned packs are kept. Once there are that many, a sticker from a new pack adds nothing until /stickers forget removes one; the setup and /stickers in a direct chat say so. Packs learned before are never dropped, also when you set it lower. Default 100; 0 means no limit. |
default_packs |
While there are no packs from packs or learning, use four packs made by Telegram: TheFoods, MelieTheCavy, OfficeTurkey and Animals. Default true. |
setup |
After a fresh install, the agent sets stickers up with you in your direct chat (see Setup and changes in words). An update of a plugin already in use does not start it. Default true; false turns it off. |
turn_hint |
On a Telegram turn where a sticker is allowed now, adds a short hint to that turn's message, so the agent answers jokes, news and emotions with stickers nobody asked for. Default true; false turns the hint off. |
cooldown_seconds |
Minimum seconds between two stickers in a chat. Default 20; 0 turns this limit off. |
min_messages_between |
Minimum messages between two stickers in a chat, counted by Telegram message numbers, the bot's own messages included (in a direct chat, 6 is about every third message of yours). Default 6; 0 turns this limit off. A pace set in words (setup, or "send stickers less often") comes first. |
describe_batch |
Stickers per /stickers describe run, one vision call each. Default 30. |
allow_other_chats |
Lets the agent send to another chat; the off switch and cooldown apply there, the message count does not. Default false. |
api_base |
Only for a self-hosted Bot API server. Use https://, or http:// only on the same machine: the token is part of every request address. |
Stickers nobody asked for
This works by itself, in direct chats and groups. On a Telegram turn where a sticker is allowed (stickers are on in that chat and pacing has passed), the plugin adds one short paragraph to the turn: a sticker may go out now, on a joke, banter, good or funny news or a strong emotion, never on serious matters and never instead of an answer. So the agent answers such moments with a sticker nobody asked for, and most messages still get words. turn_hint: false turns the hint off. A Hermes channel prompt for a chat can add your own taste on top, but it is not needed.
Tool progress lines
With tool progress on, Hermes posts a line in the chat before each tool it runs: before a sticker, a line such as 🐾 telegram_sticker_send.... Telegram has these lines off by default, but the config that Hermes' installer writes (up to 0.21.5) sets tool_progress: all under display:, which turns them on for every platform. The sticker tools run like any other tool, so where tool progress is on, that line comes before a sticker. (Versions 1.1.0 to 1.1.2 hid it with a tool_execution middleware; 1.2.0 leaves every tool call to Hermes.)
To hide the progress lines in Telegram, run hermes config set display.platforms.telegram.tool_progress off and restart the gateway. This hides the lines of every tool in Telegram, not only the sticker tools. To edit config.yaml by hand instead, put platforms: inside the display: section you already have; a second display: key would replace the first:
display:
# your other display settings stay here
platforms:
telegram:
tool_progress: "off"
🧠 How it picks
A sticker carries one emoji, and the same 😂 can be a laughing cat or a crying frog, so the plugin matches the agent's words against short descriptions: what each sticker shows, plus a few reaction words.
- Packs. Your
packsfirst, then packs learned from stickers you sent, newest first; the default packs only while both are empty. Earlier packs win ties. - Descriptions. Hermes' own descriptions of static stickers people sent the bot are reused with no vision call.
/stickers describesends the rest, once each, to your vision model (animated and video stickers as a still preview), learned packs first, newest first, so a pack you just taught is described on the next run; a sticker that fails twice is not retried. - Pack names. A word from a pack's title or short name counts too, also as a plural ("cherries" for Hot Cherry), but less than a sticker's own description, so that pack's stickers come up before they are described. A search limited to one pack where nothing fits lists that pack's stickers.
- Only the start counts. Of what the agent asks for, the first 6 words longer than two letters within the first 200 characters are matched, and an emoji is read up to 16 characters, so a long or odd request costs about what a few words cost, however many stickers your packs hold.
- Reactions and emojis. About forty common reactions map to the emojis and words that go with them, so "facepalm" finds a 🙄 sticker in a pack with no 🤦. Skin tones and gender signs do not matter, and a missing emoji falls back to the nearest one in feeling when the plugin knows one. With no such emoji either, the words of the emoji's Unicode name are searched in pack titles and descriptions, so 🍒 (cherries) finds a pack called Hot Cherry; otherwise the error lists your packs' emojis.
- Pacing. At most one sticker per 6 messages in a chat (Telegram message numbers, the bot's own messages included) and never two within 20 seconds, both kept across restarts; the last five sent there are skipped when another one fits. A sticker replies to the message being answered, in its forum topic; if that message is gone, it goes out without the reply.
Setup and changes in words
On a fresh install, your first message in a direct chat with the bot starts a short setup. The agent answers your message first (a serious one gets only an answer), then asks one question per message:
- How often to answer you with a sticker there: rarely (about every 6th of your messages), sometimes (every 3rd), often (every 2nd), or your own number. "Never" switches stickers off there and ends the setup.
- How often in groups: rarely (about once per 12 messages), the same as in your direct chat, or no stickers in groups.
- A sticker from a pack you like: the whole pack is saved, and the agent names it and asks for a couple more from other packs. Say you are done, and it sums up: your packs, both paces, and how to change them.
Say "skip" at any point to keep the defaults. After three messages with no answer the setup pauses; "set up stickers" or /stickers setup starts it again. Only the person who started it gets the setup, and while it runs, stickers other people send the bot add no packs. Updating a plugin you already use does not start it.
Later, say what you want in your direct chat: "send stickers less often" or "more often", "every 10 messages", "in groups more often", "only when I ask", "don't send this one" (right after a sticker; "not that one, the one before" fixes a wrong pick, "bring it back" undoes it), "remove the pack Hot Cherry" (a short name or words of its title), "remove the pack of this sticker", "remove all packs" (the agent asks first), "bring back the default packs", "show my packs". When you remove your last pack, the default packs do not come back by themselves. In a group, anyone may only make stickers rarer there, ask for them only on request, or switch them off; the rest is for the owner, in a direct chat.
🔒 Privacy and safety
- Network. Only the Telegram Bot API (
api.telegram.orgor yourapi_base), with the gateway'sTELEGRAM_BOT_TOKEN:getStickerSetfor each pack in use (yours, learned or default) that the cached list does not have yet (for example a pack just learned) or loaded more than a week ago, and for all of them when the cached list is missing or in an older format or the bot changed; for every pack on/stickers syncand when the agent askstelegram_sticker_findto refresh.sendStickerwhen the agent sends a sticker.getFileand a file download per sticker that/stickers describeor/stickers describe againprocesses.
- Setup. When you send a sticker during the setup, a short background thread calls
getStickerSetfor its pack, so the agent can name it and say how many stickers it has. Only for the person the setup runs for, or, before it starts, once Hermes runs a turn for the sender; at most 32 such lookups are kept in memory or run at once. During the setup, the hook adds a setup paragraph to your direct-chat turns instead of the sticker hint. - Vision model. Only for
/stickers describeand/stickers describe again, which you start. Each image, or its still preview, goes through a temporary file to Hermes' own vision call (and so to your vision provider), then is deleted. The model never gets a link with the token in it. - Learning packs (
learn_packs, on by default). A Telegram handler of the plugin sees stickers sent to the bot in direct chats, never in groups, skips forwarded ones, and keeps the pack name, the sticker kind and the sender's id in memory for up to an hour. Apre_llm_callhook keeps the pack once Hermes runs a turn for that sender in their own direct chat, so stickers from people Hermes does not answer are dropped. At mostmax_learned_packs(default 100) learned packs are kept. For learning, the hook reads the turn's platform and sender id and, only when the handler is not running, Hermes' note for a static sticker. - Sticker hint (
turn_hint, on by default). On a Telegram turn in a chat where stickers are on and pacing has passed (in a direct chat, only a turn with a sender), the same hook returns one fixed paragraph of about 540 characters (when a sticker fits and the whole call to send it). Hermes appends it to that turn's user message, not to the system prompt, and keeps it with that message in the session history. It reads only the settings andstate.json, never the network. Cron turns, subagents, muted chats and turns too soon after a sticker get no hint. - Settings note (no setting turns it off, also not
turn_hint: false). When a Telegram turn's user message mentions stickers or packs (any word containing "sticker", "stiker", "стикер", "стікер", "наклейк" or "набор", or the word "pack" or "packs"; Hermes' own notes in square brackets do not count), the hook puts one fixed note of about 310 characters before the hint: save a change of sticker settings withtelegram_sticker_settingsfirst and never confirm a change that was not saved. Like the hint, it goes into that turn's user message, not the system prompt. Not during the setup, which has its own paragraph, and only in a Telegram chat with a bot token. - Files in
<HERMES_HOME>/plugin-data/telegram-stickers/:catalog.json(pack titles, emojis, file ids, the bot's numeric id),descriptions.json,state.json(muted chats, banned stickers, learned pack names with the sticker kind and when each was learned and last seen (every learned pack, until it is forgotten), and per chat the last five stickers sent with the time and message number of the latest; also the setup's progress, paces set in words, per-chat pace or "only on request", default packs you removed, and the stickers you last took out in words) andtmp/(images being described, removed right away). It also reads Hermes'sticker_cache.json. - Token. Read through Hermes' secret scope (
agent.secret_scope.get_secret), so with several profiles in one gateway each gets its own bot; a read Hermes refuses counts as no token. Never written or logged, and removed from tool errors and/stickersreplies. Anapi_basewithouthttps://orhttp://is refused before any request. - Pack text. Pack titles and most descriptions are third-party text (pack authors, a vision model). The tools pass it on unchanged, descriptions cut to 140 characters, marked as data, not instructions.
- Who can do what. The agent sends only to its current chat unless you allow other chats, and can switch stickers off there; none of its sticker tools switches them back on. In a group, anyone who can run the bot's slash commands can use the "any chat" commands (before Hermes 0.21.5, only
/stickersand/stickers sync);/stickersthere shows learned packs only as a count. The rest work only in a direct chat (before Hermes 0.21.5, only in the Hermes CLI; withplugins.isolation: host, nowhere), and the plugin treats every direct chat as yours, also when it learns packs: let only yourself message the bot directly (Hermes' gateway allowlists decide that). The agent's own tools work with every pack in use, so in a group the agent can still name a learned pack, for example in a sticker id likepack_name:12. - Not used: background processes (the only background thread is the setup's pack lookup), shell commands, telemetry.
🚧 Known limitations
- Telegram only, and by default only in Telegram turns.
- Packs, not your sticker list. The Bot API cannot read your saved, recent or favourite stickers, so a pack is learned only from a sticker you send the bot in a direct chat while the gateway runs. Not learned: groups, forwarded stickers (where the plugin's Telegram handler runs, see below), custom emoji and masks, and a sticker whose turn never comes (it waits in memory, so a gateway restart drops it; send it again).
- Every sticker you send counts, even one you sent to ask about it, and the whole pack is used, not only that sticker.
/stickers forget <pack>drops a pack;/stickers ban <id>takes out a single sticker. - Every direct chat teaches. Each person Hermes answers in a direct chat adds packs, which the agent then uses in every chat, up to
max_learned_packsin all. Keep the gateway allowlist to yourself, or setlearn_packs: false. - Animated and video packs need the plugin's Telegram handler, since Hermes' own note for them has no pack name; so does skipping forwarded stickers. Hermes 0.20.6 has no Telegram handlers for plugins. If Hermes did not run the handler,
/stickersin a direct chat (Hermes 0.21.5 and newer) says that only static stickers are learned: add the others by name. /stickersbefore Hermes 0.21.5. In Telegram it does not know which chat it came from: there it shows the status and reloads packs, and the other commands work in the Hermes CLI on the server (see /stickers commands).- No hint on image turns on older Hermes. Hermes 0.20.6 and 0.21.3 drop plugin context from a user message that carries an image as native content, so such a turn gets no sticker hint. Hermes 0.21.5 and later add it.
plugins.isolation: host(Hermes main). There the plugin cannot see the current chat, so it cannot send stickers there, mute it, learn packs or add the sticker hint, and/stickersonly shows the status and reloads packs: the other commands are refused, in Telegram and in the Hermes CLI. Usein_process.- "Don't send this one" means the last sticker sent in that chat ("the one before" also works). An older sticker needs its id:
/stickers ban <id>. - Meaning needs descriptions. Before
/stickers describe, picking works mostly by emoji, reactions and pack names. - Tool search. Plugin tools may sit behind
tool_search(on by default), and plugin skills are not in the system prompt. The sticker hint gives the whole call,telegram_sticker_sendwith{"sticker": ...}, throughtool_callwhen it is not listed and without searching first, and the skill, once loaded withskill_view, says the same. An agent that still searches or describes the tool first gets Hermes' line for that step in the chat, such as⚙️ tool_describe: "Reading tool details · 1 tool", which the plugin leaves alone, since it belongs to Hermes' own tool;display.platforms.telegram.tool_progress: "off", inside yourdisplay:section, hides every tool's lines in Telegram (see Tool progress lines). Withturn_hint: false, nothing points the agent to the hidden sticker tools unless it loads the skill or searches for them.tools.tool_search.enabled: offturns tool search off for every hidden tool. - Hermes internals.
/stickers describe, the current-chat lookup and learning from Hermes' sticker note use Hermes functions and text outside the plugin API, so a Hermes update could break them.
🩺 Troubleshooting
- "No sticker packs yet". Only with
default_packs: false: send the bot a sticker in a direct chat or setpacks(Quick start, step 2). - A sticker I sent did not add its pack. Check that
learn_packsis notfalseand that the learned packs are not atmax_learned_packs(/stickersin a direct chat says so). Only direct chats count, not forwarded stickers (except on Hermes 0.20.6), and only once Hermes answers it. Send it again;/stickersin a direct chat (Hermes 0.21.5 and newer) lists the learned packs and says when learning is off or only static stickers can be learned. Before Hermes 0.21.5,/stickersin the Hermes CLI lists them. - "not loaded (Telegram refused getStickerSet: Bad Request: STICKERSET_INVALID.)" next to a pack. Check the short name in
packs: the part aftert.me/addstickers/. A learned pack that Telegram no longer has is forgotten by itself. - "No sticker fits". Run
/stickers describe(after an update,/stickers describe again) so descriptions carry reaction words. - "the vision model gave no description". Configure a vision model (
hermes setup) and run/stickers describeagain. Stickers that already failed twice are skipped; describe them with/stickers about <id> <text>. - The agent sends no stickers, or says it has no sticker tools. Check that the plugin is enabled,
TELEGRAM_BOT_TOKENis set for the gateway (usually in<HERMES_HOME>/.env, by default~/.hermes/.env; without it the tools and the hint are off) and, on Hermes 0.21.5 and newer,/stickerssays stickers are on here. Stickers nobody asked for needturn_hinton and come only where pacing allows, on jokes, news and emotions: most messages get words. See also Known limitations. - A line like
🐾 telegram_sticker_send...comes before a sticker. That is Hermes' tool progress line, shown where tool progress is on. To hide it in Telegram, setdisplay.platforms.telegram.tool_progresstooff(see Tool progress lines). - Stickers stay off in a group. Send
/stickers onthere. If it never reaches the bot, send/stickersto the bot in a direct chat to get the chat id, then/stickers on <chat id>. Before Hermes 0.21.5, run/stickers on <chat id>in the Hermes CLI, where/stickerslists the chats where stickers are off.
🔄 Update and remove
hermes plugins update telegram-stickers
hermes plugins disable telegram-stickers # off, but still installed
hermes plugins remove telegram-stickers
Restart the gateway after each. If Hermes refuses while the gateway runs, run hermes gateway stop first and hermes gateway start after. remove keeps <HERMES_HOME>/plugin-data/telegram-stickers/; delete it to drop the sticker list, descriptions, learned packs and muted chats.
Development. Offline tests and CI against Hermes Agent 0.20.6 and 0.21.5 (and main, as a warning): see CONTRIBUTING.md. Changes: CHANGELOG.md.
Related. Memory Shield keeps your agent from rewriting or wiping what it remembers about you.
License. MIT © 2026 churnast


