Introduction¶
The philosophy of DSH is “everything is a plugin.” When you want to add a capability you can use to your Harness, the common practice is to write a panel, defining fields yourself, piecing together interfaces, and copying styles. This plugin takes a different path: it first has an independent local web application managing real data, and then the Harness panel only acts as “reading the same data + performing the same operations.” What follows is the dsh-closet-tracker maintained by ramanasai.
What is this¶
A repository manifests in two forms: app/ is a zero-dependency Bun web application, responsible for scraping product links, storing data, and generating statistics; the repository root directory itself is a DSH plugin package, which places a hanger icon in the Harness left sidebar and renders a full wishlist panel in the main column, reading from the same app/data/items.json.
It solves the problem of: keeping data consistent on both sides, so entries you add in the web app will immediately appear in the Harness panel, and vice versa. The plugin is categorized under “Client-side” in the SkillHub community directory.
Core Features¶
The following capabilities come from the README:
- Read the same data source, sharing
app/data/items.jsonon both sides - Add items by pasting links: the app scrapes name, image, price, shop, brand, category, and the entry goes into the grid immediately
- Statistics: total wishlist value, items still to buy, items bought, price drops since last check
- Filter, search, sort: status tabs (All / Wishlist / Bought), category filtering, free text search, sort by latest / price / name / price drop amount
- Item operations: check price instantly, toggle between Wishlist and Bought, two-step confirmation to delete
- Sync all: re-scrape all tracked links and report price drops
- Native look: uses only theme tokens, follows Harness light/dark mode; empty states and offline states explain what to do; when the local app crashes, it silently retries every 12 seconds
Installation and Enablement¶
Installation is two steps: first, get the web app running, then install the plugin package. The web app does not need bun install:
cd app
bun run start # http://localhost:3003
open http://localhost:3003
The plugin package requires DeepSeek Harness (built for 0.2.1-rc.5) and a profile. The official installation method is to first clone the repository, then pass the clone’s absolute path as target to plugin_manager install_bundle—the repository root directory is the plugin package itself:
git clone https://github.com/ramanasai/dsh-closet-tracker.git
plugin_manager install_bundle target=/absolute/path/to/dsh-closet-tracker
Alternatively, you can select “Install bundle from local directory” in the Harness Plugin Manager UI and enter the same path.
Another way without cloning: download dsh-closet-tracker-1.0.0.tgz from Releases and pass the tarball path directly as target:
plugin_manager install_bundle target=/absolute/path/to/dsh-closet-tracker-1.0.0.tgz
After installation, a hanger icon labeled “Closet Tracker” appears in the sidebar. The plugin is responsible only for the interface; data is displayed only when the app is running; if the Harness page was already open before installation, reload it once after finishing.
Configuration¶
The upstream address is written in cordis.patch.yml and inserted into the profile via the bundle’s patch:
- insert:
- id: closet-tracker
name: dsh-closet-tracker
config:
# The local app. localhost reaches IPv4 or IPv6 loopback listeners.
baseUrl: http://localhost:3003
If the port changes, start the app with PORT=4000 bun run start, and then match the baseUrl. The default 3003 comes from the app itself (process.env.PORT || 3003).
Internal Structure¶
The plugin is split in two, separated by a proxy. index.js is the Host side, and client.js is the Client side.
The app is a local process that does not send CORS headers. Since Harness plugin guidelines do not allow wrapping pages in iframes, the Host side registers a same-origin proxy route, and the Client side calls it via /closet-api/api/.... The proxy behavior is quite restrained:
- Only forwards
/closet-api/api/*; other paths are not proxied - Preserves method, request body, upstream status code, and content-type
- Upstream receives only
host,content-type, andaccept; Harness session cookies andAuthorizationare not forwarded - Uses browser authentication via Harness Connection; fails closed when the Connection service is unavailable, returning 401
- Upstream address is fixed by
config.baseUrl; request path cannot change it; upstream timeout is 45 seconds; returns structured 502 JSON when the app is unreachable
The Client side renders using React in the Harness module table, using only --dsw-alias-* theme tokens. Visible text uses Harness locale service registration. There are three registration points: sidebar.panellist (id: closet-tracker, order: 30, hanger icon), main (key: closet-tracker → wishlist panel), and Host route prefix /closet-api.
Typical Usage¶
After installation, daily usage consists of three paths.
- See a product you like, paste the link into the web app. After the app scrapes it, it writes the entry to
items.json; the Harness panel refreshes to show the new entry. - In the panel, use status tabs to switch between All / Wishlist / Bought, use category filtering and search to locate items, and sort by price or price drop amount. You can check the price instantly (requests the app to scrape once), toggle between Wishlist and Bought, and delete with two-step confirmation in item operations.
- Want to see the overall drop? Click “Sync all”, and the app re-scrapes every tracked link and reports price drops.
The testing part uses Node’s built-in test runner, no Bun or a real app is required—the test starts a stub upstream itself:
npm test # node --test: proxy forwarding, allowlist, gate, header hygiene
node --check index.js client.js # syntax
cd app && bun run start # run the app itself
Applicable Scenarios and Notes¶
Suitable for two types of people: first, developers who want a privacy-controlled shopping list panel in Harness and are willing to run a local app themselves; second, people who want to study how the Host and Client halves in DSH plugins work together and what boundaries the proxy must observe—the test/proxy.test.mjs covers forwarding whitelist, auth gate, and request header hygiene and can serve as a reference.
A few points to note. The plugin runs with the permissions of the current DSH process, so read through index.js, client.js, and cordis.patch.yml as well as its license before installing; the license is MIT, and there is another copy of jsPDF packaged in app/public/vendor/ in the repository, also licensed by its author under MIT. The app’s app/data/ is a personal data directory and is already gitignored. The web app depends on no framework and can be used in any browser; installing the plugin does not affect the app itself. The README explicitly states that scraping Amazon and Ajio links has poor results (both block scrapers), but items will still be added; you will need to use the app’s edit dialog to complete them manually.
Common issues and fixes:
- Panel shows “Closet Tracker is not reachable at http://localhost:3003”: first run
cd app && bun run start; the panel retries every 12 seconds, or you can click “Try again” - Sidebar icon doesn’t appear after installation: reload the Harness page once to let the new client module take effect
- Panel shows data from another app: confirm that the
baseUrlincordis.patch.ymlmatches the app port - Port in use:
cd app && make stopwill kill the listener process occupying thatPORT(default 3003); when starting with a different port, updatebaseUrlsynchronously. Note thatmake stopkills by port; to confirm you are killing the right thing, you can uselsof -nP -iTCP:3003 -sTCP:LISTEN
Conclusion¶
The value of this plugin lies in clear division of labor: the app manages data and scraping, the plugin manages presentation within Harness, and a same-origin proxy with authentication and a whitelist connects them. The data on both sides is the same copy; changing one is sufficient. Directory page and source code are below.
- SkillHub Directory Page: https://www.skillhub.cn/plugins/ramanasai/dsh-closet-tracker
- GitHub: https://github.com/ramanasai/dsh-closet-tracker