Open-source Telegram bot that drafts replies for you. Try it: @DraftGuruBot
π For users 18+ only.
- π Connect your account via
/connect(phone number or QR code). - π¦ When you receive a private message, the bot automatically drafts a reply right in the input field.
- βοΈ Write an instruction in the draft β the bot will rewrite it as soon as you leave the chat.
Auto-replies work in private chats only. Draft instructions work everywhere.
- By default, the bot only writes drafts and never sends messages on your behalf. Auto-sending is only possible when the auto-reply timer is explicitly enabled in
/settings. - Messages are not stored. The bot doesn't save conversations β chat history is fetched via Telegram API on each event and is never persisted. The context is limited to the last 30 messages or 16,000 characters (whichever comes first); older messages are dropped.
- Saved Messages (self-chat) and Telegram service notifications are fully ignored β the bot doesn't read, draft, or process messages in them. Additional chats can be excluded via
IGNORED_CHAT_IDSinconfig.py. - Telegram sessions are encrypted with
Fernet(SESSION_ENCRYPTION_KEY) before being stored in the database.
git clone https://github.com/oponfil/draftguru.git
cd draftguru
pip install -r requirements.txtcp .env.example .envFill in .env:
BOT_TOKENβ get from @BotFatherPYROGRAM_API_IDandPYROGRAM_API_HASHβ from my.telegram.orgSUPABASE_URLandSUPABASE_KEYβ from Supabase Dashboard (use the service_role key)SESSION_ENCRYPTION_KEYβFernetkey for encryptingsession_stringbefore storing in DBEVM_PRIVATE_KEYβ private key of a Base wallet with USDC for AI payments
Generate SESSION_ENCRYPTION_KEY:
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"Optional for debugging:
DEBUG_PRINT=trueβ verbose console logs (defaultfalse)LOG_TO_FILE=trueβ save full AI requests/responses tologs/for local debugging (defaultfalse)DASHBOARD_KEYβ secret key for dashboard access (see Dashboard section)
Important: keep LOG_TO_FILE disabled in production β it logs full prompts, chat history, and model responses.
Run schema.sql in the SQL Editor of your Supabase project.
python bot.py| Command | Description |
|---|---|
/start |
Welcome message and quick usage guide |
/settings |
Settings: model (FREE/PRO), prompt, communication style, auto-reply timer, timezone |
/chats |
Per-chat settings: individual style, auto-reply timer, and system prompt for each chat (connected users only) |
/poke |
Scan the 16 most recent private chats and draft replies to unanswered messages and follow-ups (connected users only) |
/status |
Connection status |
/connect |
Connect Telegram account via phone or QR code (supports 2FA) |
/disconnect |
Disconnect account (idempotent: stops listener and clears session in DB) |
The command menu is dynamic: /connect and /disconnect are shown based on connection status. /chats and /poke are only visible to connected users. /start is not shown in the menu.
By default, /connect prompts for a phone number. A button below the message lets you switch to QR code. For 2FA, the bot asks for the cloud password in a separate message. Phone number, confirmation code, and password are kept visible during authorization and automatically deleted after successful login or timeout.
Code masking: During authorization, the bot will ask you to enter the confirmation code with letters or spaces (e.g. 12x345) to prevent Telegram from blocking your login attempt.
| Setting | Description | Default |
|---|---|---|
| Model (π€) | AI mode: FREE (Gemini 3.1 Flash Lite) or PRO. In PRO mode, the model is selected by communication style: GPT-5.4 for most styles, Gemini 3.1 Pro Preview for seducer. | PRO |
| Prompt (π) | Custom prompt: describe your persona and add instructions (max 600 chars). The AI uses this to build a USER PROFILE & CUSTOM INSTRUCTIONS block. We recommend adding a self-description β gender, age, occupation, and texting habits β so the AI mimics your style more accurately. Example: "I'm a 28 y/o guy, designer. I text short, 1β2 sentences, never use periods at the end. I swear a lot and use stickers." Applied to all chats. Applied to drafts and auto-replies. | β OFF |
| Style (π¦/π»/π/πΌ/π°/π΅οΈ/π) | Communication style: Userlike, Friend, Romance, Business, Sales, Paranoid, Seducer. Sets the tone and manner of replies (including direct bot chat). | π¦ Userlike |
| Auto-reply (β°) | Auto-reply timer. If the user doesn't send the draft within the specified time, the bot sends the message itself. Options: OFF, π Ignore, 1 min, 5 min, 15 min, 1 hour, 16 hours. Ignore disables drafts and auto-replies by default for all chats, but any per-chat override in /chats still takes priority. Actual delay: from base to 2Γbase (e.g. 16 h β 16β32 h, avg 24 h). |
OFF |
| Timezone (π) | User timezone. The button shows the current time β tap to cycle through 30 popular UTC offsets (including +3:30, +4:30, +5:30, +9:30). Affects message timestamps in AI context. | UTC0 |
The /chats command shows recent chats, prioritizing chats with per-chat auto-reply overrides first, then chats where the bot has replied or where custom per-chat settings already exist. Each chat is shown as a single button with the chat name.
Tapping a chat opens a new message with three vertical buttons:
- Style (
π¦ Style: Userlike) β tap to cycle through styles - Prompt (
π Prompt: β ON) β tap to open the prompt editor for this chat. Shows the current prompt and lets you set a new one, clear it, or cancel. Per-chat prompt is appended to the global prompt (max 300 chars). - Auto-reply (
β° Auto-reply: β OFF) β tap to cycle through auto-reply timers for this chat. The second option in the cycle is π Ignore β fully disables drafts, auto-replies, and message polling for that chat.
Per-chat settings override the global ones from /settings. If a per-chat value matches the global one, the override is automatically cleared. Available only to connected users.
Typing indicator: While generating a reply, the bot shows a status in the chat with the active style emoji (e.g. π is typing... for Romance or π is typing... for Seducer).
Emoji shortcut in draft: put a style emoji in the chat draft β the bot will switch the style and generate a reply. If the chosen emoji matches your global style (set in /settings), the per-chat override will be cleared.
| Emoji | Style |
|---|---|
| π¦ | Userlike |
| π» | Friend |
| π | Romance |
| πΌ | Business |
| π° | Sales |
| π΅οΈ | Paranoid |
| π | Seducer |
You can combine: π tell her I miss her β switches the style to Seducer and executes the instruction.
All voice messages in the chat history β from both sides (yours and the contact's) β are automatically transcribed via Telegram Premium TranscribeAudio and included in the AI context as text. Voice messages are transcribed sequentially to avoid Telegram rate limits; results are cached so repeated reads don't re-transcribe. If transcription fails (e.g. no Premium), the message is included as [voice message] so the AI still knows a voice was sent. Requires Telegram Premium on the connected account (or trial attempts for free users).
Stickers are processed by emoji β the bot sees the sticker's emoji in the conversation context and generates an appropriate reply.
DraftGuru includes a built-in monitoring dashboard β a single-page web UI with live metrics and logs.
Features:
- KPI cards: users (total / connected / active 24h), prepaid balance, balance spent
- LLM stats: requests, tokens, latency, models, errors
- Draft / auto-reply / voice counters
- Live log viewer with filtering (All / Errors / Warnings) and Copy All
- Auto-refresh every 5 seconds
Access:
Set DASHBOARD_KEY in .env, then open:
https://<your-domain>/dashboard?key=YOUR_KEY
After the first visit, a cookie is set for 30 days β no need to pass the key again.
The dashboard runs on the same port as the bot ($PORT, default 8080). If DASHBOARD_KEY is not set, the dashboard is disabled.
- Create a project on Railway
- Connect your GitHub repository
- Add environment variables (from
.env.example) - Railway will automatically detect the
Procfileand start the bot
The bot can answer questions about its own functionality, settings, and source code. It uses Retrieval-Augmented Generation β the codebase is indexed into a vector database (Supabase pgvector) and relevant fragments are automatically retrieved for each question.
How it works:
- On each deploy,
scripts/index_knowledge.pyparses source files (Python AST, Markdown headers, SQL) and stores embeddings in Supabase. - Indexing is incremental: content is hashed (SHA-256) and only changed chunks are re-embedded, saving API costs.
- When you ask a question, the bot finds the most relevant chunks via vector similarity search and injects them into the AI prompt.
Manual re-indexing:
python scripts/index_knowledge.pypytest tests/ -vAll external dependencies are mocked β tests are fully offline and don't require .env.
Tests run automatically on GitHub on push to main/dev and on PRs (GitHub Actions).
SESSION_STRINGβ a secret key for your account. Generation scripts don't display it in the terminal without explicit confirmation. Never share it with third parties.
- bot.py β Entry point: handler registration, bot startup, dashboard server
- handlers/ β Bot commands and Pyrogram events
- config.py β Constants and environment variables
- prompts.py β AI prompts
- system_messages.py β System messages with auto-translation
- clients/ β API clients (x402gate, Pyrogram)
- logic/ β Reply generation business logic
- dashboard/ β Monitoring dashboard (aiohttp server, in-memory stats, HTML SPA)
- database/ β Supabase queries
- utils/ β Utilities
- scripts/ β CLI scripts (Railway logs, session generation)
- tests/ β Unit tests (pytest)
- Python 3.13
- python-telegram-bot β Telegram Bot API
- Pyrogram β Telegram Client API (reading messages, drafts)
- x402gate.io β OpenRouter β any model (configured in
config.py, paid with USDC on Base) - aiohttp β Dashboard HTTP server
- Supabase β PostgreSQL (DB)
- Railway β hosting
See CONTRIBUTING.md