DeepSeek Harness Plugin

yakoylp/dsh-localnotify

Stars ★ 0 Category Notifications & Integrations Added 2026-09-08

In-app local notification center for DSH: a sidebar Notifications entry with unread badge, full-screen center with level color coding (info/success/warn/error), time/source filters, sorting, title/content search, read/unread, delete, detail popup with one-click copy, and pagination; written by the notify_add agent tool or the dsh-localnotify CLI (with auto-cleanup retention), page refreshes live, UI follows dsh web language (zh/en).

Install

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:yakoylp/dsh-localnotify

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

🌐 中文: README.md · 🤖 Agent Guide: README.agent.md

CI

A local notification center plugin for DSH (DeepSeek Harness): adds a Notifications entry to the Web UI sidebar, opening a full-screen notification center. Notifications are shown as cards (title + one-line body preview) with level color coding, time/source filtering, sorting, title/body search, read/unread marking, and deletion. Clicking a card opens a detail popup with the full information and one-click copy of the title/body. Notifications are written by the agent tool (notify_add) or the CLI (dsh-localnotify) into a local JSON file, and the page refreshes in real time — fully local, no external services.

Typical use: the agent writes a notification to remind you when a task finishes; scripts and cron jobs can deliver notifications through the CLI.

Features

  • Sidebar Notifications entry: bell icon + unread-count badge (dot badge in collapsed rail), beside Settings at the sidebar foot — additive, does not cover existing UI
  • Full-screen notification center (shell.overlay, independent of any session):
    • Card list: title + one-line body preview (ellipsis when truncated), unread cards highlighted with a level-colored left border and dot; compact card height
    • Level color coding: info (brand) / success (green) / warn (yellow) / error (red); level tags shown on cards and in the detail popup
    • Pagination: bottom bar with "per page 10/20/50/100" (default 20) and prev/next paging (shows N total · page x/y); only the current page is rendered
    • Time filter: All / Today / Last 7 days / Last 30 days
    • Source filter: filter by notification source (agent / cron / cli …, collected automatically)
    • Sorting: newest first (default) / oldest first / unread first
    • Title + content search: real-time filtering (case-insensitive)
    • Detail popup: clicking a card shows full info (full timestamp / level / source / read state + full body) with one-click copy of title, body, or both (the button shows "已复制 ✓" after copying); opening a detail auto-marks it read
    • "Mark all read" button; card "Delete" with two-step confirmation (prevents accidental deletion)
    • Close via the close button or clicking the backdrop
  • Real-time refresh: polls every 3s while the page is open, every 30s otherwise (agent/CLI writes appear within seconds)
  • Theme aware: all colors use DSH official theme tokens (--dsw-alias-*), following light/dark themes automatically
  • i18n: UI text follows the dsh web language automatically (zh / en; switches take effect live)
  • Auto cleanup: optional retention (in days); older notifications are removed automatically on each write (disabled by default; the 500-cap always applies)
  • Write paths (no create-form in the UI, keeping the interface clean):
    • Agent tool: the agent calls notify_add during a conversation (supports level)
    • CLI: dsh-localnotify add "title" -b "body" [--level success], for scripts / cron

Data storage

Notifications live in ~/.dsh/notify/notifications.json (DSH_HOME takes precedence), shaped as:

{
  "version": 2,
  "notifications": [
    {
      "id": "n_mtisij3d_q32zcn",
      "title": "Task done",
      "body": "23 pages converted to Markdown.",
      "createdAt": 1788274582825,
      "read": false,
      "source": "agent",
      "level": "success"
    }
  ],
  "settings": { "retainDays": 0 }
}
  • level: info | success | warn | error (missing on old data renders as info)
  • settings.retainDays: auto-cleanup retention in days; 0 = keep forever (default); >0 removes notifications older than N days on each write (set via CLI config --retain-days). version-1 files are upgraded to version 2 on the first write
  • Writes are atomic (temp file + rename), so a partial file can never appear
  • A missing or corrupt file falls back to an empty store and is never overwritten
  • In-process writes are serialized; at most 500 notifications are kept (oldest trimmed)
  • The file is transparent and editable, easy to back up or migrate with ~/.dsh

Install

From GitHub (recommended)

dsh plugin --profile web add github:yakoylp/dsh-localnotify

From a local directory (development)

Clone the repository (or unpack the source archive) anywhere, then install from that directory:

git clone https://github.com/yakoylp/dsh-localnotify.git
dsh plugin --profile web add ./dsh-localnotify               # macOS / Linux
dsh plugin --profile web add "C:\path\to\dsh-localnotify"    # Windows (use your real path)

Restart dsh web after installing (the client bundle is loaded at web startup). The 🔔 Notifications entry appears at the sidebar foot; verify with dsh-localnotify add "test".

CLI

dsh-localnotify add "Task done" -b "converted"                        # add a notification
dsh-localnotify add "Reminder" --source cron --level warn              # custom source & level
dsh-localnotify add "Deploy OK" --level success                        # level: info/success/warn/error
dsh-localnotify list                                                   # list (* = unread; [E]/[W]/[OK] level marks)
dsh-localnotify list --unread                                          # unread only
dsh-localnotify list --level error                                     # error-level only
dsh-localnotify list --json                                            # JSON output (script-friendly)
dsh-localnotify read n_xxxx                                            # mark one as read
dsh-localnotify read --all                                             # mark all as read
dsh-localnotify delete n_xxxx                                          # delete one
dsh-localnotify config [--retain-days 7]                               # show/set auto-cleanup days (0=keep forever)
dsh-localnotify prune                                                  # clean up expired notifications now
dsh-localnotify --help                                                 # help
dsh-localnotify --file /path/to/notifications.json add ...             # override storage path

The CLI reads/writes the same JSON file directly and does not require cordis — usable in any terminal, script, or cron job.

Agent tool

The plugin registers notify_add; the agent calls it in-conversation to write notifications (validated: title required ≤200 chars, body ≤5000 chars). Example when a task completes:

notify_add(title: "Conversion done", body: "23 scanned pages converted to Markdown ...", level: "success")

level is an optional enum info | success | warn | error for visual coding: success for completed tasks, error for failures, warn for things needing attention, omit for ordinary messages (default info).

Notification submission paths (how agents / scripts deliver)

Path Who uses it Prerequisite
notify_add tool DSH agents (same profile) Registered automatically on install; agents see the tool in their tool list and call it per its description (task done, important progress, needs attention) — no extra config
dsh-localnotify CLI scripts / cron / terminal Installed (bin linked into the profile's node_modules/.bin); or node <plugin-path>/lib/cli.js directly
Direct JSON file write any program Write ~/.dsh/notify/notifications.json per the format above; visible within ~3s

Note: the notify_add tool is visible to agents in the same DSH profile where the plugin is installed; other environments/agents need their own install for the tool path, while the CLI and file write are environment-independent.

HTTP API

The host registers same-origin POST /dsh-localnotify/api/<method> (reachable only by the DSH web server); JSON in/out with an { ok, value } or { ok: false, error: { code, message } } envelope:

Method Args Description
list {} Returns { notifications, storagePath }
markRead { id } Mark one as read
markAllRead {} Mark all as read
delete { id } Delete one

Architecture

  • Node half (mounted via cordis.patch.yml, lib/index.js): registers the notify_add tool (ctx.tools.register) and the /dsh-localnotify/api/* route (ctx.webServer.register, prefix match); storage logic lives in lib/store.js (shared by host and CLI)
  • Browser half (dsh.client + exports["./client"]lib/client.js): a hand-written ModuleLoader bundle (window.__ModuleLoader__.load({ id, factory }), same format as official tsdown output, depending only on the baseline external react); registers sidebar.footer.action (entry) and shell.overlay (center) via ctx.slots.inject/register, fetching data from the host API
  • Theme: all colors reference DSH theme tokens (--dsw-alias-bg-* / --dsw-alias-label-* / --dsw-alias-border-* / --dsw-alias-brand-primary, etc.)

Development

node --test                    # run all tests (store layer + API handler + CLI end-to-end)
node lib/cli.js --file ./tmp-notify.json add "test" -b "body" --level success
node lib/cli.js --file ./tmp-notify.json list
node lib/cli.js --file ./tmp-notify.json config --retain-days 7

Troubleshooting

  • Sidebar entry visible but the notification center list stays empty: first check whether the host route is registered — curl -X POST http://127.0.0.1:<port>/dsh-localnotify/api/list -H "Content-Type: application/json" -d "{}". If it returns 405 (empty body), the host route is not registered; upgrade to ≥1.1.0 (1.0.0 silently skipped route registration because webServer was missing from inject). If it returns { ok:true, value: { notifications, ... } }, the route works — check the storage file for data
  • Cards compressed to thin lines with many notifications / no scrollbar: flex-layout bug in 1.0.0; upgrade to ≥1.1.0 (cards are flex: none, the list scrolls properly)

Known limitations

  • The notification center is a full-screen overlay (not a routed page); closing returns to the previous session — a deliberate trade-off to stay lightweight
  • Real-time updates rely on polling (3s/30s); no Host→Client push yet. Polling cost is negligible (small same-origin requests); will be revisited if DSH provides a push channel
  • Concurrent writers (CLI + host) rely on atomic rename; the last writer wins under extreme concurrency. Write frequency is low for notifications, so this is safe enough (in-process writes are already serialized)
  • External file edits are picked up on read (visible within ~3s)

Tests & CI

  • Test coverage spans three layers: the store (add/validation/level/auto-cleanup/legacy-file compat/corrupt fallback/500 cap), the HTTP API (method dispatch/error envelope/read-write flows), and the CLI (spawn end-to-end: add/list/read/delete/config/prune/error paths)
  • GitHub Actions runs the full suite on Node 18 / 20 / 22 (.github/workflows/test.yml)

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.