DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
N

dsh-notification-badge

Notification Badge

桌面、浏览器和 webhook 通知,以及 DeepSeek Harness 的应用图标提示徽章——了解您的代理何时完成一轮操作、遇到错误或等待您的批准。

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:suleymanyaryev/dsh-notification-badge#d7bd5101cfb54751efbad7e336b5931813c30599
README兼容性版本

兼容性与来源证明

Notification Badge 以 dsh-notification-badge 发布,当前版本为 0.1.0。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/10/18

版本

0.1.0stable
2026/10/18

相关插件

正在加载相关插件…

最新版
0.1.0
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 0
周下载
0
最近提交
2026/10/18
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 integrations-communication 分类下经过校验的插件。

Acp App@deepseek-ai/dsh-acp-appdsh ACP 配置文件包:基于 dsh-base 的仅限自动化的 JSON-RPC stdio 和进程生命周期管理Remote Web Ui@linxin666/dsh-remote-web-ui通过扫码配对访问 dsh Web GUI,共享一个官方界面:设置按钮旁的二维码可将手机和 PC 配对到同一个 Web GUI(手机采用竖屏触控适配层,PC 使用完整桌面界面),通过一次性令牌和 rRemote Bridge@linxin666/dsh-remote-bridgeDSH 远程桥接:主机端通过唯一且精确的 /ios/v1 WebSocket 路由提供协议 v1——会话列表、历史记录基线、提示、包含工具活动的实时回合增量、中断以及进程内代理审批——连接到通过一次性配对的设备Ab Wechat Scrapedsh-ab-wechat-scrape--- description: "树外 wechat_scrape 工具:获取微信公众号文章,过滤推广区块,并将每篇文章保存为 Markdown 文件,供此机器的 dsh 配置文件维护者使用。" kind: "package-reference" ---

README

dsh-notification-badge

Desktop, browser + webhook notifications and an attention badge on the app icon for DeepSeek Harness on macOS · Linux · Windows: know when your agent finishes a turn, hits an error, or is waiting for your approval — without watching the tab.

Long agent turns are the norm: you kick off a task, switch away, and come back to find the agent finished five minutes ago — or worse, stuck on an approval prompt the whole time. dsh-notification-badge listens to the harness's own lifecycle events, pings you the moment your attention is needed, and keeps a count on the application icon while you are away.

What it does

EventTriggerDefault
Agent finishedagent/status flips running → idle, and the turn ran ≥ minTurnDurationMson
Agent erroragent/error (a step or turn errored)on
Approval neededapproval/request waterfall (observe-only; always delegates with next())on
Waiting for youa session's pendingInteraction appears (browser half)on
App-icon badgeeither of the above while the window is not focused (desktop shell)on

Each event can go to:

  • Desktop notification — zero dependencies: osascript (macOS), notify-send (Linux), PowerShell toast (Windows), optionally with a sound on macOS.
  • Browser notification — the standard Notification API in the Web UI.
  • Webhook — a JSON POST with a Slack-compatible text field, so a Slack incoming webhook works as-is. Other services need their own field: Discord, for example, ignores text and wants the same string as content, so point the webhook at a small relay (or a Slack-compatible bridge) when you need Discord messages.
  • App-icon badge — the count of sessions that need you, on the macOS Dock tile, the Windows taskbar button, or the Linux launcher entry.

Where each channel fires

ChannelRuns onBest for
Desktop (desktop)the machine running the dsh serverdsh web on your own machine
Browser (browser)the machine viewing the Web UIa remote server, or any Web UI use
Badge (badge)the machine viewing the Web UI, desktop shell onlyseeing "3 things need you" at a glance
Webhook (webhookUrl)wherever the URL pointsphones, Slack, unattended runs

Browser notifications ask for permission on your first click or keypress, and by default popups appear only while the window is hidden or unfocused — a window you are looking at already has your attention (set browserOnlyWhenHidden: false to change that).

The badge counts a session once, while the window is unfocused, and clears the moment you come back — it means "things you have not looked at yet", not "unread messages". Sessions that stay short (minTurnDurationMs) are ignored, and subagent sessions never notify or badge.

Desktop and browser channels overlap on a local desktop

On the DeepSeek Harness desktop app the server and the page run on the same machine, so both default-on channels fire for one event: a native osascript/notify-send notification from the host and a page Notification (which Electron also renders natively). That is two popups per turn. Keep one:

# ~/.dsh/profiles/desktop/cordis.patch.yml
- id: notify-badge
  name: dsh-notification-badge
  config:
    desktop: false     # the page already notifies, and owns the app-icon badge

desktop: true is the right default for dsh web on a remote or headless machine, where the page is somewhere else.

Do not run this together with dsh-dock-badge. Both drive the same Badging API and each clears the icon when the page loads, so they overwrite each other's count. This plugin covers everything that one does (and reads pending interactions from uiSession.sessionStatus, which the session list does not expose), so keep only one of them enabled.

Install

The package is a bundle: dsh plugin add writes the dependency and selects the bundle row.

# Web / headless profiles:
dsh plugin --profile web add dsh-notification-badge

The desktop profile is owned by the application: install it from Settings → Plugins in the DeepSeek Harness app. dsh plugin --profile desktop add … also works, but only with the app fully quit and the profile initialized once (dsh refuses to touch an uninitialized desktop profile).

The package ships plain ESM JavaScript — no build step, so a git or registry install needs no allowBuilds entry. The Web UI picks the client bundle up on the next load.

Manual installation

Add the dependency to ~/.dsh/profiles/<profile>/package.json and list it as a bundle:

"dsh": { "profile": { "bundles": ["…", "dsh-notification-badge"] } }

Configuration

Override the row in your profile's cordis.patch.yml:

- id: notify-badge
  name: dsh-notification-badge
  config:
    minTurnDurationMs: 10000        # only notify for turns ≥ 10s
    webhookUrl: 'https://hooks.slack.com/services/XXX/YYY/ZZZ'
    notifyOnApproval: true
    desktop: true
    browser: true
    badge: true
    badgeMode: count                # count | dot
    title: 'DSH'
FieldTypeDefaultMeaning
notifyOnIdlebooleantrueNotify when a turn finishes
notifyOnErrorbooleantrueNotify on agent/error
notifyOnApprovalbooleantrueNotify when a tool call awaits approval
minTurnDurationMsnumber5000Skip notifications for quick turns
desktopbooleantrueNative desktop notification on the server host
browserbooleantrueBrowser Notification popups in the Web UI
browserOnlyWhenHiddenbooleantrueSuppress popups while you are looking at the window
webhookUrlstring''Optional POST target (Slack-compatible payload)
titlestring'DeepSeek Harness'Title for desktop and browser notifications
soundstring'Glass'macOS: a system sound name (looked up in ~/Library/Sounds, /Library/Sounds, /System/Library/Sounds) or an audio file path (absolute, or relative to ~/Library/Sounds); '' is silent
windowsAppIdstring''Windows: AppUserModelID the toast is attributed to; empty uses the posting process's registered identity
badgebooleantruePut the attention count on the application icon
badgeDesktopOnlybooleantrueOnly badge in the desktop shell (a browser tab has no app icon)

Every field is declared .volatile(), so the values are live: the dsh-settings document serves them, and a change applies without a reload. webhookUrl is role('secret'), so its value is stripped before settings cross the wire to the browser.

Webhook payload

{
  "text": "Agent finished — done in 2m 14s",
  "summary": "Agent finished",
  "body": "done in 2m 14s",
  "level": "info",
  "ts": "2026-08-21T12:34:56.000Z"
}

The app-icon badge

The Dock tile belongs to the Electron browser process, so a host-side plugin can never touch it. The renderer does not need to: Electron implements the standard Badging API in the browser process, so navigator.setAppBadge(n) from the page reaches the same code path as app.setBadgeCount() — no shell patch, no IPC channel, no preload hook. The API is [SecureContext], and the desktop shell serves the UI from dsh-app:// (registered secure: true).

Three sharp edges, all handled:

  • Never call setAppBadge(0). Chromium treats a numeric zero as a protocol violation and Electron answers with ReportBadMessage, which terminates the renderer. Clearing always goes through clearAppBadge().
  • Counts above 99 saturate to a localized 99+, so badgeMaxCount above 99 changes nothing.
  • The call rejects with NotAllowedError when the document may not badge; the plugin swallows that and retries on the next change.

A browser tab gets no badge by default (badgeDesktopOnly: true): Chrome and Edge only badge installed PWAs, so outside the desktop shell the call is inert at best.

If nothing appears in the Dock, check System Settings → Notifications → DeepSeek Harness → "Badge application icon" — an app that was never granted notification permission has its badge ignored by the system. To test the plumbing directly, from the app window's console:

navigator.setAppBadge(7);   // badge shows "7"
navigator.clearAppBadge();  // badge disappears

Design notes

  • Everything registered through ctx is an effect. Cordis registers each listener through the plugin fiber, so they are removed automatically on unload/hot-reload; there is no manual cleanup path.
  • approval/request is a waterfall. This plugin only observes it, so its listener always calls next() — returning without it would claim the decision (and resolve as unavailable), swallowing the real answerers.
  • The browser half reads its options from the settings document. The client module system creates every browser plugin entry with { name: id } and no config, so apply on the client receives no row config; the host half declares the options .volatile() and the client reads them back through ctx.configForms.get('notify-badge') — the same path official client plugins use. The entry id in cordis.patch.yml is that namespace, so if you rename the row, update ENTRY_ID in client.js.
  • Session status comes from uiSession.sessionStatus. sessions.list rows carry running but not pendingInteraction; the status projection is the client's own view of { running, pendingInteraction, completionUnread }, and a pendingInteraction is an object whose kind is approval, question, or plan-review.
  • A failed turn is never announced as a finish. The loop emits agent/error and then flips the status to idle. The error is recorded before the notifyOnError gate, so the idle flip stays quiet whether error notifications are on (the error was already announced) or off (nothing is posted at all) — a failed turn is never reported as "Agent finished".
  • Subagents are filtered. Sessions the harness marks origin: "subagent" never notify or badge. The host half learns that from session/created; the browser half can only read origin from the session list, so a session the list has not delivered yet stays untracked until it can be classified (and is adopted then, so an already-waiting session still badges).
  • An unserved settings namespace is reported. If the profile row id and ENTRY_ID disagree, the client logs one warning instead of silently running on defaults.
  • Never break the loop. Desktop spawns are detached and fire-and-forget; webhook failures are logged and swallowed. A notifier must never surface an error into the agent's turn.

Compatibility

Verified against DeepSeek Harness 0.2.1-rc.2, and engines.dsh declares ^0.2.1-rc.2. The installer refuses dsh plugin add for a package whose range does not match the running harness (unless that exact package@version is version-exempted with dsh plugin allow-version); a bundle that is already listed in a profile is only warned about, so the declared range is an install gate rather than a load gate. client.js is hand-written in the shape the client module system expects, so no build step and no source map are needed.

Local development

From a checkout of this package:

npm install      # @deepseek-ai/schemastery, for the Config schema
npm test         # syntax check + host and browser-half tests

To run it inside a harness source checkout, point a patch file at this directory and start the Web UI:

# dev.patch.yml (keep it out of version control)
- insert:
    - id: notify-badge
      name: dsh-notification-badge
      config:
        minTurnDurationMs: 0
pnpm dsh web --patch ./path/to/dev.patch.yml

Edits to index.js hot-reload without a restart; a rebuilt client.js is picked up on the next page load.

License

MIT © 2026 Suleyman Yaryev suleymanyaryev@gmail.com. The notification half is derived from dsh-notification by Nishit Patel, and the icon badge from dsh-dock-badge; both were MIT-licensed, and the original copyright notice is retained in LICENSE.

badgeModecount | dotcountNumber of sessions, or an unnumbered dot
badgeMaxCountnumber99Highest number rendered
badgeOnIdlebooleantrueCount a finished turn
badgeOnApprovalbooleantrueCount a session waiting on you (including one already waiting at load)
badgeClearOnFocusbooleantrueClear the badge when the window is focused or visible again
  • The host half is the anchor. A client bundle is only served while its package's host entry is active, so index.js is required even on a machine where only the browser half does anything.