opencode-telegram-bot

grinevMIT活跃维护

把 OpenCode 编码任务接到 Telegram 上的移动客户端,代码仍在本地跑,用手机就能随时发起和监控 AI 编程任务。

OpenCode mobile client via Telegram: run and monitor AI coding tasks from your phone while everything runs locally on your machine. OpenCode V2 support.

v0.27.0发布于 2026-11-06 22:18 UTC1,348star +4 / 7 天252fork同步于 2026-11-10 11:48 UTC

怎么上手

由 README 提炼,执行前请确认
npm install -g @grinev/opencode-telegram-bot
opencode-telegram start
硬件要求按 README 说明

README 未说明显存或 GPU 要求;需在 macOS、Windows 或 Linux 上运行 Node.js 22.14+ 与本地 OpenCode 服务,模型算力由本机 OpenCode 承担。

支持 Apple Silicon
下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

通过 Telegram 远程操控本地 OpenCode CLI 跑 AI 编码任务,不开端口不暴露 API

把 OpenCode 编码任务接到 Telegram 上的移动客户端,代码仍在本地跑,用手机就能随时发起和监控 AI 编程任务。

核心能力

  • 用 Telegram 发提示词,结果以文件形式回传代码
  • 固定消息实时显示项目、模型、上下文用量与改动文件
  • 内联按钮回答 agent 提问并审批权限请求
  • 支持语音转写提示词、图片/PDF/文本附件与定时任务
  • 严格用户 ID 白名单,仅本人可访问机器人

容易踩的坑

需先在本机运行 opencode serve,默认连接 http://localhost:4096;需先在 @BotFather 创建机器人并准备自己的 Telegram 用户 ID;在源码目录内执行 npx 命令可能报 opencode-telegram: not found,源码运行需走 Development 流程。

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v0.27.0
  1. v0.27.0最新正式版2026-11-06 · 2026-11-06 22:18 UTC

    Changes

    • Goal command support (OpenCode V2) — Use /goal to enter and confirm an objective that continues on its own, with its status and Pause, Continue or Delete controls always within reach on the bottom keyboard.
    • Session search — Find sessions by title or ID in /sessions, with the current session marked in both the list and search results.
    • Project search — Find a project by name using Search in /projects.
    • Enable or disable recurring tasks — Disable and re-enable recurring tasks in /tasklist without deleting them, with alarm and sleep icons distinguishing enabled and disabled tasks.
    • Mute background session notifications — Silence notifications from other sessions in /settings while keeping replies, questions and permission requests from the selected session visible.
    • Generation speed in the footer (OpenCode V2) — See generation speed in tokens per second and an interruption marker when an attached client stops a turn after its reply has arrived.
    • Standalone server support (OpenCode V2) — /opencode_start can run a separate server without replacing or adopting your registered background service.

    Fixes

    • OpenCode startup — /opencode_start now finds OpenCode in common installation directories on Linux and macOS even when a service's PATH does not include it (@MohamedAlsayed334).
    • File delivery — Receive generated files even from a read-only bot installation, without temporary-file collisions between same-named uploads (@Realmagnum).
    • Detach guidance — /detach now points to /recent so you can find and reattach to the session after detaching (@atn18).
    • Dashboard file counts — The pinned dashboard now shows additions and deletions from OpenCode's session diff, keeping live counts consistent after switching sessions or restarting the bot.

    Full changelog: https://github.com/grinev/opencode-telegram-bot/compare/v0.26.6...v0.27.0

  2. v0.26.62026-10-27 · 2026-10-27 23:48 UTC
    查看更新说明

    Changes

    • Connect to a moved OpenCode V2 server — when the configured address stops answering because OpenCode has registered its background server on another port (for example after a self-update), /opencode_start and auto-restart now connect the bot to that server instead of failing.
    • One-line compact summary — in compact mode a finished progress message turns into a single line of what that stretch of work did (✅ commands: 3, reads: 4, changed files: 2), leaving out zero counts, and is removed when there is nothing to count.

    Fixes

    • Waiting input on session pick — picking a session in /sessions that is still replying now also shows the newest message still waiting for its reply. (@atn18)
    • Commands after a session pick — picking a session that is still streaming no longer leaves the bot ignoring your commands until that stream calms down. (@atn18)
    • Microsoft Edge voice replies — text-to-speech through Microsoft Edge works again after the service started rejecting the bot's requests. (@Realmagnum)
    • Images sent as files — images that Telegram delivers as generic files without an image type are now recognized and sent to the model as images. (@vinceferro)

    Full changelog: https://github.com/grinev/opencode-telegram-bot/compare/v0.26.5...v0.26.6

  3. v0.26.52026-10-17 · 2026-10-17 20:39 UTC
    查看更新说明

    Changes

    • Named nested launches — when a subagent launches another one, its card's activity line now says which task it started, as in 🤖 Running Task: Count Kotlin files, and compact mode names the launched task the same way.
    • Shorter execute lines — long code in OpenCode V2 Code Mode execute calls is cut in the chat the same way long bash commands are, so a big script no longer floods the conversation.
    • No link previews under the bot's own messages — tool lines such as 🌐 webfetch <url>, cards, prompts, the dashboard and command replies no longer unfold a link preview, while the agent's own reply keeps it.

    Fixes

    • Voice replies — a prompt sent by voice now gets a spoken reply for every assistant message of the turn, including the final answer, not just the first one. (@xiehuanyi)
    • Background work after /abort — a background subagent or command that OpenCode keeps running after /abort keeps its live line and timer and ends with its real result instead of showing ⏹ Interrupted or freezing, and the /abort reply says how many are still running.
    • Your own pins — switching or clearing a session now unpins only the bot's dashboard instead of every pinned message in the chat, and no longer stalls on Telegram's rate limit. (@atn18)
    • Pinned dashboard on long sessions — switching to a long session no longer stalls on loading its whole history, and the dashboard shows the session's full cost. (@atn18)
    • Duplicate dashboard at startup — the bot no longer pins two dashboards for the same session when it starts. (@atn18)
    • Session preview — picking a session in /sessions shows the messages already loaded instead of "No recent messages" when a later page of its history fails to load. (@atn18)
    • Files on the dashboard after a switch — on OpenCode V2, the pinned dashboard of a session picked in /sessions or /recent shows its Files (N) block from the first frame instead of dropping it.

    Full changelog: https://github.com/grinev/opencode-telegram-bot/compare/v0.26.4...v0.26.5

  4. v0.26.42026-10-11 · 2026-10-11 18:09 UTC
    查看更新说明

    Changes

    • Prebuilt Docker images — stable releases are now published as multi-arch (linux/amd64, linux/arm64) images on ghcr.io/grinev/opencode-telegram-bot, so you can pull the bot instead of building it locally. (@mitchellhuang)
    • Docker health check — the Docker image now reports the container as unhealthy when the bot stops responding, through a loopback-only health endpoint that also tells whether OpenCode is reachable. (@iagorobo24-hub)

    Fixes

    • Background subagents on OpenCode V1 — a subagent launched in the background keeps its live card after the turn ends instead of losing it with the parent's reply. (@vheins)
    • Tool lines — a tool call no longer appears as a bare tool name while the agent is still composing it; its line shows up once, already complete with its arguments.
    • Starting subagent cards — a new subagent card shows a short 🧩 Starting task line until its task, agent and model are known, instead of Unknown or empty labels, and parallel subagents no longer swap each other's task and agent.
    • Interrupted subagents — a subagent stopped by /abort, an attached OpenCode TUI or Desktop, or the server now ends its card with ⏹ Interrupted instead of ✅ Completed or ❌ Aborted.
    • Nested subagents — a subagent launched by another subagent now shows as a 🤖 Running Task line on its parent's card instead of getting a card of its own.
    • Pinned dashboard after a switch or restart — the pinned status message shows the session's real context, cost and changed files from the moment it appears, instead of zeros until the next update.
    • Pinned dashboard after a model change — picking a model, or an agent that brings its own model, updates the pinned status message to that model and its context limit right away, even mid-run.

    Full changelog: https://github.com/grinev/opencode-telegram-bot/compare/v0.26.3...v0.26.4

  5. v0.26.32026-10-03 · 2026-10-03 10:17 UTC
    查看更新说明

    Fixes

    • No live polls for questions that already ended — a poll delayed by Telegram rate limits no longer appears with live buttons after its question was cancelled or answered elsewhere, and an answer that fails to reach OpenCode keeps the poll answerable with a visible outcome instead of being silently lost.
    • Queue buttons clear after a reconnect on OpenCode V2 — messages the agent has already picked up no longer keep their ❌ queue buttons on the reply keyboard after OpenCode's event stream reconnects.
    • Removed models disappear from the model menu — models OpenCode no longer offers stop showing in favorites, recent, providers and search right after a start or /reload, and a selected model that was removed falls back to the config model.
    • Deleted folders are hidden on OpenCode V2 — sessions, projects and worktrees whose folder no longer exists are left out of /sessions, /projects and /worktree, and a prompt, /new or /task in such a project answers with a notice pointing to /projects or /worktree.

    Full changelog: https://github.com/grinev/opencode-telegram-bot/compare/v0.26.2...v0.26.3

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    OpenCode Telegram Bot

    npm version CI License: MIT Node.js Follow updates Community

    OpenCode Telegram Bot is a secure Telegram client for OpenCode CLI that runs on your local machine.

    Run AI coding tasks, monitor progress, switch models, and manage sessions from your phone.

    No open ports, no exposed APIs. The bot communicates with your local OpenCode server and the Telegram Bot API only.

    Platforms: macOS, Windows, Linux

    Languages: English (en), العربية (ar), Deutsch (de), Español (es), Français (fr), Bahasa Indonesia (id), Italiano (it), 한국어 (ko), Português (Brasil) (pt), Русский (ru), Türkçe (tr), 简体中文 (zh)

    I use boardown, my open-source Markdown-based task board, to plan and track this project. It stores tasks in plain .md files and can be used as a VS Code extension or a desktop app.

    Features

    • OpenCode V2 support — works with the new OpenCode V2 as well as the classic V1; for setup details, see Old and New OpenCode Versions
    • Remote coding — send prompts to OpenCode from anywhere, receive complete results with code sent as files
    • Session management — create new sessions or continue existing ones, search sessions by title or ID in /sessions, and find projects by name in /projects
    • Track live session — follow a live OpenCode CLI session; see Track Existing Session
    • Background session notifications — get short notifications when detached or non-current sessions in the current project/worktree reply, ask questions, or request permissions. Turn them off in /settings (default on); that silences the chat notices only and does not stop tracking or cancel a pending request
    • Live status — pinned message with current project/worktree, model, context usage, and changed files list, updated in real time
    • Model switching — pick models from OpenCode favorites and recent history directly in the chat (favorites are shown first), or browse all models by provider
    • Agent modes — switch between Plan and Build modes on the fly
    • Subagent activity — watch live subagent progress in chat, including the current task, agent, model (with variant when set), and active tool step
    • Custom Commands — run OpenCode custom commands (and built-ins like init/review) from an inline menu with confirmation
    • Skills Catalog — browse OpenCode skills from an inline menu and run them immediately or with arguments in the next message
    • Session goals (V2) — /goal asks for the objective in a separate text message and confirms automatic work and token spending. Start and Continue use the selected agent, model and variant, including in a fresh session before any ordinary prompt. The bottom keyboard keeps its short objective and Pause, Continue or Delete below queued messages. Pause stops future continuations; /abort also interrupts the current turn. To create another goal, stop and delete the old one first
    • Interactive Q&A — answer agent questions and approve permissions via inline buttons
    • Runtime settings — use /settings to change runtime preferences; see Runtime Settings
    • Voice prompts — send voice/audio messages, transcribe them via a Whisper-compatible API, and optionally enable spoken replies in /settings
    • File attachments — send images, PDF documents, and text-based files to OpenCode, including multiple files in one Telegram album
    • Scheduled tasks — schedule prompts to run later or on a recurring interval; see Scheduled Tasks
    • Message queue — messages sent while the agent is busy are held and sent one by one afterwards (Queue) or, on OpenCode V2, steered into the running task (Steer); each waiting message is a bottom-keyboard button you can tap to withdraw it; /detach leaves waiting messages to the session they were sent to
    • Context control — tap the bottom 📊 button to see context usage and the latest assistant message's tokens and cost; compact from the details with an inline confirmation
    • Input flow control — when an interactive flow is active, the bot accepts only relevant input to keep context consistent and avoid accidental actions
    • Git worktree switching — browse and switch between existing git worktrees for the current repository with /worktree
    • Security — strict user ID whitelist; no one else can access your bot, even if they find it
    • Localization — UI localization is supported for multiple languages (BOT_LOCALE)
    • Docker support — run the bot as a container while OpenCode stays on the host; see Docker Deployment
    • Interactive file browser — use /ls to browse files and directories inside the current project, open subdirectories, go back, and download files by tapping them
    • Attach a file to your next prompt — tap 📎 Attach to next prompt on a text file in /ls, and it is sent to OpenCode together with your next message, once

    Planned features currently in development are listed in Current Task List.

    Prerequisites

    • Node.js 22.14+ — download
    • OpenCode — install from opencode.ai or GitHub
    • Telegram Bot — you'll create one during setup (takes 1 minute)

    Quick Start

    1. Create a Telegram Bot

    1. Open @BotFather in Telegram and send /newbot
    2. Follow the prompts to choose a name and username
    3. Copy the bot token you receive (e.g. 123456:ABC-DEF1234...)

    You'll also need your Telegram User ID — send any message to @userinfobot and it will reply with your numeric ID.

    2. Start OpenCode Server

    Run the OpenCode server on the same machine where the bot runs:

    opencode serve
    

    The bot connects to the local OpenCode API at http://localhost:4096 by default. For OpenCode V2, see Old and New OpenCode Versions.

    After the bot is configured, you can also start and stop the local OpenCode server from Telegram with /opencode_start and /opencode_stop.

    3. Install & Run

    The fastest way — run directly with npx:

    npx @grinev/opencode-telegram-bot@latest
    

    Note: This README tracks the main branch, which may include unreleased changes. The latest npm release may not include every feature described here yet. See recent commits on main.

    Quick start is for npm usage. You do not need to clone this repository. If you run this command from the source directory (repository root), it may fail with opencode-telegram: not found. To run from sources, use the Development section.

    If required configuration is not supplied through process environment variables or an .env file, an interactive wizard will guide you through setup. It asks for interface language first, then your bot token, user ID, the OpenCode version (V1 or V2; V2 is offered on a first setup, a re-run offers the saved one), the OpenCode API URL (its default follows the version), and the OpenCode server credentials: the username, and a password that is optional for V1 and required for V2 (see Old and New OpenCode Versions for where to get it; on a re-run, Enter keeps the saved password). After that, you're ready to go. Open your bot in Telegram and start sending tasks.

    Alternative: Global Install
    npm install -g @grinev/opencode-telegram-bot
    opencode-telegram start
    

    start runs in the foreground by default. This is the recommended mode for systemd, Docker, local debugging, and other external process managers.

    To run the bot in the built-in background mode instead:

    opencode-telegram start --daemon
    opencode-telegram status
    opencode-telegram stop
    

    Built-in daemon mode is intended for standalone npm installs without an external supervisor. For systemd, pm2, or Docker, keep using opencode-telegram start without --daemon.

    For Linux systemd setup, see docs/LINUX_SYSTEMD_SETUP.md.

    To reconfigure at any time:

    opencode-telegram config
    

    Supported Platforms

    PlatformStatus
    macOSFully supported
    WindowsFully supported
    LinuxFully supported (tested on Ubuntu 24.04 LTS)

    Bot Commands

    CommandDescription
    /statusBot version, server health, current project, session, and model info
    /newCreate a new session
    /abortAbort the current task
    /detachDetach from the current session without stopping it
    /sessionsBrowse, search by title or ID, and switch sessions
    /recentBrowse recent sessions across projects and worktrees, see their status and attach directly
    /messagesBrowse user messages, revert or fork from a previous state
    /projectsBrowse, search by name, and switch OpenCode projects
    /worktreeSwitch between existing git worktrees
    /openAdd a project by browsing directories
    /lsList directory contents, then tap to open or download
    /settingsChange bot settings
    /renameRename the current session
    /commandsBrowse and run custom commands
    /skillsBrowse and run OpenCode skills
    /mcpsBrowse and toggle MCP servers
    /taskCreate a scheduled task
    /tasklistBrowse, delete and enable or disable recurring scheduled tasks
    /opencode_startStart the local OpenCode server on the bot machine
    /opencode_stopStop the local OpenCode server, including during a run
    /reloadReload the OpenCode configuration without restarting the server (V2 only)
    /goalEnter a goal in the next message; view it and pause, continue or delete it from the bottom keyboard (V2 only)
    /helpShow available commands

    Any regular text message is sent as a prompt to the coding agent only when no blocking interaction is active. Voice/audio messages are transcribed and then sent as prompts when STT is configured.

    When the current project is a git repository, /worktree shows the existing worktrees for that repository. Status and pinned updates display the main project path with the active branch, and show a separate Worktree line when a linked worktree is selected.

    Message History, Revert, and Fork

    The /messages command displays all user messages in the current session, sorted by time (newest first). Select a message to view its full text and access the Revert and Fork actions.

    Revert rolls back the session state to the selected message, discarding all subsequent messages and agent responses. This is useful when you want to retry a different approach from a specific point in the conversation.

    Fork creates a new session that branches from the selected message. The original session remains unchanged, and you can continue working in the new forked session. This is useful when you want to explore an alternative approach without losing the original conversation history.

    Scheduled Tasks

    Scheduled tasks let you prepare prompts in advance and run them automatically later or on a recurring schedule. This is useful for periodic checks, routine code maintenance, or tasks you want OpenCode to execute while you are away from your computer. Use /task to create a scheduled task and /tasklist to review or delete existing ones. Recurring tasks can also be disabled and re-enabled without deleting them; missed runs are not replayed.

    • Each task is created from the currently selected OpenCode project, model, and agent
    • The agent is fixed when the task is created and every run uses it; it is shown in the creation confirmation and in the task details in /tasklist
    • Tasks run outside your active chat session, so they do not interrupt or affect the current session flow
    • The minimum recurring interval is 5 minutes
    • If a recurring task is still running when its next interval arrives, the bot does not start a parallel copy of the same task and does not replay missed intervals later
    • By default, the bot waits up to 120 minutes for one scheduled task run; change this with SCHEDULED_TASK_EXECUTION_TIMEOUT_MINUTES if needed
    • Up to 10 scheduled tasks can exist at once by default; change this with TASK_LIMIT in your .env

    Track Existing Session

    After you create a new session, select an existing one, or let the bot auto-create one from your first prompt, the bot automatically starts tracking that session. It follows live events from the same OpenCode session, shows external text input sent from another client, and lets you continue the same session from Telegram.

    With OpenCode V2 this works out of the box: all clients (TUI, desktop, web) connect to one background service, so just point the bot to it (see Old and New OpenCode Versions) and select or create the same session in Telegram.

    With OpenCode V1 the console OpenCode instance must be started on the same port the bot connects to. By default, OpenCode starts on a random port, so use one of the setups below.

    • Single TUI, simplest setup — start OpenCode on a fixed port: opencode --port 4096
    • Point the bot to http://127.0.0.1:4096, then select or create the same session in Telegram
    • Multiple TUI clients, shared backend — start one backend: opencode serve --port 4096
    • In each terminal client, connect with: opencode attach http://127.0.0.1:4096
    • In the bot, select or create the same session to start tracking it automatically

    Old and New OpenCode Versions

    The bot works with both the classic OpenCode V1 (opencode-ai) and the new OpenCode V2 (@opencode/cli). Their server APIs differ and the bot does not detect the version, so set OPENCODE_SERVER_VERSION (v1 by default, or v2); changing it needs a bot restart.

    V1V2
    Serveropencode servebackground service (opencode serve --service) by default; opencode serve without --service when OPENCODE_SERVER_MODE=standalone
    Default URLhttp://localhost:4096http://127.0.0.1:49374 (service). Standalone has no default: set OPENCODE_API_URL
    Passwordoptionalrequired: opencode service get password, or OPENCODE_SERVER_PASSWORD for a standalone server

    Set OPENCODE_API_URL (host and port, no /api suffix) if the server runs elsewhere. Sessions are not shared between the versions. A wrong password or a server of the other version shows up as an error in the bot log.

    /opencode_start and auto-restart run opencode serve --port <port> on V1 and, on V2, the background server (opencode serve --service --port <port>) unless OPENCODE_SERVER_MODE=standalone. Standalone runs opencode serve --port <port> without --service on an explicit OPENCODE_API_URL and does not connect to a registered server on another port. The port is taken from OPENCODE_API_URL. The bot refuses to start a server and logs the reason if the password is rejected, if the server or the local opencode is the other version, or, in service mode, if another V2 background server already runs on a different port. An unknown mode, or standalone without OPENCODE_API_URL, refuses bot startup instead. With both versions installed, the bot starts whichever one the opencode command runs. V1 ignores OPENCODE_SERVER_MODE.

    Configuration

    Localization

    • Supported locales: en, ar, de, es, fr, id, it, ko, pt, ru, tr, zh
    • The setup wizard asks for language first
    • You can change locale later with BOT_LOCALE

    Local JSON Commands

    Trusted local commands live in <appHome>/local-commands/, one JSON file per command. The filename becomes the command name, so quota.json appears as /quota in Telegram’s command menu after the bot restarts:

    {
      "description": "Show provider quota limits",
      "exec": "node /home/you/bin/quota.js",
      "allowWhenBusy": true
    }
    

    description and exec are required; description is a single line of at most 256 characters. Extra fields are ignored. Commands run through the platform shell with the bot’s OS permissions and inherited environment, from <appHome>; treat every file in this directory as trusted code. They receive no Telegram text or attachments, never invoke OpenCode, time out after 30 seconds, and are not listed in /help or /commands. allowWhenBusy defaults to false; it permits a command while OpenCode is working but never during an active bot interaction.

    Environment Variables

    Configuration can be provided through process environment variables or an .env file. Process environment values take precedence. When installed via npm, the configuration wizard handles any missing required values and stores the generated .env file in your platform's app data directory:

    • macOS: ~/Library/Application Support/opencode-telegram-bot/.env
    • Windows: %APPDATA%\opencode-telegram-bot\.env
    • Linux: ~/.config/opencode-telegram-bot/.env
    VariableDescriptionRequiredDefault
    TELEGRAM_BOT_TOKENBot token from @BotFatherYes—
    TELEGRAM_ALLOWED_USER_IDYour numeric Telegram user IDYes—
    TELEGRAM_PROXY_URLSOCKS or HTTP(S) forward proxy for Telegram Bot API calls and file downloadsNo—
    TELEGRAM_API_ROOTCustom Telegram Bot API root URL (e.g. nginx reverse-proxying api.telegram.org); applied to API calls and file downloadsNohttps://api.telegram.org
    TELEGRAM_PROXY_SECRETShared secret sent as X-Proxy-Secret header on every Bot API request and file download (used with TELEGRAM_API_ROOT)No—
    TELEGRAM_FORCE_IPV4Force IPv4 for direct Telegram API and file requests; useful when IPv6 DNS works but outbound IPv6 is brokenNofalse
    OPENCODE_SERVER_VERSIONOpenCode server API version: v1 or v2; must match the server you run; set by the setup wizardNov1
    OPENCODE_SERVER_MODEV2 only: service (default) or standalone. Standalone needs OPENCODE_API_URL and does not follow a registered server. V1 ignores it. An unknown value refuses startupNoservice
    OPENCODE_BIN_PATHAbsolute executable path for OpenCode on Linux/macOS; takes precedence over PATH and standard install-directory discoveryNo—
    OPENCODE_API_URLOpenCode server URLNohttp://localhost:4096 (V1), http://127.0.0.1:49374 (V2)
    OPENCODE_AUTO_RESTART_ENABLEDAutomatically restart a local OpenCode server when health-checks failNofalse
    OPENCODE_MONITOR_INTERVAL_SECHealth monitor interval in seconds when OpenCode auto-restart is enabledNo300
    OPENCODE_SERVER_USERNAMEServer auth usernameNoopencode
    OPENCODE_SERVER_PASSWORDServer auth password (needed for V2, see Old and New OpenCode Versions)No—
    OPENCODE_MODEL_PROVIDERDefault model providerYesopencode
    OPENCODE_MODEL_IDDefault model IDYesbig-pickle
    BOT_LOCALEBot UI language (supported locale code, e.g. en, ar, de, es, fr, id, it, ko, pt, ru, tr, zh)Noen
    SESSIONS_LIST_LIMITSessions per page in /sessions and maximum sessions in /recentNo10
    MESSAGES_LIST_LIMITUser messages per page in /messagesNo10
    PROJECTS_LIST_LIMITProjects per page in /projectsNo10
    PROJECTS_EXCLUDED_PATHSComma-separated absolute paths hidden from /projects (exact worktree match)No(none)
    OPEN_BROWSER_ROOTSComma-separated paths /open is allowed to browse (supports ~)No~ (home directory)
    COMMANDS_LIST_LIMITItems per page in /commands and /skillsNo10
    MODELS_LIST_LIMITProviders and provider models per page in the model pickerNo10
    TASK_LIMITMaximum number of scheduled tasks that can exist at onceNo10
    SCHEDULED_TASK_EXECUTION_TIMEOUT_MINUTESMaximum time the bot waits for one scheduled task run before marking it failedNo120
    SCHEDULED_TASK_DISABLE_NOTIFICATIONSend scheduled task result/error messages without Telegram push notificationsNofalse
    BASH_TOOL_DISPLAY_MAX_LENGTHMaximum displayed length for bash commands and execute code in Telegram summaries; longer ones are truncatedNo128
    TRACK_BACKGROUND_SESSIONSTrack detached/non-current sessions in the current selected project/worktree and send short notificationsNotrue
    MESSAGE_FORMAT_MODEAssistant reply formatting mode: markdown (native Telegram rich blocks) or raw (plain text)Nomarkdown
    MESSAGE_MERGE_WINDOW_MSMerge Telegram-split long text messages into one prompt after this wait window (ms); 0 disables mergingNo1500
    INITIAL_SETTINGS_PRESETJSON object that seeds default /settings values on first run (keys not yet persisted); see Runtime SettingsNo{}
    CODE_FILE_MAX_SIZE_KBMax file size (KB) to send as documentNo100
    STT_API_URLWhisper-compatible API base URL (enables voice/audio transcription)No—
    STT_API_KEYAPI key for your STT providerNo—
    STT_MODELSTT model name passed to /audio/transcriptionsNowhisper-large-v3-turbo
    STT_LANGUAGEOptional language hint (empty = provider auto-detect)No—
    STT_REQUEST_FORMATSTT request format: multipart (standard OpenAI/Groq Whisper) or json (base64 input_audio body, e.g. OpenRouter)Nomultipart
    STT_NOTE_PROMPTOptional note prepended to the LLM prompt as [Note: ...] for voice transcriptions; empty / false / 0 disable itNo—
    DOC_EXTRACTOR_URLDocument text extraction API URL (enables PDF/DOCX/PPTX extraction)No—
    DOC_EXTRACTOR_API_KEYAPI key for the document extractor (optional for self-hosted extractors)No—
    TTS_PROVIDERTTS provider: openai for OpenAI-compatible APIs, elevenlabs for ElevenLabs, or google for Google Cloud TTSNoopenai
    TTS_API_URLTTS API base URL for OpenAI-compatible APIs or ElevenLabsNo—
    TTS_API_KEYTTS API key for OpenAI-compatible APIs or ElevenLabsNo—
    TTS_MODELTTS model name. Passed as model for OpenAI-compatible APIs and model_id for ElevenLabsNogpt-4o-mini-tts
    TTS_VOICETTS voice name or ElevenLabs voice ID. Defaults to alloy, 21m00Tcm4TlvDq8ikWAM, or en-US-Studio-O by providerNoprovider-specific
    GOOGLE_APPLICATION_CREDENTIALSPath to a Google Cloud service account JSON key file for TTS_PROVIDER=googleNo—
    LOG_LEVELLog level (debug, info, warn, error)Noinfo
    LOG_RETENTIONNumber of log files to keep: launch files in sources, daily files in installedNo10
    BOT_HEALTH_PORTPort of the internal health endpoint (/health, /health/live, /health/ready) on 127.0.0.1; 0 disables itNooff; 3100 in Docker

    Keep your .env file private. It contains your bot token. Never commit it to version control.

    Logs are written to ./logs when running from sources and to the runtime config directory logs/ folder in installed mode. Log rotation depends on runtime mode: sources creates one file per bot launch, while installed appends to one file per day. Old log files are removed according to LOG_RETENTION.

    Runtime Settings

    Runtime preferences are changed from /settings and stored in settings.json:

    • Compact output mode: one progress message per stretch of work between replies and prompts, from the moment the model starts thinking or writing in that stretch. When the reply or prompt lands, or when the run ends if nothing followed, it turns into one line of what was done (✅ commands: 3, reads: 4, changed files: 2), or is removed when there is nothing to count
    • Delete progress on finish: available while compact output mode is on, removes each of those progress messages when that stretch finishes
    • Thinking content display
    • Assistant run footer display
    • Pin session dashboard
    • Notifications from other sessions: on by default. Off silences chat notices about replies, questions and permission requests from sessions that are not the one selected in the bot. Tracking keeps running, and a pending question or permission stays answerable from a TUI or Desktop
    • Diff file attachments
    • Response streaming mode: edit or draft (experimental); applies only to final assistant replies, not thinking messages
    • Audio replies: off, all, or auto when TTS is configured
    • Message queue: Off, or what happens to text, voice, photos, rich formatted messages with photos, documents, and media groups sent while the agent is busy — on OpenCode V2 Queue or Steer (the default), on V1 On (the bot's own queue, off by default)

    With the message queue on, text, transcribed voice, photos, rich formatted messages with photos, supported documents, and media groups sent while the agent is busy are accepted instead of being turned down. At most MAX_QUEUED_PROMPTS (5) messages wait at a time. Waiting messages appear as buttons above the usual bottom-keyboard grid — tap one to withdraw it — and /abort, /opencode_stop or a session/project switch withdraws them all. When a waiting message is picked up, its button disappears and its text is quoted as external user input.

    /detach does not withdraw them: they stay with the detached session and reach it as if the bot had stayed attached, with the agent and model selected at /detach — a message still being transcribed or downloaded included. Their buttons leave the keyboard and they no longer count toward the limit. A later session or project switch leaves them alone; /abort after returning to that session, or /opencode_stop, withdraws them. Picked up while detached, they show nothing in the chat beyond the usual background notification; back in the session before pickup, each is quoted as external user input when it starts.

    On OpenCode V2 a waiting message is sent to OpenCode at once and waits in the session's inbox, not in the bot: with Steer the running task picks it up at its next step and keeps going in the same progress message with one footer at the end; with Queue it starts its own run once the task finishes. Nothing is held by the bot, so there is no queued-media size limit, and after a bot restart the buttons are gone while OpenCode still delivers the messages.

    On OpenCode V1 the bot holds the messages itself and sends them one at a time as each run finishes. Its queue also holds at most 20 MiB of raw Telegram media bytes in total; the limit is checked from reliable Telegram file_size metadata before media is downloaded or prepared, while base64 data-URI expansion is not counted. Queued media without a reliable source size is refused while the task is busy.

    You can seed the initial defaults for any of these settings without hard-coding them in your Docker image by setting INITIAL_SETTINGS_PRESET to a JSON object. Only keys not yet persisted in settings.json are affected — settings the user has already changed via /settings are left untouched:

    INITIAL_SETTINGS_PRESET={"showAssistantRunFooter":false,"compactOutputMode":true,"ttsMode":"auto","pinnedDashboardEnabled":true}
    

    Settings are written atomically: the new content goes to a temporary file that then replaces settings.json, and the previous version is kept as settings.json.bak. A crash during a write can never leave a truncated file — the bot falls back to the backup on the next start. If both settings.json and settings.json.bak are unreadable, the bot refuses to start instead of overwriting them, and the error names the file so you can fix or remove it manually.

    Reverse Proxy (Optional)

    For environments that block api.telegram.org but allow your own HTTPS endpoint (corporate networks, restricted regions), you can route Bot API traffic through a reverse proxy you control. This is an alternative to the SOCKS/HTTP forward proxy configured with TELEGRAM_PROXY_URL.

    Set TELEGRAM_API_ROOT to your reverse-proxy URL — both Bot API calls and file downloads (including voice/audio files) will use it. Optionally set TELEGRAM_PROXY_SECRET so the bot sends an X-Proxy-Secret header your proxy can use to authorize callers.

    .env:

    TELEGRAM_API_ROOT=https://tg-proxy.yourdomain.com
    TELEGRAM_PROXY_SECRET=some-long-random-string
    

    Example nginx config:

    server {
        listen 443 ssl http2;
        server_name tg-proxy.yourdomain.com;
    
        ssl_certificate     /etc/letsencrypt/live/tg-proxy.yourdomain.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/tg-proxy.yourdomain.com/privkey.pem;
    
        access_log off;  # the bot token appears in URL paths
        client_max_body_size 50m;
    
        if ($http_x_proxy_secret != "some-long-random-string") { return 403; }
    
        location / {
            proxy_pass https://api.telegram.org;
            proxy_ssl_server_name on;
            proxy_set_header Host api.telegram.org;
        }
    }
    

    TELEGRAM_API_ROOT and TELEGRAM_PROXY_URL are alternative connectivity modes — the former picks the URL the bot connects to (a reverse proxy on your side), while the latter tunnels TCP through a forward proxy. Configure only one of them; the bot rejects using both at startup.

    Force IPv4 for Telegram (Optional)

    If the bot fails during startup with errors such as Network request for 'setMyCommands' failed or Network request for 'getWebhookInfo' failed, and the same machine has broken outbound IPv6 connectivity, force direct Telegram requests to use IPv4:

    TELEGRAM_FORCE_IPV4=true
    

    This affects direct Bot API calls and Telegram file downloads. It is not a replacement for TELEGRAM_PROXY_URL or TELEGRAM_API_ROOT when Telegram is blocked by the network.

    Voice and Audio Transcription (Optional)

    If STT_API_URL and STT_API_KEY are set, the bot will:

    1. Accept voice and audio Telegram messages
    2. Transcribe them via POST {STT_API_URL}/audio/transcriptions
    3. Show recognized text in chat
    4. Send the recognized text to OpenCode as a normal prompt

    If STT_NOTE_PROMPT is set to a non-empty value other than false or 0, the bot prepends [Note: ...] to the transcription before sending it to the LLM. The recognized text shown in Telegram stays unchanged.

    If TTS credentials are configured, you can choose spoken reply behavior in /settings: off disables audio replies, all sends audio for every assistant reply, and auto sends audio only after voice/audio prompts. The preference is stored in settings.json and persists across restarts.

    OpenAI-compatible TTS configuration example:

    TTS_PROVIDER=openai
    TTS_API_URL=https://api.openai.com/v1
    TTS_API_KEY=your-tts-api-key
    TTS_MODEL=gpt-4o-mini-tts
    TTS_VOICE=alloy
    

    ElevenLabs TTS configuration example:

    TTS_PROVIDER=elevenlabs
    TTS_API_URL=https://api.elevenlabs.io/v1
    TTS_API_KEY=your-elevenlabs-api-key
    TTS_MODEL=eleven_flash_v2_5
    TTS_VOICE=21m00Tcm4TlvDq8ikWAM
    

    Google Cloud TTS configuration example:

    TTS_PROVIDER=google
    TTS_VOICE=en-US-Studio-O
    GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account-key.json
    

    Supported provider examples (Whisper-compatible):

    • OpenAI
      • STT_API_URL=https://api.openai.com/v1
      • STT_MODEL=whisper-1
    • Groq
      • STT_API_URL=https://api.groq.com/openai/v1
      • STT_MODEL=whisper-large-v3-turbo
    • Together
      • STT_API_URL=https://api.together.xyz/v1
      • STT_MODEL=openai/whisper-large-v3

    If STT variables are not set, voice/audio transcription is disabled and the bot will ask you to configure STT.

    Document Text Extraction (Optional)

    If DOC_EXTRACTOR_URL is set, the bot will extract text from PDF, DOCX, PPTX, and other document files using an external API when the current model does not natively support document input.

    The API contract is:

    • Endpoint: POST {DOC_EXTRACTOR_URL}
    • Content-Type: multipart/form-data
    • Field: file — the document binary
    • Authorization: Bearer {DOC_EXTRACTOR_API_KEY} (only sent when a key is configured)
    • Response: JSON { "text": "extracted content..." }

    If the extractor is not configured and the model doesn't support documents, the bot replies with a notice and forwards only the caption text.

    Model Configuration

    The model picker uses OpenCode local model state (favorite + recent):

    • Favorites are shown first, then recent
    • Models already in favorites are not duplicated in recent
    • Current model is marked with ✅
    • Default model from OPENCODE_MODEL_PROVIDER + OPENCODE_MODEL_ID is always included in favorites

    To add a model to favorites, open OpenCode TUI (opencode), go to model selection, and press Cmd+F/Ctrl+F on the model.

    To pick a model that is neither a favorite nor recent, tap 🗂 Providers in the model picker: it lists the connected providers, then the models of the selected one, both paginated by MODELS_LIST_LIMIT.

    Security

    The bot enforces a strict user ID whitelist. Only the Telegram user whose numeric ID matches TELEGRAM_ALLOWED_USER_ID can interact with the bot. Messages from any other user are silently ignored and logged as unauthorized access attempts.

    Since the bot runs locally on your machine and connects to your local OpenCode server, there is no external attack surface beyond the Telegram Bot API itself. The optional health endpoint (BOT_HEALTH_PORT) binds to 127.0.0.1 only and serves read-only status.

    Development

    Running from Source

    git clone https://github.com/grinev/opencode-telegram-bot.git
    cd opencode-telegram-bot
    npm install
    cp .env.example .env
    # Edit .env with your bot token, user ID, and model settings
    

    Build and run:

    npm run dev
    

    Docker Deployment

    The bot can also be run as a container using Docker and Docker Compose. The image contains only the Telegram bot. OpenCode stays on the host and must already be running before you start the container (opencode serve --port 4096 on V1; for V2 see below). /opencode_start and /opencode_stop do not work from inside the container.

    git clone https://github.com/grinev/opencode-telegram-bot.git
    cd opencode-telegram-bot
    cp .env.example .env
    # Edit .env with your bot token, user ID, and model settings
    

    .env stays on the host. It is injected at runtime and is not copied into the image.

    Published container images

    Official container images are published to GitHub Container Registry at ghcr.io/grinev/opencode-telegram-bot for linux/amd64 and linux/arm64. Download the latest stable image with:

    docker pull ghcr.io/grinev/opencode-telegram-bot:latest
    

    To use a specific published release, replace latest with its version number (without the v prefix). Release candidates use their exact version tag, such as 0.27.0-rc.1, and do not update latest. The Docker Compose commands below build the image locally instead of using the published image.

    Linux (OpenCode on the host at 127.0.0.1:4096):

    docker compose up -d --build
    

    macOS / Windows (Docker Desktop): host networking does not reach OpenCode on the Windows/macOS localhost. Use the Desktop override, which talks to the host via host.docker.internal:

    docker compose -f docker-compose.yml -f docker-compose.desktop.yml up -d --build
    

    Follow logs:

    docker compose logs -f opencode-bot
    

    Stop:

    docker compose down
    
    Persistence

    Runtime state (settings, logs, SQLite databases) is stored in a Docker named volume opencode-bot-data mapped to /app/data inside the container. The volume is created automatically on first run. It is the bot's own state, not your project files. OpenCode on the host continues to edit projects on the host disk.

    Configuration

    All configuration is provided through environment variables in the .env file. Compose also sets OPENCODE_TELEGRAM_CONTAINER=1 so the bot can warn about commands that need the host filesystem or a local OpenCode process.

    • OPENCODE_API_URL — URL of the OpenCode server. On Linux with the default compose file this is http://127.0.0.1:4096 via network_mode: host. The Desktop override sets http://host.docker.internal:4096.
    • BOT_HEALTH_PORT — the image serves a health endpoint on 127.0.0.1:3100 by default, and its HEALTHCHECK probes /health/live: the container is unhealthy only when the bot itself does not answer, or when the endpoint could not start (for example, the port is taken on the host under network_mode: host; the log says why). OpenCode being down does not make the container unhealthy — /health reports it as degraded and /health/ready answers 503. Set another port in .env if 3100 is taken, or 0 to turn the endpoint off (the healthcheck then always passes). The endpoint is reachable from the host's loopback with the Linux compose file and only from inside the container with the Desktop override.
    • OpenCode V2 in Docker — both compose files point to a V1 server on port 4096. For V2, set OPENCODE_SERVER_VERSION=v2, OPENCODE_SERVER_PASSWORD and OPENCODE_API_URL together: in .env on Linux (for example http://127.0.0.1:49374), and by changing the URL in docker-compose.desktop.yml on Docker Desktop to the host address the V2 server listens on.
    Commands that are not available in Docker

    These need the bot process to see host project paths or to spawn/stop opencode in the same machine namespace. The default image does neither, so the bot replies with a warning instead of a generic error:

    • /open — directory browser to add a project
    • /ls — project file browser / download / attach
    • /opencode_start and /opencode_stop
    • /worktree

    /projects, /sessions, prompts, and live updates still go through the OpenCode HTTP API and work as usual.

    Port 4096 is not exposed by the bot image; it belongs to the OpenCode server, which runs separately. The only port the bot itself listens on is the loopback health port.

    Available Scripts

    ScriptDescription
    npm run devBuild and start (development)
    npm run buildCompile TypeScript
    npm startRun compiled code
    npm run release:prepareBump version and seed release notes
    npm run release:notes:previewPreview auto-generated release notes
    npm run lintESLint check (zero warnings policy)
    npm run typecheckType-check src and tests
    npm run formatFormat code with Prettier
    npm testRun tests (Vitest)
    npm run test:coverageTests with coverage report

    Note: No file watcher or auto-restart is used. The bot maintains persistent SSE and long-polling connections — automatic restarts would break them mid-task. After making changes, restart manually with npm run dev.

    Troubleshooting

    Bot doesn't respond to messages

    • Make sure TELEGRAM_ALLOWED_USER_ID matches your actual Telegram user ID (check with @userinfobot)
    • Verify the bot token is correct

    "OpenCode server is not available"

    • Ensure an OpenCode server is running at the configured OPENCODE_API_URL (default: http://localhost:4096 on V1, http://127.0.0.1:49374 on V2)
    • Check that OPENCODE_SERVER_VERSION matches the server you run, and on V2 that OPENCODE_SERVER_PASSWORD is correct (an authentication error in the bot log means a wrong password)
    • For a local setup, you can start it with opencode serve or use /opencode_start in Telegram
    • For VPS/systemd setups with scheduled tasks, enable OPENCODE_AUTO_RESTART_ENABLED=true to let the bot restart a local OpenCode server when health-checks fail
    • If OPENCODE_API_URL points to a remote server, verify that the address is reachable from the bot machine and that the remote server is healthy

    No models in model picker

    • Add models to your OpenCode favorites: open OpenCode TUI, go to model selection, press Ctrl+F on desired models
    • Verify OPENCODE_MODEL_PROVIDER and OPENCODE_MODEL_ID point to an available model in your setup

    Linux: permission denied errors

    • Make sure the CLI binary has execute permission: chmod +x $(which opencode-telegram)
    • Check that the config directory is writable: ~/.config/opencode-telegram-bot/

    Contributing

    Please follow commit and release note conventions in CONTRIBUTING.md.

    Community

    Have questions, want to share your experience using the bot, or have an idea for a feature? Join the Telegram group for announcements and discussions, or start a thread in GitHub Discussions.

    Support

    This project is free and open source. Development and testing run on paid AI model subscriptions, and donations go directly toward those.

    If you find this bot useful, you can support it here: Donate

    Any amount helps — thank you!

    License

    MIT © Ruslan Grinev