Production bot available: If you want the full-featured bot with Claude-powered reasoning, medication photo detection, and the RoboTerri persona, see
bot/roboterri.pyand its README. The tutorial below builds a simpler version from scratch for learning purposes.
This tutorial walks you through building a Telegram bot that runs ClawBio skills. By the end, you'll be able to send a genetic data file to your bot and receive a pharmacogenomics report, equity score, or genome comparison β all running locally on your machine.
Time: ~20 minutes | Difficulty: Intermediate | Prerequisites: Python 3.11+, a Telegram account
- Overview
- Prerequisites
- Clone and Install ClawBio
- Create a Telegram Bot
- Get Your Telegram Chat ID
- Set Up Your API Key
- Build the Bot
- Run It
- Test It
- Next Steps
- Troubleshooting
You (Telegram) β Your bot (your machine) β ClawBio skills (local)
β β
βββββββββ report + figures βββββββββββββββββββββ
The bot you'll build:
- Accepts messages and genetic data files in Telegram
- Routes to the correct ClawBio skill via the CLI
- Runs the analysis locally β no genetic data leaves your machine
- Sends back a summary, report, and figures directly in Telegram
| Requirement | Version | Check |
|---|---|---|
| Python | 3.11+ | python3 --version |
| pip | latest | pip3 install --upgrade pip |
| Git | any | git --version |
| Telegram | account + app | telegram.org |
brew install python@3.11sudo apt update && sudo apt install python3.11 python3.11-venv python3-pipgit clone https://github.com/ClawBio/ClawBio.git
cd ClawBio
pip3 install -r requirements.txtVerify it works:
python3 clawbio.py list
python3 clawbio.py run pharmgx --demoYou should see a pharmacogenomics report generated in under 1 second.
- Open Telegram and search for @BotFather
- Send
/newbot - Choose a name (e.g., "My ClawBio Agent")
- Choose a username (must end in
bot, e.g.,my_clawbio_bot) - BotFather replies with your bot token β save it securely
Security: Never share your bot token or commit it to Git. Treat it like a password.
Still in the BotFather chat, send /setcommands, select your bot, then paste:
start - Start the bot
demo - Run a ClawBio demo skill
Restrict your bot so only you can use it. To find your chat ID:
- Start a conversation with your new bot (press Start)
- Send any message (e.g., "hello")
- Open this URL in your browser (replace
YOUR_BOT_TOKEN):
https://api.telegram.org/botYOUR_BOT_TOKEN/getUpdates
- Look for
"chat":{"id":123456789}β that number is your chat ID
Alternatively, search for @userinfobot on Telegram and send /start.
Install the Telegram bot library:
pip3 install "python-telegram-bot[job-queue]"Create a file called .env in the ClawBio directory:
TELEGRAM_BOT_TOKEN=your-bot-token-here
TELEGRAM_CHAT_ID=your-chat-id-here
Add .env to your .gitignore so it never gets committed:
echo ".env" >> .gitignoreCreate a file called telegram_bot.py in the ClawBio directory:
#!/usr/bin/env python3
"""Minimal Telegram bot that runs ClawBio skills."""
import os
import subprocess
import tempfile
from pathlib import Path
from dotenv import load_dotenv
from telegram import Update
from telegram.ext import (
Application,
CommandHandler,
ContextTypes,
MessageHandler,
filters,
)
load_dotenv()
BOT_TOKEN = os.environ["TELEGRAM_BOT_TOKEN"]
ALLOWED_CHAT_ID = int(os.environ["TELEGRAM_CHAT_ID"])
CLAWBIO = Path(__file__).parent / "clawbio.py"
def is_authorised(update: Update) -> bool:
return update.effective_chat.id == ALLOWED_CHAT_ID
async def start(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
if not is_authorised(update):
return
await update.message.reply_text(
"ClawBio Telegram Bot\n\n"
"Commands:\n"
" /demo <skill> β Run a demo (pharmgx, equity, nutrigx, compare)\n"
" /list β List available skills\n\n"
"Or send a genetic data file (.txt, .csv, .vcf) to analyse it."
)
async def list_skills(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
if not is_authorised(update):
return
result = subprocess.run(
["python3", str(CLAWBIO), "list"],
capture_output=True, text=True, timeout=30,
)
await update.message.reply_text(f"```\n{result.stdout}\n```", parse_mode="Markdown")
async def demo(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
if not is_authorised(update):
return
skill = ctx.args[0] if ctx.args else "pharmgx"
await update.message.reply_text(f"Running {skill} demo...")
with tempfile.TemporaryDirectory() as tmpdir:
cmd = ["python3", str(CLAWBIO), "run", skill, "--demo", "--output", tmpdir]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
if result.returncode != 0:
await update.message.reply_text(f"Error:\n```\n{result.stderr[:2000]}\n```", parse_mode="Markdown")
return
# Send stdout summary
if result.stdout.strip():
for chunk in [result.stdout[i:i+4000] for i in range(0, len(result.stdout), 4000)]:
await update.message.reply_text(chunk)
# Send generated files (reports, figures)
output = Path(tmpdir)
for md_file in sorted(output.rglob("*.md")):
await update.message.reply_document(document=open(md_file, "rb"))
for img_file in sorted(output.rglob("*.png")):
await update.message.reply_photo(photo=open(img_file, "rb"))
async def handle_file(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
"""Auto-detect genetic file and run the appropriate skill."""
if not is_authorised(update):
return
doc = update.message.document
if not doc:
return
await update.message.reply_text(f"Received {doc.file_name}. Analysing...")
# Download file
tg_file = await doc.get_file()
with tempfile.TemporaryDirectory() as tmpdir:
local_path = Path(tmpdir) / doc.file_name
await tg_file.download_to_drive(local_path)
# Detect skill by extension
ext = local_path.suffix.lower()
if ext in (".txt", ".csv"):
skill = "pharmgx"
elif ext == ".vcf":
skill = "equity"
else:
await update.message.reply_text(f"Unsupported file type: {ext}")
return
out_dir = Path(tmpdir) / "output"
out_dir.mkdir()
cmd = ["python3", str(CLAWBIO), "run", skill, "--input", str(local_path), "--output", str(out_dir)]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
if result.returncode != 0:
await update.message.reply_text(f"Error:\n```\n{result.stderr[:2000]}\n```", parse_mode="Markdown")
return
if result.stdout.strip():
for chunk in [result.stdout[i:i+4000] for i in range(0, len(result.stdout), 4000)]:
await update.message.reply_text(chunk)
for md_file in sorted(out_dir.rglob("*.md")):
await update.message.reply_document(document=open(md_file, "rb"))
for img_file in sorted(out_dir.rglob("*.png")):
await update.message.reply_photo(photo=open(img_file, "rb"))
def main():
app = Application.builder().token(BOT_TOKEN).build()
app.add_handler(CommandHandler("start", start))
app.add_handler(CommandHandler("list", list_skills))
app.add_handler(CommandHandler("demo", demo))
app.add_handler(MessageHandler(filters.Document.ALL, handle_file))
print("Bot is running. Press Ctrl+C to stop.")
app.run_polling()
if __name__ == "__main__":
main()This is a self-contained bot (~100 lines) that:
- Restricts access to your chat ID only
- Runs
/demo pharmgx,/demo equity,/demo compareetc. - Auto-detects genetic file types when you send a document
- Sends back reports and figures
python3 telegram_bot.pyYou should see:
Bot is running. Press Ctrl+C to stop.
# Using nohup
nohup python3 telegram_bot.py > bot.log 2>&1 &
# Or using screen
screen -S clawbio-bot
python3 telegram_bot.py
# Detach: Ctrl+A, then D
# Reattach: screen -r clawbio-botOpen your Telegram bot and try:
You: /list
Bot: Available skills:
pharmgx Pharmacogenomics reporter ...
equity HEIM equity scorer ...
...
You: /demo pharmgx
Bot: Running pharmgx demo...
CYP2D6 *4/*4 β Poor Metabolizer β 10 drugs AVOID
[report.md attached]
[figures attached]
- Export your 23andMe raw data (Settings > 23andMe Data > Download Raw Data)
- Send the
.txtfile to the bot - The bot auto-detects the format and runs PharmGx Reporter
You: [attach 23andMe_raw_data.txt]
Bot: Received 23andMe_raw_data.txt. Analysing...
CYP2C19 *1/*2 β Intermediate Metabolizer
...
- Add more skills: Extend
handle_file()to route.fastqto metagenomics, or add keyword detection - Add Claude reasoning: Use the Anthropic SDK to add conversational AI around the skill results
- Build your own skill: See CONTRIBUTING.md and the skill template
- Explore the architecture: See docs/architecture.md
- Watch the demo: ClawBio at UK AI Agent Hack
pip3 install "python-telegram-bot[job-queue]"- Verify your chat ID matches what's in
.env - Check the bot token is correct (no extra spaces or quotes)
- Send
/startto your bot first
Run it standalone to isolate the issue:
python3 clawbio.py run pharmgx --demoMake sure clawbio.py is executable or invoke it via python3:
python3 clawbio.py run pharmgx --demoClawBio is a research and educational tool. It is not a medical device and does not provide clinical diagnoses. Consult a healthcare professional before making any medical decisions.