We vibe-coded a farm of Telegram agents in 2–3 days — here are the guts

“All you need is software, proxies and cheap inference.” Sounds simple. Ha. Let us show you where that simplicity has teeth.

Hi, this is the dev team. This article isn’t a landing page or “10 reasons to adopt AI.” It’s a dev diary: here’s the stack, here’s how it’s wired, here are the rakes we stepped on so you don’t have to. If you vibe-code and “what if I stood up a farm of agents” is already rattling around your head — take this.

We’ll build it layer by layer, bottom-up: inference → agents → tools. And yes, the whole thing really did come together in 2-3 days — but only because we didn’t reinvent the parts that were already invented.

Three layers: agents, tools, inference

Layer 0 — the thing the whole idea dies without: cheap inference

Money first, because that’s exactly what kills 90% of these farms.

One agent is cheap. Ten live agents that actually chat every day — suddenly expensive. Not in code. In tokens. A live conversation isn’t one request: context, history, reactions to replies. One conversation easily becomes 5-15 model calls. Multiply by accounts, multiply by days — and on a regular API you’re counting the bill, not the leads.

So the first thing we wired up wasn’t an agent — it was the inference router. We run everything through our own OpenAI-compatible router.mingles.ai on top of a decentralized network. For code it’s three parameters:

  • URLrouter.mingles.ai
  • key — your API key
  • model — whatever you want (ours: a Kimi-class primary + two open-weight models as fallbacks)

Swap the base URL and existing code just starts costing a fraction. No new SDKs, no refactor. Bonus: a fallback chain — a model drops on the network (503), the runtime hops to the next one, the agent never notices.

Remember this line, it repeats for every agent below. One endpoint — one shared economy.

Layer 1 — agents: don’t write a runtime, take Hermes

The vibe-coder’s temptation is to write your own conversation loop. Don’t. We took Hermes (nousresearch/hermes-agent) as a base and saved a day on that alone.

The model: one container → several “profiles” → one gateway per profile, all under s6. Each profile is isolated — its own config, memory, sessions and its own Telegram bot. One gateway per profile = a small blast radius: the support brain and the admin brain, with different permissions, never mix.

What it looks like in practice:

  • a profile = one YAML (model + fallback, which bot, which MCP, where the token lives). Secrets aren’t in git — injected from env at sync;
  • channels — each agent has its own Telegram bot; private ones are locked to an allow-list of user ids, support is public. Support also exposes an internal OpenAI-compatible HTTP endpoint — the site’s chat widget rides on it;
  • add an agent = drop in a new YAML and sync. Not rewrite the system.

Two rakes that ate our hours (catch them for free):

  1. the model provider must be custom, not openai — otherwise the agent sends an empty model and every call 422s;
  2. the Telegram allow-list is read from the per-profile .env, not from the config — otherwise “all users denied.”

Both are now baked into our sync script so we don’t step on them twice.

Layer 2 — tools: the server decides security, not the model (MCP)

The key architectural call, and the most un-vibe-coder one: don’t trust the LLM to decide what it’s allowed to do. All tools sit behind a single MCP server, and the server holds the gate.

How it works:

  • the agent authenticates to MCP with a bearer token;
  • the token is bound to a role;
  • the role has a static allow-list of tool names;
  • the gate is enforced server-side, at call time — not in the prompt. A jailbroken model physically cannot call what its role doesn’t grant;
  • every call is rate-limited and audited.

One server — different superpowers per token:

AgentRoleCan do
Supportsupport_escalationread account/usage/errors, tickets, escalate to a human
Marketingmarketing_partnerread-only — growth analytics + partner/referral data
Admin/Opsadmin_executorthe privileged operational surface — gated and audited

Add a capability = add a line to a role and rebuild. Remove one = delete a line. The registry won’t register a tool no role claims — so the catalog and code can’t silently drift.

And “leveling up” an agent is just another MCP: a knowledge base (retain/recall), web search (a DuckDuckGo sidecar), a browser, product analytics. Marketing grabbed all four + a read-only internal-analytics role: it pulls real numbers, googles, checks a landing page — but is structurally incapable of touching billing.

MCP: role gate enforced at call time

Layer 3 — the farm itself (Marketing/Userbot)

Once you have cheap inference, profile isolation and role-gated tools — the marketing agent is the same kit, turned outward.

Right now we run 3-5 userbots (deliberately few — watching what works, what gets banned). One userbot is:

  • a separate account + its own proxy profile — one account = one IP = one identity;
  • its own persona — character, tone; holds a native conversation instead of fan-blasting one canned text;
  • built-in limits and warm-up — the folk “5 a day and you won’t get banned,” but by rules: randomized timing, capped volume, gradual warm-up;
  • two strategies — DMs and group chats, different funnels.

Everything flows into a mini-CRM: who replied, who’s warmed up, who to hand off to a human. The bots think, naturally, through router.mingles.ai — which is why live daily conversations across several accounts aren’t a cost line, and scaling is a “when,” not a “can we afford it.”

Anatomy of a userbot and the flow into the mini-CRM

Network hygiene (short but important)

The agent container can’t see the DB and publishes no ports. Outbound is only three routes: the inference router, the Telegram API, an isolated bridge to MCP. No docker.sock, no shell tools — all side effects go through audited MCP. Through-line: fail closed — when in doubt, the system refuses rather than risks.

TL;DR for whoever’s going to copy this

  1. Inference first — point the URL at router.mingles.ai, bring key and model. Without cheap inference the farm dies on the token bill.
  2. Don’t write a runtime — Hermes, profile = YAML, one bot per profile. You’ll trip on provider: custom and the allow-list in .env — now you know.
  3. Security isn’t in the prompt — one MCP, role = allow-list, gate server-side. Leveling up an agent = another MCP.
  4. The farm — account + proxy + persona + limits, all into a mini-CRM.

We’re still early, 3-5 accounts, collecting numbers — once we nail a working setup, we’ll share the figures. Don’t wait for us: set the URL, key, model — and go vibe-code your own farm. The brain for it is already here.


Everything above runs on Mingles Router — one OpenAI-compatible endpoint for open-weight models. Grab a free key or read the quickstart.