Skip to content
All posts

Building agents-hub · Part 3 of 9 · Architecture

Why my AI team lives in Telegram

agents-hub started as a Google Chat app. Here is why it moved to Telegram, why one hub bot does all the reading, and why the whole server has zero npm dependencies.

Photo of Kush Ahuja

Kush Ahuja

· 3 min read

agents-hub is an AI team you talk to in a chat. You sign in with Google once, unlock the agents you want, and each one joins your Telegram group as its own bot: a Gmail agent, a Calendar agent, a Tasks agent, a Docs agent and a Maps agent. They work inside your real accounts. You just type.

It did not start in Telegram. This post is about that choice and the two decisions that fell out of it.

The first plan was Google Chat

The agents already live in Google, so Google Chat looked obvious. Then I read the fine print. Building a Chat app needs a paid Google Workspace Business or Enterprise account, and people on a personal Gmail most likely cannot use a custom Chat app at all. My first customers are exactly those people.

I looked at the rest. Discord makes people join a server. WhatsApp needs Meta business verification and charges per conversation. A web chat of my own was the most work and could wait. Telegram is free, everyone can install it, and a bot can ask Telegram for new messages (long polling), so it runs from a laptop with no public URL. That last part mattered a lot while I was testing every day.

One hub reads, every agent speaks

I wanted it to feel like a team: paste a task into the group and the right agent picks it up. The obvious build is one bot per agent, each listening. It does not work, for two reasons.

  • Telegram bots cannot see messages sent by other bots, so agents cannot coordinate by talking to each other in the group.
  • If every bot polled, every message would be handled once per bot.

So only the hub bot reads. It plans the round, can split one message across several agents ("mail Priya the deck and block Friday 4pm" becomes a Gmail part and a Calendar part), and each agent sends its reply with its own bot token. The customer sees a team. The code has one decision point.

Agents in the same round do not see each other’s replies from that round. Each gets its own part plus the full message. Without that rule, the email draft kept saying "please add it to the calendar" because it could see the other request.

Zero dependencies, on purpose

The bot, the router, the agents and the website are plain TypeScript run directly by Node 22. --experimental-strip-types runs the .ts files, and --env-file loads secrets. There is no npm install on the server and nothing to build.

node --experimental-strip-types --env-file=.env apps/telegram/bot.ts

The cost is small and known: type stripping cannot handle enums or constructor parameter properties, so erasableSyntaxOnly is on in the tsconfig to catch them early. In return, anyone can open any file and read it top to bottom without a framework in the way.

The one rule every agent follows

Every agent exports the same shape from agents/<name>/agent.ts: an id, a name, a command like /gmail, a description, a few examples, and a handle(request) that returns the reply. All reachable agents are listed in one file, agents/index.ts.

Adding an agent is a new folder and one line in that list. The Telegram command menu updates itself from it. The agent shape does not know Telegram exists, which is why the mobile app I built later runs the same agents with no changes.

What I would tell myself on day one

  • Check who can actually use a platform before building on it. The Workspace requirement would have blocked every early user.
  • Keep the agent contract separate from the chat surface. It paid for itself the day the app arrived.
  • Fewer dependencies means fewer surprises when you host it. Moving to Railway was a copy of the env vars and one command.