DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Tab Status Dot — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins
T

@pxy/dsh-tab-status-dot

Tab Status Dot

DeepSeek Harness web client plugin: a live browser-tab favicon status dot — light green when a session finished while you were away, light blue while a session awaits your choice, both dots when both coexist; hidden-tab aware with reload-persistent reminders.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:linksdeact-sys/dsh-tab-status-dot#fca57c9ea5b423c780ef689ee95eff8b831fc20d
READMECompatibilityVersions

Compatibility and provenance

Tab Status Dot is published as @pxy/dsh-tab-status-dot and currently resolves to version 0.1.4. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
github
Registry updated
9/12/2026

Versions

0.1.4stable
9/12/2026

Related plugins

Loading related plugins…

Latest
0.1.4
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
web
License
MIT
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
9/12/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in ui-customization.

Better Sidebardsh-better-sidebarDSH web plugin: a VSCode-like right sidebar (explorer / editor / terminal / git / browser), isolated per conversation session. Exposes a service for other plugins to register sidebar tabs and file viewers.Whale Widgetdsh-whale-widgetDeepSeek balance whale widget in the bottom-right corner of the DSH Web interface: balance/today’s usage/peak-off-peak pricing, customizable bubble click sequence (text/balance/today/peak-off-peak/image/random phrases and parallel weighted selection), per-line styles and fonts, floating quick editinCodex Ui@michengai/dsh-codex-uiDSH Codex UI — 为 DeepSeek Harness Web 提供 Codex 风格侧栏、工作区会话树、全局搜索和轮次导航 · A Codex-style sidebar, workspace session tree, global search, and turn navigation for DSH WebDeepseek Ipptdeepseek-ipptiPolloWork PPT Studio and its curated slide templates as a native DeepSeek Harness conversation view.

README

dsh-tab-status-dot

A tiny browser-side plugin for the DeepSeek Harness Web GUI (dsh web) that shows a status dot as the browser-tab favicon, telling you at a glance whether any conversation has finished while you were away, or is waiting for you to make a choice.

No page-title text is modified — the indicator lives entirely in the tab icon (favicon), where size and colour are fully controllable.

New to this? Read the beginner-friendly Getting started (中文版) — step-by-step for Windows, Linux and macOS, no coding required.

states

States

FaviconMeaningReturns to neutral when
Neutral dotDefault / a task is currently running—
Light-green dot≥1 session finished running while you were not looking (tab in background, or viewing another session)You open that session; if it was already the open session, staying on the page ≈1 s counts as read. Every unfinished "viewed" item must be handled before the dot returns to neutral
Light-blue dotA session is waiting for your choice (question / approval / plan review) — not answered yetOnly after you actually answer/choose and the run resumes; merely viewing does not clear it
Two light dots (green + blue)Both conditions above exist at the same timeGreen clears by viewing; blue clears by answering

Rules

  • A session finishing while you are looking at the page and at that session does not light up (you saw the result).
  • A session finishing while the tab is hidden/backgrounded lights up green even if it is the currently open session — you were not actually watching it.
  • Running again, or deleting the session, removes its stale reminder.
  • Unviewed completions persist in localStorage, so a page reload does not lose them.

Why it exists

The runtime's built-in model treats "session selected" as "viewed" — so a task finishing in the open session while the tab was hidden never produced a reminder. This plugin redefines "you were not looking" as session not selected or page hidden, which matches how people actually use the app (start a task → switch away → come back).

How it works

  • Registered as a dual-face cordis plugin (dsh.client, platform: web): the host half (lib/index.js) is an empty apply, the browser half (exports["./client"] → lib/client.js) is a classic-script module-loader bundle.
  • Subscribes to the sessions service (ctx.get("sessions").list), an observable snapshot carrying per-session running, completed and the open-session current id.
  • Pending operator choices come from the runtime's own source: on DSH 0.1.5-rc.1+ that is uiSession.pendingInteractions (an observable Map<SessionId, interaction>); on older versions the per-summary pendingInteraction field is scanned instead. Both paths are supported.
  • Completeness signals: the runtime's own completed flag plus our own running→idle edge detection plus a "page was hidden since last visible observation" flag — so reminders are armed even when the browser throttles background timers and the transition is only observed after you return.
  • Background resilience: browsers suspend requestAnimationFrame (and some event delivery) for hidden tabs, so the plugin also
    • polls the cheap cached snapshot every second,
    • paints through a short-timeout fallback as well as rAF,
    • refreshes immediately on visibilitychange / window focus.
  • Rendering is coalesced & change-checked: at most one DOM write per frame, raw-string favicon comparison (never the normalized .href read-back), no writes when nothing changed.
  • Takes over the favicon (<link rel=icon>) so browsers do not pick a competing brand icon; the original icon is restored on unload.

Compatibility

DSHStatus
0.1.5-rc.1 (current)Supported — sessions from @deepseek-ai/dsh-api-session-controller, pending from uiSession.pendingInteractions.
≤ 0.1.0-rc.xSupported — sessions from the then-current runtime, pending scanned from the session summary.

The plugin deliberately declares no package-name inject edges (dsh.client.inject), only the service name it needs (exports.inject = ["sessions"]). Package names move between DSH releases (the sessions runtime itself moved in 0.1.5-rc.1), and an edge naming a package that no longer exists silently prevents the row from ever materializing — which is exactly how the indicator went dark. Waiting on the service name is stable across versions.

After installing or updating the plugin, restart dsh web (and reopen the URL it prints). The client module registry caches package metadata per specifier until restart, so a page refresh alone will not pick up a changed package.json.

Requirements

  • DeepSeek Harness with a web profile (see the runtime's profile/plugin conventions), any modern browser.

Installation

How plugin deployment works in DeepSeek Harness

Every DSH surface is a profile directory ($DSH_HOME/profiles/<name>, e.g. ~/.dsh/profiles/web). A plugin only has to satisfy two things:

  1. the package is resolvable from the profile — i.e. it lives in <profile>/node_modules/<package-name> (pnpm installs there, but a plain copy works just as well);
  2. the profile registers a loader row for it — either the package's own bundle patch (see below) or one insert entry in <profile>/cordis.patch.yml naming the package.

After that the instance composes the row and serves the client bundle. Current DSH caches package metadata until the process restarts, so restart dsh web after installing or changing package.json and open the (authenticated) URL it prints; only lib/client.js content changes need just a page refresh.

This package is an official-form plugin (and a bundle)

Per the DSH documentation, every capability is a plugin row in a cordis.yml, and a package can ship a bundle patch layer that adds its own row:

dsh: {
  bundle: { patch: "./cordis.patch.yml" },   // this package's row lives here
  client: { platform: "web" }                // dual-face client plugin (./client export)
}

That gives two equivalent activation routes — use exactly one:

RouteHowNeeds
A. Bundle (official CLI route)dsh plugin --profile web add github:linksdeact-sys/dsh-tab-status-dot, then add "@pxy/dsh-tab-status-dot" to dsh.profile.bundles in <profile>/package.jsonpnpm (the dsh plugin command forwards to it)
B. Scripts / manual copyinstall.ps1 / install.sh (or a plain copy into node_modules) + the insert row in <profile>/cordis.patch.ymlnothing

Why not a dynamic Cordis plugin? DSH also offers runtime plugins defined through the cordis_* tools, but the official authoring guide forbids them from touching the page directly ("Do not manipulate document.body, window, or hard-coded product DOM selectors"). A tab-favicon indicator inherently needs exactly that, so it must be a packaged client bundle like this one.

Verified installers. CI exercises them on four real environments — ubuntu-latest (where sh is dash), macos-latest (BSD userland), Alpine/BusyBox sh, and windows-latest (Windows PowerShell 5.1). Each job installs into a profile shaped exactly like the shipped template (comment header + bare [], no trailing newline), validates the resulting YAML with js-yaml, and checks the idempotent, append-to-existing-entries and uninstall paths. A separate job validates these package conventions (test/bundle.test.mjs), so a metadata regression cannot silently disable the plugin again.

Method 1 — install script (recommended)

# Windows (PowerShell)
git clone https://github.com/linksdeact-sys/dsh-tab-status-dot.git
cd dsh-tab-status-dot
powershell -ExecutionPolicy Bypass -File .\install.ps1
# macOS / Linux
git clone https://github.com/linksdeact-sys/dsh-tab-status-dot.git
cd dsh-tab-status-dot
./install.sh

The script copies the package into the web profile, appends the registration block to cordis.patch.yml (idempotent, keeps a .bak backup), and prints the next steps. Options: -Profile <name> / --profile <name>, -DshHome <path> / --dsh-home <path>, --uninstall.

Method 2 — package manager (dsh plugin)

If pnpm is available, the official route installs straight from GitHub into the profile:

dsh plugin --profile web add github:linksdeact-sys/dsh-tab-status-dot

…then register the row by appending this to ~/.dsh/profiles/web/cordis.patch.yml:

# >>> dsh-tab-status-dot >>>
- insert:
    - id: tab-status-dot
      name: '@pxy/dsh-tab-status-dot'
# <<< dsh-tab-status-dot <<<

Method 3 — manual copy

Download the release zip (or copy from a clone) so the profile ends up with:

<profile>/node_modules/@pxy/dsh-tab-status-dot/
├── package.json
└── lib/
    ├── index.js
    └── client.js

and add the same insert block shown in Method 2 to <profile>/cordis.patch.yml.

Verify

  1. Refresh the Harness page — hard refresh (Ctrl+F5) if the old bundle was cached.
  2. The tab icon shows a neutral dot. Start a task and switch to another page: when it finishes while you are away the dot turns light green; a question/approval waiting for you turns it light blue.
  3. Optional server-side check: GET http://127.0.0.1:3080/plugins/@pxy/dsh-tab-status-dot/client.js returns 200.

Uninstall

powershell -ExecutionPolicy Bypass -File .\install.ps1 -Uninstall   # Windows
./install.sh --uninstall                                           # macOS / Linux

or delete <profile>/node_modules/@pxy/dsh-tab-status-dot and the insert block by hand.

Troubleshooting

SymptomFix
Nothing appears after refreshMake sure cordis.patch.yml holds the insert row with the exact package name, then hard-refresh; if your instance does not hot-reload patches, restart dsh web once.
GET /plugins/.../client.js returns 404The row is not registered in the running instance (patch layer not applied), or the package is not in the profile's node_modules.
dsh plugin … add failspnpm is missing/unavailable — use Method 1 or 3; neither needs a package manager.
Page looks broken after installingRemove the row from cordis.patch.yml (or run the uninstaller) and refresh: the plugin unloads completely, including its favicon override.

See INSTALL.md for the original step-by-step notes and operational details.

Development

├── package.json          # dsh.client declaration (platform=web, injects client-runtime)
├── lib/
│   ├── index.js          # host half: empty apply (pure client plugin convention)
│   └── client.js         # browser bundle: module-loader factory + state machine + renderer
└── test/
    ├── core.test.mjs         # pure-logic cases + node:vm sandbox smoke test (no CJS globals)
    └── browser.e2e.mjs       # real-browser E2E (Playwright) + browser/fixture.html kernel stub

Unit tests (no dependencies)

node test/core.test.mjs        # or: npm test

The harness evaluates client.js inside a node:vm sandbox that provides only browser-ish globals (window, document, localStorage) — the same conditions the DSH module loader creates — so a missing CommonJS-style wrapper (exports is not defined) or any load-time crash is caught before it ever reaches a real page.

Browser E2E (Playwright)

# Locally, reusing an installed Chrome/Edge (no browser download):
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm install --no-save --no-package-lock playwright
PW_CHANNEL=msedge node test/browser.e2e.mjs

# Or with Playwright's own Chromium:
npm install --no-save --no-package-lock playwright
npx playwright install --with-deps chromium
node test/browser.e2e.mjs      # or: npm run test:e2e

test/browser/fixture.html stands in for the DSH kernel: it captures the bundle's __ModuleLoader__ registration and exposes a controllable fake sessions service. The test then drives real conversation state and asserts the favicon the browser resolves: neutral → light green (finished while you were away) → cleared on open; green for a hidden-tab finish of the open session plus its ~1 s read-dwell auto-clear; light blue while a choice waits and its clearing on answer; two dots when both hold; the reminder restored after a page reload; and full cleanup on disposal. It also fails on any page or console error.

Edit lib/client.js → refresh the page to test live (the bundle is served no-cache).

Notes & limitations

  • Browser tab titles are plain text: a coloured dot there can only be an emoji, whose size/colour are fixed. That is why state colours live in the favicon and the page title is left untouched.
  • Reminders are per-browser (localStorage); two browser tabs of the same profile share storage with last-write-wins semantics.

License

MIT