tgbot 0.1.3
tgbot: ^0.1.3 copied to clipboard
A CLI tool that bridges Telegram messages to AI CLIs, allowing you to interact with AI agents through a Telegram bot.
tgbot #
tgbot is a Dart CLI that connects a Telegram bot to AI CLIs (codex, opencode, gemini, claude). It long-polls Telegram, forwards authorized messages into the configured provider CLI, keeps a per-chat thread ID in memory, and sends streamed text plus local file/image artifacts back to Telegram.
Install #
dart pub global activate tgbot
If Dart's global bin directory is not already on your PATH, add it first so tgbot is runnable from the shell.
Requirements #
- Dart SDK
- One supported provider CLI installed and available on
PATH(codex,opencode,gemini, orclaude), unless overridden withai_cli_cmd - A Telegram bot token from
@BotFather - Your Telegram numeric user ID
Provider CLI references:
Quick Start #
Create a starter config:
tgbot init
You can also start from the checked-in example: tgbot.yaml.example.
Edit tgbot.yaml:
bots:
- name: my-bot
telegram_bot_token: "YOUR_TELEGRAM_BOT_TOKEN"
allowed_user_ids:
- 123456789
project_path: /absolute/path/to/project
Validate it:
tgbot validate
Start the bridge:
tgbot start
Then open your bot in Telegram and send it a message.
CLI #
tgbot <command> [options]
| Command | Description |
|---|---|
start |
Start all bots declared in the config file |
init |
Generate a starter tgbot.yaml |
validate |
Parse and validate a config file without starting bots |
upgrade |
Reinstall the latest published tgbot with Dart |
Global flags:
| Flag | Description |
|---|---|
-h, --help |
Print usage help |
-v, --version |
Print the version |
Examples:
tgbot start
tgbot start -c custom.yaml
tgbot init
tgbot init -o other.yaml
tgbot validate
tgbot validate -c custom.yaml
tgbot upgrade
Telegram Setup #
Bot token #
- Open Telegram and find
@BotFather. - Run
/newbot. - Follow the prompts.
- Copy the token into
telegram_bot_token.
User ID #
- Open Telegram and find
@userinfobot. - Send it any message.
- Copy the numeric ID into
allowed_user_ids.
Only that user can interact with the configured bot.
Configuration #
tgbot loads one YAML file, defaulting to tgbot.yaml.
Top-level keys:
bots(required): non-empty list of bot definitionsdefaults(optional): shared values inherited by each bot
Minimal config #
bots:
- name: my-bot
telegram_bot_token: "YOUR_TELEGRAM_BOT_TOKEN"
allowed_user_ids:
- 123456789
project_path: /absolute/path/to/project
Config with shared defaults #
defaults:
project_path: /absolute/path/to/default/project
provider: codex
ai_cli_cmd: codex
ai_cli_args:
- --model
- gpt-5
ai_cli_allow_dirs:
- ~/Workspace/shared
poll_timeout_sec: 60
ai_cli_timeout_sec: 1000
bots:
- name: repo-a
telegram_bot_token: "TOKEN_A"
allowed_user_ids:
- 123456789
- name: repo-b
telegram_bot_token: "TOKEN_B"
allowed_user_ids:
- 123456789
project_path: /absolute/path/to/repo-b
additional_system_prompt: |
Keep answers brief and focus on production issues.
Bot fields #
| Key | Required | Notes |
|---|---|---|
name |
Yes | Used in logs and status messages |
telegram_bot_token |
Yes | Telegram Bot API token |
allowed_user_ids |
Yes | Telegram user IDs allowed to use the bot |
project_path |
Yes | Absolute working directory used for the selected provider CLI; may be inherited from defaults |
provider |
No | Provider name: codex, opencode, gemini, or claude; default codex |
ai_cli_cmd |
No | Executable to run for the selected provider, defaults by provider (codex, opencode, gemini, claude) |
ai_cli_args |
No | Extra args passed to the provider CLI; accepts a YAML list or whitespace-delimited string |
ai_cli_allow_dirs |
No | Codex-only helper that appends --add-dir; accepts a YAML list or comma-delimited string, and ~ is expanded |
poll_timeout_sec |
No | Telegram long-poll timeout in seconds, default 60 |
ai_cli_timeout_sec |
No | Per-request provider timeout in seconds, default 1000 |
additional_system_prompt |
No | Extra system instructions prepended before each user request |
final_response_only |
No | When true, suppresses streamed partial messages and sends only the final assistant response, default false |
telegram_commands |
No | Extra Telegram slash commands registered for this bot |
Notes:
defaultsapplies only when a bot omits that key.- Every bot must end up with an effective
project_path. telegram_commandsmust be a non-empty list when provided.- Command names must match
^[a-z0-9_]{1,32}$. - Built-in
/start,/new, and/stopcommands are always present unless you override them intelegram_commands. ai_cli_allow_dirsis ignored for non-codexproviders.codex_cmd,codex_args,codex_allow_dirs, andcodex_timeout_secare not supported.project_pathis normalized to an absolute path at startup.
Custom Telegram Commands #
You can register Telegram slash commands that map to prompt templates:
bots:
- name: my-bot
telegram_bot_token: "YOUR_TELEGRAM_BOT_TOKEN"
allowed_user_ids:
- 123456789
project_path: /absolute/path/to/project
telegram_commands:
- command: review
description: Review the current branch and list bugs first.
- command: fix
description: Fix this issue: {args}
Behavior:
- Telegram shows these commands via
setMyCommands. - If
descriptioncontains{args}, text after the command replaces that placeholder. - Otherwise command arguments are appended to the description with a blank line.
Examples:
/reviewbecomesReview the current branch and list bugs first./fix login racebecomesFix this issue: login race
Runtime Behavior #
- One polling loop runs per configured bot.
- Only messages from IDs in
allowed_user_idsare processed. - Messages are processed serially per chat so responses stay ordered.
/startreturns a short help message plus the registered command list./newclears the in-memory thread/session id for that Telegram chat./stopterminates the active provider CLI process for that Telegram chat, if one is running.- Some runtime status messages currently use the word "Codex" even when another provider is configured.
- If a run is already in progress for a chat, new prompts wait in that chat's queue until the active run finishes or is stopped.
- Any other text message is forwarded to the configured provider CLI.
- The current thread/session id is stored per chat and reused until
/newor process restart.
Provider invocation patterns:
codex ...args exec --skip-git-repo-check --json <prompt>
opencode ...args run --format json <prompt>
gemini ...args --prompt <prompt> --output-format json
claude ...args --verbose --print --output-format stream-json <prompt>
Resume behavior:
codex ...args exec resume --skip-git-repo-check --json <thread_id> <prompt>
opencode ...args run --session <thread_id> --format json <prompt>
gemini ...args --resume <thread_id> --prompt <prompt> --output-format json
claude ...args --verbose --print --output-format stream-json --resume <thread_id> <prompt>
Notes:
gemini,opencode, andclaudesession ids are captured from provider output when available.
Streaming and Replies #
By default, tgbot reads provider output incrementally when streaming JSON is available and forwards assistant messages to Telegram as they arrive. It also:
- keeps Telegram's typing indicator active while the provider CLI is running
- avoids re-sending duplicate streamed messages
- chunks long Telegram messages at newline or word boundaries
- falls back to reconstructed assistant messages if only final JSON output is available
If final_response_only: true is set for a bot, streamed partial replies are not sent and only the final assistant response is delivered.
File and Image Delivery #
tgbot can send local artifacts back through Telegram during the same reply flow.
Preferred mechanism:
TG_ARTIFACT: {"kind":"image","path":"artifacts/plot.png","caption":"Latest chart"}
Supported artifact detection:
TG_ARTIFACT: {...}marker lines- standalone JSON artifact objects in provider output
- local Markdown image/link syntax when no explicit artifact marker is present
Rules:
- image files are uploaded with
sendPhoto - non-image files are uploaded with
sendDocument - relative paths are resolved from
project_path - artifact paths must stay inside
project_path - missing files and path traversal are rejected
Error Handling #
- Telegram API calls retry up to 3 times on HTTP
429 - Telegram
retry_aftervalues are respected - empty outgoing messages are skipped
- Provider CLI failures and timeouts are reported back to the Telegram chat
- bot tokens are never logged
Project Layout #
bin/tgbot.dart: CLI entry point and subcommandslib/tgbot.dart: public package exportslib/src/app.dart: bridge runtime and message routinglib/src/config.dart: YAML parsing and validationlib/src/runner/codex_runner.dart: Codex execution and output parsinglib/src/runner/: provider runner interface, factory, and provider-specific runnerslib/src/telegram/telegram_client.dart: Telegram Bot API clientlib/src/session/session_store.dart: in-memory per-chat thread statelib/src/models/telegram_models.dart: Telegram API modelsexample/main.dart: package exampletest/: unit tests
Development #
Run the standard Dart checks locally:
dart analyze
dart test
License #
MIT. See LICENSE.