ServerChan3 (Server酱) push notifications when a turn finishes — title, model, project directory, git branch, status and a reply excerpt, with subagent filtering and fire-and-forget delivery.
Install
# from npm (prebuilt)
dsh plugin --profile web add dsh-serverchan-notify
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:nickhelion/dsh-plugins#path:/packages/serverchan-notify
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
🔔 dsh-serverchan-notify
A DeepSeek Harness (DSH) plugin that pushes a Server酱3 (ServerChan³) notification to your WeChat every time an agent turn finishes an answer — and every time the agent asks you a question. Codex Stop-hook parity for DSH, plus the case codex never covered: an agent blocked on you.
What it does
- Subscribes to the DSH session event stream (
ctx.on("session/event", …)). - On every
turn/end(completed/error/blocked/max-tokens/aborted), pushes one Markdown notification to Server酱3 → your WeChat. Each notification carries: conversation title, model, project directory, git branch, turn status, finish time, session id, and the latest reply excerpt (truncated at 16 000 chars). - Also pushes when the agent asks you a question. An
ask_user_questiontool call means the agent is blocked until a human answers — the worst case to miss — so it gets a notification of its own, carrying every question, its options, and their descriptions. Disable withnotifyQuestions: false. - Fire-and-forget: a failed push only logs a warning and never blocks or interrupts the agent loop.
- Skips subagent sessions by default (no spam from internal subtasks).
| codex Stop hook | this plugin | |
|---|---|---|
| Trigger | one per finished turn | one per finished turn (turn/end), plus one per ask_user_question call |
| Key source | env / ~/.codex/secrets/… |
env / config / $DSH_HOME/secrets/… (see SendKey resolution) |
| Failure handling | never blocks the turn | never blocks the turn |
| Scope | global hooks.json |
global $DSH_HOME/cordis.patch.yml (or per profile) |
🔐 This repository contains no SendKey. Keys come from the environment, a file, or plugin config — never from source code.
Requirements
- DeepSeek Harness (DSH) — verified against
0.1.1-rc.2and0.1.2-rc.1(@deepseek-ai/cordis^4.0.1). The plugin reads the session log through whichever accessor the running Harness exposes, so both API lines are supported. - Node.js ≥ 18
- A Server酱3 SendKey (free account at https://sct.ftqq.com/)
Quick start
1. Get a SendKey
Log in at https://sct.ftqq.com/, open the SendKey tab, and copy your key — it looks like sctp<number>txxxx…. The plugin auto-derives your dedicated push domain (https://<number>.push.ft07.com/send/<key>.send); legacy keys without a channel number use https://sctapi.ftqq.com/<key>.send.
2. Save the key (recommended)
mkdir -p ~/.dsh/secrets
echo '你的SendKey' > ~/.dsh/secrets/serverchan_sendkey
chmod 600 ~/.dsh/secrets/serverchan_sendkey
3. Register the plugin
Edit your DSH patch layer and restart the harness:
# global — all profiles (like codex's global hooks.json):
# $DSH_HOME/cordis.patch.yml (default ~/.dsh/cordis.patch.yml)
# per profile:
# $DSH_HOME/profiles/<name>/cordis.patch.yml
- insert:
- id: serverchan-notify
name: 'dsh-serverchan-notify'
config:
sendkeyFile: '~/.dsh/secrets/serverchan_sendkey'
Plugin rows are only resolved at boot — restart the harness process after editing.
Installing the package
The package declares a dsh.bundle manifest, so npm installation is one command:
# recommended
dsh plugin --profile web add dsh-serverchan-notify
# fixed version
dsh plugin --profile web add dsh-serverchan-notify@1.0.2
# GitHub monorepo fallback
dsh plugin --profile web add 'github:nickhelion/dsh-plugins#main&path:/packages/serverchan-notify'
# local development
git clone https://github.com/nickhelion/dsh-plugins.git
dsh plugin --profile web add "$PWD/dsh-plugins/packages/serverchan-notify"
The bundled cordis.patch.yml inserts the plugin row with all-default config; override any option by addressing the row id serverchan-notify from your own patch layer.
SendKey resolution
The first non-empty value wins, in this order:
| # | Source | Example |
|---|---|---|
| 1 | env var SERVERCHAN_SENDKEY |
export SERVERCHAN_SENDKEY=sctp… |
| 2 | inline config sendkey |
config.sendkey: 'sctp…' |
| 3 | env var SERVERCHAN_SENDKEY_FILE (path to a key file) |
export SERVERCHAN_SENDKEY_FILE=… |
| 4 | config sendkeyFile (supports ~) |
config.sendkeyFile: '~/.dsh/secrets/…' |
| 5 | default file $DSH_HOME/secrets/serverchan_sendkey |
~/.dsh/secrets/serverchan_sendkey |
Configuration
| Key | Default | Description |
|---|---|---|
sendkey |
— | Inline key (overridden by the SERVERCHAN_SENDKEY env var) |
sendkeyFile |
$DSH_HOME/secrets/serverchan_sendkey |
Path to a key file; ~ is expanded |
reasons |
[completed, blocked, error, max-tokens, aborted] |
Which turn/end reasons trigger a push (interrupted is never pushed) |
notifyQuestions |
true |
Push when the agent calls ask_user_question and waits for you |
notifySubagents |
false |
Also push subagent sessions (off by default to avoid spam) |
timeoutMs |
8000 |
HTTP timeout in milliseconds |
maxResponseChars |
16000 |
Reply excerpt / question text truncation length |
disabled |
false |
Disable without removing the row (no key read, no subscription) |
Sample notification
Turn finished:
DSH 完成:
- 对话标题:…
- 模型:deepseek-official / deepseek-v4-pro
- 项目目录:
/home/you/project- Git 分支:
main- 回合状态:完成
- 完成时间:2026-08-18T21:00:00.000Z
- 会话 ID:
session-12DSH 最新回复
…the latest assistant reply…
The agent is waiting on you:
DSH 提问:
- 对话标题:…
- 模型:deepseek-official / deepseek-v4-pro
- 项目目录:
/home/you/project- Git 分支:
main- 提问时间:2026-08-18T21:05:00.000Z
- 会话 ID:
session-12DSH 正在等待你的回答
1. Choose Mode
Which path should I take?
- Ship it (Recommended) — small and reversible
- Plan first — one extra review round
2. Scope
- README
- Tests > 该问题可多选
Troubleshooting
| Symptom | Fix |
|---|---|
| "未找到 Server酱 SendKey" warning at boot | Provide the key via one of the 5 sources above |
HTTP 403 / timeout in the log |
Network / proxy issue; the push domain is derived from the key (<n>.push.ft07.com) |
| No push after restart | Confirm the row id is unique and the package resolves — dsh --profile web --dump-config | grep -A8 serverchan-notify |
| Too many pushes | Turn on notifySubagents: false (default), trim reasons, or set notifyQuestions: false |
| Question reminder shows "无法解析本次提问内容" | The model emitted malformed tool arguments; the harness still got the question — open DSH to answer |
| Temporarily stop | disabled: true, then restart |
Development
npm install # installs devDependencies (cordis) for the smoke test
npm test # smoke test — stubbed fetch, no real push
REPORT=1 npm test # smoke test + print the assembled payload
npm run test:live # send one real test push with the configured key
Repository layout
lib/index.js plugin entry — event subscription, message assembly, HTTP push (turn end + agent question)
test-send.mjs standalone real push (same key resolution order as the plugin)
smoke-test.mjs cordis in-process test with a stubbed fetch
package.json package metadata + npm scripts
README.md English docs
README.zh-CN.md 中文文档
Contributing
PRs are accepted in the canonical nickhelion/dsh-plugins monorepo. Two ground rules:
- Never commit a SendKey (or any absolute machine path) — keys flow through env / file / config only.
- The event listener must stay non-throwing and fire-and-forget — a notification must never affect the harness.
License
Links
More in this category
xmanrui/dsh-im★ 1995
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★ 1750
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.
inclusionAI/Avernet#deepseek-harness-channel-bcn★ 620
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.
Oscar-Williams/dsh-deepcanary★ 90
Evidence-first attention supervision for DeepSeek Harness with C0–C3 policy, deduplicated Inbox alerts, quiet hours, and redacted outcome records.
omdsh-dev/dsh-notification★ 89
Desktop notifications for turn completions, with per-outcome controls and keyword rules.
whyihaveyou/dsh-suite#plugin-notify★ 60
IM webhook and local notifications on turn completion, errors, or approval (Feishu/WeCom/DingTalk/Slack/Discord/custom).
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.