dsh-plugin-web-notify
August 22, 2026 · View on GitHub
Browser notifications for the DeepSeek Harness Web GUI.
Shows a browser notification when:
- the agent explicitly sends a meaningful update during a long-running turn;
- a conversation turn finishes while you are not watching that session;
- the agent starts waiting for you — an approval request, a plan review, or a question.
Features
- Agent-requested updates — the model receives
web_notify__send(message)and can notify you at a meaningful intermediate milestone without ending its turn. Routine progress, final completion, and pending interactions remain automatic and should not call it. - Click to focus and switch — clicking the notification brings the GUI window to the front and switches to the finished/asking session.
- Work-segment summaries — when a logical work segment completes, the notification first shows a "summarizing…" hint (only when the host summary capability is detected) and is then replaced with a one-sentence summary of what the segment accomplished, generated by a small model (host-side; configurable provider/model).
- Continuation-aware completion — a turn that successfully hands off through Turn Memory does not notify. When the final continued turn finishes, the summary covers the complete linked work segment instead of only the last physical turn.
- Stays until dismissed — notifications use
requireInteractionand stay on screen until you click or dismiss them (set theREQUIRE_INTERACTIONconstant inclient/index.tstofalse, then rebuild, for the OS default auto-dismiss timing). - Chime — plays a short two-tone sound along with the notification (browsers allow page audio after the page has been interacted with at least once).
- No interruptions — no notification while the page is focused on the finished/asking session; you already see it.
- One toast per session — notifications for the same session replace each other instead of stacking.
- Subagents ignored — subagent sessions do not produce notifications.
- Permission on first click — the notification permission is requested automatically on the first click inside the page; grant it once and you are done.
- Bilingual — notification text follows the browser language (Chinese / English).
Install
Add the plugin to your dsh profile and register it in the Loader.
From GitHub
dsh plugin --profile web add github:vilicvane/dsh-plugin-web-notify
This is equivalent to running pnpm add github:vilicvane/dsh-plugin-web-notify
inside the profile directory.
From npm
Once the package is published to the npm registry:
dsh plugin --profile web add dsh-plugin-web-notify
Then append an insert row to the profile's cordis.patch.yml
($DSH_HOME/profiles/web/cordis.patch.yml):
- insert:
- id: web-notify
name: dsh-plugin-web-notify
config:
provider: deepseek-official
model: deepseek-chat
The config block is optional and defaults to deepseek-official /
deepseek-chat. All settings and their defaults:
| Key | Default | Meaning |
|---|---|---|
provider | deepseek-official | LLM provider route used for summaries. |
model | deepseek-chat | Small/fast model used for summaries. |
maxInputChars | 4000 | Per-side cap on joined human input and assistant output from the completed logical work segment sent to the model. |
maxOutputTokens | 150 | Cap on the summary length. |
timeoutMs | 60000 | Summary generation timeout. |
systemPrompt | (built-in) | System prompt for the summarization call. |
Restart dsh web, refresh the page, and click anywhere once to grant the
notification permission.
How it works
index.tsis the host assembly layer. It registers/web-notify/summaryand/web-notify/capabilityon the DSH web server, registers theweb_notify__send(message)tool and its session projection, and delegates to typed modules underlib/.lib/tool.tsreturns a normal successful tool result whose durable presentation metadata contains the notification request. It does not end the turn or append a plugin-private event.lib/projection.tsfolds the latest successful request from Nativetool/resultevents or Code Modetool/code-dispatchevents intowebNotifyRequest.lib/turn-summary.tsfinds the latest matchingturn/start→turn/endinterval and follows only verified Turn Memory continuation links to their predecessor turns. It includes human-authored user messages and text-bearing assistant messages from that completed logical segment, while excluding runtime/plugin context, unrelated older turns, and a later open turn.lib/summary-service.tscalls the configured model throughctx.llm.streamwith thesession-titlepurpose, deduplicates concurrent requests for the same completed logical segment, and bounds its in-memory cache.client/index.tsis the typed Cordis client source. It injects thesessionsservice and watches the session-list snapshot forrunning → falsetransitions and forpendingInteraction(approval/plan-review/question) arrivals, as well as changes to thewebNotifyRequestprojection. Pending interactions take priority over an agent-requested update in the same snapshot. It probes the capability route at apply (and again after server connection resets), sowebNotifyCompletionprojection suppresses the transient idle boundary after a successfulcontinue_after_turn_compressionhandoff. Other completion notifications start with a "summarizing…" hint only when the host summary is actually available. The client polls the summary route; the summary replaces the hint (same tag) once ready, and failures degrade back to the plain completion text. A per-session generation invalidates an older summary request as soon as a newer completion or pending interaction arrives, preventing stale summaries from replacing actionable notices. Projection identities are seeded from the initial snapshot, so refreshing or reconnecting never replays an old agent-requested notification.scripts/build-client.mjsbundlesclient/index.tsinto the published loader artifactclient.js. The generated file is checked in so GitHub and npm installs work without a build step.
Notes
- Windows may deliver Chrome notifications quietly (notification center only, no banner, no sound). Check Windows Settings → System → Notifications → Google Chrome and enable "Show notification banners" and "Play a sound"; also make sure Focus Assist is off.
- Browsers do not expose a configurable auto-dismiss duration; the operating
system controls it. This plugin uses
requireInteractionso notifications stay visible until clicked or dismissed. - The chime is subject to the browser autoplay policy: it plays only after the page has been interacted with at least once.
- Bringing a window to the front without a user gesture is restricted by browsers, so automatic focusing on show is best-effort; clicking the notification always focuses the window and switches to the session.
- Summaries are generated only when a completion notification actually fires (one small-model call per completed logical segment), and only the bounded human and assistant text from its verified continuation-linked turns is sent. Tool results, model reasoning, runtime snapshots, and unrelated session history are not transmitted.
Development
pnpm install
pnpm build:client
pnpm check
pnpm check proves that client.js matches its TypeScript source, runs the
host/client behavior tests, and type-checks both environments. See
design.md for the lifecycle and concurrency invariants.
License
MIT