AI chat bot that turns your Telegram channel into a chat list
Project description
Postak
Turn a Telegram channel into a personal AI chat list.
Start a chat with /new. Each post becomes a conversation title; its comment thread is the chat. Postak replies as you type and names the post after the first reply.
[!CAUTION] Postak is under active development. APIs, commands, and storage may change.
Features
- Channel as chat list — each
/newpost becomes an auto-titled conversation. - Rich streaming replies — rich Telegram messages: tables, checklists, ...
- Per-thread memory — each conversation keeps its own context.
- multi-channel support · Custom prompts · Commenter mentions · Scoped access · Thread tools · Pluggable models and storage
How it works
- Send
/newin your channel — or in its discussion group — to start a conversation. - Telegram forwards the post into its discussion group as a comment thread.
- Reply in the thread — Postak answers, streaming as it types.
- The first reply auto-titles the post, so your feed reads like a chat list.
Requirements
- Python 3.10+
- A Telegram bot (@BotFather) and a channel with a linked discussion group
- An OpenAI-compatible LLM endpoint
Start in five minutes
- In Telegram, create a channel and enable comments by linking a discussion group. Add your bot as an admin of both.
[!IMPORTANT] Turn the bot's privacy mode off so it can see comments: in @BotFather run
/setprivacy→ select your bot → Disable. If the bot was already in the group, remove and re-add it after changing this.
- Configure and run:
uv sync
cp .env.example .env # fill in BOT_TOKEN, TARGET_CHANNEL_ID, LLM_MODEL, …
uv run postak
# or, from PyPI:
# pip install postak
# postak # reads .env from the current directory
- Send
/newin your channel or discussion group, then reply in the new thread.
[!TIP] To serve another channel later, link its discussion group in Telegram, then either run
/postak addin that group or just send/newthere — no restart needed. See Admin commands.
Configuration
Postak reads settings from the environment (via a .env file):
| Variable | Required | Default | Description |
|---|---|---|---|
BOT_TOKEN |
✔ | — | Telegram bot token from @BotFather |
TARGET_CHANNEL_ID |
— | Channel id(s) to serve, comma-separated (e.g. -1001234567890,-1009876543210). Leave empty and a Postak admin can add channels later — see Admin commands |
|
LLM_MODEL |
✔ | — | Model name, e.g. gpt-4o-mini |
LLM_ENDPOINT |
OpenAI API | Base URL of an OpenAI-compatible endpoint | |
LLM_API_KEY |
not-needed |
API key for the LLM endpoint | |
POSTAK_ADMINS |
— | Comma-separated Telegram user ids who may manage Postak. Required if TARGET_CHANNEL_ID is empty, since that's the only way to add a channel |
|
DATABASE_URL |
sqlite+aiosqlite:///postak.db |
Store URL: a SQLite path, or :memory: |
|
HISTORY_WINDOW |
20 |
Max recent messages kept as context (the system prompt is always kept) |
Library usage
from aiogram import Bot, Dispatcher
from postak import OpenAIGenerator, Postak
postak = Postak(
generator=OpenAIGenerator(model="gpt-4o-mini", api_key="..."),
store="sqlite+aiosqlite:///postak.db",
channels=[-1001234567890],
admins=[123456789],
)
bot = Bot("telegram-token")
dp = Dispatcher()
postak.attach(dp)
dp.run_polling(bot)
Admin commands
Postak admins manage everything with /postak (/postak help lists it all):
Access
admin list— show admins ·admin add|remove <user_id>— grant or revoke rightsaccess list— show all access rulesaccess allow|revoke <user_id> global|group|thread— per-user accessaccess public on|off global|group|thread— open or close a scope to everyone; a public/allowed group (or global scope) also lets non-admins run/newin an already-linked group, not just comment
Channels
add [chat_id]— link a channel, discovering its discussion group via Telegram; defaults to the chat you're in, or pass either side's idremove [chat_id]— unlink it and drop that group's access rules
A Postak admin can skip add entirely: sending /new in a group Postak doesn't know yet links its channel and starts the conversation in one step.
In a thread
digest— summarize the conversationcompress— replace history with a compact summarytitle— regenerate the post title ·settitle <text>— set it yourselfregenerate— redo the last answerdelete— delete the message you replied to
Model
model get— show the current model ·model set <model>— switch it
System prompt — targets the surrounding thread when run inside one, else the global default
sysprompt— show it ·sysprompt <text>— set it ·sysprompt delete— reset it- The global prompt applies to conversations opened after the change and is admin-only; a thread's prompt takes effect on its next reply and can also be managed by anyone allowed to chat in that thread
Development
uv sync
uv run python -m unittest discover -s tests
uv run ruff check .
uv run mypy postak
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file postak-0.1.0.tar.gz.
File metadata
- Download URL: postak-0.1.0.tar.gz
- Upload date:
- Size: 36.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ec93cf804770c9c3b9fbd64b4b27da2c4d106c5912f4fe3be3b0530dd983dd3b
|
|
| MD5 |
22cdfada1023914d9b8d9ffd3a8b2b00
|
|
| BLAKE2b-256 |
c97d36f72d45a3d4eed08f104f0028fae4f0c4ad3fb000f5bce8a70b15225cd8
|
File details
Details for the file postak-0.1.0-py3-none-any.whl.
File metadata
- Download URL: postak-0.1.0-py3-none-any.whl
- Upload date:
- Size: 33.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa0db1c08c585dea079bc3522a4d6c63d253313f7e1c37b05b762f171dc146b8
|
|
| MD5 |
5b11778cc923c0d9f77c558f4aebd604
|
|
| BLAKE2b-256 |
0849afddde31717e1e233e05611dc883c8c2492f66fc7a6005aa266eed1f477b
|