Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.mirage.strukto.ai/llms.txt

Use this file to discover all available pages before exploring further.

The Telegram resource exposes Telegram chats as a virtual filesystem mounted at some prefix such as /telegram/. For token setup, see Telegram Setup.

Config

import os

from mirage import MountMode, Workspace
from mirage.resource.telegram import TelegramConfig, TelegramResource

config = TelegramConfig(token=os.environ["TELEGRAM_BOT_TOKEN"])
resource = TelegramResource(config=config)
ws = Workspace({"/telegram": resource}, mode=MountMode.READ)

Filesystem Layout

/telegram/
  groups/
    <chat-title>__<chat-id>/
      <yyyy-mm-dd>.jsonl
      ...
  channels/
    <channel-title>__<chat-id>/
      <yyyy-mm-dd>.jsonl
      ...
  private/
    <user-name>__<chat-id>/
      <yyyy-mm-dd>.jsonl
      ...
Example:
/telegram/
  groups/
    Dev Team__-1001234567890/
      2026-04-10.jsonl
      2026-04-11.jsonl
    Friends__-987654321/
      2026-04-11.jsonl
  channels/
    Announcements__-1009876543210/
      2026-04-11.jsonl
  private/
    alice__123456789/
      2026-04-10.jsonl
      2026-04-11.jsonl
Directory names embed the Telegram chat ID after __ so that write commands (telegram-send-message --chat_id, etc.) can reference the correct resource without extra lookups.

Groups

/telegram/groups/ lists group and supergroup chats the bot has access to. The chat ID is appended after __. Each chat directory contains day-partitioned .jsonl history files.

Channels

/telegram/channels/ lists channel chats the bot has access to. The chat ID is appended after __. Channels require the bot to be added as an administrator.

Private

/telegram/private/ lists private (one-on-one) chats. The chat ID is appended after __.
Note: Telegram bots have a 24-hour message window limitation. The bot can only fetch messages from the last 24 hours of updates it has received. Older messages may not be available.

Cache

The Telegram resource uses IndexCacheStore (same as Discord, Slack, and other resources). Index entries store chat IDs and chat metadata for directory listing. There is no separate content cache - file content caching is handled by the workspace IOResult mechanism.

Example

import asyncio
import os

from dotenv import load_dotenv

from mirage import MountMode, Workspace
from mirage.resource.telegram import TelegramConfig, TelegramResource

load_dotenv(".env.development")

config = TelegramConfig(token=os.environ["TELEGRAM_BOT_TOKEN"])
resource = TelegramResource(config=config)


async def main():
    ws = Workspace({"/telegram": resource}, mode=MountMode.READ)

    # List categories
    r = await ws.execute("ls /telegram/")
    print(await r.stdout_str())

    # List groups
    r = await ws.execute("ls /telegram/groups/")
    print(await r.stdout_str())

    groups = r.stdout_str().strip().splitlines()
    if groups and groups[0].strip():
        chat = groups[0].strip()
        base = f"/telegram/groups/{chat}"

        # List date files
        r = await ws.execute(f'ls "{base}/"')
        print(await r.stdout_str())

        dates = r.stdout_str().strip().splitlines()
        if dates:
            target = dates[0].strip()
            file_path = f"{base}/{target}"

            # Read messages
            r = await ws.execute(f'cat "{file_path}" | head -n 5')
            print(await r.stdout_str())

            # Extract sender names with jq
            r = await ws.execute(
                f'jq ".from.first_name" "{file_path}" | head -n 5')
            print(await r.stdout_str())

    # Tree view
    r = await ws.execute("tree -L 2 /telegram/")
    print(await r.stdout_str())


if __name__ == "__main__":
    asyncio.run(main())
See examples/chat/telegram.py for the full working example.

Finding Chat IDs

Chat IDs are embedded in directory names after __:
# Chat ID - embedded in directory name after "__"
ls /telegram/groups/
# -> Dev Team__-1001234567890   <- chat_id = -1001234567890

ls /telegram/channels/
# -> Announcements__-1009876543210   <- chat_id = -1009876543210

ls /telegram/private/
# -> alice__123456789   <- chat_id = 123456789

# Message ID - inside JSONL messages
jq -r '"\(.message_id) [\(.from.first_name)] \(.text)"' \
  "/telegram/groups/Dev Team__-1001234567890/2026-04-11.jsonl" | head -n 5
# -> 42 [Alice] hello world

# Find a message then reply
jq -r 'select(.text | test("hello")) | .message_id' \
  "/telegram/groups/Dev Team__-1001234567890/2026-04-11.jsonl"
# -> 42
telegram-send-message --chat_id -1001234567890 \
  --text "Reply" --reply_to_message_id 42

Working with Chats

Tips for efficient access:
# Check message count per day
wc -l "/telegram/groups/Dev Team__-1001234567890/2026-04-11.jsonl"

# Read only recent messages
tail -n 10 "/telegram/groups/Dev Team__-1001234567890/2026-04-11.jsonl"

# Search across all dates
rg "keyword" "/telegram/groups/Dev Team__-1001234567890/"

# Extract specific fields to reduce output
jq -r '"\(.from.first_name): \(.text)"' \
  "/telegram/groups/Dev Team__-1001234567890/2026-04-11.jsonl" | head -n 20

# Count messages per user
cat "/telegram/groups/Dev Team__-1001234567890/2026-04-11.jsonl" \
  | jq -r '.from.first_name' | sort | uniq -c

Shell Commands

Standard commands available on the mounted Telegram tree:
CommandNotes
lsList categories, chats, dates
catRead .jsonl history
head / tailFirst/last N lines
grep / rgPattern search (file or directory level)
jqQuery JSON; use .[] prefix for JSONL
wcLine/word/byte counts
statFile metadata (name, size, type)
findRecursive search with -name, -maxdepth
treeDirectory tree view
Resource-specific commands:

telegram-send-message

Send a message to a chat, optionally as a reply.
telegram-send-message --chat_id -1001234567890 --text "Hello from MIRAGE"
telegram-send-message --chat_id -1001234567890 --text "Reply" --reply_to_message_id 42
OptionRequiredDescription
--chat_idyesTelegram chat ID
--textyesMessage text to send
--reply_to_message_idnoMessage ID to reply to
The chat ID can be found in directory names under /telegram/groups/, /telegram/channels/, or /telegram/private/ (after __). Returns the posted message JSON.