Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.bumbleagi.com/llms.txt

Use this file to discover all available pages before exploring further.

Setup

1

Create a bot

Talk to @BotFather on Telegram and create a new bot. Copy the token.
2

Set the token

Copy .env.example to .env at the repo root and set:
TELEGRAM_TOKEN=your_token_here
The .env file is gitignored and loaded automatically.
3

Add the platform

In your entity YAML (configs/entities/<name>.yaml):
presence:
  platforms:
    - type: "telegram"
      token_env: "TELEGRAM_TOKEN"
4

Run

bumblebee run canary --ollama
Use run (not talk) — the daemon owns the bot connection.

Commands

Use /commands for the full catalog. Common entries:
CommandWhat it does
/startRich intro with quick-start actions
/helpUsage guide with examples
/commands [page] [filter]Paginated, filterable command catalog
/statusSOMA / GEN snapshot, runtime health, and Bars excerpt from body.md
/bodyDump soma/body.md from the execution host (not via the model)
/feelingsDetailed emotional read
/memories [count]Recent episodic memory summaries
/meRelationship snapshot — familiarity, warmth, trust
/modelsInference and runtime model configuration
/toolsActive tools for this entity
/routinesScheduled automations
/pingLiveness check
/busyToggle busy indicator for this chat (on / off / status)
/whoamiYour Telegram user ID
/resetClear in-memory conversation (episodic memory unchanged)
Session, privacy, compaction, and self-update commands (/session_*, /privacy, /compact, /update, etc.) are documented in-app via /commands.

Media

  • Photos and image documents — downloaded and passed to the model as vision input. Caption optional.
  • Voice and audio messages — downloaded and passed to the harness as audio input (handling depends on your cognition / transcription setup).

Human-paced multi-bubble replies

Plain-text replies (the usual deliberate path) are not sent as a single giant message whenever they fit under Telegram’s 4096-character cap. The adapter splits outgoing text using harness presence settings so multi-line answers can read like a person texting in several bubbles.
SettingDefaultRole
message_chunk_max400Target maximum characters per bubble (clamped 120–3900). Lines are packed up to this size, similar to Discord’s line-aware chunking.
chunk_delay2.0Base seconds between bubbles before jitter and compose time are added.
typing_speed_base30Characters-per-second style baseline; used to add a length-scaled pause before the next bubble (shorter follow-ups feel snappier; longer ones wait a bit longer).
typing_speed_variance0.3Random jitter on the base pause between bubbles (chunk_delay × roughly 1 ± variance).
Between bubbles the bot also triggers a typing action (send_chat_action) so the gap does not look like a dead connection. Configure these under presence: in configs/default.yaml or your entity YAML (same block as heartbeat_interval / initiative_cooldown). Hard cap: individual Telegram messages are still limited by the API (~4096 characters); very long lines without newlines are split mechanically so nothing is dropped. say() tool: each say() is still one outbound message from the tool path. Natural multi-bubble without multiple say() calls comes from the final reply going through send_plain_chunks with the settings above.

Busy indicator

While the harness runs perceive for an incoming Telegram message, the bot can show a short busy line (not limited to tool use — it covers the whole turn):
  • Monospace (<code> in HTML mode) with a braille-style spinner and a single random gerund in the style of Claude Code (e.g. thinking, reticulating, vibing). The spinner updates every edit; the word changes every ~20 spinner frames.
  • Posted as a reply to the user’s message when metadata allows.
  • Pinned quietly (disable_notification) so it stays visible.
  • The system “pinned a message” service line is deleted when it refers to this pin (whether Telegram attributes that line to the bot or the user).
  • Unpinned and deleted when the turn finishes and the real reply is delivered.
This is harness-only UX. The line does not append to conversation history for the model, and it does not enter the observe tool message ring. Typing actions (send_chat_action) may still run in parallel.

Turning it off

Some chats prefer not to see the pinned line. /busy toggles the indicator per chat (also /busy on, /busy off, /busy status). The choice is stored in the entity database and survives restarts. Implementation: TelegramPlatform.run_busy_indicator + main.py on_inp (see the main repo).

/body command

/body prints the raw soma/body.md file as one or more Telegram HTML <pre> blocks — the same file Soma flushes for the agent, under the entity workspace (…/soma/body.md).
  • It uses the execution client (read_file on soma/body.md): local disk when the worker has a workspace, or HTTP execution RPC when BUMBLEBEE_EXECUTION_RPC_URL / tools.execution.base_url points at Railway — so hybrid setups read the worker’s file, not your laptop’s.
  • It does not go through the main LLM; if your deployment blocks file tools (e.g. hybrid without RPC), /body is blocked with the same guidance as read_file.
Long files are split across multiple messages so each stays under Telegram’s size limit.

Privacy and operators

Operators can lock the bot to approved users only.

Configure operators

Set operator user IDs in entity YAML:
presence:
  platforms:
    - type: "telegram"
      token_env: "TELEGRAM_TOKEN"
      operator_user_ids: [123456789]
Or via environment variable (useful for Railway where canary.yaml isn’t in the image):
BUMBLEBEE_TELEGRAM_OPERATOR_IDS=123456789,987654321
Values from both sources are merged. Use /whoami in chat to find your ID.

Privacy commands

CommandEffect
/private onLock to operators only
/private offOpen to everyone
/privacy lockSame as /private on
/privacy openSame as /private off
/privacy allow <id>Grant access to a specific user
/privacy deny <id>Revoke access
The allowlist persists in the entity database and survives restarts. While locked, static allowed_user_ids in YAML are ignored.

Optional settings

presence:
  platforms:
    - type: "telegram"
      token_env: "TELEGRAM_TOKEN"
      concurrent_updates: 1      # updates processed in parallel (1–256)
      poll_timeout: 25.0          # long-poll timeout (seconds)
      poll_interval: 0.35         # interval between polls (seconds)
      allowed_user_ids: []        # restrict DMs (empty = open)
      operator_user_ids: []       # /privacy operators

Inline mode

In BotFather, run /setinline for your bot and pick a placeholder. Users can then type @YourBot ... in any chat for quick identity cards.