Bridges DeepSeek Harness to LINE: runs its own signed webhook server, sets up a Cloudflare Tunnel (quick URL or an API-token tunnel), keeps the LINE webhook endpoint pointed at the current tunnel, and gives each LINE user a separate session with a chosen persona, plus optional scheduled check-ins. Requires a LINE Messaging API channel (Channel ID and Channel Secret); only allow-listed LINE users, or users approved from the pending queue, can talk to the bot.
Install
# from npm (prebuilt)
dsh plugin --profile web add dsh-line-bot
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:Hanson0901/dsh-line-bot
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
Languages / 語言: 繁體中文 · 简体中文 · English · 日本語 · 한국어
A plugin that connects a LINE Official Account (Messaging API) to DeepSeek Harness. Replies are produced by the DSH Agent in the same process — essentially chatting with your DSH assistant on LINE. Personas can come from the dafeiyu plugin (dsh-persona-dafeiyu) when it is installed, or from the plugin's own custom personas (no persona plugin required).
Built in:
- Webhook server: opens a local HTTP server on
127.0.0.1, handling LINE'sX-Line-Signatureverification, event deduplication, and a separate queue per user. - Cloudflare Tunnel: one click opens a quick tunnel (
*.trycloudflare.com, no Cloudflare account needed), or paste a Cloudflare API token to create a named tunnel + DNS for a fixed URL; once the URL is ready it writes the webhook endpoint back to LINE and runswebhook/test. - LINE credentials: fill in Channel ID + Channel Secret and it issues an access token automatically (
/v2/oauth/accessToken, about 30 days, auto-renewed near expiry); you can also paste an existing Channel Access Token. - Without the dafeiyu plugin: the plugin falls back to its own Traditional-Chinese editions of 大肥魚 / 阿茶 / 聽瀾, stored in the same
personas.jsonand editable like custom personas. Selecting dafeiyu again switches back automatically. - Proactive messages: a scheduler built into the plugin (no launchd). Each user gets an independent randomized countdown (between a minimum and maximum interval); it only speaks when the countdown is due and the user has been idle long enough. Configurable min/max interval, daily/monthly caps, minimum gap, quiet hours, idle time, unanswered limit (pause after that many unanswered proactive messages, reset when the user replies), target users and prompt. The Agent can reply
SKIPwhen it is not a good moment. - Split replies: optionally split a reply into up to five LINE bubbles by blank line (paragraph) or every newline, instead of one long bubble; the panel can change the mode or turn it off.
- Full settings panel: every setting lives under Settings → LINE Bot and is stored in
<DSH_HOME>/line-bot/config.json(mode 600).
About "log in with LINE Business ID and have the panel create the bot": since 2024-09 LINE only allows creating a Messaging API channel manually in LINE Official Account Manager, with no public API; LINE Login only authenticates identity and cannot grant management rights over an Official Account. So the panel does not create the bot, but it gives you the correct entry links and automates everything after "you have the Channel ID / Secret" (issuing the token, setting the webhook, testing it).
Installation
Requirements: DeepSeek Harness ≥ 0.2.0-rc.1, Node.js ≥ 22. The persona plugin (dafeiyu, dsh-persona-dafeiyu) is optional — the plugin's built-in custom personas work without it.
Option 1: Install from the panel (recommended)
In DSH: Settings → Plugins → Install bundle, enter dsh-line-bot and install, then refresh the page. A LINE Bot page appears in Settings.
Option 2: One-line npx install
First quit DSH completely (on the desktop app, close the window and make sure no process is left), then run:
npx dsh-line-bot install
It detects which profile to install into (defaults to desktop; use --profile <name> to choose), installs the package with DSH's bundled pnpm, adds the bundle to the profile, and reminds you to restart DSH.
npx dsh-line-bot status # which profile it is installed in, and whether it is enabled
npx dsh-line-bot uninstall # remove it (settings and credentials are kept)
Option 3: Manual
dsh plugin --profile desktop add dsh-line-bot
Then add dsh-line-bot to the dsh.profile.bundles array in ~/.dsh/profiles/desktop/package.json (see what npx dsh-line-bot install does), or install from the panel instead.
If it is not on npm yet, you can install directly from GitHub:
npx github:Hanson0901/dsh-line-bot install --spec github:Hanson0901/dsh-line-botOr from source:
git clone https://github.com/Hanson0901/dsh-line-bot.git, then choose that folder in the DSH panel's "Install bundle", or rundsh plugin --profile desktop add /path/to/dsh-line-bot.
Companion plugins (optional)
The bot works on its own; these plugins add capabilities:
| Plugin | What it adds | Recommended |
|---|---|---|
dsh-persona-dafeiyu |
Persona catalog and Tieba sync | Yes |
dsh-meme |
Image/sticker replies | Yes |
dsh-tieba-dive |
Source of Tieba learning sync | Optional |
The install CLI detects what is missing and offers to install it:
npx dsh-line-bot install --with-companions
npx dsh-line-bot install --no-companions
Without them: no dafeiyu means only plugin-local personas; no dsh-meme means text-only replies; no dsh-tieba-dive means Tieba sync stays off.
First run (5 steps)
- Create / obtain credentials: go to LINE Official Account Manager and create an Official Account → LINE Developers Console and create (or pick) a Messaging API channel → open the Use webhook toggle on the "Messaging API" tab → copy the Channel ID and Channel secret.
- Fill in the panel: under "LINE Bot → LINE credentials", paste the Channel ID and Channel Secret, click "Save changes" → "Verify and read bot info". On success you will see the bot's name and Basic ID.
- Start the webhook server: on "Overview", click "Start all", or "Start" to bring up both the webhook server and the tunnel (auto-start is on by default).
- Open the tunnel: for a quick tunnel just click "Start tunnel"; for a fixed URL, paste an API token under "Cloudflare Tunnel" → "Verify API token" → "Create/update tunnel and DNS" (token permissions: Account → Cloudflare Tunnel → Edit, Zone → DNS → Edit, Zone → Zone → Read). A quick tunnel's URL changes on every restart (the plugin writes the new URL back to the LINE webhook automatically); a named tunnel's URL is fixed.
- Auto-configure the webhook: once the tunnel is ready the endpoint is PUT to LINE automatically; if that fails, click "Apply tunnel URL to webhook" and then "Test webhook". After that, add the bot as a friend in LINE and send it a message; the first message lands in the pending queue — approve your userId under Users in the panel before the bot replies (the allowlist starts empty).
Panel sections
At the top of the panel is a sticky save bar: "Save changes / Refresh" stays visible wherever you scroll. Below it is a quick navigation menu; clicking an item jumps to that section (the current section is highlighted while scrolling).
| Section | Contents |
|---|---|
| Overview | Green-light status for webhook server / tunnel / LINE / persona / proactive messages, public URL, one-click bring-up and start/stop |
| LINE credentials | Channel ID, Channel Secret, Access Token, auto-issue, loading animation, split replies, bot info, webhook apply/test, allow-list |
| Cloudflare Tunnel | quick / API token modes, token, hostname, tunnel name, Account/Zone ID, download cloudflared, start/stop, auto-configure webhook, bring your own public URL |
| Model & provider | Pick the provider/model and reasoning effort for LINE replies; disables DeepSeek balance when the provider is not deepseek-account |
| Reply persona | Choose a persona (dafeiyu or a plugin custom one), add/edit/delete custom personas, copy the current persona into a custom one, enforce, allow users to switch personas, switch dafeiyu to session mode, test an Agent reply |
| Tieba learning sync | Writes Tieba tone samples into the persona (built-ins use an overlay), preview diff, sync now |
| Jokes | Text joke library: built-in seeds, Tieba quotes, wanjiqi barrage memes; per-source toggles, per-turn injection count, add/delete entries |
| Personal memory | Per-user long-term memory, expiry cleanup, daily self-review, manual delete |
| Memes | Reply with images/stickers from the dsh-meme library, enable/disable, image limit, and sample previews |
| Sticker & image vision | Fetch incoming LINE stickers or images and show them to the model; when the model cannot read images, describe them with modlens or a vision model (can be disabled) |
| DeepSeek balance | Current balance, per-turn context, low-balance proactive reminder, threshold and cooldown (deepseek-account only) |
| Proactive messages | Toggle, per-user countdown, min/max interval, unanswered limit, daily/monthly caps, minimum gap, quiet hours, idle, target users, prompt, send a test now, statistics (next possible time and paused users) |
| Users | Pending approval queue (approve / deny), the DSH session each LINE user maps to, their own workspace folder, their current persona (editable), message count, last interaction, clear memory / reset session |
| Groups | Per-group session, workspace folder, persona, message count; reply chance when not addressed; always reply on @ / quote; clear group memory |
| Advanced | Port, Agent provider/model/effort/cwd/timeout, one workspace per user (and its root), welcome/error/empty replies, logs, reload host modules (dev) |
Configuration files
<DSH_HOME>/line-bot/config.json: all settings, including the LINE secret and Cloudflare token (mode 600; plaintext is never returned to the panel).<DSH_HOME>/line-bot/state.json: LINE user ↔ DSH session mapping, message counts, proactive-message counters, webhook state.<DSH_HOME>/line-bot/logs/YYYY-MM-DD.log: daily logs (the panel also shows the last 400 lines).
DSH_HOME defaults to ~/.dsh.
How it works
- LINE POSTs a message to the Cloudflare tunnel → the plugin's webhook server (after signature verification it returns 200 immediately).
- It finds (or creates) the DSH session and workspace folder for that
userId, then decides the session's persona: for dafeiyu it sets the session persona through dafeiyu's HTTP bridge; for a plugin custom persona it first asks dafeiyu to step aside in that session (none), then injects the custom persona into the system prompt. - It creates/resumes the Agent in the same DSH process with
agents.create/agents.resume, sends one user message withfollowup, and waits for the turn to end, subagents to settle, and the session to flush. - It takes the last assistant text from the session events and replies with LINE reply; if the reply token has expired it falls back to push.
- Every minute the scheduler checks each user's countdown; when it is due and the user has been idle long enough it asks the Agent to say something on its own and pushes it. After too many unanswered proactive messages it pauses until the user replies.
Model & provider
The "Model & provider" card chooses the provider/model used for LINE replies:
- Providers come from this DSH profile; models are fetched live and the first one is preselected when you pick a provider.
- "Follow DSH default" leaves the choice to
agentDefaultModel(the panel shows the effective value). - Reasoning effort can stay empty to use the provider default.
- DeepSeek balance and low-balance reminders only work when the provider is
deepseek-account; other providers grey out that card, and switching back restores it.
Persona sources
- dafeiyu (optional): when
dsh-persona-dafeiyuis installed, the panel lists its personas (built-in + your own); LINE selects them per session, without changing other GUI conversations. It must be insessionmode; the panel tells you and offers a one-click switch. - Plugin custom personas: no persona plugin required. In "Reply persona → Custom personas" you can add/edit/delete them; data lives in
<DSH_HOME>/line-bot/personas.json(0600). When a custom persona is selected, the plugin asks dafeiyu to opt out in that session (if it is installed), then injects the custom persona into that agent's system prompt. - Both kinds appear in the same dropdown. The same applies when a user switches with a LINE command (
人設,人設 2,人設 <name>).
Groups and multi-user chats
When the bot is added to a group (or a multi-user room):
- Being @-mentioned always triggers a reply, and quoting any message always triggers a reply; any other message is answered only when a dice roll against the group reply chance (default 15%) succeeds, otherwise it stays quiet.
- Each group gets its own DSH session, workspace folder, persona and personal memory, separate from direct chats and other groups.
- The
personacommand works in groups too; the panel's Groups card lets you tune the reply chance, toggles, per-group persona and clear a group's memory. - Each member has their own memory points inside a group; replies also look at the last 4–6 messages from others so the bot can pick up the thread.
- If you join a group late, use Import chat on the Groups card and pick a LINE-exported
.txt; it builds a group summary and per-member memory points (stored locally only). - Proactive messages and DeepSeek balance reminders still target direct chats only.
Per-user memory and personas
- Memory is not shared: every LINE user gets their own DSH session and their own Agent workspace folder
<DSH_HOME>/line-bot/users/<LINE userId>/. The files the Agent sees,AGENTS.md, and workspace memory are specific to that user; nobody reads anyone else's. You can turn this off under "Advanced → One workspace per user" (off means everyone sharesagent.cwd, i.e. the old behaviour); you can also pointagent.workspaceRootat another root. - Users can choose their persona: when "Reply persona → Allow users to switch personas" is on, LINE users can send:
人設(or人格/persona) → lists available personas and the current one.人設 2→ switch by list index;人設 阿茶→ switch by name;人設 預設→ back to the panel default. The switch only affects that user and applies from the next reply; an admin can also change it from the persona dropdown in the "Users" table.
- Clear memory: "Clear memory" in the Users table deletes that user's session and their workspace folder (including files), starting from a clean slate; "Reset session" only keeps the folder.
Tieba learning auto-sync
The "dive into Tieba" plugin evolves its own tone at most once a day (stored in <DSH_HOME>/tieba-duty/persona.json), and that is a separate system from the dafeiyu persona LINE uses (<DSH_HOME>/storages/dsh-persona-dafeiyu/personas.json). This plugin can bridge them:
- In the panel, "Reply persona → Tieba learning sync" lets you set the toggle, the target persona (any dafeiyu persona, including built-ins), the check interval (default 60 minutes), whether to sync personality numbers, and whether to reload the dafeiyu plugin after writing. Built-in personas cannot be edited in place, so their learning goes to
<DSH_HOME>/line-bot/persona-overlays/<id>.mdand is injected every turn without reloading; custom personas are edited directly. - Each check compares the Tieba persona version; it only acts on a new version. It replaces only the
## 貼吧學來的口氣section of the target persona text (appending it if missing) and never overwrites other hand-written content; the personality numbers (gentle / sharp / abstract / talkative / image bias) can be updated too. - Before writing it backs up to
<DSH_HOME>/line-bot/persona-backups/personas-<time>.json. - After writing it restarts
dsh-persona-dafeiyuthrough the Cordis loader so it re-reads the store; a failed restart is only a warning — the text is already written and takes effect on the next plugin reload. - If the Tieba plugin is not running or the Tieba persona does not exist, the check is skipped (
pendingshows why it has not synced yet).
Jokes and memes (text)
The Jokes panel lets the persona use a little wordplay. Three sources can be toggled independently:
- Built-in seeds: 10 common internet jokes with usage notes.
- Tieba quotes: import highly-liked short replies from the Tieba style library.
- wanjiqi memes: 6657 live-room barrage memes (optional; heavier style, off by default).
Each turn injects a few entries; at most one per reply. The prompt tells the model not to explain the joke, not to force it, and not to use jokes in serious situations. Add your own by filling in the text and usage fields, then Add to joke library; the file lives at <DSH_HOME>/line-bot/jokes.json.
Add meme bars to Tieba appends 弱智吧, 抽象吧, 搞笑吧 and 梗吧 to the Tieba plugin's bar list (with a backup). You still need to start a Tieba round for it to learn.
Tieba activity awareness
With Advanced → Let the agent know about Tieba activity enabled (default), each reply is preceded by a small block of background facts injected into the system prompt, built from the Tieba plugin's records:
- when the character last browsed Tieba (e.g. "yesterday 22:41, 5 hours ago")
- which sessions already ran today (noon / night)
- whether today's Tieba report exists
- the Tieba persona version and the last reply time
So when someone asks "did you just browse Tieba?" or "have you been on today?", the character answers from the real timestamps instead of making things up. It only reads files under <DSH_HOME>/tieba-duty/; the Tieba plugin does not need to be running, and nothing is written. If no records exist, nothing is injected.
DeepSeek balance
The DeepSeek balance card reads the wallet balance of the DeepSeek account DSH is signed in with (read-only; it never tops up):
- Every reply includes the current balance in the persona's background context, so you can just ask "how much do I have left?".
- When it drops below the threshold (default ¥10, adjustable in the panel), the persona sends you a message in its own words asking you to top up. The wording is generated on the spot, not a fixed template.
- Reminders have a cooldown (default 12 hours) and reuse the proactive-messaging quiet hours and target-user settings.
- Requires DSH to be signed in to a DeepSeek account (deepseek-account). If it is not, the card explains why and everything else keeps working.
- The threshold is money, not tokens: Platform shows a wallet balance, and token conversion varies by model and cache hits.
Personal memory
The character keeps its own memory at <DSH_HOME>/line-bot/memories.json, separated per user:
- When something important comes up (preferences, current situation, promises, notable events), it saves it with
line_memory_addon its own. - Time-limited items (exams, trips, short-term situations) can carry an expiry date and are deleted automatically; you can also just tell it to forget something.
- Once a day (4 AM by default, configurable in the panel) it reviews the list and removes expired items, one-off events that are over, or facts that no longer hold.
- Each turn only injects the most recent N entries (20 entries / 2000 characters by default); the rest stay in the file. The per-user cap defaults to 120 entries and evicts the oldest.
- Passwords, tokens, ID numbers and similar secrets should not be stored; it avoids them.
- The "Personal memory" panel card shows what it remembers, lets you delete entries, prune expired ones, or trigger a review right away.
Memes (dsh-meme)
- Sent images are copied to
<DSH_HOME>/line-bot/media/and kept for 90 days, so LINE can still fetch them when the chat is opened later. With a quick tunnel the public URL changes on restart and older images stop loading; use a named tunnel (API token + your own hostname) for permanent URLs.
The persona can attach a sticker to a text reply, or reply with just an image. Images come from the installed dsh-meme plugin's library (the built-in "大肥鱼" pack has 24 images):
- Each turn injects a numbered sample of the library into context; when the persona wants a picture, it appends
[[meme:#N]](or a caption) at the end of its reply, and the plugin turns that into a LINE image message. - Images are served to LINE through the current Cloudflare public URL (
<url>/media/<token>), and the URL follows quick-tunnel restarts automatically. - The panel's "Memes" card can disable the feature, limit images per reply (1–3), and preview library samples. To add or re-tag images, use dsh-meme's own settings.
- When a LINE sticker arrives, the bot fetches the image and shows it to the model; vision-capable models read it directly, otherwise the bot asks modlens, then tries another vision model, and only then falls back to the keywords LINE provides. Turn "Understand stickers" off in the LINE credentials card to use keywords only.
- Regular images work the same way: the bot downloads them through LINE's content API and attaches them to the message; if the model cannot read images, the same modlens / vision-model description path is used. Turn "Understand images" off in the LINE credentials card to skip them.
- Without dsh-meme installed, the feature stays off and replies are text only.
Diagnostics
- Panel → Advanced → Run diagnostics checks the server, tunnel, public URL, webhook, dsh-meme library, image converters, model, and recent errors; Safe repair only reconnects the tunnel and re-applies the webhook.
- CLI:
npx dsh-line-bot doctor,doctor --fix,doctor --json. - Agent playbook:
AGENTS.md; symptom table:TROUBLESHOOTING.md.
Troubleshooting
- The panel says "cannot connect to the LINE Bot runtime": webServer may not be ready yet; refresh. If it still fails, look for
[line-bot]messages in the DSH logs. - Webhook test fails: make sure
Use webhookis on in the LINE console, the tunnel URL is https, and the local webhook server is running (green in the panel). - Changes to
lib/*.mjsdo not take effect: click "Advanced → Reload host modules (dev)"; you do not need to reinstall the plugin. - Tieba sync does nothing: check
lastErrorin the panel's sync status; confirm the Tieba persona file exists and the target persona id is correct. "Preview diff" compares the current section with what is about to be written. - cloudflared not found: click "Download cloudflared" and the plugin fetches the official release into
<DSH_HOME>/line-bot/bin/; you can also place your own copy and settunnel.binaryPath. - Agent replies with 403 (model only available to Codex): under "Advanced → Agent model", change provider/model to
deepseek-account/deepseek-flash(already the local default), save, and test again. - Persona not applied: with dafeiyu selected it must be in
sessionmode; the panel tells you and offers "Switch dafeiyu to session mode" (an officially supported setting; it only decides whether personas can be picked per session). Plugin custom personas are not affected. - Cloudflare returns 530 / error code 1016: the DNS CNAME target of a named tunnel must be
<tunnel-id>.cfargotunnel.com(not.cfd.tunnel); also, if the subdomain is simultaneously taken by an A record, the edge answers from that host — make sure DNS has only the CNAME.
Privacy
- The plugin talks to no third-party server other than the Cloudflare API and LINE API you configure. No telemetry, no account.
- All settings and credentials live only on this machine in
<DSH_HOME>/line-bot/config.json(mode 600); the panel only shows masked values. - LINE users' sessions, workspace folders and persona choices are stored locally and never uploaded.
- The repository and the npm package contain no credentials, LINE userIds, Cloudflare accounts or domains.
Security notes
- The allowlist starts empty: unknown users are only queued as pending, with no session and no tool access, until you approve them under Users in the panel.
- This attaches the DSH Agent to LINE: anyone you approve can make the Agent use tools on your computer. Approve only LINE accounts you trust, and review the Users list periodically.
- All credentials are stored locally in
config.json(600); the panel only shows masked values; the API only listens on the DSH webServer at127.0.0.1. - Give the Cloudflare API token only the permissions it needs, and revoke it when you no longer use it.
Development
- Host logic:
lib/*.mjs(util/config/line-api/persona/agent-runner/webhook-server/cloudflare/tunnel/nudge/tieba-sync/host). - Panel:
client.js(registerssettings.sectionviawindow.__ModuleLoader__). - Entry point:
index.js(mounts/api/line-bot, dev reload, cleanup on unload).
Links
More in this category
xmanrui/dsh-im★ 3118
Connect IM bots to DeepSeek Harness via QR codes or bot credentials (9 channels: Feishu, WeChat, DingTalk, WeCom, QQ, Slack, Telegram, Discord, and WhatsApp).
shaobeichen/dsh-pocket★ 2685
Remote phone access to the DSH Web UI: scan a QR code for LAN or public (cloudflared tunnel) access with real-time sync, a mobile-adaptive layout, and a settings tab.
OpenPetsHQ/openpets#dsh★ 1373
Bridges DeepSeek Harness lifecycle status, errors, and approval requests to a locally running OpenPets desktop companion.
c1overzz/dsh-bili-scroll★ 1150
Let your DSH agent browse Bilibili on its own, read subtitles, write a daily digest, and @ you when it finds something worth your attention.
inclusionAI/Avernet#deepseek-harness-channel-bcn★ 599
Connects DeepSeek Harness to Avernet's Bot Collaboration Network over WebSocket V2, with automatic onboarding, isolated agent sessions, tool-call events, and multi-bot routing tools.
zaofan-make/dsh-qqbot★ 213
QQ official bot channel for DeepSeek Harness (feature-rich fork of tencent-connect/dsh-qqbot): group and private chat with the full agent, sticker library with auto-tagging and AI meme replies, group management (join approval and mute), botplay interactive card events with paginated catalogs, user extension registry (custom slash commands and QQ tools), scheduled wakeups, remote approvals over QQ, and a floating dock web UI.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.