← Back to Plugins
Channels

Topic Status

jzerolf By jzerolf 👁 13 views ▲ 0 votes

OpenClaw plugin that updates Telegram forum topic icons based on real agent runtime state, with configurable custom emoji IDs for working, idle, error, and timeout states.

GitHub

Install

openclaw plugins install git:github.com/jzerolf/openclaw-topic-status@main

Configuration Example

{
  "plugins": {
    "entries": {
      "openclaw-topic-status": {
        "enabled": true,
        "hooks": {
          "allowConversationAccess": true
        },
        "config": {
          "botTokenFile": "/path/to/telegram.bot_token",
          "icons": {
            "working": "5309832892262654231",
            "idle": "5357121491508928442",
            "error": "5312241539987020022",
            "timeout": "5312241539987020022"
          }
        }
      }
    }
  }
}

README

# openclaw-topic-status

OpenClaw plugin that updates Telegram forum topic icons from real agent runtime
state.

It watches OpenClaw message and agent lifecycle hooks, then calls Telegram's
`editForumTopic` Bot API method with configurable `custom_emoji_id` values.
The plugin is meant for Telegram forum topics where each topic represents a
conversation or agent thread.

## What It Does

- Sets a topic icon when a message is received.
- Keeps the topic marked as active while an agent turn is running.
- Sets a final idle or error icon when the agent turn ends.
- Sets a timeout icon if OpenClaw never emits a final `agent_end` event.
- Avoids treating `message_sent` as "done"; outgoing messages only refresh the
  watchdog timer.
- Works as an external OpenClaw plugin without patching OpenClaw core or the
  Telegram channel plugin.

## Supported States

| State | Trigger | Meaning |
| --- | --- | --- |
| `working` | `message_received`, `before_agent_run` | A user message arrived or an agent turn is active. |
| `idle` | `agent_end` with success | The agent finished cleanly. |
| `error` | `agent_end` with failure | The agent turn ended with an error. |
| `timeout` | rescue timer | No final `agent_end` arrived before `timeoutMs`. |

`message_sent` is observed only to refresh the timeout while progress updates
are delivered. It is not a reliable completion signal.

## Install

During early development, install from Git:

```bash
openclaw plugins install git:github.com/jzerolf/openclaw-topic-status@main
openclaw plugins enable openclaw-topic-status
openclaw gateway restart
```

For local development:

```bash
git clone https://github.com/jzerolf/openclaw-topic-status.git
cd openclaw-topic-status
npm test
openclaw plugins install --link .
openclaw plugins enable openclaw-topic-status
openclaw gateway restart
```

The intended public distribution target is ClawHub once the package has its
first reviewed release.

## Agent-Friendly Installation

When an operator asks an OpenClaw agent to "install this plugin", the agent
should do the following:

1. Inspect the current OpenClaw installation and find its active config file,
   plugin directory, gateway service, and Telegram channel/account settings.
2. Install the plugin from this repository:

   ```bash
   openclaw plugins install git:github.com/jzerolf/openclaw-topic-status@main
   ```

   If the plugin manager is not available, clone this repository into the
   instance's external/local plugin directory and add that path to
   `plugins.load.paths`.
3. Enable the plugin as `openclaw-topic-status`.
4. Add a `plugins.entries.openclaw-topic-status` config block with:
   - `enabled: true`
   - `hooks.allowConversationAccess: true`
   - a safe bot token source, preferably an existing Telegram `tokenFile`
   - the desired `icons` map
5. Never paste, print, or commit the Telegram bot token. Prefer `botTokenFile`
   or an existing Telegram account token file.
6. Restart the OpenClaw gateway.
7. Verify with a real Telegram forum topic: user message should switch to
   `working`, and `agent_end` should switch to `idle` or `error`.

## Configure

Minimal config:

```jsonc
{
  "plugins": {
    "entries": {
      "openclaw-topic-status": {
        "enabled": true,
        "hooks": {
          "allowConversationAccess": true
        },
        "config": {
          "botTokenFile": "/path/to/telegram.bot_token",
          "icons": {
            "working": "5309832892262654231",
            "idle": "5357121491508928442",
            "error": "5312241539987020022",
            "timeout": "5312241539987020022"
          }
        }
      }
    }
  }
}
```

The plugin can read the Telegram bot token from:

1. `config.botTokenEnv`
2. `config.botTokenFile`
3. the configured Telegram account `tokenFile`
4. the root Telegram channel `tokenFile`

Never commit bot tokens to a repo.

## Choosing Topic Icons

Telegram only accepts forum topic icon IDs returned by
`getForumTopicIconStickers`. These `custom_emoji_id` values are Telegram-wide
identifiers for the allowed forum topic icon stickers, so the examples below
should work anywhere while Telegram keeps them in that allowed set.

You can list the current allowed icons with:

```bash
curl -s "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/getForumTopicIconStickers" \
  | jq -r '.result[] | "\(.emoji)\t\(.custom_emoji_id)"'
```

Known working examples:

| Suggested state | Emoji | `custom_emoji_id` | Why it works well |
| --- | --- | --- | --- |
| `working` | ๐Ÿค– | `5309832892262654231` | Clear signal that the agent is handling the topic. |
| `idle` | ๐Ÿ‘€ | `5357121491508928442` | Quiet "watching/available" state after a clean finish. |
| `error` | ๐Ÿ”ฅ | `5312241539987020022` | Visible enough for failed turns or operational attention. |
| `timeout` | ๐Ÿ”ฅ | `5312241539987020022` | Reuse the error icon when the runtime did not emit a final event. |

Current icon reference, captured from `getForumTopicIconStickers` on
2026-05-29:

<details>
<summary>Show full Telegram forum topic icon table</summary>

| Emoji | `custom_emoji_id` | Emoji | `custom_emoji_id` | Emoji | `custom_emoji_id` |
| --- | --- | --- | --- | --- | --- |
| ๐Ÿ“ฐ | `5434144690511290129` | ๐Ÿ’ก | `5312536423851630001` | โšก๏ธ | `5312016608254762256` |
| ๐ŸŽ™ | `5377544228505134960` | ๐Ÿ” | `5418085807791545980` | ๐Ÿ—ฃ | `5370870893004203704` |
| ๐Ÿ†’ | `5420216386448270341` | โ—๏ธ | `5379748062124056162` | ๐Ÿ“ | `5373251851074415873` |
| ๐Ÿ“† | `5433614043006903194` | ๐Ÿ“ | `5357315181649076022` | ๐Ÿ”Ž | `5309965701241379366` |
| ๐Ÿ“ฃ | `5309984423003823246` | ๐Ÿ”ฅ | `5312241539987020022` | โค๏ธ | `5312138559556164615` |
| โ“ | `5377316857231450742` | ๐Ÿ“ˆ | `5350305691942788490` | ๐Ÿ“‰ | `5350713563512052787` |
| ๐Ÿ’Ž | `5309958691854754293` | ๐Ÿ’ฐ | `5350452584119279096` | ๐Ÿ’ธ | `5309929258443874898` |
| ๐Ÿช™ | `5377690785674175481` | ๐Ÿ’ฑ | `5310107765874632305` | โ‰๏ธ | `5377438129928020693` |
| ๐ŸŽฎ | `5309950797704865693` | ๐Ÿ’ป | `5350554349074391003` | ๐Ÿ“ฑ | `5409357944619802453` |
| ๐Ÿš— | `5312322066328853156` | ๐Ÿ  | `5312486108309757006` | ๐Ÿ’˜ | `5310029292527164639` |
| ๐ŸŽ‰ | `5310228579009699834` | โ€ผ๏ธ | `5377498341074542641` | ๐Ÿ† | `5312315739842026755` |
| ๐Ÿ | `5408906741125490282` | ๐ŸŽฌ | `5368653135101310687` | ๐ŸŽต | `5310045076531978942` |
| ๐Ÿ”ž | `5420331611830886484` | ๐Ÿ“š | `5350481781306958339` | ๐Ÿ‘‘ | `5357107601584693888` |
| โšฝ๏ธ | `5375159220280762629` | ๐Ÿ€ | `5384327463629233871` | ๐Ÿ“บ | `5350513667144163474` |
| ๐Ÿ‘€ | `5357121491508928442` | ๐Ÿซฆ | `5357185426392096577` | ๐Ÿ“ | `5310157398516703416` |
| ๐Ÿ’„ | `5310262535021142850` | ๐Ÿ‘  | `5368741306484925109` | โœˆ๏ธ | `5348436127038579546` |
| ๐Ÿงณ | `5357120306097956843` | ๐Ÿ– | `5310303848311562896` | โ›…๏ธ | `5350424168615649565` |
| ๐Ÿฆ„ | `5413625003218313783` | ๐Ÿ› | `5350699789551935589` | ๐Ÿ‘œ | `5377478880577724584` |
| ๐Ÿ›’ | `5431492767249342908` | ๐Ÿš‚ | `5350497316203668441` | ๐Ÿ›ฅ | `5350422527938141909` |
| ๐Ÿ” | `5418196338774907917` | ๐Ÿ• | `5350648297189023928` | ๐Ÿค– | `5309832892262654231` |
| ๐Ÿชฉ | `5350751634102166060` | ๐ŸŽŸ | `5377624166436445368` | ๐Ÿดโ€โ˜ ๏ธ | `5386395194029515402` |
| ๐Ÿ—ณ | `5350387571199319521` | ๐ŸŽ“ | `5357419403325481346` | ๐Ÿ”ญ | `5368585403467048206` |
| ๐Ÿ”ฌ | `5377580546748588396` | ๐ŸŽถ | `5377317729109811382` | ๐ŸŽค | `5382003830487523366` |
| ๐Ÿ•บ | `5357298525765902091` | ๐Ÿ’ƒ | `5357370526597653193` | ๐Ÿช– | `5357188789351490453` |
| ๐Ÿ’ผ | `5348227245599105972` | ๐Ÿงช | `5411138633765757782` | ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ | `5386435923204382258` |
| ๐Ÿ‘ถ | `5377675010259297233` | ๐Ÿคฐ | `5386609083400856174` | ๐Ÿ’… | `5368808634392257474` |
| ๐Ÿ› | `5350548830041415279` | ๐Ÿงฎ | `5355127101970194557` | ๐Ÿ–จ | `5386379624773066504` |
| ๐Ÿ‘ฎโ€โ™‚๏ธ | `5377494501373780436` | ๐Ÿฉบ | `5350307998340226571` | ๐Ÿ’Š | `5310094636159607472` |
| ๐Ÿ’‰ | `5310139157790596888` | ๐Ÿงผ | `5377468357907849200` | ๐Ÿชช | `5418115271267197333` |
| ๐Ÿ›ƒ | `5372819184658949787` | ๐Ÿฝ | `5350344462612570293` | ๐ŸŸ | `5384574037701696503` |
| ๐ŸŽจ | `5310039132297242441` | ๐ŸŽญ | `5350658016700013471` | ๐ŸŽฉ | `5357504778685392027` |
| ๐Ÿ”ฎ | `5350367161514732241` | ๐Ÿน | `5350520238444126134` | ๐ŸŽ‚ | `5310132165583840589` |
| โ˜•๏ธ | `5350392020785437399` | ๐Ÿฃ | `5350406176997646350` | ๐Ÿ” | `5350403544182694064` |
| ๐Ÿ• | `5350444672789519765` | ๐Ÿฆ  | `5312424913615723286` | ๐Ÿ’ฌ | `5417915203100613993` |
| ๐ŸŽ„ | `5312054580060625569` | ๐ŸŽƒ | `5309744892677727325` | โœ๏ธ | `5238156910363950406` |
| โญ๏ธ | `5235579393115438657` | โœ… | `5237699328843200968` | ๐ŸŽ– | `5238027455754680851` |
| ๐Ÿคก | `5238234236955148254` | ๐Ÿง  | `5237889595894414384` | ๐Ÿฆฎ | `5237999392438371490` |
| ๐Ÿˆ | `5235912661102773458` |  |  |  |  |

</details>

Use those values directly, or replace them with any other `custom_emoji_id`
returned by `getForumTopicIconStickers`.

## Changing Icons Later

This plugin does not interpret natural language itself. An OpenClaw agent can
still follow natural-language requests such as "change my working icon to the
rocket" by editing the plugin config.

Agent procedure:

1. Read the current OpenClaw config.
2. Find `plugins.entries.openclaw-topic-status.config.icons`.
3. Resolve the requested icon to a valid Telegram `custom_emoji_id`.
   Use `getForumTopicIconStickers` if the ID is not already known.
4. Update only the requested state keys:

   ```jsonc
   {
     "icons": {
       "working": "5309832892262654231",
       "idle": "5357121491508928442",
       "error": "5312241539987020022",
       "timeout": "5312241539987020022"
     }
   }
   ```

5. Restart or reload the OpenClaw gateway.
6. Confirm the change with a real forum topic or a controlled test event.

Supported icon states are `working`, `idle`, `error`, and `timeout`.

## Configuration Reference

| Key | Type | Default | Notes |
| --- | --- | --- | --- |
| `enabled` | boolean | `true` | Disable the plugin logic without unloading it. |
| `channelId` | string | `telegram` | OpenClaw channel/provider id to watch. |
| `apiRoot` | string | `https://api.telegram.org` | Override for Telegram-compatible API roots. |
| `botTokenEnv` | string | unset | Env var that contains the Telegram bot token. |
|

... (truncated)
channels

Comments

Sign in to leave a comment

Loading comments...