A Wallpaper Skin Plugin for DeepSeek Harness, Built from Scratch
DeepSeek Harness is gaining traction as a coding agent platform, but its plugin ecosystem is still thin. A worked example that documents the settings whitelist workaround, the CJS factory build constraint, and the `overrideTokens` re-entry hazard saves the next plugin author days of debugging.
DeepSeek Harness ships with light and dark themes but no custom background support. `dsh-skin-alphacoders` fills that gap by pulling popular wallpapers from Alphacoders and displaying them inside the Web GUI. The plugin supports paginated browsing, keyword search, local image uploads, four fill modes, and a 0–90% overlay intensity slider that automatically switches between white and black mist based on the active theme. Preferences persist in `settings.yaml` and survive restarts.
The build required navigating DSH's dual-half plugin architecture: a Node.js host half handles network fetching, file storage, and settings registration, while a browser half renders the React UI and background layer. Because the browser module system demands a single CJS factory wrapped in `__ModuleLoader__`, the client build chain uses tsdown plus a custom wrapper script. The theme integration hooks into DSH's official `overrideTokens` API rather than touching the DOM directly.
Several sharp edges surfaced during development. The settings wire whitelist blocks browser-side reads and writes to third-party namespaces, so the plugin routes all settings traffic through its own HTTP endpoint on the host. A re-entry storm from `overrideTokens` firing `theme/change` synchronously was tamed with signature-based deduplication. And pnpm's hardlink behavior for `file:` dependencies meant source changes didn't propagate until the dev setup switched to directory junctions.
The settings whitelist isn't a bug — it's a deliberate security boundary — but the official escape hatch of plugin-owned HTTP routes is under-documented, and this plugin's implementation effectively serves as a reference architecture for any DSH plugin that needs persistent configuration.
Requiring a CJS factory wrapped in a bespoke module loader, rather than standard ESM, adds non-trivial build complexity. This constraint will trip up anyone who assumes modern bundler defaults will work out of the box.
The `overrideTokens` re-entry problem is a classic synchronous event hazard in a plugin system. The fix — signature-based deduplication — is simple but not obvious until you've hit the 500-layer recursion yourself.
Using server-rendered microdata as an API, rather than a formal REST endpoint, is a pragmatic but fragile integration strategy. It works until Alphacoders changes their markup.