Run multiple AI workers from Telegramβresearch, operations, and development in one chat.
Claude Code - Telegram is a Telegram bot + local bridge that lets you run and coordinate parallel AI workers from one Telegram chat.
In plain English: you message your bot, the bot sends the task to a Claude worker running on your computer, and the worker replies back in Telegram.
What you need:
- A Mac or Linux/Ubuntu computer
- A Telegram account
- An Anthropic account (for API usage)
Important terms (zero assumed knowledge):
- API key: a secret key that lets Claude CLI use your Anthropic account.
- Bot token: a secret key from Telegram that lets this project control your bot.
- tmux: a terminal session manager; this project uses it to keep workers running in the background.
- Webhook: a secure URL where Telegram sends new messages so your bot can react instantly.
- cloudflared: creates a secure public tunnel so Telegram can reach your computer.
If you skip steps, workers can appear to start but fail later. Follow each step in order.
Why this matters: this creates your bot identity and gives you the bot token this project needs.
- Open Telegram and search for
@BotFather. - Open the BotFather chat and press Start.
- Send this command in BotFather:
/newbot- BotFather asks for a bot name; send any display name you want.
- BotFather asks for a username; send a unique username that ends with
bot(example:myteamhelper_bot). - Copy the token BotFather sends you.
What you should see in Telegram:
- A BotFather message similar to:
Done! Congratulations on your new bot... - A line containing your bot token.
Verification:
- Your token should look like this pattern:
123456789:AAExampleTokenStringHere.
If this fails:
- Error:
Sorry, this username is already taken. - Fix: choose another username and keep the required
botsuffix.
Why this matters: workers cannot call Claude without your API key.
- Open
https://console.anthropic.comand sign in. - Open API keys and create a new key.
- Copy the key immediately.
Verification:
- Your key should start with
sk-ant-.
If this fails:
- Error: key is missing or does not start with
sk-ant-. - Fix: create a new key and copy it again.
Note:
- API usage costs money per request. Check pricing at
https://www.anthropic.com/pricing.
Choose your platform path and complete every step in that section.
Why this matters: Homebrew makes installing required tools simple and consistent.
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"Verification command:
brew --versionYou should see output like: Homebrew 4.x.x.
If this fails:
- Error:
xcode-select: error: tool 'xcode-select' requires Xcode - Fix: run the command below, then retry Step 1.
xcode-select --installWhy this matters: Claude CLI is a Node package, so Node.js is required first.
If you prefer a visual installer, you can download Node.js from https://nodejs.org instead of using Homebrew.
brew install nodeVerification command:
node --versionYou should see output like: v20.11.1 (v18+ is required).
Why this matters: this is the claude command workers actually run.
Warning
Common failure before this step: npm ERR! code EACCES.
If you see this on macOS, install Node via Homebrew first (Step 2), then retry this command.
npm install -g @anthropic-ai/claude-codeVerification command:
claude --versionYou should see output like: 1.0.x.
Why this matters: tmux keeps multiple workers alive in parallel background sessions.
brew install tmuxVerification command:
tmux -VYou should see output like: tmux 3.4.
Why this matters: the bridge is written in Python.
brew install pythonVerification command:
python3 --versionYou should see output like: Python 3.11.x.
Why this matters: setup scripts use jq for JSON editing and checks.
brew install jqVerification command:
jq --versionYou should see output like: jq-1.7.
Why this matters: setup and tunnel workflows call curl in multiple places.
curl --versionYou should see output beginning with curl.
Why this matters: cloudflared opens the secure tunnel Telegram needs to reach your machine.
brew install cloudflaredVerification command:
cloudflared --versionYou should see output containing: cloudflared version.
Why this matters: this refreshes available package versions before installing tools.
sudo apt updateVerification command:
apt-cache policy nodejsYou should see package metadata instead of Unable to locate package.
Why this matters: Claude CLI installation depends on both Node.js and npm.
sudo apt install -y nodejs npmVerification command:
node --versionYou should see v18 or newer.
If this fails:
- Problem: Ubuntu repo may install an older Node version.
- Fix: run NodeSource setup, then reinstall Node.js.
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -sudo apt install -y nodejsWhy this matters: this provides the claude executable used by worker sessions.
Warning
Common failure before this step: npm ERR! code EACCES.
Fix: retry with sudo on Ubuntu.
sudo npm install -g @anthropic-ai/claude-codeVerification command:
claude --versionYou should see output like: 1.0.x.
Why this matters: these are required by the bridge runtime and setup scripts.
sudo apt install -y tmux jq curl python3Verification command:
tmux -VYou should see output like: tmux 3.3a.
Verification command:
python3 --versionYou should see output like: Python 3.10.x or newer.
Why this matters: download and webhook troubleshooting commands use curl.
curl --versionYou should see output beginning with curl.
Why this matters: cloudflared download URL depends on CPU type.
uname -mYou should see x86_64 or aarch64.
Why this matters: this fetches cloudflared for most Intel/AMD Linux systems.
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o /tmp/cloudflaredIf your previous step returned aarch64, use this command instead:
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64 -o /tmp/cloudflaredWhy this matters: this places cloudflared in your executable path.
sudo install /tmp/cloudflared /usr/local/bin/cloudflaredVerification command:
cloudflared --versionYou should see output containing: cloudflared version.
If this fails:
- Error:
Permission deniedwhile installing. - Fix: rerun Step 8 with
sudoexactly as shown.
Why this matters: workers run in tmux sessions, and tmux must inherit ANTHROPIC_API_KEY from your shell startup file.
Important detail: this bridge propagates bridge-specific variables into workers, but it does not inject ANTHROPIC_API_KEY for you.
Warning
Do not create ~/.claude/.credentials.json for API-key auth.
It can cause: OAuth error: Invalid code.
Why this matters: ~/.zshrc runs every time you open a terminal.
echo 'export ANTHROPIC_API_KEY="sk-ant-paste-your-real-key-here"' >> ~/.zshrcReplace sk-ant-paste-your-real-key-here with your real key from Part 1.
source ~/.zshrcecho "$ANTHROPIC_API_KEY"You should see your key printed, starting with sk-ant-.
Why this matters: ~/.bashrc runs every time you open a terminal.
echo 'export ANTHROPIC_API_KEY="sk-ant-paste-your-real-key-here"' >> ~/.bashrcReplace sk-ant-paste-your-real-key-here with your real key from Part 1.
source ~/.bashrcecho "$ANTHROPIC_API_KEY"You should see your key printed, starting with sk-ant-.
If this fails:
- Symptom: command prints a blank line.
- Fix: repeat the
echo 'export ANTHROPIC_API_KEY=...' >> ...step carefully and reload withsource.
Why this matters: first-run setup must finish once interactively, or workers can get stuck in setup and never answer.
claude --dangerously-skip-permissionsIn the interactive wizard:
- Pick any theme.
- Choose
Yeswhen asked about custom API key. - Confirm permissions bypass.
- Type
/exitto close.
Verification command:
claude --versionYou should see only a version line (no wizard prompts).
If this fails:
- Error:
OAuth error: Invalid code. - Fix: remove the wrong credentials file, then rerun this step.
rm -f ~/.claude/.credentials.jsonChoose one option.
Why this matters: clone gives you easy future updates.
- Clone the repository.
git clone https://github.com/beastoin/claudecode-telegram- Verify key project files are present.
ls claudecode-telegram/You should see entries including bridge.py, claudecode-telegram.sh, hooks, DOC.md, and test.sh.
- Enter the project folder.
cd claudecode-telegramIf this fails:
- Error:
git: command not found. - Fix (macOS): run
brew install git. - Fix (Ubuntu): run
sudo apt install -y git.
Why this matters: this works when GitHub clone access is unavailable.
- Extract the tarball.
tar xzf claudecode-telegram.tar.gz- Verify key project files are present.
ls claudecode-telegram/You should see entries including bridge.py, claudecode-telegram.sh, hooks, DOC.md, and test.sh.
- Enter the project folder.
cd claudecode-telegramWhy this matters: hooks are small scripts that send worker replies from Claude sessions back into Telegram.
./claudecode-telegram.sh hook installYou should see success lines mentioning Stop/SessionStart hooks.
If this fails:
- Error:
jq: command not found. - Fix: install jq (Part 2), then rerun this step.
Why this matters: the bridge cannot call Telegram without TELEGRAM_BOT_TOKEN.
export TELEGRAM_BOT_TOKEN="123456789:paste-your-real-bot-token-here"Replace the entire value with the token from BotFather.
Verification command:
echo "$TELEGRAM_BOT_TOKEN"You should see a value with digits, a colon, and a long token string.
If this fails:
- Symptom: output is blank.
- Fix: rerun the
export TELEGRAM_BOT_TOKEN=...command.
Why this matters: this starts bridge + tunnel + webhook so Telegram can reach your workers.
Warning
Common failure before this step: tmux: command not found.
Fix: install tmux first (Part 2), verify with tmux -V, then rerun.
./claudecode-telegram.sh runYou should see output similar to:
Bridge started on port 8270Tunnel URL: https://...Webhook configured
Verification command (open a second terminal in the same folder):
./claudecode-telegram.sh statusYou should see node status marked running.
If this fails:
- Error:
Connection refused. - Fix: the bridge is not running; run
./claudecode-telegram.sh runagain and keep that terminal open. - Error:
Webhook setup failed (DNS may still be propagating). - Fix: wait 20-60 seconds and rerun
./claudecode-telegram.sh run.
Why this matters: all manager/operator actions happen in Telegram.
- Open Telegram.
- Search for your bot username from BotFather.
- Press Start.
Why this matters: no one can receive tasks until a worker exists.
Send this in Telegram:
/hire myworkerYou should see confirmation that worker myworker was created.
If this fails:
- Error:
No one assignedon later messages. - Fix: run
/teamthen/focus myworker.
Why this matters: this validates end-to-end delivery from Telegram to worker and back.
Send this in Telegram:
Summarize todayβs priorities from our latest commit messages.What to expect:
- Bot reacts with
π(delivery confirmed). - Worker replies as
myworker: ....
If this fails:
- Symptom: no
πreaction. - Fix: verify
TELEGRAM_BOT_TOKENand bridge status. - Symptom:
πappears but no reply. - Fix: run
/progress, then/restartif the worker is stuck.
- Ask your operator to complete setup once.
- Open the bot in Telegram.
- Send
/hire myworker. - Start assigning work in plain English.
- Open terminal in
claudecode-telegram. - Export bot token if not already set in your shell profile.
- Run
./claudecode-telegram.sh run. - Confirm with
./claudecode-telegram.sh status.
/hire ops/hire triage/hire research/hire frontend/hire qa/ops Run 5 worker queue: scrape refunds, reconcile invoices, update CRM notes, draft escalation email, and ping @qa for flaky test owners/triage Triage the latest GitHub issues; label, close dupes, and summarize top 10 with links/research Compare auth flows across api/, web/, and mobile/ repos; highlight inconsistencies + suggested fix/frontend Audit the settings UI for missing states and propose copy improvements/qa Reproduce the top crash from yesterday and draft a minimal repro@ops Coordinate with @frontend on status banner copy; @research share findings with @triage/progress/progress(later, when you return)@ops Post the nightly summary + anything blocked
You can also drop a screenshot and ask: What is wrong with this UI?
| Command | What it does |
|---|---|
/hire <name> |
Add a worker |
/focus <name> |
Set who gets your next message |
/progress |
See if the focused worker is busy |
/team |
List workers + focus |
/end <name> |
Remove a worker |
/pause |
Interrupt active worker |
/restart |
Restart active worker |
/restart --clean |
Restart with fresh context |
/learn |
Ask focused worker what they learned |
@name <msg> |
Send one-off message to a specific worker |
<message> |
Send to current focused worker |
Backend selection examples:
/hire alice --codex/hire codex-alice/hire gemini-worker --gemini/hire op-worker --opencode/hire custom --backend <name>
| Command | What it does |
|---|---|
./claudecode-telegram.sh run |
Start bridge + tunnel + webhook |
./claudecode-telegram.sh restart |
Restart node, preserve tmux sessions |
./claudecode-telegram.sh stop |
Stop node |
./claudecode-telegram.sh clean |
Reset admin/chat ID |
./claudecode-telegram.sh status |
Show status |
./claudecode-telegram.sh webhook <url> |
Set webhook URL manually |
./claudecode-telegram.sh webhook info |
Show webhook details |
./claudecode-telegram.sh webhook delete |
Remove webhook |
./claudecode-telegram.sh hook install |
Install Claude hooks |
./claudecode-telegram.sh hook uninstall |
Remove Claude hooks |
./claudecode-telegram.sh hook test |
Send test message to Telegram |
| Flag | Meaning |
|---|---|
--node <name> |
Target one node (example: prod/dev) |
--all |
Apply command to all nodes (status/stop) |
--port <port> |
Set bridge port |
--no-tunnel |
Skip cloudflared + webhook automation |
--tunnel-url <url> |
Use an existing tunnel URL |
--headless |
Non-interactive mode |
--json |
JSON output for status |
- You send a task.
- Bot reacts with
πto confirm delivery. - Worker replies later as
worker_name: ....
| Symptom | Likely cause | Fix |
|---|---|---|
| Bot doesn't respond | Bridge down or wrong admin | Run ./claudecode-telegram.sh status and restart if needed |
π but no reply |
Worker busy or stuck | Run /progress, then /restart |
No one assigned |
No focused worker | Run /team, then /focus <name> |
Why it happens:
- Claude CLI was not fully initialized with API-key flow, or
~/.claude/.credentials.jsonwas manually created.
Fix:
rm -f ~/.claude/.credentials.jsonclaude --dangerously-skip-permissionsThen complete wizard and exit with /exit.
Why it happens:
- Python 3 is missing or not in PATH.
Fix (macOS):
brew install pythonFix (Ubuntu):
sudo apt install -y python3Verify:
python3 --versionWhy it happens:
- tmux is not installed, so workers cannot stay alive.
Fix (macOS):
brew install tmuxFix (Ubuntu):
sudo apt install -y tmuxVerify:
tmux -VWhy it happens:
ANTHROPIC_API_KEYis not available inside tmux-created sessions.
Fix:
echo "$ANTHROPIC_API_KEY"If blank, add the key to your shell startup file (Part 3), open a new terminal, then restart the bridge.
./claudecode-telegram.sh restartWhy it happens:
- Invalid/missing
TELEGRAM_BOT_TOKEN, webhook misconfiguration, or bridge down.
Fix:
echo "$TELEGRAM_BOT_TOKEN"./claudecode-telegram.sh status./claudecode-telegram.sh runWhy it happens:
- Bridge process is not listening on expected port.
Fix:
./claudecode-telegram.sh runThen verify:
./claudecode-telegram.sh statusCommon errors:
cloudflared: command not found- webhook not updating after startup
Fix:
cloudflared --versionIf command not found, install cloudflared (Part 2) and rerun bridge.
./claudecode-telegram.sh runWhy it happens:
- Tunnel URL changed but Telegram still points to old URL.
Fix:
./claudecode-telegram.sh webhook info./claudecode-telegram.sh webhook delete./claudecode-telegram.sh runWhy it happens:
- First user to message becomes admin when
ADMIN_CHAT_IDis not set.
Fix:
./claudecode-telegram.sh cleanThen restart and send the first message from the correct Telegram account.
Why it happens:
- Hooks were not installed or Claude settings are stale.
Fix:
./claudecode-telegram.sh hook installThen restart your Claude worker session (/restart) or end/hire worker again.
The bridge includes built-in security defaults. These optional steps add defense-in-depth for production deployments.
- Localhost-only binding: Bridge binds to
127.0.0.1β only cloudflared (on the same machine) can reach it. Override withBRIDGE_BIND=0.0.0.0if needed. - HMAC-signed hook endpoints:
/responseand/notifyrequireX-Hook-Signatureheaders. The bridge generates a per-run secret and exports it to worker sessions automatically. Rogue local processes cannot inject messages without the secret. - Webhook secret: Set
TELEGRAM_WEBHOOK_SECRETto verify incoming Telegram webhooks. The bridge rejects forged webhook requests. - Token isolation: Workers never see
TELEGRAM_BOT_TOKEN. Responses flow through the bridge, which holds the token.
Why: prevents workers from reading bridge environment (including the bot token) via /proc.
sudo useradd --system --create-home --shell /usr/sbin/nologin bridge-userRun the bridge as bridge-user and workers as your normal user. Workers cannot read /proc/<bridge-pid>/environ.
Why: prevents any user from listing other users' processes and reading their environment.
sudo mount -o remount,hidepid=2 /procTo make it permanent, add to /etc/fstab:
proc /proc proc defaults,hidepid=2 0 0
Why: prevents the first random person who finds your bot from becoming admin.
export ADMIN_CHAT_ID="123456789"Get your chat ID by messaging @userinfobot on Telegram.
Why: ensures only Telegram (not an attacker who discovers your tunnel URL) can send webhooks.
export TELEGRAM_WEBHOOK_SECRET="$(openssl rand -hex 16)"The bridge passes this to Telegram during webhook setup and verifies it on every incoming request.
- Single admin: First person to message becomes admin unless
ADMIN_CHAT_IDis set. - Focus resets + context persists: After restart, run
/focusagain. Want a clean slate?/end <name>then/hire <name>. - Telegram limits: Long replies split after 4096 chars.
claudecode-telegram/
|-- bridge.py
|-- claudecode-telegram.sh
|-- hooks/
|-- DOC.md
`-- test.sh
- Throughput while offline. Run multiple workers in parallel so work continues after hours.
- Less context tax. Long-lived workers keep state, so you do not re-explain.
- One place to coordinate. Broadcast, delegate, and check status from a single chat.
- @chen triaged 290 issues in one session and tagged priorities + root causes.
- @geni did deep research on 2 OSS projects, tracing end-to-end flows and dependencies.
- Ops manager keeps 5 workers running; code ships while they are offline.
- Messages stay in Telegram. The bridge does not store message history elsewhere.
- Worker context is the chat. Each worker continues from the same ongoing Telegram thread.
- Easy to resume. Pick up any time from the existing chat history.
- Fewer places for data to live means lower risk.
- Less to secure and less to monitor.
- Easier reviews when you need to check what happened.
- Fewer moving parts to break.
- Ops: incident updates, checklists, status notes.
- Research: quick briefs, vendor comparisons, market scans.
- Triage: sort tickets, label issues, route requests.
- Support: draft replies, summarize threads, suggest next steps.
- Keep a lightweight team memory with two shared files:
~/team/playbook.mdand~/team/learnings.md. - Daily: ops manager asks for learnings/help, team adds quick notes.
- Result: the team gets smarter every day and repeats fewer mistakes.
- See our playbook template with real examples
Original project by Han Xiao (hanxiao/claudecode-telegram).
MIT