Introduction

Running long tasks with DSH is the norm: initiate a task, go do something else, and return only to find the agent finished five minutes ago—or worse, it’s stuck on a prompt waiting for your approval, doing nothing. The issue isn’t that the agent is slow, but that you weren’t notified in time.

dsh-notification solves exactly this. It listens to the harness’s own lifecycle events and issues a notification the moment attention is needed. Below is an introduction to its features, installation, and configuration.

What is it

dsh-notification is a DeepSeek Harness (DSH) plugin maintained by nishit130, currently at version 0.1.1 under the MIT license. One-sentence positioning: it notifies you via desktop, browser, or webhook when the agent finishes a turn, encounters an error, or waits for your approval, without you needing to stare at the tab.

DSH’s philosophy is “everything is a plugin,” and peripheral capabilities like notifications are perfectly suited to be mounted as plugins without requiring changes to the harness itself.

Which three event types does it monitor

  1. Agent finished: Triggered when agent/status changes from running to idle, provided the turn duration is ≥ minTurnDurationMs. Enabled by default.
  2. Agent error: Listens for agent/error, triggered when a step or turn encounters an error. Enabled by default.
  3. Approval needed: Listens to the approval/request waterfall. The plugin observes (observe-only) and always delegates with next(), never making approval or rejection decisions for you. Enabled by default.

The role of minTurnDurationMs is filtering: quick turns that finish in seconds are not worth disturbing; only turns reaching the threshold trigger a notification.

Three notification channels, and where they trigger

First, it is important to clarify on which machine each channel triggers, as this determines which one you should enable:

  • Desktop notification (desktop): Zero dependencies. Uses osascript on macOS, notify-send on Linux, and PowerShell toasts on Windows. Triggers on the machine running the dsh server, suitable for cases where dsh web runs on your own machine.
  • Browser notification (browser): Uses the standard Notification API and triggers on the machine viewing the Web UI. By default, it only pops up when the tab is hidden—since a visible tab implies you are looking at it. Set browserOnlyWhenHidden to false to change this behavior.
  • Webhook (webhookUrl): POSTs JSON to the configured URL. The text field is Slack-compatible, so Slack, Discord, or generic incoming-webhook URLs work out of the box. Suitable for sending messages to a phone, a Slack channel, or unattended scenarios.

The three channels can be toggled independently, for example: desktop: false or browser: false.

One combination to note: when running on a single machine and the tab is hidden, the same event might trigger both desktop and browser notifications. If this is redundant, simply turn off one of the channels.

Installation

dsh plugin --profile web add dsh-notification
# or straight from git:
dsh plugin --profile web add github:nishit130/dsh-notification

Choose either command. The plugin is pure ESM JavaScript with no build steps, so installing from git does not require adding an entry to allowBuilds.

Configuration

Override plugin configuration in the profile’s cordis.patch.yml (or via the Settings UI):

- insert:
    - id: notify
      name: dsh-notification
      config:
        minTurnDurationMs: 10000        # Only notify turns ≥ 10 seconds
        webhookUrl: 'https://hooks.slack.com/services/XXX/YYY/ZZZ'
        notifyOnApproval: true
        desktop: true
        title: 'DSH'

This configuration sets the turn duration threshold to 10 seconds, hooks up a Slack webhook, keeps desktop notifications enabled, and changes the notification title to DSH.

All configuration items and their defaults:

Configuration Item Type Default Value Meaning
notifyOnIdle boolean true Notify when a turn ends
notifyOnError boolean true Notify on agent/error
notifyOnApproval boolean true Notify when a tool call is waiting for approval
minTurnDurationMs number 5000 Do not notify turns shorter than this duration
desktop boolean true Send native desktop notifications on the server host
browser boolean true Show browser notifications in the Web UI
browserOnlyWhenHidden boolean true Suppress browser notifications when the tab is visible
webhookUrl string '' Optional POST target (Slack-compatible payload)
title string 'DeepSeek Harness' Desktop notification title

The webhook payload looks like this:

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

text is the Slack-compatible field, while summary and body allow custom consumers to separate the display. level and ts provide the severity level and timestamp.

Three design decisions

After the steps above, the plugin should be working. Its implementation features a few design decisions worth knowing about:

  1. Everything registered via ctx is an effect. Listeners are automatically removed on unloading or hot reloading; there is no manual cleanup path (Cordis revertible effects).
  2. approval/request is a waterfall. The plugin only observes; the listener always calls next()—failing to do so would seize the decision-making power and swallow the actual responder.
  3. Never interrupts the agent loop. Desktop notifications are spawned in a detached “fire-and-forget” manner, webhook failures are swallowed, and the notifier never throws errors to the agent turn.

Local Development

To modify the code, first copy dev.patch.example.yml to dev.patch.yml (which is gitignored), point it to the absolute path of your checkout, and then run:

pnpm dsh web --patch ./path/to/dsh-notification/dev.patch.yml

Changes to index.js can be hot-reloaded without restarting. Run tests with npm test.

Use Cases and Notes

Choose the channel based on your deployment method:

  • Harness runs on your own machine: Enable desktop notifications.
  • Harness runs on a remote server, but you view the Web UI locally: Enable browser notifications.
  • Unattended or long-running tasks: Configure a webhook to send messages to Slack, Discord, or any service that accepts POST requests.

Two reminders:

  1. The plugin runs with the permissions of the current dsh process. It is recommended to review the source code and license before installing (this project is MIT licensed). From the files field in package.json, the plugin only contains index.js, client.js, and cordis.patch.yml, so the cost of inspection is low.
  2. Browser notifications require the Web UI to request permission upon your first click or keypress. After installation, interact with the page once to grant permission.

Conclusion

dsh-notification solves a specific problem: when the agent runs long tasks, you no longer need to periodically return to refresh the tab. With three event types, three channels, and one duration threshold, the configuration scope is small, and the default values work out of the box.

  • Plugin directory page: https://www.skillhub.cn/plugins/nishit130/dsh-notification
  • GitHub: https://github.com/nishit130/dsh-notification

skillhub.cn, which hosts this plugin, is a community-maintained plugin directory and has no affiliation with the DeepSeek official project.