DeepSeek Harness Plugin

idoall/dsh-session-colors

Stars ★ 0 Downloads (30d) 2,584 Category Sessions & Messages Added 2026-09-23 npm @idoall/dsh-session-colors

Give any Session a colour mark, shown as a chip in the sidebar and picked from the conversation header; marks are stored on the Host, so a colour chosen on one device is visible on every other one.

Install

# from npm (prebuilt)

dsh plugin --profile web add @idoall/dsh-session-colors

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

dsh plugin --profile web add github:idoall/dsh-session-colors

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

✅ Supports DSH 0.2.2-rc.1 — the current release candidate (npm next). Compatibility checked against the installed runtime, as well as the previously verified 0.2.2-alpha.3, 0.2.2-alpha.2, 0.2.1-rc.4, 0.2.1-rc.3, 0.2.1-rc.2, 0.2.1-alpha.5, 0.2.1-alpha.4, 0.2.1-alpha.3, 0.2.0-rc.2, 0.2.0-rc.1, 0.1.7-rc.2, 0.1.7-rc.1 and 0.1.7-alpha.2; see Compatibility.

DSH Session Colors is a DeepSeek Harness community plugin. It does not modify DSH core and does not rewrite any Session or Workspace data: a mark is only "Session id → one colour".

Work is spread across several workspaces, and the workspace list is a wall of look-alike titles. Once a task finishes, the Session you were just in is hard to find again — the status dot is idle and the title is one of twenty. A colour you chose yourself is the cheapest way to make one row recognisable.

Features

  • A colour mark on the Session row — a short bar in the row's left padding that deliberately avoids the status dot, so "which one finished" is never covered up.
  • A system-style colour picker — a large saturation/value field, hue and alpha sliders, hex and RGBA fields, seven theme swatches, your saved colours, and screen eyedropper where the browser supports EyeDropper. It sits in the Session header's utilities, not next to the title.
  • Marked once, visible everywhere. Marks live on the Host, not in the browser, so a colour chosen on your computer is also there on your phone — over a LAN address or a tunnel alike.
  • Visible on a phone too. A phone turns the sidebar into a drawer, and the chips follow it: they travel with the drawer as it slides in, and they are painted above it.
  • Changes arrive on their own. The page re-reads marks when it becomes visible again and every 20 seconds, so a colour set on another device shows up without a refresh.
  • Never blocks the UI. The chip layer is click-through and clipped to the sidebar's scroll container; the worst case is that a chip does not appear.
  • A failure says so. When the store cannot be reached, the header control shows ⚠ with a reason instead of looking like a Session with no colour.

Install

Requirements:

  • DeepSeek Harness with a Web profile
  • Node.js 20 or newer
  • Verified DSH version: 0.2.2-rc.1 (the current release candidate), 0.2.2-alpha.3, 0.2.2-alpha.2, 0.2.1-rc.4, 0.2.1-rc.3, 0.2.1-rc.2, 0.2.1-alpha.5, 0.2.1-alpha.4, 0.2.1-alpha.3, 0.2.0-rc.2, 0.2.0-rc.1, 0.1.7-rc.2, 0.1.7-rc.1 and 0.1.7-alpha.2 — plugin 0.1.16 (see Compatibility)
dsh plugin --profile <profile> add @idoall/dsh-session-colors@latest

The compatibility table lists the exact versions, if you need to pin one to a specific DSH release.

Working on the plugin itself? Install the directory instead:

dsh plugin --profile <profile> add link:/path/to/dsh-session-colors

Then give it a data directory in the profile's cordis.patch.yml — the same shape other plugins that need durability use, because the plugin never guesses the profile path:

- id: dsh-session-colors
  config:
    dataDir: /absolute/path/to/profiles/<profile>/data/dsh-session-colors

Finally restart dsh web (the Host half loads only at boot), then refresh the Web GUI. It also works without dataDir, but then marks live only for the life of the Host process.

Usage

  1. Open the Session you want to mark.
  2. Click the colour control in the Session header (🎨 when the Session has no colour, the colour itself once it has one).
  3. Pick a colour, or paste a hex value. The bar appears on that Session's sidebar row immediately.
  4. To clear it, open the picker again and click Clear mark, or choose the transparent swatch among the theme colours.

Opening the picker on a marked Session starts from its current colour. Colours are stored as HSVA, so alpha round-trips exactly.

Compatibility

Current release: plugin 0.1.16 is compatibility-checked against DeepSeek Harness 0.2.2-rc.1 — the current release candidate (npm next) — and retains previous verification for 0.2.2-alpha.3, 0.2.2-alpha.2, 0.2.1-rc.4, 0.2.1-rc.3, 0.2.1-rc.2, 0.2.1-alpha.5, 0.2.1-alpha.4, 0.2.1-alpha.3, 0.2.0-rc.2, 0.2.0-rc.1, 0.1.7-rc.2, 0.1.7-rc.1 and 0.1.7-alpha.2.

Plugin version Verified DeepSeek Harness npm status What it is
0.1.16 0.2.2-rc.1 (RC), 0.2.2-alpha.3, 0.2.2-alpha.2, 0.2.1-rc.4, 0.2.1-rc.3, 0.2.1-rc.2, 0.2.1-alpha.5, 0.2.1-alpha.4, 0.2.1-alpha.3, 0.2.0-rc.2, 0.2.0-rc.1, 0.1.7-rc.2, 0.1.7-rc.1, 0.1.7-alpha.2 latest Records DSH 0.2.2-rc.1 compatibility. Executable code and load range unchanged; no migration from 0.1.15.
0.1.15 0.2.2-alpha.3 (alpha), 0.2.2-alpha.2, 0.2.1-rc.4, 0.2.1-rc.3, 0.2.1-rc.2, 0.2.1-alpha.5, 0.2.1-alpha.4, 0.2.1-alpha.3, 0.2.0-rc.2, 0.2.0-rc.1, 0.1.7-rc.2, 0.1.7-rc.1, 0.1.7-alpha.2 published Fixes chip tracking for the alpha.3 native drawer with reduced motion or instant close. Host and load range unchanged; no migration from 0.1.14.
0.1.14 0.2.2-alpha.2 (alpha), 0.2.1-rc.4, 0.2.1-rc.3, 0.2.1-rc.2, 0.2.1-alpha.5, 0.2.1-alpha.4, 0.2.1-alpha.3, 0.2.0-rc.2, 0.2.0-rc.1, 0.1.7-rc.2, 0.1.7-rc.1, 0.1.7-alpha.2 published Records DSH 0.2.2-alpha.2 compatibility and adds the 0.2.2 prerelease tuple to the declared load range. No executable-code change; upgrading from 0.1.13 needs no migration.
0.1.13 0.2.1-rc.4 (RC), 0.2.1-rc.3, 0.2.1-rc.2, 0.2.1-alpha.5, 0.2.1-alpha.4, 0.2.1-alpha.3, 0.2.0-rc.2, 0.2.0-rc.1, 0.1.7-rc.2, 0.1.7-rc.1, 0.1.7-alpha.2 published Records DSH 0.2.1-rc.4 compatibility. No executable-code or load-range change; upgrading from 0.1.12 needs no migration.
0.1.12 0.2.1-rc.3 (RC), 0.2.1-rc.2, 0.2.1-alpha.5, 0.2.1-alpha.4, 0.2.1-alpha.3, 0.2.0-rc.2, 0.2.0-rc.1, 0.1.7-rc.2, 0.1.7-rc.1, 0.1.7-alpha.2 published Records DSH 0.2.1-rc.3 compatibility. No executable-code or load-range change; upgrading from 0.1.11 needs no migration.
0.1.11 0.2.1-rc.2 (RC), 0.2.1-alpha.5, 0.2.1-alpha.4, 0.2.1-alpha.3, 0.2.0-rc.2, 0.2.0-rc.1, 0.1.7-rc.2, 0.1.7-rc.1, 0.1.7-alpha.2 published Verifies the same code on DSH 0.2.1-rc.2, where every package this plugin consumes is byte-identical to 0.2.1-alpha.5. No logic change over 0.1.10; upgrading needs no migration.
0.1.10 0.2.1-alpha.5 (alpha), 0.2.1-alpha.4, 0.2.1-alpha.3, 0.2.0-rc.2, 0.2.0-rc.1, 0.1.7-rc.2, 0.1.7-rc.1, 0.1.7-alpha.2 published Verifies the same code on DSH 0.2.1-alpha.5, where every package this plugin consumes is byte-identical to 0.2.1-alpha.4. No logic change over 0.1.9; upgrading needs no migration.
0.1.9 0.2.1-alpha.4 (alpha), 0.2.1-alpha.3, 0.2.0-rc.2, 0.2.0-rc.1, 0.1.7-rc.2, 0.1.7-rc.1, 0.1.7-alpha.2 published Verifies the same code on DSH 0.2.1-alpha.4 and moves the load range to the field that alpha.4 actually enforces, top-level engines.dsh. No logic change over 0.1.8; upgrading needs no migration.
0.1.8 0.2.1-alpha.3 (alpha), 0.2.0-rc.2, 0.2.0-rc.1, 0.1.7-rc.2, 0.1.7-rc.1, 0.1.7-alpha.2 published Verifies the same code on DSH 0.2.1-alpha.3 and names that tuple in the declared load range. No logic change over 0.1.7; upgrading needs no migration.
0.1.7 0.2.0-rc.2 (RC), 0.2.0-rc.1, 0.1.7-rc.2, 0.1.7-rc.1, 0.1.7-alpha.2 published Verifies the same code on DSH 0.2.0-rc.2 and adds that exact version to the declared load range. No logic change over 0.1.6; upgrading needs no migration.
0.1.6 0.2.0-rc.1 (RC), 0.1.7-rc.2, 0.1.7-rc.1, 0.1.7-alpha.2 published Verifies the same code on DSH 0.2.0-rc.1 and rewrites the declared load range so the plugin survives the 0.2.0 final release. No code change over 0.1.5; upgrading needs no migration.
0.1.5 0.1.7-rc.2 (latest 0.1.7 RC), 0.1.7-rc.1, 0.1.7-alpha.2 published Confirms the same code runs unchanged on the second release candidate and declares it. No code change over 0.1.4; upgrading needs no migration.
0.1.4 0.1.7-rc.1 (RC), 0.1.7-alpha.2 published Confirms the 0.1.7 adaptation runs unchanged on the first release candidate and declares it. No code change over 0.1.3.
0.1.3 0.1.7-alpha.2 published Adapts to DSH 0.1.7: the Session id comes from the row's own data-row-key (fiber fallback kept), chips follow the Web-Animations row gliding 0.1.7 introduced, and the Host dependency is declared the way 0.1.7 resolves a linked plugin.
0.1.2 0.1.6-alpha.2 published Fixes chips staying at their old coordinates for ~20s when a workspace is collapsed or expanded: a second MutationObserver.observe() on the same target had silently replaced the childList watch.
0.1.1 0.1.6-alpha.2 published Documentation only: the packaged README no longer says "not published", and the market screenshots are declared.
0.1.0 0.1.6-alpha.2 published First release: Session colour marks, Host-side storage, visible inside a phone's sidebar drawer

0.1.16 supports DSH 0.2.2-rc.1, the current npm next release candidate. This patch updates compatibility metadata and documentation only. Executable code, storage format and load range are unchanged, retaining the native-drawer tracking fix from 0.1.15.

Official 0.2.2-alpha.3 / 0.2.2-rc.1 artifacts were compared: the Host webServer, connection, locale, conversation, layout, workspace, slot renderer, standard Session props and primitives have identical lib artifacts; client-modules only changes its embedded build commit. Available installed artifacts match their registry counterparts (primitives are supplied by the shell rather than standalone lib files in this installation). Host inspection confirms route and authentication contracts. Client inspection confirms the active session-color-chips occupant in shell.overlay, but did not return an available header-utilities tree.

All 39 unit tests pass. An additional check using installed schemastery 3.19.0 exercised Config, apply and a mocked in-memory GET route without writing real marks. This stable version satisfies ^3.18.2, so the previous prerelease peer mismatch no longer applies to this installation. The existing DSH engine and both DSH peer ranges admit rc.1. This release does not claim real GUI, mobile or cross-device visual acceptance: registration is not visual verification. No temporary server was started and DSH was not restarted.

Registry check on 2026-11-04: DSH next is 0.2.2-rc.1, alpha is 0.2.2-alpha.3, and latest is 0.2.1-rc.5. 0.2.1-rc.5 is not on this plugin's verified list.

0.1.9 moved that range to top-level engines.dsh, the field DSH 0.2.1-alpha.4 made authoritative — it decides alone when present, and the marketplace reads the same field. That relocation still stands and is unchanged here. Upgrading from 0.1.15 needs no migration. On an older DSH — including 0.1.6-alpha.2 — keep plugin 0.1.2. Newer DSH releases are not auto-declared compatible.

  • Verified DeepSeek Harness lists the exact DSH releases assessed for this plugin. Verification depth and any browser-testing limits are stated above. That list has one home — dsh.compatibility.dshReleases in package.json — and a test keeps both READMEs' compatibility sections word-for-word with it and inside the range both peerDependencies and engines.dsh declare. A DSH version that is not listed is never claimed as compatible.
  • peerDependencies declare >=0.1.7-alpha.2 <0.2.0-0 || 0.2.0-rc.1 || 0.2.0-rc.2 || >=0.2.0 <0.3.0 || >=0.2.1-alpha.3 <0.3.0 || >=0.2.2-alpha.2 <0.3.0 for dsh-client-ui-layout and dsh-client-ui-conversation, and top-level engines.dsh declares the same range as the Host requirement: that is the range allowed to load, which is not the same as verified. The six alternatives are deliberate: a prerelease is admitted only when a comparator names its exact major.minor.patch, so the 0.1.7 line needs its own comparator, 0.2.0-rc.1 and 0.2.0-rc.2 are each pinned exactly (a 0.2.0-rc.3 nobody tested stays out), the stable 0.2.0 line is admitted so the plugin survives the final release, and the 0.2.1 and 0.2.2 lines each cover the verified alphas and RCs of their own tuple. The lower bound names the alpha on purpose: a range like >=0.1.6-0 <0.2.0 admits none of the verified versions.
  • DSH evaluates those requirements at boot and disables a plugin row whose range is not satisfied, so a correct range is load-bearing rather than cosmetic. Since 0.2.1-alpha.4, the boot precheck gives top-level engines.dsh priority over peer ranges (which is why 0.1.9 moved the range there). The declared DSH range accepts 0.2.2-rc.1; no range widening is needed.
  • DSH 0.1.7-rc.2 added a real Session-row seat, sidebar.session.row.leading — a 16px cell before the title. The chip deliberately stays on its own click-through layer: that seat shares its cell with the status dot and is mounted only while the row is idle (a running, waiting or archived row renders no occupant), so a chip placed there would vanish exactly when it is most useful. See Limitations and the design record.
  • @deepseek-ai/schemastery is a peer, not a plain dependency: DSH 0.1.7 resolves only a linked plugin's peer dependencies from the running installation, so a link: install of this directory would otherwise fail to import the Host half.
  • DSH moving faster than this plugin does not break it: chips depend on DSH's row DOM (see Limitations), so a large change to the row structure can at worst stop chips from appearing — it cannot block clicking.

Cross-device and LAN

Storage goes through the plugin's own HTTP route (GET/POST /plugins/dsh-session-colors/marks), persisted to one JSON file in the profile's data directory. That is deliberate:

DSH's own user-settings service host-backs settings only for loopback pages —

persistence = $host.isLoopback ? "host" : "memory"

— so a page opened over a LAN address or a tunnel gets a permanently unavailable scope: it can neither read nor write. An own route is not subject to that rule, which is exactly what makes a mark visible on every device. LAN forwarders (dsh-bridge, dsh-lan-proxy, and friends) rewrite Host/Origin to loopback and inject the auth cookie, so a request that arrives over the LAN still looks like loopback to DSH and the route answers normally.

Configuration

Field Type Meaning
dataDir absolute path Where session-colors.json is written. Without it, marks live in process memory only.

A mark is one JSON document:

{
  "version": 1,
  "marks": {
    "session-0698599a-…": { "h": 211.3, "s": 1, "v": 1, "a": 1 }
  }
}

Writes are atomic (temporary file, then rename). To drop a mark, use Clear mark in the picker, or remove that line from the file.

Troubleshooting

The colour still is not visible on my phone. First check which build the device runs:

document.querySelector('.dsh-sc-layer').dataset
// { dshScBuild, dshScStatus, dshScWritable, dshScMarks, dshScError }

If dshScBuild is not host-routes+animated-rows, the device is running a cached client: refresh the page (the browser half reloads on a refresh, no DSH restart needed). If dshScStatus is not ready, the store cannot be read — see the next item.

The header control shows ⚠. That means the store cannot be reached: dshScError carries the reason and dshScWritable says whether writes are possible. This happens when the Host route was never registered (the profile did not load the plugin) or the data directory is not writable. It is not the same as "this Session has no colour".

A LAN page behaves differently. Since 0.1.0 this plugin behaves identically on LAN/tunnel pages and loopback pages, because storage uses its own route. If you see the old "settings unavailable" behaviour, check which version is installed.

Chips are in the wrong place, or gone. The layer finds rows by ARIA role and reads the Session id from the row's data-row-key (falling back to React internals). A large change to DSH's sidebar structure can make it find nothing; chips then disappear, but clicking is unaffected because the layer is click-through.

Security boundaries

  • A mark stores only a Session id and a colour. It never writes Session logs, titles, history, status, archive records, or Workspace membership.
  • It never creates, copies, moves, or reorders a Session; a mark is not part of Session data.
  • The chip layer never accepts pointer events and is clipped to the sidebar's scroll container: the worst case is a chip that does not appear.
  • The Host route reuses DSH's own auth fence (connection.requestRejection), and writes add a same-origin check on top.
  • The plugin registers no model Tool, spawns no subprocess, and only uses same-origin HTTP requests for marks; it contacts no third-party service.

Limitations

  • Pre-existing limits. Current search-result rows use result.id, which the fiber fallback does not recognise, so chips are not guaranteed there. Host disk-write errors can still fall back to memory without reporting the persistence failure; this patch does not fix these existing issues.

  • The chip depends on DSH's row DOM. It reads rows by ARIA role and the Session id from the row's data-row-key, falling back to React internals. A future DSH release can stop chips from appearing; it cannot break clicking.

  • The chip is not a row occupant. DSH 0.1.7-rc.2 declares a real sidebar.session.row.leading seat in the row's status-dot cell, and this plugin deliberately does not use it: that seat is mounted only while a row is idle, so a chip placed there would disappear for running, waiting and archived Sessions. The chip stays on its own click-through layer, which keeps it visible in every state and never covers the dot.

  • Marks are per DSH instance. They live in one profile's data directory, so two independent DSH servers do not share them.

  • No permission model. Anyone who can reach the Host's authenticated routes for this profile can read and write marks.

  • Colour only. No labels, icons, or emoji.

Uninstall

dsh plugin --profile <profile> remove @idoall/dsh-session-colors

Restart DSH and refresh the Web GUI. session-colors.json in the data directory is not deleted for you; remove it yourself if you do not want it.

Development

npm test        # 39 tests: bundle shape, store, route, cross-device, geometry, docs

The browser half is a hand-authored __ModuleLoader__ bundle, which is the only format the DSH client loader accepts for a package client half. It is written by hand on purpose: there is no build step, so nothing can drift from the DSH version it targets.

src/index.js       Host half: routes, the JSON store, auth fence
src/client.js      Browser half: picker, chip layer, the fetch-backed store
tests/             Unit tests for both halves, plus the doc-consistency checks
docs/              The design record (Chinese) and the README screenshots
demos/             A standalone HTML demo of the picker

Design decisions and measurements live in docs/plugin-design.zh.md (the current part starts at the 「会话颜色标记版」 section).

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.