Go Telegram Multibot
A scalable, multi-bot solution for Telegram using Go, GORM, and the Anthropic API.
Design Considerations
- AI-powered (Anthropic Claude)
- Voice message support (ElevenLabs STT + TTS) — optional, enabled per bot via config
- Supports multiple bot profiles
- Uses SQLite for persistence
- Implements rate limiting and user management
- Modular architecture
- Comprehensive unit tests
Usage
Docker Deployment (Recommended)
-
Clone the repository:
git clone https://github.com/HugeFrog24/go-telegram-bot.git cd go-telegram-bot -
Copy the default config template and edit it:
cp config/default.json config/mybot.json nano config/mybot.json
Important
Keep your config files secret and do not commit them to version control.
- Create data directory and run:
mkdir -p data docker-compose up -d
Native Deployment
-
Install using
go get:go get -u github.com/HugeFrog24/go-telegram-bot cd go-telegram-bot -
Configure as above, then build:
go build -o telegram-bot
Trying Out New Behavior Safely
Want to experiment with a different personality, tone, or set of instructions without disturbing the bot your users already talk to? Run a second, separate bot just for testing.
Each bot profile is its own config file with its own Telegram token, and bots are fully independent — separate identity, separate chat history, separate settings. So a "test twin" is quick to set up:
- Create a new bot with @BotFather and copy its token.
- Copy your existing config to a new file, e.g.
cp config/mybot.json config/mybot-test.json. - In the new file, paste the new token, give it a different
id, and editsystem_promptsto try your changes. - Start it alongside your main bot. Chat with the test bot, tweak its prompt, and restart the test bot to try again — your real users never see the experiments.
- Happy with the result? Copy the same change into your main bot's config and restart it.
Note
A test bot always needs its own token. Telegram only lets one running bot listen on a given token, so you can't point a second copy at your live bot — give the twin its own @BotFather bot instead.
Configuration
Each bot is one JSON file in config/ (see config/default.json for the template). Keys of note:
| Key | Type | Default | Description |
|---|---|---|---|
max_tokens |
number | 1000 |
Maximum output tokens per reply. Thinking tokens count toward this limit — raise it (e.g. 4000+) whenever thinking is "adaptive", or a turn can spend the whole budget on reasoning and produce no text. |
thinking |
string | (omitted) | Reasoning mode: "adaptive" (the model decides when and how much to think) or "disabled". Omit the key entirely to use the model's own API default. If the configured model doesn't support the chosen mode, the API rejects the request with a 400 — owners/admins see the raw error, regular users get the generic fallback. Check Anthropic's model docs for per-model support. |
thinking_display |
string | (omitted) | "summarized" or "omitted". Only valid together with "thinking": "adaptive". Controls whether the API returns a readable summary of the reasoning (logged, never sent to chat). Thinking is billed the same either way; when omitted, the API's per-model default applies. |
Every reply logs one accounting line — [usage] model=... in=... out=... thinking=... stop=... — so thinking spend (billed even when its text is omitted) stays visible in journalctl/docker compose logs. A stop=max_tokens line is accompanied by an error-level warning that the reply was truncated.
Tip
For deep request/response debugging, the Anthropic Go SDK ships
option.WithDebugLog(...)(dumps full HTTP bodies with auth headers redacted). It is not wired into the bot — dev-only, add it temporarily to the client constructor if you ever need wire-level traces.
Future: persistent memory
The Anthropic memory tool (memory_20250818) is a candidate future feature for cross-conversation recall (a self-hosted analog of ChatGPT's "memory"). The Go SDK already ships the types (BetaMemoryTool20250818Param and its tool-union slot plus the six-command union: view/create/str_replace/insert/delete/rename), but — unlike the Python/TypeScript/Java SDKs — provides no handler helper: the bot would have to hand-write client-side command dispatch against per-chat storage, including strict path validation (canonicalize and confine every model-supplied path under a fixed memory root; reject ../symlink traversal) and a no-secrets policy for stored content. Not implemented yet.
Systemd Unit Setup
To enable the bot to start automatically on system boot and run in the background, set up a systemd unit.
-
Copy the systemd unit template and edit it:
sudo cp examples/systemd/telegram-bot.service /etc/systemd/system/telegram-bot.serviceEdit the service file:
sudo nano /etc/systemd/system/telegram-bot.serviceAdjust the following parameters:
- WorkingDirectory
- ExecStart
- User
-
Enable and start the service:
sudo systemctl daemon-reloadsudo systemctl enable telegram-botsudo systemctl start telegram-bot -
Check the status:
sudo systemctl status telegram-bot
For more details on the systemd setup, refer to the demo service file.
Logs
Docker
docker-compose logs -f telegram-bot
Systemd
journalctl -u telegram-bot -f
Commands
| Command | Access | Description |
|---|---|---|
/stats |
All users | Show global bot statistics (total users and messages) |
/stats user |
All users | Show your own message statistics |
/stats user <user_id> |
Admin/Owner | Show statistics for a specific user |
/whoami |
All users | Show your Telegram ID, username, and role |
/clear |
All users | Soft-delete your own chat history |
/clear <user_id> |
Admin/Owner | Soft-delete all messages for a user across every chat |
/clear <user_id> <chat_id> |
Admin/Owner | Soft-delete a user's messages in a specific chat |
/clear_hard |
All users | Permanently delete your own chat history |
/clear_hard <user_id> |
Admin/Owner | Permanently delete all messages for a user across every chat |
/clear_hard <user_id> <chat_id> |
Admin/Owner | Permanently delete a user's messages in a specific chat |
/set_model <model-id> |
Admin/Owner | Switch the AI model live without restarting |
Note: In private DMs each user's
chat_idequals theiruser_id. The scoped<chat_id>form is mainly useful for group chat moderation.
Testing
The GitHub actions workflow already runs tests on every commit:
However, you can run the tests locally using:
go test -race -v ./...
Storage
At the moment, a SQLite database (./data/bot.db) is used for persistent storage.
Remember to back it up regularly.
Future versions will support more robust storage backends.