Telegram bridge for Gas Town overseer communication. Chat with the Mayor agent and receive workspace notifications from any Telegram client.
Install
# One-line installer (recommended — downloads signed binary with checksum verification) curl -fsSL https://raw.githubusercontent.com/leonletto/gt-telegram/main/scripts/install.sh | sh
Or with Homebrew:
brew install leonletto/tap/gt-telegram
Or with Go:
go install github.com/leonletto/gt-telegram@latest
Or build from source:
git clone https://github.com/leonletto/gt-telegram
cd gt-telegram
make installQuick Start
# 1. Create a bot via @BotFather on Telegram, copy the token # 2. Configure and pair (from your Gas Town root, or set GT_TOWN) export GT_TOWN=~/gt gt-telegram configure --token "123456789:AAH..." # → Send any message to your bot from Telegram # → Confirm the sender: [y/n] # → Done! chat_id and allow_from are set automatically # 3. Run the bridge gt-telegram run
No need to manually look up your chat ID or user ID — the pairing flow captures them automatically from your first message.
If you already know your IDs, you can skip pairing:
gt-telegram configure --token "123456789:AAH..." --chat-id <ID> --allow-from <ID>
Commands
| Command | Description |
|---|---|
gt-telegram configure |
Set token and pair (auto-pairs unless --allow-from set) |
gt-telegram pair |
Pair your Telegram account with an already-configured bridge |
gt-telegram status |
Show bridge configuration (token masked) |
gt-telegram status --json |
Machine-readable status |
gt-telegram run |
Run bridge in foreground (Ctrl-C to stop) |
gt-telegram version |
Show version and build info |
How It Works
You (Telegram) Gas Town
│ │
│ "Hi mayor, status?" │
├───────────────────────────────→ │
│ Bot API long-poll │
│ → AccessGate (allow_from) │
│ → RateLimiter (30/min) │
│ → gt mail send mayor/ │
│ → gt nudge hq-mayor │
│ │
│ Mayor processes
│ mail, replies to
│ overseer inbox
│ │
│ "@mayor/: All systems green" │
│ ←──────────────────────────────┤
│ ReplyForwarder polls │
│ overseer inbox every 3s │
│ → bot.SendMessage() │
Inbound (Telegram → Mayor)
- Bot long-polls Telegram with 30s timeout
- Access gate rejects bots, checks
allow_fromlist (fail-closed) - Rate limiter enforces per-user sliding window (default 30 msgs/min)
- Message sent as mail:
from: overseer,to: mayor/,subject: Telegram - Nudge queued to
hq-mayorso Mayor picks it up on its next turn
Outbound (Mayor → Telegram)
- Reply forwarder polls overseer inbox every 3s via
bd list - Forwards Mayor's replies to Telegram with thread mapping
- Seeds forwarded set on startup to prevent duplicates on restart
Event Notifications
Tails .feed.jsonl and forwards matching events:
| Category | Events |
|---|---|
stuck_agents |
mass_death, session_death |
escalations |
escalation_sent |
merge_failures |
merge_failed |
Configuration
Config lives at <GT_TOWN>/mayor/telegram.json with 0600 permissions.
{
"token": "123456789:AAH...",
"chat_id": 123456789,
"allow_from": [123456789],
"target": "mayor/",
"enabled": true,
"notify": ["escalations"],
"rate_limit": 30
}Environment Variables
| Variable | Description |
|---|---|
GT_TOWN |
Gas Town root directory (default: cwd) |
GT_TOWN_ROOT |
Alias for GT_TOWN |
Configuration Reference
| Field | Type | Default | Description |
|---|---|---|---|
token |
string | required | BotFather bot token |
chat_id |
int64 | required | Telegram chat for outbound messages |
allow_from |
[]int64 | [] |
Allowed user IDs (fail-closed) |
target |
string | "mayor/" |
Mail recipient for inbound messages |
enabled |
bool | true |
Enable/disable the bridge |
notify |
[]string | ["escalations"] |
Notification categories |
rate_limit |
int | 30 |
Max inbound messages per user per minute |
Documentation
- Setup Guide — step-by-step walkthrough from bot creation to running
- Architecture — component design, package structure, security model
- Troubleshooting — common issues and solutions
Requirements
- A running Gas Town instance
gtandbdcommands on PATH- A Telegram bot token (from @BotFather)
