Skip to content

Repository files navigation

tg-guest-bot

A personal Telegram bot built on Telegram's Guest Mode. You can tag the bot anywhere — group, DM, anyone's chat — and it will reply only to you.

Powered by Claude. Pick your backend:

  • Claude Code (uses your existing claude login — no extra API key)
  • Anthropic API (pay-as-you-go API key)

How it works

You tag @yourbot in any chat
        ↓
Telegram sends `guest_message` update → your server (HTTPS via Caddy)
        ↓
Bot checks `from.id == OWNER_USER_ID`  ← anyone else: silent drop
        ↓
LLM (Claude) generates reply, optionally with web search
        ↓
Bot calls `answerGuestQuery` → message appears in the chat

The bot is invisible to anyone except you. Strangers tagging it get nothing.

Prerequisites

  • A small Linux server (1 vCPU, 1 GB RAM is plenty) with Docker + docker-compose
  • A domain you control, with ability to add an A-record
  • One of:
    • Claude Pro/Max subscription + claude CLI installed and logged in on the server, or
    • Anthropic API key from console.anthropic.com

Setup (≈10 min)

1. Create the bot

In Telegram, open @BotFather:

  1. /newbot → follow prompts → save the BOT_TOKEN
  2. /mybots → choose your bot → Bot Settings → Guest Mode → Enable

2. Find your user ID

DM @userinfobot. It will reply with your numeric id.

3. Point a subdomain at your server

Add a DNS A-record:

bot.example.com   A   <your server's public IP>

4. Clone and configure

git clone https://github.com/scrm77/tg-guest-bot.git
cd tg-guest-bot
./setup.sh

setup.sh will ask for BOT_TOKEN, your user id, your domain, and which LLM backend to use, then write a .env (chmod 600) and a random webhook secret.

5. Deploy

docker compose up -d

This starts two containers: the bot, and Caddy (which auto-issues a Let's Encrypt certificate). First start may take ~30 s for the SSL handshake.

Sanity check:

curl https://bot.example.com/healthz   # → "ok"

6. Register the webhook with Telegram

python3 -m pip install httpx python-dotenv
python3 register_webhook.py

Or, if you'd rather not install anything locally:

docker compose exec bot python register_webhook.py

7. Test it

Tag your bot in any chat:

@yourbot what time is it in Tokyo?

You get a reply. Anyone else tagging the bot — silence.

Configuration

All settings live in .env. See .env.example for the full list with comments. Highlights:

Variable What
BOT_TOKEN From @BotFather
OWNER_USER_ID Only this user's messages are processed
WEBHOOK_SECRET Auto-generated by setup.sh
PUBLIC_URL, PUBLIC_HOST Your domain
LLM_BACKEND claude-code or anthropic-api
CLAUDE_CONFIG_DIR Path to your ~/.claude (claude-code backend only)
ANTHROPIC_API_KEY API key (anthropic-api backend only)
ANTHROPIC_MODEL Default: claude-sonnet-4-6

Security model

Three layers protect you from someone else triggering your bot:

  1. Owner filterbot.py rejects any guest_message whose from.id isn't your OWNER_USER_ID. Reply is never generated, Claude is never called, Telegram is never re-contacted. Just a 200 OK with a log line.
  2. Webhook secret — Telegram sends X-Telegram-Bot-Api-Secret-Token on every webhook call; we verify it. Nobody who learns the URL can spoof updates.
  3. HTTPS — Caddy auto-issues Let's Encrypt certs; webhook traffic is end-to-end encrypted.

from.id cannot be forged by other users because the update arrives directly from Telegram's servers (validated by the secret token).

Adding more knowledge to the bot

You can extend the bot beyond plain web search. A few patterns:

  • Local wiki / notes: bind-mount a directory into the container and let the bot read it (the Read tool is already allowed in the claude-code backend).
  • Calendar / Notion / Gmail: if you use the claude-code backend, any Claude connectors you've authenticated on your account become available to the bot. Add the relevant mcp__* tool names to the _ALLOWED_TOOLS list in bot.py.
  • Personal context: put facts about yourself in SYSTEM_PROMPT in bot.py so the bot doesn't have to ask twice.

Troubleshooting

  • curl https://your.domain/healthz hangs or fails — DNS hasn't propagated yet, or Caddy hasn't gotten the cert. Check docker compose logs caddy.
  • Telegram says "Webhook was set" but the bot doesn't reply — check docker compose logs bot. Common causes: wrong OWNER_USER_ID, wrong BOT_TOKEN, or Guest Mode isn't enabled in BotFather.
  • claude-code backend errors about credentials — make sure your CLAUDE_CONFIG_DIR actually contains .credentials.json and that the bind-mount path in docker-compose.yml is correct.

License

MIT — see LICENSE.

About

Personal Telegram guest-mode bot powered by Claude. Reply only to you, in any chat.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages