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 requireInteraction and stay on screen until you click or dismiss them (set the REQUIRE_INTERACTION constant in client/index.ts to false, 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:

KeyDefaultMeaning
providerdeepseek-officialLLM provider route used for summaries.
modeldeepseek-chatSmall/fast model used for summaries.
maxInputChars4000Per-side cap on joined human input and assistant output from the completed logical work segment sent to the model.
maxOutputTokens150Cap on the summary length.
timeoutMs60000Summary 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.ts is the host assembly layer. It registers /web-notify/summary and /web-notify/capability on the DSH web server, registers the web_notify__send(message) tool and its session projection, and delegates to typed modules under lib/.
  • lib/tool.ts returns 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.ts folds the latest successful request from Native tool/result events or Code Mode tool/code-dispatch events into webNotifyRequest.
  • lib/turn-summary.ts finds the latest matching turn/startturn/end interval 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.ts calls the configured model through ctx.llm.stream with the session-title purpose, deduplicates concurrent requests for the same completed logical segment, and bounds its in-memory cache.
  • client/index.ts is the typed Cordis client source. It injects the sessions service and watches the session-list snapshot for running → false transitions and for pendingInteraction (approval / plan-review / question) arrivals, as well as changes to the webNotifyRequest projection. 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), so webNotifyCompletion projection suppresses the transient idle boundary after a successful continue_after_turn_compression handoff. 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.mjs bundles client/index.ts into the published loader artifact client.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 requireInteraction so 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