DeepSeek Harness Plugin

nickhelion/dsh-plugins#serverchan-notify

Stars ★ 0 Downloads (30d) 1,014 Category Notifications & Integrations Added 2026-08-22 npm dsh-serverchan-notify

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.

English · 简体中文

CI

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_question tool 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 with notifyQuestions: 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.2 and 0.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-12

DSH 最新回复

…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-12

DSH 正在等待你的回答

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:

  1. Never commit a SendKey (or any absolute machine path) — keys flow through env / file / config only.
  2. The event listener must stay non-throwing and fire-and-forget — a notification must never affect the harness.

License

MIT

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →

Community comments

Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.