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:
| Command | Notes |
|---|
ls | List categories, chats, dates |
cat | Read .jsonl history |
head / tail | First/last N lines |
grep / rg | Pattern search (file or directory level) |
jq | Query JSON; use .[] prefix for JSONL |
wc | Line/word/byte counts |
stat | File metadata (name, size, type) |
find | Recursive search with -name, -maxdepth |
tree | Directory 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
| Option | Required | Description |
|---|
--chat_id | yes | Telegram chat ID |
--text | yes | Message text to send |
--reply_to_message_id | no | Message 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.