agentleFS
reza10menreza10men/telegram-rich-messages/skills/telegram-serverless/SKILL.md

telegram-serverless

Skill1 starsChanged 10 days agoMITView on GitHub

Authoritative architecture, engineering specification, and deployment toolkit for Telegram Serverless (tgcloud CLI 0.2.0+), V8 isolate handlers, Mini App endpoints, platform-managed SQLite database, migrations, and serverless bot backends on Telegram infrastructure.

  • Deletes or force-pushes
  • Sends data out

2 other projects use a version of this.

Adopted by

Most recently taken up by

  • Other versions2 projects use a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 2

    1. stark-ai-de/agent-skills★ 8same name
    2. yousifraad01/Telegram-Serverless-Skill★ 1same name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repositoryOne other file it gives its agents.

The file

We split this skill into the rules it gives an agent

9 rules. About 0 are common, 4 are distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈4

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Colocated Managed SQLite: Every bot receives an isolated, zero-latency SQLite database accessible synchronously in execution context …

    line 51
  2. Distinctive:

    Bot Registration: Create a bot via @BotFather or select an existing one.

    line 64
  3. Very specific:

    All serverless code runs from the tgcloud/ directory at the project root:

    line 88
  4. Very specific:

    Relative Imports Require Extensions: Always write import { users } from '../schema.js'.

    line 120
  5. Very specific:

    When Telegram receives an update, it inspects your deployed handlers/ directory.

    line 130
  6. Distinctive:

    Every bot is provisioned with a dedicated SQLite database located physically beside the V8 sandbox.

    line 238
  7. Very specific:

    All queries are asynchronous.

    line 278
  8. Distinctive:

    All commands can be invoked from anywhere in the project tree.

    line 340
  9. Very specific:

    Call any Bot API method via api.<methodName>(params).

    line 386

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Telegram Serverless Architecture & Engineering Specification

Version: CLI 0.2.0+ (October 2026)
Official Specification: core.telegram.org/bots/serverless
Runtime Environment: Telegram V8 Sandbox & Distributed Edge Infrastructure


1. Mental Model & Architecture

Telegram Serverless executes bot backends, Mini App RPC endpoints, and background tasks directly inside Telegram's core data-center infrastructure. There are no external virtual private servers (VPS), cloud functions, Docker containers, public webhooks, or process managers (PM2/systemd) to provision, patch, or scale.

┌─────────────────────────────────────────────────────────────────────────────┐
│                       Telegram Global Infrastructure                        │
│                                                                             │
│   Incoming Update / Mini App RPC ────────► Platform Router                  │
│                                                   │                         │
│                                            ┌──────▼──────┐                  │
│                                            │ V8 Isolate  │                  │
│                      ┌─────────────────────┤   Sandbox   ├────────────────┐ │
│                      │                     └──────┬──────┘                │ │
│                      ▼                            ▼                       ▼ │
│               ┌─────────────┐              ┌─────────────┐          ┌─────────┐
│               │ sdk/api     │              │ sdk/db      │          │ sdk/fetch
│               │ (Bot API    │              │ (Managed    │          │ (Outbound
│               │  Zero-Hop)  │              │  SQLite)    │          │  HTTP)  │
│               └─────────────┘              └─────────────┘          └─────────┘
└─────────────────────────────────────────────────────────────────────────────┘
                               ▲
                       npx tgcloud push
                               │
               ┌───────────────┴───────────────┐
               │    Developer Local Machine    │
               │  tgcloud/ project directory   │
               └───────────────────────────────┘

Key Architectural Tenets

  1. Zero Cold-Start Overhead: Handlers run in pre-warmed, secure V8 isolates adjacent to Telegram Bot API servers.
  2. Platform-Managed Webhook: The incoming update webhook is maintained automatically by the platform; you never expose an HTTPS IP, configure TLS certificates, or call setWebhook.
  3. Colocated Managed SQLite: Every bot receives an isolated, zero-latency SQLite database accessible synchronously in execution context through asynchronous Promise APIs.
  4. Three Execution Planes:
    • Local Workspace: Code in tgcloud/, schema.js, and Mini App static assets.
    • Cloud Runtime: Deployed V8 isolates, managed SQLite database, and Mini App static CDN.
    • CLI Bridge (tgcloud): Sync engine managing optimistic locking, diff detection, atomic deployment, and schema migrations.

2. Prerequisites & BotFather Activation

To activate Telegram Serverless on an existing or new bot:

  1. Local Tooling: Node.js 18.0.0 or higher.
  2. Bot Registration: Create a bot via @BotFather or select an existing one.
  3. Activate Serverless:
    • In @BotFather, open: /mybots → Select your Bot → Bot Settings → Serverless → Turn On.
    • Navigate to: Serverless → CLI Access → Access Token.
  4. Credentials Distinction:
    • Bot API Token (123456:ABC-DEF...): Used only for direct Bot API requests or local authoring tools.
    • CLI Access Token (app<id>:<secret>): Used exclusively by tgcloud CLI for code deployment, schema migrations, and remote execution.

Authentication

Authenticate locally in interactive environments:

npx tgcloud login
# Prompts for CLI access token: app<id>:<secret>

For CI/CD pipelines and headless environments, supply the token via environment variable without writing to disk:

export TGCLOUD_TOKEN="app<id>:<secret>"
npx tgcloud status

3. Project Anatomy (CLI 0.2.0+)

All serverless code runs from the tgcloud/ directory at the project root:

my_telegram_bot/
├── tgcloud/                  # Sole deployment directory — only code here is shipped
│   ├── handlers/             # Telegram update handlers — FLAT (one level only)
│   │   ├── message.js        # Handles incoming Message updates
│   │   ├── callback_query.js # Handles inline button clicks
│   │   └── inline_query.js   # Handles inline search queries
│   ├── endpoints/            # Mini App RPC endpoints — FLAT (one level only)
│   │   ├── getProfile.js     # Called via Telegram.WebApp.Serverless.call
│   │   └── createOrder.js
│   ├── lib/                  # Shared business logic & templates (NESTING ALLOWED)
│   │   ├── rich.js           # Rich message builder & validators
│   │   ├── auth/
│   │   └── db/
│   └── schema.js             # Platform SQLite database schema — EXACTLY ONE FILE
├── tgcloud.jsonc             # Mini App static hosting & header configuration
├── package.json              # Dev tooling and scripts
└── .tgcloud/                 # CLI local state and cached cloud revision (GITIGNORED)

Module Types & Layout Rules

ComponentPathStructural RulesInvocability
Database Schematgcloud/schema.jsExactly one file. Named exports of table(...).Evaluated at build/deploy; applied via tgcloud migrate.
Handlerstgcloud/handlers/<type>.jsStrictly flat. File name MUST match a valid Telegram update type.Invoked automatically by Telegram router upon matching update.
Endpointstgcloud/endpoints/<name>.jsStrictly flat. Exported default async function.Invoked via Mini App frontend RPC (Serverless.call).
Librarytgcloud/lib/**Nesting allowed. Helper utilities, templates, math.Imported by handlers or endpoints; never invoked directly.

Strict V8 Runtime Constraints

  • Relative Imports Require Extensions: Always write import { users } from '../schema.js'; (failing to include .js throws resolution errors).
  • Import Boundary: Imports cannot traverse outside tgcloud/. Paths such as ../../config.js fail to resolve.
  • Zero npm Packages: The isolate has no node_modules and no runtime package loader. All dependencies must be inlined or imported from the built-in sdk.
  • No Node Filesystem (fs): There is no file system. Templates and configuration must be authored as JavaScript ES modules.
  • Controlled Outbound Networking: The Node http/https and raw socket APIs are absent. Outbound network traffic must use fetch from sdk.

4. Handler Routing & Update Lifecycle

When Telegram receives an update, it inspects your deployed handlers/ directory. If a file matching the update type exists and contains a non-empty export default, Telegram dispatches execution to that handler isolate.

Handler Signature

// tgcloud/handlers/message.js
import { api, db } from 'sdk';

export default async function (payload, ctx) {
  // payload: Unwrapped Telegram object (e.g. Message, CallbackQuery)
  // ctx.update: Raw Telegram Update container (contains update_id)
  
  await api.sendMessage({
    chat_id: payload.chat.id,
    text: `Received: ${payload.text ?? '(media)'}`,
  });
}

Unwrapped Payloads

The platform automatically unwraps the outer Update envelope:

  • handlers/message.js receives Message (update.message)
  • handlers/callback_query.js receives CallbackQuery (update.callback_query)
  • handlers/inline_query.js receives InlineQuery (update.inline_query)
  • handlers/chat_member.js receives ChatMemberUpdated (update.chat_member)

Note: If an update arrives for which no handler file exists (e.g. handlers/edited_message.js is missing), the platform drops the update immediately without waking a V8 isolate.


5. Mini App Endpoints & Static Hosting

5.1 Endpoints (tgcloud/endpoints/)

Endpoints serve as secure RPC backends for Telegram Mini Apps, bypassing the need for custom CORS or JWT schemes.

// tgcloud/endpoints/getProfile.js
import { db, EndpointError } from 'sdk';
import { eq } from 'sdk/db';
import { users } from '../schema.js';

export default async function (input, ctx) {
  // ctx.initData is cryptographically validated by Telegram before handler execution
  const telegramUser = ctx.initData.user;
  if (!telegramUser) {
    throw new EndpointError('User data unavailable', { code: 'NO_USER' });
  }

  const profile = await db.select()
    .from(users)
    .where(eq(users.tgId, telegramUser.id))
    .get();

  if (!profile) {
    throw new EndpointError('Profile not found', { code: 'NOT_FOUND' });
  }

  return profile;
}

Trust & Error Protocol

  • Built-in Authentication: Calls without valid Telegram init data are rejected with HTTP 401 at the platform edge before invoking isolate code.
  • Expected Errors: throw new EndpointError(message, parameters) returns structured errors to the client with err.type === 'ENDPOINT_ERROR' and exposes err.parameters.
  • Unexpected Errors: Any unhandled standard Error thrown inside an endpoint returns a generic error to the frontend while logging the detailed stack trace to private serverless logs.

Calling Endpoints from Mini App Frontend

Include official telegram-web-app.js in your Mini App HTML/SPA:

Telegram.WebApp.Serverless.call('getProfile', { extraParam: true }, (err, result) => {
  if (err) {
    if (err.type === 'ENDPOINT_ERROR') {
      console.error('Handled failure:', err.message, err.parameters);
    }
    return;
  }
  console.log('User profile:', result);
});

5.2 Mini App Static Frontend Hosting (tgcloud.jsonc)

Serverless hosts Mini App client builds alongside your bot at https://app<app_id>.tgcloud.ai/.

{
  "$schema": "./node_modules/@tgcloud/cli/schema/tgcloud.json",
  "static": {
    "source": "dist",          // Relative directory containing SPA build output
    "spa": true,               // Rewrites non-file routes to index.html
    "immutable": [             // Content-hashed files cached for 1 year
      "/assets/*"
    ],
    "headers": [
      {
        "path": "/*",
        "set": { "Referrer-Policy": "no-referrer" }
      }
    ],
    "redirects": []
  }
}

⚠️ Iframe Warning: Telegram Web renders Mini Apps inside an <iframe>. Never add X-Frame-Options or restrictive Content-Security-Policy: frame-ancestors headers, or the app will fail to load in desktop web browsers.


6. Platform-Managed SQLite Database

Every bot is provisioned with a dedicated SQLite database located physically beside the V8 sandbox.

6.1 Defining Tables in tgcloud/schema.js

Tables are declared using a Drizzle-compatible schema builder imported from sdk/db:

import { table, integer, text, boolean, json, index, sql } from 'sdk/db';

export const users = table('users', {
  id:        integer('id').primaryKey({ autoIncrement: true }),
  tgId:      integer('tg_id').unique(),
  name:      text('name').notNull(),
  lang:      text('lang').default('en'),
  isAdmin:   boolean('is_admin').default(false),
  prefs:     json('prefs'),
  createdAt: integer('created_at', { mode: 'timestamp' }).default(sql`(unixepoch())`),
}, (t) => ({
  tgIdIdx:    index('idx_users_tg_id').on(t.tgId),
  createdIdx: index('idx_users_created').on(t.createdAt),
}));

6.2 Data Types & Conversion Modes

FactorySQLite ColumnStorage TypeJS Representation
text()TEXTStringstring
integer()INTEGER64-bit Intnumber / bigint
boolean()INTEGER0 or 1boolean (auto-converted)
json()TEXTStringified JSONobject / array (auto-parsed)
integer(name, { mode: 'timestamp' })INTEGERUnix Epoch (seconds)Date instance
integer(name, { mode: 'timestamp_ms' })INTEGERUnix Epoch (ms)Date instance
blob()BLOBBinaryUint8Array (Note: No Node.js Buffer)

6.3 No Foreign Keys — Critical Platform Rule

The platform runs SQLite with PRAGMA foreign_keys = OFF. To prevent false assumptions around cascading deletes:

  • Calling .references() or foreignKey() throws an exception at schema declaration time.
  • Relational integrity must be handled in application logic (e.g. store foreign keys as plain integer('user_id')).

6.4 Asynchronous Querying & Mutations

All queries are asynchronous. Always use await:

import { db } from 'sdk';
import { eq, and, desc } from 'sdk/db';
import { users } from '../schema.js';

// Select single record
const user = await db.select().from(users).where(eq(users.tgId, 12345)).get();

// Select multiple records
const allAdmins = await db.select().from(users).where(eq(users.isAdmin, true)).all();

// Upsert (Insert with conflict resolution)
await db.insert(users)
  .values({ tgId: 12345, name: 'Alice' })
  .onConflictDoUpdate({
    target: users.tgId,
    set: { name: 'Alice' },
  })
  .run();

// Raw queries (Warning: raw queries bypass schema mode conversions)
const result = await db.run('UPDATE users SET lang = ? WHERE tg_id = ?', ['fa', 12345]);

7. Migrations & Schema Evolution

The Decoupled Schema Philosophy

Deploying code (npx tgcloud push) never touches or modifies the database schema. It registers the desired schema in the cloud and reports whether pending differences exist.

Schema changes are reviewed and applied strictly via:

npx tgcloud migrate

Migration Safety Levels

LevelClassificationBehavior in tgcloud migrate
safeAdditive columns, new tables, non-unique indexesBatch-applied upon user confirmation.
warningDropping columns or tables, large index creationsPresented one at a time; each requires separate confirmation.
manualColumn type alterations, primary key alterationsCannot be automated by SQLite without data copy; CLI provides guidance.
undocumentedLive DB columns/tables missing from schema.jsFlagged for operator awareness; left untouched.

Safely Dropping Columns or Tables

Deleting a table or column definition from schema.js will not drop it from SQLite. To drop an entity, mark it deprecated in schema.js:

// Drop column:
text('deprecated_column').deprecated('Replaced by new_column')

// Drop table:
export const oldLogs = table('old_logs', { /* ... */ }).deprecated('No longer needed');

Once npx tgcloud migrate runs and confirms the drop, delete the declaration from schema.js.


8. CLI Command Reference (tgcloud)

All commands can be invoked from anywhere in the project tree.

# Inspection and comparison (offline)
npx tgcloud status         # File modifications, additions, deletions vs cloud
npx tgcloud diff           # Line-by-line diff of pending local changes

# Deployment & sync
npx tgcloud push           # Atomic deployment of handlers, endpoints, lib, & static assets
npx tgcloud push handlers/message.js # Targeted single-file deployment
npx tgcloud push --force   # Overwrite remote revision lock (use cautiously)

# Database & migrations
npx tgcloud migrate        # Interactive diff & application of database schema
npx tgcloud migrate --safe # Automatically apply safe changes, skip warnings
npx tgcloud migrate --dry-run # Preview pending migration SQL without executing
npx tgcloud db             # Open interactive database shell or check database status

# Local execution & debugging
npx tgcloud run handlers/message '{ chat: { id: 100 }, text: "/start" }'
npx tgcloud run endpoints/getProfile '{}' --ctx '{ initData: { user: { id: 100 } } }'
npx tgcloud logs           # Stream telemetry, uncaught errors, and console.* output

# Webhook management
npx tgcloud webhook        # Inspect managed webhook state and allowed_updates
npx tgcloud webhook sync   # Re-align webhook with deployed handler types

Optimistic Revision Lock

The cloud assigns an integer revision to your project. If a teammate or CI runs tgcloud push while you have unpulled changes, your push is rejected. Resolve via:

npx tgcloud fetch          # Inspect latest cloud revision
npx tgcloud pull           # Pull remote code updates into local workspace

9. The SDK Runtime (sdk)

Inside tgcloud/, import runtime services from 'sdk':

import { api, db, fetch, InputFile, BotApiError, EndpointError } from 'sdk';

9.1 Bot API Client (api)

  • Call any Bot API method via api.<methodName>(params).
  • Method parameters use canonical Telegram snake_case.
  • The Bot API response envelope { ok: true, result: ... } is automatically unwrapped; methods return result directly.
  • Non-OK responses throw BotApiError containing .code, .description, .method, and .parameters.

9.2 File Handling (InputFile)

Upload multipart binaries without reading from a local disk:

import { api, InputFile } from 'sdk';

const pdfBytes = new Uint8Array([...]);
const file = new InputFile(pdfBytes, 'statement.pdf', { type: 'application/pdf' });

await api.sendDocument({
  chat_id: 12345,
  document: file,
  caption: 'Monthly Statement',
});

Download files using the platform's zero-hop buffer:

const bytes = await api.getFileContent(file_id); // Returns Uint8Array (max 20 MB)

9.3 Outbound Networking (fetch)

import { fetch } from 'sdk';

const res = await fetch('https://api.example.com/data', {
  method: 'POST',
  body: fetch.body.json({ query: 'status' }),
});
const data = await res.json();

Limits: Response body size ceiling is 30 MB. For AI token streaming, iterate chunks using for await (const chunk of res.body).


10. Integration with Telegram Rich Messages

Serverless handlers and endpoints serve as the high-speed backend dispatcher for Telegram Rich Messages (Bot API 10.1–10.3+).

import { api } from 'sdk';
import { rich, sendRich, sendDraft, streamRich } from '../lib/rich.js';

export default async function (message) {
  const chatId = message.chat.id;

  // Ephemeral streaming draft (thinking indicator permitted ONLY in drafts)
  await sendDraft(chatId, 101, '<tg-thinking>Formulating financial report...</tg-thinking>');

  // Final permanent rich message
  await sendRich(chatId, `
    <h1>📊 Quarterly Financial Breakdown</h1>
    <table bordered striped compact>
      <caption>Fiscal Year Performance</caption>
      <tr><th>Metric</th><th>Target</th><th>Actual</th></tr>
      <tr><td>Revenue</td><td>$1.2M</td><td>$1.45M</td></tr>
      <tr><td>EBITDA</td><td>$400K</td><td>$520K</td></tr>
    </table>
    <tg-button-row align="center">
      <tg-button type="url" style="primary" url="https://app.example.com">Launch Analytics</tg-button>
    </tg-button-row>
  `);
}

💡 Companion Skill Notice:
For comprehensive specifications, canvas markup design rules, native table constraints, LaTeX math syntax, interactive button rows, and pre-flight validation rules, refer to the companion skill:
telegram-rich-messages (or telegram-messaging).


11. Templates & References Inventory

This skill provides ready-to-use reference documents and clean starter boilerplate:

FilePurpose
references/serverless.mdExhaustive Telegram Serverless engineering reference and official specifications.
templates/serverless_rich_lib.jsComplete tgcloud/lib/rich.js module enforcing HTML rules, RTL detection, and streaming drafts.
templates/starter/tgcloud.jsoncStarter configuration for static Mini App hosting, SPA fallback, and security headers.
templates/starter/schema.jsClean platform SQLite schema starter with indexed users table and mode builders.
templates/starter/handlers/message.jsProduction-ready update handler demonstrating user upserts, command branching, and api replies.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.