← Back to home@HLhhh

dsh-skill-stats

Skill usage statistics panel for DeepSeek Harness: every installed skill with its use count, session coverage, and share of all skill use.

Stars
0
Language
JavaScript
Created
Oct 25, 2026
Updated
Oct 25, 2026

Introduction

dsh-skill-stats

简体中文

License: MIT Node GitHub stars

Which skills are actually being used — and which ones you installed and forgot. A left-sidebar panel for DeepSeek Harness that lists every installed skill with its use count, the number of conversations it appeared in, and its share of all skill use.

Skill stats panel, light theme

Screenshots use sample data; the panel itself reads your own local session logs.

Why

Harness shows you which skills exist. It does not show you which skills you use. Two consequences:

  • A skill you installed months ago and never touched looks exactly like your most-loaded one.
  • A skill you rely on constantly has no evidence you can point at.

This panel answers both with the smallest honest dataset: the two moments where a skill is really used.

What counts as one use

Counting starts the first moment the plugin is enabled. Two live host events are the only inputs:

  1. an agent calls the skill tool;
  2. you invoke a skill with /name.

Nothing else counts, and no session log is ever read — not on open, not in the background. Sessions that happened before you installed the plugin are invisible by design.

ColumnMeaning
CallsNumber of the two events since enablement, inside the selected window
SessionsDistinct conversations that used the skill
ShareThis skill's calls ÷ every counted call in the current filter
Last usedWhen the most recent use happened
Source dotWhere the skill comes from: you, a plugin, bundled with Harness, a project, or uninstalled

Features

  • Live counting, no log parsing. Counts come from the host's own events (tools/result and session/event), are debounced into a small JSON file, and survive restarts. Opening the panel costs one file read.
  • Every installed skill is listed, including skills that are only callable as /name (they carry a small manual tag) and plugin-provided skills.
  • Honest source labels. bundled in the skills service only means "from a bundled skill root", so origin is resolved from the file's real location: a plugin's own skill//skills/ directory is labelled with that plugin's package name.
  • Time windows and filters: all time, today, 7 days, 30 days; filter by origin; search; "never used only"; optionally include skills that are no longer installed.
  • Local only. The counter file lives in your own DSH home. No network requests, no telemetry.

Install

This package is plain JavaScript — no build step.

From GitHub (recommended until the npm release)

dsh plugin --profile web add github:HLhhh/dsh-skill-stats

Replace web with your profile name if it differs.

From a local checkout or tarball

npm pack                                   # produces dsh-skill-stats-0.1.0.tgz
dsh plugin --profile web add ./dsh-skill-stats-0.1.0.tgz

From an agent session

Point the plugin manager at the package directory:

plugin_manager install_bundle target=/absolute/path/to/dsh-skill-stats

After installing, refresh the page once — the sidebar icon appears next to the other panel icons.

Update / remove

dsh plugin --profile web update github:HLhhh/dsh-skill-stats
dsh plugin --profile web remove dsh-skill-stats

Usage

EntryWhat it does
Sidebar bar-chart iconOpens the Skill usage panel
Panel headerInstalled / used / never used / total calls / sessions
Filter barTime window, source, search, never-used-only, include uninstalled
Table headerClick any column to sort; click again to reverse

Nothing else registers: no tools, no slash commands, no changes to other panels.

Compatibility

SurfaceStatus
DeepSeek Harness0.2.x (built and tested against 0.2.1-rc.3 Desktop and Web)
Node^22.19.0 || >=24.0.0 (uses zlib.zstdDecompressSync)
PlatformsDesktop and Web profiles with the skills feature

How the inventory is built

ctx.skills.list() only reports the layer visible to a host plugin's own scope, and a desktop profile mounts ~/.dsh/skills inside the agent preset's standing composition. The panel therefore merges four sources and de-duplicates by name:

  1. ctx.skills.list() — everything the global scope can see;
  2. the disk skill roots — $DSH_HOME/skills, ~/.agents/skills, $DSH_BUNDLED_SKILL_DIR, and the default working directory's .dsh/skills / .agents/skills, parsing SKILL.md frontmatter (CRLF and BOM tolerant, disable-model-invocation respected);
  3. skills shipped inside installed plugin packages (skill/, skills/, assets/), which is what turns a plugin's skill into plugin:<package> instead of the generic bundled;
  4. each agent preset's scope, so preset-mounted skills appear too.

The result is cached for a minute and invalidated by skills/change.

Known limitations

  • No history. Counting begins when the plugin is first enabled; anything before that is not counted — by design, because it would require reading old session logs.
  • Deleting $DSH_HOME/storages/dsh-skill-stats/usage.json resets the baseline; reload the plugin afterwards so the new file is created at that moment.
  • A skill that is used but cannot be discovered by any inventory source appears under "uninstalled" (toggle it in the filter bar).
  • Duplicate skill names are resolved to the effective one; the shadowed copy is not shown.
  • Failure marking knows only the isError result the host reports for the skill tool.

Development

npm test          # syntax + behavior smoke tests, no dependencies
npm pack --dry-run

Repository layout:

index.js            host half: session scan, aggregation, /dsh-skill-stats/api
client.js           browser half: sidebar icon + panel (plain JS, no build)
cordis.patch.yml    one Loader row
locale/             plugin-manager title/description (en, zh)
icon.svg            plugin and sidebar icon
docs/               screenshots
test/smoke.mjs      dependency-free smoke tests, also run in CI

How changes land

This repository has one maintainer and an AI agent working on it. Before changing code, the agent asks which path to take — it never decides alone:

PathWhen
Pull requestBehaviour changes, version bumps, UI changes, anything that touches counting — and whenever review is wanted
Direct push to mainOnly when the maintainer explicitly asks for it

main has no branch protection, on purpose: the choice is made per change by the maintainer, not enforced by the platform. Pull requests use ./.github/pull_request_template.md.

License

MIT — see LICENSE.