Telegram bot framework with Claude Code session integration
Project description
TeleClaude
A Python framework for building Telegram bots that use Claude Code to read, plan, and edit their own codebase - with human-in-the-loop approval, voice transcription via OpenAI Whisper, and self-restarting deployment.
anthropic claude-code claude-code-channels telegram-bot ai-agent self-improving-software whisper voice-to-code agentic-coding python
The idea: let Claude Code edit itself through Telegram
Your bot is a thin Telegram relay. Claude Code is the agentic part - it reads the codebase, proposes changes, and writes files when you approve. The bot just forwards your messages to Claude Code and sends back the response.
The result is a closed-loop development cycle: chat -> analyze -> plan -> approve -> edit -> restart. No IDE, no SSH, no deploy pipeline. Just a conversation with your running application from your phone - or even a voice message transcribed via Whisper.
What about Claude Code Channels? Anthropic's official Telegram/Discord/iMessage channels are a promising direction, but they're still in research preview - when we last tested them, the experience wasn't stable enough for production use. TeleClaude was built to fill that gap: your bot runs Claude Code as a subprocess on the server where it's deployed, with a plan/approve workflow and self-restart baked in. No local machine needed, no --channels flag, no Bun dependency - just pip install and go. If Channels matures into a solid production path, we'd love to add it as an alternative backend - contributions welcome.
How it works
+----------------+ +-----------------+ +--------------------+
| Telegram | msg | TeleClaude | stdin | Claude Code |
| (phone) |------->| (Python bot) |------->| (subprocess) |
| |<-------| |<-------| |
| | reply | plan/approve | stdout | reads/edits |
| | | workflow | | your codebase |
+----------------+ +-----------------+ +--------------------+
- You send a message in Telegram
- TeleClaude routes it to Claude Code in read-only plan mode
- Claude analyzes your codebase and proposes a plan
- You
/approveor/rejectfrom Telegram - On approve, Claude executes with file-edit permissions
/restartreloads the bot to pick up code changes- The application is now running its improved version of itself
Quickstart
Prerequisites
- Python >= 3.10
- Claude Code CLI installed and authenticated
- A Telegram bot token from @BotFather
Install
pip install teleclaude
Create your bot
import os, time
from dotenv import load_dotenv
from teleclaude import ClaudeSession, TeleClaudeBot, kill_previous
load_dotenv()
kill_previous("bot.pid")
session = ClaudeSession(project_dir=".")
bot = TeleClaudeBot(
token=os.environ["TELEGRAM_BOT_TOKEN"],
chat_id=os.environ["TELEGRAM_CHAT_ID"],
claude_session=session,
)
bot.start_polling()
try:
while bot.running:
time.sleep(1)
except KeyboardInterrupt:
bot.stop_polling()
That's it. Send any message in Telegram and Claude Code responds. Built-in commands:
| Command | What it does |
|---|---|
| Free text | Chat with Claude Code (read-only mode) |
| Voice msg | Transcribed via Whisper, then routed to Claude |
/claude |
Interactive menu: model switcher, session info, flush, approve/reject |
/approve |
Execute Claude's pending plan (allows file edits) |
/reject |
Discard the pending plan |
/session |
Session management (/session pin <id>, /session clear) |
/context |
Check Claude Code availability (rate-limit detection) |
/restart |
Restart the bot process (picks up code changes) |
/help |
Show all available commands |
Add your own commands
Subclass TeleClaudeBot and override domain_commands() to register custom /commands:
import subprocess
from teleclaude import ClaudeSession, TeleClaudeBot, kill_previous
class MyBot(TeleClaudeBot):
def domain_commands(self):
return {
"/status": (self.cmd_status, "Show git status"),
}
def cmd_status(self):
result = subprocess.run(
["git", "log", "--oneline", "-5"],
capture_output=True, text=True, cwd=self._project_dir,
)
self.send(f"<pre>{result.stdout or 'No git history.'}</pre>")
Other hooks you can override:
| Hook | Purpose |
|---|---|
on_domain_callback(data, message_id) |
Handle inline keyboard callbacks |
help_text() |
Customize /help output |
on_restart() |
Customize restart behavior |
plan_prompt_wrapper(text) |
Customize the prompt sent to Claude in plan mode |
Features
Voice messages
Send a voice message in Telegram and it gets auto-transcribed via OpenAI Whisper, then routed to Claude. Install the optional dependency:
pip install openai-whisper
The Whisper model (base) is lazy-loaded on first voice message. If not installed, the bot replies with install instructions.
Session handoff
The /claude menu includes Flush & New Session, which:
- Asks Claude to write a
.handoff.mdsummary of the current session context - Clears the session pin
- On the next message, a new session bootstraps from
.handoff.mdautomatically
To enable automatic handoff bootstrap, pass bootstrap_file to ClaudeSession:
session = ClaudeSession(project_dir=".", bootstrap_file=".handoff.md")
Rate-limit detection
When Claude returns a rate-limit error, the bot automatically starts background polling (every 5 min, up to 12 h) and notifies you when Claude is back online. You can also manually check via /context or the /claude menu.
Configuration reference
ClaudeSession options
session = ClaudeSession(
project_dir=".", # repo root (resolved to absolute path)
model="opus", # "opus", "sonnet", or "haiku"
output_format="json", # "json" or "stream-json"
bootstrap_file=".handoff.md", # auto-inject on new sessions (None to disable)
auto_pin=True, # auto-save session ID on first use
session_name_prefix="mybot", # generates mybot-1, mybot-2, etc.
plan_max_turns=25, # max turns in plan (read-only) mode
edit_max_turns=25, # max turns in edit mode
plan_tools=["Read", "Grep"], # override default plan-mode tools
edit_tools=["Read", "Edit"], # override default edit-mode tools
on_session_fallback=callback, # called when pinned session expires
)
Development
git clone https://github.com/ofir5300/teleclaude.git
cd teleclaude
pip install -e .
cd example && cp .env.example .env # fill in your tokens
python main.py
Contributing
Contributions welcome! Open an issue or PR on GitHub.
License
MIT - Ofir Cohen
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file teleclaude-0.3.0.tar.gz.
File metadata
- Download URL: teleclaude-0.3.0.tar.gz
- Upload date:
- Size: 1.0 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
72a8dc87bfef77f60d3442c9d6fe8f71906b959c3d3798950c35d7b4c3217227
|
|
| MD5 |
d8a1d4ff459c66abaf56fa340e29ef02
|
|
| BLAKE2b-256 |
9d104edfacf5daf249d1e35e0ef37661cba731f49cf1ada3b035130d31bc865b
|
Provenance
The following attestation bundles were made for teleclaude-0.3.0.tar.gz:
Publisher:
publish.yml on ofir5300/teleclaude
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
teleclaude-0.3.0.tar.gz -
Subject digest:
72a8dc87bfef77f60d3442c9d6fe8f71906b959c3d3798950c35d7b4c3217227 - Sigstore transparency entry: 1448279637
- Sigstore integration time:
-
Permalink:
ofir5300/teleclaude@a4a3f0cfe86c9349b70c1dfd1a2cb65fcde3651c -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/ofir5300
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a4a3f0cfe86c9349b70c1dfd1a2cb65fcde3651c -
Trigger Event:
push
-
Statement type:
File details
Details for the file teleclaude-0.3.0-py3-none-any.whl.
File metadata
- Download URL: teleclaude-0.3.0-py3-none-any.whl
- Upload date:
- Size: 29.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3970230f3ce7ccdefe544bf010c5a1cbe2a5ea8cbfcb18777e4be23b8d381057
|
|
| MD5 |
7fcb0ea8de6d99c8f2e721538810cca8
|
|
| BLAKE2b-256 |
d140906a3655b7db758a434d2c545b5c9a95b78c9b7d84c5782564b14ca424a5
|
Provenance
The following attestation bundles were made for teleclaude-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on ofir5300/teleclaude
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
teleclaude-0.3.0-py3-none-any.whl -
Subject digest:
3970230f3ce7ccdefe544bf010c5a1cbe2a5ea8cbfcb18777e4be23b8d381057 - Sigstore transparency entry: 1448279694
- Sigstore integration time:
-
Permalink:
ofir5300/teleclaude@a4a3f0cfe86c9349b70c1dfd1a2cb65fcde3651c -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/ofir5300
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a4a3f0cfe86c9349b70c1dfd1a2cb65fcde3651c -
Trigger Event:
push
-
Statement type: