← Back to all posts

Using Telegram as a Visible Control Plane for Multi-Machine AI Agents

Why a chat-based control plane is still needed

I already had two layers of agent collaboration infrastructure.

The first layer is Git-based memory and handoff: rules, long-term memory, project context, and asynchronous messages between agents all live in a repository. This layer is reliable, auditable, and replayable, but it is not a real-time entry point. It is good at preserving facts, not at letting me say from my phone, “have this machine run something for me.”

The second layer is machine-to-machine execution through protocols such as A2A. One agent can dispatch a task to another agent and wait for the result. This layer solves the execution channel between machines.

But there was still a missing layer: how does the human enter the network?

I did not want to SSH into a machine every time, and I did not want to search through a dozen terminals to find which agent was online. The natural entry point should feel like a group chat: I can see what each machine is saying, send a task to a specific device, interrupt while something is running, and occasionally broadcast a task to all agents.

That is where Telegram fits. It is not the memory layer, and it is not the execution protocol. It is the human-visible control plane.

Topology: one group, one topic per machine

The final shape is simple:

Telegram supergroup
  ├─ Topic: control
  │    └─ control bot -> control machine agent
  ├─ Topic: laptop
  │    └─ laptop bot -> laptop agent
  ├─ Topic: cloud
  │    └─ cloud bot -> cloud agent
  └─ Topic: phone
       └─ phone bot -> phone agent

Two design choices matter here.

First, one bot per machine. Do not let multiple machines share the same Telegram bot token. Telegram long polling allows only one consumer for the same token at a time. If several machines share it, they will fight over getUpdates, and one machine will appear to randomly stop receiving messages. Multiple bots in the same group are fine, as long as each bot has its own token.

Second, use topics for device routing. The group is the shared observation surface; the topic is the device boundary. A machine’s bot only processes messages in its own topic and silently ignores the rest. This prevents the failure mode where one sentence in the group causes every machine to answer at once.

The real Telegram bot traps

Telegram integration is not complicated, but a few details can burn a lot of time.

Group Privacy blocks group messages by default. After creating a bot, if Group Privacy is not disabled in BotFather, the bot will only see a very limited subset of group messages. The confusing part is that this state may be cached when the bot joins the group. The correct sequence is to disable privacy first and then add the bot to the group. If you did it in the opposite order, remove the bot and add it again, or make it a group administrator.

Chat allowlists and topic allowlists are two separate gates. A user allowlist only says who may operate the bot; it does not replace where the bot should respond. Group messages should pass both chat and topic filtering. When a message is sent to the wrong topic, the usual symptom is not an error, but silence.

Manual getUpdates competes with the gateway. It is useful for fetching a user id or checking whether the poller is alive, but it competes with the running gateway for the same long-poll stream. If a healthy gateway is already holding the poll, a manual request seeing a conflict can actually be a good sign. If manual calls repeatedly return empty results, then the gateway may not really be polling.

A live process does not mean a live poller. Some failures leave the gateway process running and the state file looking normal, while the underlying long-polling thread has stopped. A health check that only uses pgrep will miss this half-dead state. A better check includes an application-level signal: whether messages are actually being pulled, whether long polling is still occupied, and whether a read-only test message can be answered.

Staying alive: a phone is not a server

On a standard Linux server, keeping a gateway alive can be delegated to systemd. Write a unit file, set a restart policy, enable it at boot, and the job is done.

A phone-hosted Linux environment is not a standard server. There may be no systemd, no cron, and the host operating system may reclaim processes under battery-management rules. Server assumptions do not transfer cleanly.

The structure that worked for me had four layers:

boot trigger
  -> foreground holder keeps the subsystem session alive
  -> keepalive watchdog
  -> ensure script performs idempotent startup
  -> gateway runs long polling in the foreground

The important part is not the script names, but the split of responsibilities:

  • ensure only answers: “if it is not running, start it detached from the current shell.”
  • keepalive answers: “if the process or application health fails, bring it back.”
  • the boot trigger answers: “recover after the device restarts.”
  • a shell startup hook answers: “self-heal when a human enters the environment.”

There is also a small but nasty shell trap: do not casually write pkill -f "some command". It can match the shell that is currently executing the kill command and terminate itself. Operate by pid, or use a pattern that cannot match itself.

Security boundary: this is an entry point that can drive a shell

Telegram looks like a chat tool, but behind this path sits a local agent, and the agent may drive a terminal. In other words, this is not an ordinary bot. It is a remote operation entry point.

The security constraints need to come first:

  • Bot tokens stay in local secret files, not in repositories, articles, or commit messages.
  • Only explicit user ids are allowed.
  • Only explicit groups are allowed.
  • Only explicit topics are allowed.
  • Unknown groups and unknown users must not be able to trigger local agents.
  • Public services need at least TLS and a rotatable bearer token.
  • Tools that eventually execute shell commands should be scoped down; a chat entry point must not become unlimited remote root.

The danger in this kind of system is not a single command. The danger is that the chain becomes too smooth: a sentence from a phone can make a remote machine actually execute something. Smoothness is the feature, and also the risk.

How it fits with A2A and Git memory

Looking back, the separation of the three layers is clear.

The Git memory layer answers: where do long-term facts, rules, project context, and cross-session handoff live? It is slow, but reliable.

The A2A data layer answers: how do machines dispatch real-time tasks to one another and get results back? It is fast, but closer to an execution channel.

The Telegram control plane answers: how does a human observe, interrupt, dispatch, and temporarily take over? It is not the source of truth, and it should not carry the final audit trail. It is what makes the network operable.

Mixing these layers causes problems. Treat Telegram as the memory store, and context gets lost. Treat Git as the real-time control plane, and it is too slow. Treat A2A as the human entry point, and you lose visibility and intervention.

The right composition is:

Telegram = human-visible control plane
Git       = long-term memory and audit plane
A2A       = machine-to-machine execution plane

The main lesson: get routing and visibility right first

This integration looks like “adding bots to a group,” but what it really adds is an operator console for a multi-machine agent system.

Without topic routing, the group becomes a noise pool. Without allowlists, it becomes a risk entry point. Without persistence and health checks, it becomes an interface that appears online while half-dead underneath. Without Git memory and the A2A execution layer, it is only chat, not system capability.

So the design priority of this layer is not novelty. It is visibility and control.

Visibility means I can tell which machine is responding and where a task went. Control means I can constrain tasks to the right group, the right topic, the right user, and the right execution surface.

The further a multi-agent system goes, the less it resembles “opening a few AI chat windows.” It starts to look like maintaining a set of automated nodes with permissions, state, and network topology. Telegram is only the entry point, but if the entry point is poorly designed, the capabilities behind it become an uncontrollable black box.