How Automations Enable Telegram Topic Routing for New Sessions in Craft Agents OSS

Craft Agents OSS automations route new sessions to specific Telegram forum topics by reading the telegramTopic field from the automation matcher, expanding environment variables and placeholders, and binding the session to a cached thread ID via the TopicRegistry.

Craft Agents OSS is an open-source framework for building AI agents with structured automation flows. The platform supports Telegram topic routing for new sessions through a declarative configuration system that maps automation triggers to specific forum topics (threads) within Telegram supergroups. This routing mechanism operates through a chain of components spanning the shared automation schema, prompt handling logic, and the messaging gateway's topic registry.

Automation Schema: Defining the telegramTopic Field

In the shared package, the automation schema defines an optional telegramTopic property that specifies the target forum topic name.

In packages/shared/src/automations/types.ts (lines 181 and 260), the TypeScript interface declares:

telegramTopic?: string;   // optional forum-topic name

The validation schema in packages/shared/src/automations/schemas.ts (line 152) enforces constraints:

telegramTopic: z.string().min(1).max(128).optional(),

When creating an automation, users can specify values like "Support: $LABEL" to organize sessions into dedicated threads.

Prompt Handler: Expanding Topic Name Variables

During automation execution, the prompt handler processes the raw telegramTopic string to resolve environment variables and placeholders.

In packages/shared/src/automations/handlers/prompt-handler.ts (lines 73-94), the handler expands the topic name:

const telegramTopic = matcher.telegramTopic?.trim();
const expandedTopic = telegramTopic ? expandEnvVars(telegramTopic, env).trim() : undefined;
// …
telegramTopic: finalTopic,

If the expanded string is empty, the system drops the topic binding; otherwise, it preserves the processed name for session creation.

Session Manager: Binding New Sessions to Topics

When spawning a new session, the SessionManager checks for the presence of telegramTopic in the triggering matcher and initiates the binding process.

In packages/server-core/src/sessions/SessionManager.ts (lines 7572-7633), the binding logic executes:

// ... SessionManager sees matcher.telegramTopic and will bind the session.
if (this.automationBinder && telegramTopic && telegramTopic.trim().length > 0) {
    // create a TopicRegistry entry (or reuse an existing one)
    this.topicRegistry.bind({
        supergroupChatId,
        topicName: telegramTopic.trim(),
    });
    // later sendMessage uses this binding
}

This call establishes the link between the session and the Telegram forum topic before any messages are sent.

Topic Registry: Caching Forum Thread IDs

The TopicRegistry maintains a mapping between user-defined topic names and Telegram's internal message_thread_id values.

In packages/messaging-gateway/src/topic-registry.ts (lines 30-34), the registry class manages these mappings:

/** Each entry maps a user-specified topic name to a Telegram forum-topic */
export class TopicRegistry {
    // supergroup chat ID + Telegram thread ID (message_thread_id)
}

When bind() is invoked, the registry either returns a cached thread ID or calls TelegramAdapter.createForumTopic to create a new forum topic in the supergroup. The resulting message_thread_id is stored for reuse across subsequent sessions using the same automation.

Telegram Adapter: Executing API Calls

The actual Telegram API interaction occurs through the TelegramAdapter, which creates forum topics and sends messages with the appropriate thread identifiers.

In packages/messaging-gateway/src/adapters/telegram/index.ts, the createForumTopic method handles the API request to Telegram, returning the message_thread_id required for routing.

When sending messages, the renderer in packages/messaging-gateway/src/renderer.ts includes the threadId field, ensuring messages appear in the correct forum topic:

await telegramAdapter.sendMessage({
  chatId: supergroupChatId,
  text: "Hello from automation",
  threadId: bound.threadId,   // <-- forces the message into the forum topic
});

Summary

  • Automation definitions configure Telegram forum topics via the optional telegramTopic field in packages/shared/src/automations/types.ts.
  • Prompt handlers expand environment variables and placeholders in topic names before session creation.
  • SessionManager binds new sessions to topics by calling TopicRegistry.bind() when telegramTopic is present in the matcher.
  • TopicRegistry caches message_thread_id values to avoid creating duplicate forum topics for the same automation.
  • TelegramAdapter executes the actual createForumTopic API calls and routes messages using the cached thread IDs.

Frequently Asked Questions

How does the system handle duplicate topic names across different automations?

The TopicRegistry caches forum topic IDs based on the combination of supergroupChatId and the processed topicName. When multiple sessions trigger the same automation (or different automations with identical topic names), the registry reuses the existing message_thread_id rather than creating new forum topics, ensuring all related conversations consolidate into a single thread.

What happens if the telegramTopic field is empty or resolves to an empty string?

In packages/shared/src/automations/handlers/prompt-handler.ts, the prompt handler trims the expanded topic name and checks its length. If the result is an empty string, the system sets telegramTopic to undefined, and the SessionManager skips the binding logic. The session then operates without a specific topic binding, sending messages to the general chat instead of a forum topic.

Can topic names include dynamic variables like labels or environment values?

Yes. The expandEnvVars function processes the telegramTopic string in the prompt handler, allowing dynamic values such as $LABEL or environment variables. This enables automations to create contextual forum topics like "Support: ${customerTier}" that organize sessions based on runtime data.

Where is the forum topic actually created in the Telegram API?

The TelegramAdapter in packages/messaging-gateway/src/adapters/telegram/index.ts implements the createForumTopic method, which calls the Telegram Bot API's createForumTopic endpoint. This occurs inside the TopicRegistry.bind() method when no cached entry exists for the requested topic name and supergroup combination.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →