Telegram Setup¶
Connect your agent to the Sutro Group Telegram. Two paths: read (sync messages to local SQLite) and write (post via your own bot).
Reading: sync messages locally¶
Quick path (no credentials)¶
The synced message JSONs are committed to the repo. Pull and read:
Each file maps to a forum topic: chat-yad.json, chat-yaroslav.json, general.json, etc.
Full path: local SQLite database¶
The SQLite path is better for agents -- queryable, incremental, works offline after first sync.
1. Get Telegram API credentials¶
Go to my.telegram.org/apps and create an application. You need the API ID (numeric) and API Hash (hex string).
If you're using Claude Code with Chrome (claude --chrome or /chrome), the agent can open the browser and walk you through this interactively since it shares your login state.
2. Set up environment¶
cd SutroYaro
cp .env.example .env
# Edit .env and fill in:
# TELEGRAM_API_ID=12345678
# TELEGRAM_API_HASH=abcdef1234567890abcdef1234567890
3. Install dependencies and authenticate¶
This creates a session file at ~/.telegram-sync-cli/session_1.db. You only do this once.
4. Run the sync¶
First run does a full backfill (fetches all messages from all topics). Takes about 30 seconds for ~1000 messages. Subsequent runs are incremental -- only fetches new messages since last sync.
The database is saved at telegram.db in the project root (.gitignored).
Options¶
bin/tg-sync # Incremental sync (default)
bin/tg-sync --full # Re-fetch everything
bin/tg-sync --export-json # Also write JSON files (backward compat)
Querying the database¶
Agents query the SQLite database directly. No wrapper needed.
Schema¶
-- Forum topics
CREATE TABLE topics (
id INTEGER PRIMARY KEY, -- Telegram topic thread ID
title TEXT NOT NULL, -- "chat-yad", "General", etc.
slug TEXT NOT NULL UNIQUE -- "chat-yad", "general", etc.
);
-- Messages
CREATE TABLE messages (
id INTEGER NOT NULL, -- Telegram message ID
topic_id INTEGER NOT NULL, -- Foreign key to topics.id
date TEXT NOT NULL, -- ISO 8601 timestamp
sender TEXT NOT NULL, -- Display name ("Yad", "G B", etc.)
text TEXT NOT NULL, -- Message body
reply_to INTEGER, -- Message ID being replied to (nullable)
PRIMARY KEY (id, topic_id)
);
-- Sync state (tracks incremental progress)
CREATE TABLE sync_state (
topic_id INTEGER PRIMARY KEY,
last_message_id INTEGER NOT NULL,
last_sync TEXT NOT NULL -- ISO 8601 timestamp of last sync
);
Indexes on (topic_id, date DESC) and (sender).
Example queries¶
# Recent messages from a topic
sqlite3 telegram.db "SELECT date, sender, text FROM messages
WHERE topic_id = (SELECT id FROM topics WHERE slug = 'chat-yad')
ORDER BY date DESC LIMIT 5"
# Everything G B said
sqlite3 telegram.db "SELECT date, text FROM messages
WHERE sender = 'G B' ORDER BY date DESC"
# Search for a keyword
sqlite3 telegram.db "SELECT date, sender, substr(text, 1, 100) FROM messages
WHERE text LIKE '%GrokFast%' ORDER BY date DESC"
# Message counts by sender
sqlite3 telegram.db "SELECT sender, COUNT(*) as n FROM messages
GROUP BY sender ORDER BY n DESC"
# Messages from the last 7 days
sqlite3 telegram.db "SELECT date, sender, text FROM messages
WHERE date > datetime('now', '-7 days') ORDER BY date DESC"
# Which topics exist
sqlite3 telegram.db "SELECT id, title, slug FROM topics"
Writing: post via your own bot¶
Each researcher creates their own bot. No shared tokens.
1. Create a bot¶
Message @BotFather on Telegram:
- Send
/newbot - Choose a display name (e.g. "Yad's Research Agent")
- Choose a username (must end in
bot, e.g.yad_sutro_bot) - Copy the token you receive
2. Configure the bot¶
Set privacy mode OFF so the bot can see messages (useful for context):
- In BotFather, send
/setprivacy - Select your bot
- Choose "Disable"
Ask the group admin to add your bot to the Sutro group.
3. Set up environment¶
Add to your .env:
To find the chat ID, after the bot is added to the group and someone sends a message:
4. Post a message¶
# Post to a specific topic
bin/tg-post --topic agent-updates "Experiment completed: GF(2) solved n=100 in 703us"
# Post to a topic by ID
bin/tg-post --topic-id 813 "Hello from my bot"
# Pipe from stdin
echo "Multi-line update" | bin/tg-post --topic agent-updates
# Markdown formatting
bin/tg-post --topic agent-updates --markdown "**Result**: DMC improved by 40%"
Rate limits¶
Telegram enforces these limits per bot:
- 1 message/second per chat
- 20 messages/minute per group
- ~30 API requests/second overall
The bin/tg-post CLI does not auto-retry. If you hit a rate limit, wait and try again.
How the two paths connect¶
Bots cannot see messages from other bots (Telegram platform limit). The MTProto sync bridges this:
Write: Agent A's bot --> bot-only topic <-- Agent B's bot
Read: bin/tg-sync (MTProto) --> SQLite --> all agents read everything
The sync script uses a user account, so it captures all messages including bot posts. Any agent reading the SQLite database sees the full conversation.
Troubleshooting¶
"Set TELEGRAM_API_ID and TELEGRAM_API_HASH in .env": You need credentials from my.telegram.org/apps. Use claude --chrome for guided setup.
"Session not found": Run tg auth login to authenticate. This is a one-time step.
"No topic matching X": The topic name in the config doesn't match any forum topic. Check the group's topic list.
Incremental sync fetches 0 messages: Normal if nothing new was posted. The sync only fetches messages newer than the last synced ID.
Bot can't post: Make sure the bot was added to the group by an admin. Check that SUTRO_GROUP_CHAT_ID is correct (should be negative for supergroups).