๐ค dsh-telegram
August 28, 2026 ยท View on GitHub
Telegram remote control for DeepSeek Harness โ your agent in your pocket.
Drive your dsh sessions from Telegram: list, bind, prompt, watch live streaming replies, answer agent questions with one tap, and stop or re-point sessions โ all through the exact same channel the Web UI uses, from any chat you whitelist.
โจ Features
- Full session console โ
/attachbind a session,/statusinspect it, plain text becomes a prompt, live replies edit in place on one message. - Real-time streaming replies โ assistant output is streamed into a single message and edited in place across the whole turn (
๐ญ Think/๐ง toolaction lines per step), then finalized as Telegram HTML with a token-usage footer. - Interactive questions as buttons โ when the agent calls
ask_user_question, the chat gets an answerable inline keyboard instead of a wall of text: tap to answer, tap to cancel; the outcome races the Web UI first-claimant-wins. - One-tap keyboards โ reply keyboards carry
/create/archive/attachand/stop/closeaction rows; session lists and workspace pickers render as inline buttons. Almost everything is a tap, everything still works typed. - Safe by default โ only
allowChatIdscan talk to the bot; everyone else getsโ ๆ ๆ่ฎฟ้ฎใand zero session facts. The plugin opens no inbound port: all traffic is outbound Telegram long polling (optionally through a CONNECT proxy). - Secrets never land on disk โ
botTokenis referenced as!!js process.env.TELEGRAM_BOT_TOKEN; the token lives in the environment (or$DSH_HOME/.env, 0600). - Cold-session resume โ binding and prompting go through the host
apiProxy, the exact path the Web UI uses, including cold-session resume and queued-message semantics.
๐ธ Demo
A real session, driven from Telegram:

| Attach & live streaming reply | One-tap keyboards | Answer a question by tapping |
|---|---|---|
![]() | ![]() | ![]() |
๐ Quick Start
Prerequisites
- A dsh source checkout (the plugin is installed into it) โ or an already-running dsh deployment for the package route.
- Node.js โฅ 22.19, pnpm, git.
- A bot token from @BotFather, and outbound access to
api.telegram.org(or a CONNECT proxy).
Option 1 (recommended): install into your dsh source tree
git clone https://github.com/Kevin66Z0/dsh-telegram.git dsh-telegram
cd dsh-host-telegram
./install.sh /path/to/deepseek-harness # your existing dsh checkout
install.sh syncs the plugin under src/packages/host/telegram, registers it in the
workspace, and (when DSH_HOME is set) writes the mount row into
$DSH_HOME/profiles/web/cordis.patch.yml. It is idempotent โ re-run after git pull to update.
Then three steps, once:
# 1) Inject the token (no plaintext anywhere)
echo 'TELEGRAM_BOT_TOKEN=<token-from-@BotFather>' >> "$DSH_HOME/.env"; chmod 600 "$DSH_HOME/.env"
# 2) Whitelist your chat(s) โ hot-reloaded, per-field override of the plugin row
# in $DSH_HOME/settings.yaml:
# telegram:
# allowChatIds: [123456789] # find yours below
# # proxy: 'http://127.0.0.1:7890' # only if api.telegram.org is blocked
# 3) Restart your dsh service (your usual start command / deployment script)
Find your chat id: with an empty allowlist, the first run logs every rejected chat id โ
copy it into allowChatIds and it activates without a restart.
Verify: the log shows telegram: bot @<username> listening; message the bot /start.
Option 2: already-running dsh deployment
If your dsh is not run from a source checkout, install the plugin package into your profile:
dsh plugin --profile web add git+https://github.com/Kevin66Z0/dsh-telegram.git
โฆthen the same token / allowlist / restart steps. This route installs the plugin as a
separate package (all @deepseek-ai/* imports resolve from the running host). Don't combine
both routes: one plugin row id: telegram per deployment.
Update / remove
cd dsh-host-telegram && git pull && ./install.sh /path/to/deepseek-harness # update
# or, package route: dsh plugin --profile web update/remove @deepseek-ai/dsh-host-telegram
โ๏ธ Configuration
| Field | Type | Default | Meaning |
|---|---|---|---|
botToken | string | required | Bot token; referenced as !!js process.env.TELEGRAM_BOT_TOKEN, injected via env or $DSH_HOME/.env |
allowChatIds | number[] | required | Chats allowed to use the console; empty denies everything (first run logs rejected ids) |
proxy | string | ALL_PROXY, then HTTPS_PROXY | HTTP CONNECT proxy for Telegram API traffic |
The plugin registers the telegram settings namespace: fields in $DSH_HOME/settings.yaml
(or the Web settings page, Plugins โ Telegram) override the composition row and rebuild the
bot session without a restart.
๐น๏ธ Commands
| Command | What it does |
|---|---|
/attach [scope|n|id|none|arc] | Bind this chat to a session (scope picker โ session list as inline buttons) and show the recent dialogue + running-turn actions; plain text then goes to the bound session |
/create | Creation sub-menu: /new (fresh session) or /fork (fork the bound session) |
/operate | Operation sub-menu: /archive, /stop, /curTasks |
/new [path|n|none] | Create a session (workspace picker; none = ungrouped) |
/fork [n|id] | Fork from the last completed turn of a session and bind to it |
/archive [n|id] | Archive a session (two-step confirm; ungroups it and unbinds) |
/delete [n|id] | Archive from the picker |
/stop | Cancel the running turn of the bound session (inline list when unbound) |
/keyboard | Re-wake the reply-keyboard area after /close or an overlay |
/status [n|id] | Session details: last assistant output, state, usage footer |
/model [name] | Set the global default model (tap the model list, or type a name) |
/rename [title] | Rename the bound session (interactive without argument) |
/curTasks | Print the bound session's todo list (same source as the Web sidebar) |
/preset [name|n] | Pick an agent preset (PTC / standard / minimalโฆ) |
/start | Full help; /close dismisses the keyboards |
๐ Security & Privacy
- Whitelist-gated: chats outside
allowChatIdsare rejected with a fixed generic reply and learn nothing about your sessions. - No inbound listener: the plugin only long-polls Telegram outbound; no port to open, no public IP needed, works behind NAT.
- Secrets not in config: the token is an env reference; docs and templates carry placeholders only.
- Rotation is cheap: if a token ever leaks,
/revokeit in @BotFather โ the allowlist, not the token, is the real access control.
๐ง How it works
Telegram app dsh process (one node process)
โโโโโโโโโโโโโ HTTPS โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ your phoneโ โโโโโโโโโบ โ grammY Bot (long polling, this plugin) โ
โโโโโโโโโโโโโ outbound โ โ apiProxy (the Web UI channel) โ
โ โผ โ
โ sessions / agent loop / LLM / tools โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The plugin is a Cordis function plugin (name: telegram, inject: [apiProxy]) โ the same
plugin architecture every dsh component uses, so it composes into any profile that stacks
dsh-web-app (headless-only hosts lack apiProxy and cannot mount it). No durable stream of
its own: it reads the session/question event feed, exactly like the web UI.
โ FAQ
Why does it need the web profile? It drives sessions through apiProxy, the same RPC
channel the Web UI uses โ a headless-only dsh has no apiProxy.
How do I find my chat id? Leave allowChatIds empty, message the bot once, and copy the
id from the log line about the rejected chat.
api.telegram.org is blocked in my region? Configure proxy in the telegram: settings
section (defaults to ALL_PROXY/HTTPS_PROXY).
My dsh upstream already ships a telegram package? install.sh overwrites the plugin
source with this repo's version; or use only the package route โ never both for the same row.
Plugin fails at startup? Usually the token didn't reach the process: write
$DSH_HOME/.env and restart. Config errors fail loudly at load.
๐ ๏ธ Development
Source mirrors packages/host/telegram from the dsh monorepo. Contributors keep working in
the monorepo (its AGENTS.md applies) and sync back here:
bash scripts/sync-from-monorepo.sh [monorepo-path] # defaults to ../dsh/src
The READMEs (this file and the Chinese mirror) are maintained in this repo and are not
overwritten by the script. Built lib/ is committed so package consumers never build.
๐ License
MIT. docs/official/ mirrors Telegram's public Bot API documentation for offline reference.
Built on DeepSeek Harness.


