A local-first Telegram bot for personal memory, files, schedules, and lightweight relay workflows.
It runs through a local OpenCode server, keeps canonical state in the repository, and treats Telegram as a platform adapter rather than the center of the architecture.
- remember and retrieve personal facts
- organize uploaded files and materials
- create and manage schedules
- send messages or scheduled deliveries to authorized users or known group chats
- let the admin manage durable user roles through the bot
The bot is organized as a small layered system: interaction, scheduling, roles, support, operations, and records, with OpenCode tools used as the preferred deterministic side-effect boundary.
Interaction
receive and deliver user messages
|
v
Scheduling
coordinate loops, sessions, and timing
|
+-- Assistant
| one main agent for interpretation + tool execution
| |
| +--> OpenCode Tools
| | system_* plus narrower Telegram tools
| | |
| | +--> Operations / Records
| | domain logic and canonical state
|
+-- Maintainer
cleanup and repair
|
+--> Operations
The current conversation path is centered on a single assistant lane:
- the assistant interprets the request and performs needed tool work directly
- when tool work is needed, it should call
telegram_reply_currentfirst with a brief acknowledgment - runtime code keeps waiting-state UI, interruption, merge, and duplicate-publication safeguards
- fixed UI text stays in i18n; natural conversational wording is generated by the model
- user-facing assistant replies follow the user's natural conversation language, while
/languageonly controls fixed UI text
Short-term conversational context is kept in OpenCode sessions by scope:
- private chat -> one session per user
- group / supergroup -> one session per chat
Long-term facts, access roles, schedules, and structured state do not rely on model session history. They live in repository state such as system/users.json, system/chats.json, system/tasks.json, system/runtime-state.json, and system/schedules.json. These stores are intended to be managed through project tools instead of prompt-defined persistence protocols.
cp config.toml.example config.toml
cp .env.example .env
just install
just serveFill in at least:
telegram.bot_tokentelegram.admin_user_id
Typical setup:
[telegram]
bot_token = "YOUR_TELEGRAM_BOT_TOKEN"
admin_user_id = 333333333
waiting_message = "Thinking..."
waiting_message_candidates = ["Still thinking...", "Almost there..."]
waiting_message_rotation_seconds = 5
input_merge_window_seconds = 3
menu_page_size = 8
[bot]
language = "zh"
persona_style = "Speak like the Defect from Slay the Spire."
default_timezone = "Asia/Tokyo"
[maintenance]
enabled = true
idle_after_minutes = 15
[opencode]
base_url = "http://127.0.0.1:4096"Useful optional settings:
telegram.menu_page_size: Telegram inline menu page sizetelegram.input_merge_window_seconds: short window for merging follow-up text/files into the same in-flight turntelegram.waiting_message/telegram.waiting_message_candidates: Telegram waiting UI text; ifwaiting_messageis empty, no waiting message is shownbot.language: default UI locale used when a user has not selected/languageyetbot.default_timezone: fallback timezone used when the user has not explicitly provided onemaintenance.idle_after_minutes: run maintenance after this many idle minutes[opencode].base_url: local OpenCode server address
- Every user who should receive direct bot messages must have started a private chat with the bot at least once.
- If you want to use the bot in group chats, open BotFather and turn Group Privacy off for the bot.
allowed user: may chat with the bot and use basic personal featurestrusted user: may read and modify memory, files, schedules, and other persistent dataadmin user: trusted user plus admin-only operations
The admin may also temporarily allow a @username. After that, the user only needs to interact with the bot before the temporary authorization expires so the system can link the account and grant access. This can be a private chat, an @bot mention in a group, or a reply to the bot in a group.
- “Remember my passport number.”
- “What is my home address?”
- “Remind me tomorrow at 9am to submit the application.”
- “Send this to @someone: dinner is ready.”
- “Send this to the family group.”
- “Set @someone to trusted.”
/help/language/new/model(admin only)
bun run test
bun run test:nl
bun run test:nl-live
just testThe regression suite covers deterministic storage behavior and live natural-language flows, including schedule CRUD, user access-level changes, outbound delivery, persona-aware reply composition, and requester-timezone-aware time injection.