Telegram Integration
Pilot provides a Telegram bot interface for conversational task submission, voice messages, image analysis, and real-time execution status. It’s the most interactive way to communicate with Pilot.
The Telegram adapter supports five interaction modes: Task execution, Questions, Research, Planning, and Chat. It automatically detects your intent and responds appropriately.
Setup
1. Create a Telegram Bot
- Open Telegram and find @BotFather
- Send
/newbotand follow the prompts - Copy the bot token (format:
123456789:ABC-DEF1234ghIkl-zyx57W2v1u123ew11)
2. Get Your Chat ID
To find your Telegram user/chat ID:
- Start a chat with your new bot
- Send any message
- Visit
https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates - Look for
"chat":{"id":123456789}in the response
Or use @userinfobot to get your user ID.
3. Configure Pilot
# ~/.pilot/config.yaml
adapters:
telegram:
enabled: true
bot_token: ${TELEGRAM_BOT_TOKEN}
chat_id: "123456789"
allowed_ids:
- 123456789 # Your user ID
project_path: /path/to/repo
polling: true
plain_text_mode: trueAlways set allowed_ids to restrict who can trigger Pilot via Telegram. Without it, anyone who discovers your bot can submit tasks.
Configuration Reference
| Field | Type | Default | Description |
|---|---|---|---|
enabled | bool | false | Enable the Telegram adapter |
bot_token | string | required | Bot token from @BotFather |
chat_id | string | — | Default chat ID for outbound notifications |
message_thread_id | int64 | — | Forum topic for outbound notifications and approval prompts. Forum supergroups only |
allowed_ids | []int64 | — | User/chat IDs authorized to send tasks |
project_path | string | — | Default project path for tasks |
polling | bool | false | Enable inbound message polling |
plain_text_mode | bool | true | Use plain text instead of Markdown |
transcription.backend | string | "auto" | Voice transcription backend |
transcription.openai_api_key | string | — | OpenAI API key for Whisper |
rate_limit.enabled | bool | true | Enable per-user rate limiting |
rate_limit.messages_per_minute | int | 20 | Max messages per minute per user |
rate_limit.tasks_per_hour | int | 10 | Max task executions per hour |
rate_limit.burst_size | int | 5 | Burst allowance above rate limit |
llm_classifier.enabled | bool | false | Enable LLM-based intent classification |
llm_classifier.api_key | string | — | Anthropic API key |
llm_classifier.timeout_seconds | int | 2 | Classification timeout |
llm_classifier.history_size | int | 10 | Messages to keep per chat |
llm_classifier.history_ttl | duration | 30m | Conversation history TTL |
Forum Topics
Supergroups with Topics enabled route every message to a topic. Set
message_thread_id to post notifications and approval prompts into one topic
instead of General:
adapters:
telegram:
chat_id: "-1001234567890"
message_thread_id: 12The id is the middle segment of a link to any message in that topic —
https://t.me/c/<chat>/<topic>/<msg>. Leave it unset for chats without Topics;
sending a topic id to a non-forum chat is rejected by the Bot API.
Approval prompts addressed to an individual approver (where approvers[0] is a
chat ID) go to that chat directly and ignore this setting. Alert channels take
their own message_thread_id — see Alerts.
Replies follow the conversation
Replies to a message you sent — answers, plans, task confirmations, results —
go back to the topic that message came from, whichever topic that is.
message_thread_id is the default for messages Pilot starts on its own (task
lifecycle notifications and alerts), not a ceiling on where replies can go.
Messages sent in a forum’s General thread are answered in General. In a supergroup without Topics enabled, replies are unaffected — the Bot API only accepts a topic for forum supergroups, so Pilot deliberately ignores the thread id of an ordinary reply chain rather than sending one that would be rejected.
Chat Modes
Pilot automatically detects your intent and responds in one of five modes:
Task Mode
Triggered by action-oriented messages:
"Add a logout button to the header"
"Fix the bug in user authentication"
"Create a new API endpoint for orders"Pilot will:
- Show a confirmation message with the task details
- Wait for you to confirm (Execute/Cancel buttons)
- Execute and create a PR
- Report results back to the chat
Question Mode
Triggered by questions about the codebase:
"What handles authentication?"
"How does the payment flow work?"
"Where is the config loaded?"Pilot will:
- Explore the codebase (read-only)
- Return a concise answer
- Not make any changes
Research Mode
Triggered by research requests:
"Analyze the API response times"
"Research how competitors implement this feature"
"Investigate the memory usage patterns"Pilot will:
- Perform deep analysis
- Return structured findings
- Save results to
.agent/research/
Planning Mode
Triggered by planning requests:
"Plan the implementation for user notifications"
"How should we approach adding caching?"
"Design the architecture for the new module"Pilot will:
- Explore the codebase
- Draft an implementation plan
- Offer Execute/Cancel buttons to proceed
If planning fails, Pilot shows a specific error message depending on the failure type:
- Timeout — planning exceeded the configured
planning_timeoutduration - API error — the upstream LLM call failed
- Empty result — planning completed but produced no output
The timeout is controlled by the executor’s planning_timeout setting.
Chat Mode
Triggered by conversational messages:
"Hello"
"Thanks!"
"What can you do?"Pilot responds conversationally without code execution.
Bot Commands
| Command | Description |
|---|---|
/start, /help | Show help message |
/status | Current task and queue status |
/cancel | Cancel pending or running task |
/queue | Show queued tasks |
/projects | List configured projects |
/switch <name> | Switch active project |
/tasks | Show task backlog from .agent/tasks/ |
/run <id> | Execute task directly (e.g., /run 07) |
/stop | Stop running task |
/history | Recent task history |
/budget | Show usage and costs |
/brief | Generate on-demand daily summary |
/voice | Check voice transcription status |
/nopr <task> | Execute without creating PR |
/pr <task> | Force PR creation |
Voice Messages
Pilot supports voice transcription using OpenAI Whisper:
Enable Voice Support
adapters:
telegram:
transcription:
backend: auto
openai_api_key: ${OPENAI_API_KEY}How It Works
- Send a voice message to the bot
- Pilot transcribes it using Whisper API
- Shows you the transcription
- Processes it as if you typed it
Supported Languages
Whisper automatically detects language. Pilot shows the detected language:
🎤 Transcribed (English):
Add error handling to the payment endpointImage Analysis
Send photos to Pilot for visual analysis:
- Send a photo to the bot
- Optionally add a caption with instructions
- Pilot analyzes the image and responds
Use cases:
- Screenshot analysis
- UI mockup interpretation
- Error message screenshots
- Architecture diagrams
Multi-Project Support
Switch between configured projects:
/projects # List all projects
/switch backend # Switch to backend project
/project # Show current projectEach chat maintains its own active project. When you submit a task, it is always routed to the currently active project — use /switch to change context before submitting.
Task Confirmation
When you submit a task, Pilot shows a confirmation:
📋 New Task
TG-1234567890
"Add logout button to header"
Project: pilot
📁 /path/to/repo
[✅ Execute] [❌ Cancel]You can:
- Click Execute or reply “yes” to proceed
- Click Cancel or reply “no” to abort
- Tasks expire after 5 minutes without response
Progress Updates
During execution, Pilot updates the progress message:
🔄 Task TG-1234567890
━━━━━━━━░░ 80%
🔨 Implementing changes...The progress bar updates in real-time as phases complete.
Ephemeral Tasks
Pilot automatically detects ephemeral tasks (commands that shouldn’t create PRs):
"Run the tests"
"Start the dev server"
"Check the build"These execute without PR creation. Override with /pr <task> to force PR.
Quick Patterns
Type these shortcuts for common operations:
| Pattern | Action |
|---|---|
07 or task 07 | Run TASK-07 from .agent/tasks/ |
status? | Show project status |
todos? | List TODO/FIXME comments |
Rate Limiting
Protect against abuse with per-user rate limits:
rate_limit:
enabled: true
messages_per_minute: 20
tasks_per_hour: 10
burst_size: 5When exceeded, users receive a warning message and must wait.
LLM Intent Classification
For better intent detection, enable LLM classification:
llm_classifier:
enabled: true
api_key: ${ANTHROPIC_API_KEY}
timeout_seconds: 2
history_size: 10
history_ttl: 30mBenefits:
- More accurate intent detection
- Context-aware classification
- Better handling of ambiguous messages
Falls back to regex-based detection if LLM fails.
Inline Keyboards
Pilot uses Telegram inline keyboards for interactions:
- Execute/Cancel: Task confirmation
- Project switching: Quick project selection
- Voice setup: Transcription configuration
Singleton Mode
Only one Pilot instance can poll the same bot:
if err := handler.CheckSingleton(ctx); err == telegram.ErrConflict {
log.Fatal("Another Pilot instance is already running")
}If you see a 409 error, check for other running instances.
Notifications
Pilot can send proactive notifications to your chat:
- Task completion
- PR ready for review
- Execution failures
- Daily briefs
Configure via daily_brief.channels:
daily_brief:
channels:
- type: telegram
channel: "123456789"Security Considerations
Allowed IDs
Always configure allowed_ids:
allowed_ids:
- 123456789 # Your user ID
- 987654321 # Team member
- -1001234567890 # Group chat IDGroup chat IDs are negative numbers.
Token Security
- Never commit bot tokens to version control
- Use environment variables
- Rotate tokens if compromised
- Consider using separate bots for dev/prod
Rate Limiting
Enable rate limiting for production:
rate_limit:
enabled: true
messages_per_minute: 20
tasks_per_hour: 10Team Member Resolution
For multi-user deployments with RBAC:
adapters:
telegram:
# ... other config ...
team:
enabled: true
team_id: engineeringPilot maps Telegram user IDs to team members for access control.
Troubleshooting
Bot Not Responding
- Verify bot token is correct
- Check
polling: trueis set - Ensure no other instance is running (409 error)
- Check your user ID is in
allowed_ids - Look for errors in Pilot logs
Voice Not Working
- Verify
openai_api_keyis set - Run
/voiceto check status - Check OpenAI API quota
- Ensure audio format is supported (Telegram uses OGG)
Messages Not Authorized
- Add your user ID to
allowed_ids - For groups, add the group chat ID (negative number)
- Restart Pilot after config changes
Progress Updates Not Showing
- Check plain_text_mode setting
- Verify message edit permissions
- Look for rate limit errors
- Check Telegram API connectivity
Task Timing Out
- Default timeout is 30 minutes
- Check for infinite loops in execution
- Use
/stopto cancel stuck tasks - Check executor timeout configuration
API Usage
Pilot uses these Telegram Bot API methods:
| Method | Purpose |
|---|---|
getUpdates | Long-polling for messages |
sendMessage | Send text responses |
editMessageText | Update progress |
answerCallbackQuery | Acknowledge button clicks |
getFile | Download voice/image files |
The bot uses long-polling (30 second timeout) for real-time message reception.