My Telegram bot is just a CLI with a different surface
Don't build a chatbot. Build a CLI that takes Telegram input and returns Telegram output.
The framing that unlocked it
I built three chatbots before this one. All three failed. They tried to "have a conversation." That's the wrong frame.
The fourth one works because I stopped framing it as a bot. It's a CLI. The input surface is Telegram. The output surface is Telegram. The middle is shell scripts.
What it does
I send /brief from anywhere — I get the morning brief. /pipe returns the active pipeline. /spend returns today's API spend. /last5 returns the last 5 commits across all my repos.
Each command is a shell script in ~/openclaw-network/commands/. The Telegram bot reads inbound messages, matches against /^[a-z]+/ to pick a command, runs it, returns stdout.
That's it. No conversation state. No memory. No "the assistant remembers your preferences." Just commands.
What it costs
Total monthly cost: $0. The bot runs on the Mac that's already on. Telegram bot API is free.
API costs from agents the bot triggers: about $20/month. About 60% of the chief-of-staff briefing's monthly spend now comes from on-demand /brief requests instead of scheduled crons.
What broke
The first version had memory — it tried to "remember" what I asked yesterday. Hallucinated half of it. Confidently. Deleted the memory layer entirely. Better.
The second version had natural language input — it'd parse "what's my pipeline" or "show pipe" or "pipe please." Half the time it'd misroute. Now I require /pipe. Slash-prefix or it doesn't fire.
Strictness is a feature. The boundary makes the system reliable.
What you can steal
If you're building a chatbot:
- Don't. Build a CLI with a chat surface.
- Require slash commands. Don't try to parse natural language.
- No memory. Each command is stateless. State lives in your file system or your DB, not in the bot.
- Run the bot on a box that's already on. Don't add infra for the bot.
Total build time for mine: about 6 hours, including the part where I deleted the bad version and started over.