⏱️ Telegram: 15 min · WhatsApp: 30 min · 💰 $0 extra (only your Claude plan) · 👥 You + allowlisted friends/groups
🆕 Running it for a whole WhatsApp group? Follow Guide 11: WhatsApp group bot on local Kubernetes. It adds the k3d deployment, a separate bot number, owner vs member paths, a verified tool-free sandbox for members (ts03-bot selftest), @bot triggers, subjects from the Color Legend tab, reply formats (cards/table/json/yaml), help/about/capabilities replies and every fix found in a real rollout. This page stays as the quick single-user overview.
Why this beats Options 2 and 4
| Option 2 / 4 (cloud) | Option 6 (self-hosted) | |
|---|---|---|
| Where it runs | Cloud Run + Twilio | Your Mac |
| Public URL / inbound port | Required | None for Telegram; localhost-only for WhatsApp |
| Brain | New Python code + Claude API key + service account | Your existing ts03 commands (Claude Code + Sheets MCP + CLAUDE.md) |
| Cost | Cloud + Twilio + API usage | Nothing extra |
| Open source | Partly | Bot, gateway (WAHA core), container runtime (Colima) |
| New features | Rebuild each one | Every new ts03-* command becomes a bot command |
Choose your channel
| Telegram ⭐ recommended | WhatsApp (WAHA) | |
|---|---|---|
| Official API | ✅ Bot API | ⚠️ Unofficial (acts as a linked device) |
| Account risk | None | Possible ban: use a spare number |
| Extra software | None | Docker runtime + WAHA container |
| Inbound connection | None (long polling) | Localhost webhook only |
| Groups | ✅ Add the bot to a group | ✅ Spare number joins the group |
| Best for | Batch-wide use | Personal / small trusted group where everyone is on WhatsApp |
About WhatsApp: tools like WAHA drive WhatsApp the way WhatsApp Web does. WhatsApp's terms don't allow unofficial automation, and numbers doing it can be banned. Use a dedicated spare SIM, keep volume low, reply only to commands, and never bulk-message. If that's not acceptable, use Telegram or Meta's official WhatsApp Cloud API.
Bot commands (both channels)
| Command | Runs | Who |
|---|---|---|
/week /brief /today /tomorrow /urgent /next /month /overdue /subjects /load /plan |
matching ts03-* command |
Allowed chats |
/sub GPU Programming |
ts03-sub ... |
Allowed chats |
/ask which subject has most pending work |
ts03 ... (read-only) |
Allowed chats |
/html week |
builds the HTML report, replies with the link | Allowed chats |
/add /done /submit /move /note <details> |
write commands | Owner only |
/help |
command list | Allowed chats |
/whoami |
shows chat id and sender id | Anyone (setup helper) |
Plain messages (not starting with /) are ignored, so the bot stays quiet in group chats.
Built-in safety (scripts/ts03-bot):
- User text is shell-quoted before reaching zsh: no command injection
- Allowlist by chat id and sender id; everyone else is ignored and logged
- Writes only from OWNER_ID, even inside an allowed group
- One Claude call at a time (queue) + per-chat cooldown
- WhatsApp webhook only answers on /hook/<HOOK_SECRET>; wrong paths get 404
- Log: ~/Library/Logs/ts03-bot.log
Part A · Common setup (both channels)
Requires Guides 1-4 (and 10 for /html): ts03-brief must work on the Mac.
1Get the repo
git clone https://github.com/rpaut03l/google-sheets-mcp-guide.git
cd google-sheets-mcp-guide
2Create the config file
mkdir -p ~/.config
cp templates/ts03-bot.env.example ~/.config/ts03-bot.env
chmod 600 ~/.config/ts03-bot.env
You'll fill it in during Part B or C. Template: templates/ts03-bot.env.example
3Keep the Mac awake and logged in
The bot runs as a launchd user agent: it needs you logged in (screen can be locked) and the Mac not sleeping. System Settings → Battery → Options → prevent sleep on power adapter, wake for network access.
Part B · Telegram (recommended)
4Create the bot
Telegram → @BotFather → /newbot → name TS-03 Tracker → username e.g. my_ts03_bot. Copy the token.
Optional: /setcommands in BotFather and paste:
week - Due in the next 7 days
brief - Morning brief
urgent - Due within 3 days
next - Next deadline
subjects - Subjects and professors
html - HTML report link, e.g. /html week
help - All commands
5Add the token
nano ~/.config/ts03-bot.env # TG_TOKEN=123456:ABC...
6First run and find your id
cp scripts/ts03-bot ~/.local/bin/ && chmod +x ~/.local/bin/ts03-bot
ts03-bot telegram
In Telegram open your bot → Start → send /whoami. It replies with your chat id and sender id. Press Ctrl+C in the terminal.
7Allow yourself (and others)
nano ~/.config/ts03-bot.env
OWNER_ID=<your sender id>
ALLOWED_CHATS=<friend ids or group id, comma-separated>
8Install as a service
scripts/install-bot.sh telegram # always on
scripts/install-bot.sh telegram --digest 08:00 # + morning brief at 08:00 daily
✅ com.ts03.bot.telegram running
Test: send /week to the bot.
Step 9 (optional): Batch group
- Add the bot to the Telegram group
- Send
/whoamiin the group → copy the chat id (negative number) - Add it to
ALLOWED_CHATS, setDIGEST_CHATto it if the group should get the morning brief - Restart:
scripts/install-bot.sh telegram --digest 08:00
Members type /week or /week@my_ts03_bot; only you can use write commands.
Part C · WhatsApp (WAHA, self-hosted)
10Spare number and container runtime
- A spare WhatsApp number (second SIM / eSIM, or WhatsApp Business on another number)
- Open-source Docker runtime:
bash brew install colima docker docker-compose colima start(Docker Desktop also works.)
11Secrets
echo "WAHA_KEY=$(openssl rand -hex 16)" >> ~/.config/ts03-bot.env
echo "HOOK_SECRET=$(openssl rand -hex 16)" >> ~/.config/ts03-bot.env
grep -E "^(WAHA_KEY|HOOK_SECRET)=." ~/.config/ts03-bot.env # both should show values (empty template lines are ignored)
12Start WAHA (bound to localhost)
mkdir -p ~/waha/sessions
set -a; source ~/.config/ts03-bot.env; set +a
export WA_HOOK_HOST=host.lima.internal # Colima. Docker Desktop: host.docker.internal
docker compose -f templates/docker-compose.waha.yml up -d
docker logs -f waha # Ctrl+C once it says it's running
Compose file: templates/docker-compose.waha.yml
13Link the spare number
Open http://localhost:3000 (dashboard/Swagger; use WAHA_KEY when asked) → start session default → show the QR → on the spare phone: WhatsApp → Linked devices → Link a device → scan.
WAHA's UI and environment variable names change between versions. If something doesn't match, check https://waha.devlike.pro/.
14Install the bot and find ids
scripts/install-bot.sh whatsapp
From your own WhatsApp, message the spare number: /whoami → it replies with your chat id (e.g. [email protected]).
15Allowlist and test
nano ~/.config/ts03-bot.env
[email protected]
ALLOWED_CHATS=<group id>@g.us
(Group id: add the spare number to the group, send /whoami there.)
Restart and test:
scripts/install-bot.sh whatsapp --digest 08:00
Send /week, /html week, /ask which subject has most pending work.
Operations
launchctl list | grep ts03.bot # running? (number in first column)
tail -f ~/Library/Logs/ts03-bot.log # activity
cat ~/Library/Logs/com.ts03.bot.telegram.err # errors (or ...whatsapp.err)
scripts/install-bot.sh telegram # restart after editing ts03-bot.env
scripts/install-bot.sh whatsapp --uninstall # remove
docker compose -f templates/docker-compose.waha.yml down # stop WAHA
Troubleshooting
| Symptom | Fix |
|---|---|
| Bot silent | /whoami works? Then the chat isn't in ALLOWED_CHATS/OWNER_ID. Check the log |
/whoami also silent (Telegram) |
Wrong TG_TOKEN; see .err log |
/whoami silent (WhatsApp) |
Webhook not reaching the bot: check WA_HOOK_HOST (Colima host.lima.internal, Docker Desktop host.docker.internal), HOOK_SECRET matches, docker logs waha |
| "Only the tracker owner can change the sheet" | Expected for non-owners; set OWNER_ID to your sender id |
| "One moment, still working" | Per-chat cooldown (COOLDOWN_SECONDS) |
| Answers say "Not logged in" | Log in to Claude Code once on the Mac: claude → /login |
/html link doesn't open |
Report server from Guide 10 must be running; link works on the same Wi-Fi |
| WhatsApp session logged out | Re-scan QR in the WAHA dashboard; sessions persist in ~/waha/sessions |
Security checklist
- [ ]
~/.config/ts03-bot.envischmod 600and never committed (.gitignorecovers*.env) - [ ] WAHA published on
127.0.0.1:3000only, withWAHA_KEY - [ ] macOS firewall on; webhook port 5055 not reachable from other machines (only the container needs it)
- [ ]
OWNER_IDset,ALLOWED_CHATSminimal - [ ] Spare number for WhatsApp; no bulk messaging
- [ ] Sheet data sent in replies goes to the chat's members: only allow people who may see it
Fully open source, model included?
Swap ts03 for a local model: Ollama + an MCP-capable CLI client (e.g. mcphost) using the same mcp-google-sheets server, and point the READ command map in ts03-bot at it. Fine for simple lookups; local models are much weaker at multi-step tool use, so keep writes on Claude.
Files
| File | Purpose |
|---|---|
scripts/ts03-bot |
The bot (Telegram + WhatsApp), Python standard library only |
scripts/install-bot.sh |
launchd service + optional daily digest |
templates/ts03-bot.env.example |
Config template |
templates/docker-compose.waha.yml |
WAHA on localhost |
Questions or corrections: [email protected]