DSH Plugins Marketplace

DSH Plugins

Plugins

/

dsh-semantic-drift

Y

dsh-semantic-drift

Discovered

One versioned vocabulary of a project's business concepts, a read-only drift scan, and the same naming rules in every agent prompt.

dsh-semantic-drift

English · 简体中文

A DSH plugin that keeps one versioned vocabulary of a project's business concepts, shows where the code spells them differently, and gives a person and an agent a place to decide which spelling is canonical.

DSH shows the plugin as Semantic Drift Vocabulary (语义漂移词表).

Contents

Where it comes from

The idea is borrowed from kurapica/schema-node-csharp, which argues three things this plugin takes as given:

  1. Semantics deserve to be an independent, versioned artifact — not something re-derived from the code on every read.
  2. A small, enumerable vocabulary is easier to keep correct than an open-ended type system.
  3. Drift has to be observable and adjudicable, not something a team is expected to remember.

No implementation is borrowed. There is no Meta/Property/Relation model, no semantic compilation, no code generation. One YAML file, one read-only scanner, one panel, five agent tools.

What it does

It records what things are called. Each concept gets one entry: a dotted id, the human terms for it, a kind, the canonical symbol (plus type and unit when they matter) and a note. The file is versioned with the project, so a rename is a diff someone can review.

It finds where the code disagrees. A read-only scan compares the tree with the vocabulary and reports:

  • the same type declared twice — with the member values compared, not just names;
  • two copies that have diverged (missing members, extra members, swapped enum values);
  • a copy that is really a parameterized derivative, which must not be merged;
  • a spelling variant of a canonical name, including a canonical spelling the code never uses at all;
  • a term that appears in comments or resources but never in code.

It works from an empty vocabulary too: the structural detectors compare code with code, so a fresh project has findings before its first concept exists.

It gives the decision a home. An accepted exception carries a reason and the smallest scope that covers the case. It can be edited, reworded, removed or undone later, and each one reports how many findings it actually mutes right now. The decision is a line in the vocabulary file, not a memory in someone's head.

It puts the vocabulary in front of the agent. Every session receives one prompt section with the concepts of the workspace it runs in, plus the rules: look the concept up before naming something, spell it exactly as the canonical symbol does, register a missing concept first, record a deliberate deviation with a reason. Five tools let the agent read, register, scan and adjudicate.

It costs tokens, and you can turn that off. The prompt section is the recurring cost; the panel's settings switch disables it per profile, and the scan itself costs nothing until someone asks for it. Numbers are in Token cost.

What it does not do

  • It is lexical, not semantic. It compares identifiers, member names and comment text. Two unrelated types that share a name can still be reported.
  • It does not enforce anything. The prompt rules are advice. An agent can deviate, and the only defence is that the deviation must be recorded.
  • It does not fix code. No auto-rename, no auto-merge, no patch. The scan is trusted precisely because it never writes your source.
  • Structural detection covers three languages — C#, TypeScript and Python declarations. Other files contribute comment/string evidence only.
  • Units are stored, not checked. canonical.unit is displayed and validated as a string; there is no unit-drift detector.
  • One workspace, one vocabulary. No cross-repository view.
  • It never decides for you whether the vocabulary file is committed. That is a project decision; if you commit it, the team shares and reviews it.

Install

Any of these installs the bundle into a profile:

# from npm
dsh plugin --profile desktop add dsh-semantic-drift

# from GitHub
dsh plugin --profile desktop add github:Yubickari/dsh-semantic-drift

# from a local checkout
dsh plugin --profile desktop add link:/path/to/dsh-semantic-drift

The Web GUI offers the same under Settings → Plugins → Install from source. After installing, refresh the page once so the browser half loads, then pick Semantic Drift Vocabulary in the sidebar.

lib/ is committed, so installing from a git source needs no build step. The plugin needs DSH >=0.2.1-rc.3.

Updating

There is no in-plugin updater: DSH replaces an installed bundle when it is installed again.

# npm, a specific version
dsh plugin --profile desktop add dsh-semantic-drift@0.2.0

# GitHub, pinned to a tag
dsh plugin --profile desktop add github:Yubickari/dsh-semantic-drift#v0.2.0

Restart DSH afterwards, then read the version in the panel footer (vX.Y.Z) or at GET /semantic-drift/health; the settings dialog no longer repeats it. An update never touches your vocabulary file or its accepted exceptions.

Getting started

  1. Open Semantic Drift Vocabulary in a workspace.
  2. Press Create vocabulary — writes .dsh/semantics.yaml with the default exclusions and no concepts.
  3. Press Scan. With no concepts yet you still get structural findings ("the same type is defined twice"), which is the cold-start value.
  4. Register a concept with New concept (or semantic_upsert) and scan again. Vocabulary-dependent findings now have something to compare against.
  5. Accept a finding you intend to keep: choose the scope (this file, every directory with the same file name, the whole symbol, or a custom glob), read the count it will mute, and write a reason.

Modules

The vocabulary file

version: 1
meta:
  project: demo
  updated: 2026-10-25
exclude: ["**/node_modules/**", "**/bin/**", "**/obj/**"]
concepts:
  - id: device.target_temperature      # group.name, unique
    terms: ["target temperature", "set point"]   # what humans call it
    kind: quantity                     # entity | quantity | enum | status | reference
    canonical:
      symbol: TargetTemperature        # what the code must call it
      type: double
      unit: "°C"
    note: The temperature the device is asked to reach.
    accepted:                          # decided exceptions, each with a reason
      - symbol: TargetTemp
        path: src/Legacy/**            # a glob; omit to accept the symbol everywhere
        reason: public field kept for one release

terms may be written in any language: the scanner matches them as plain text in comments, strings and resource files.

Validation runs before every write; a document that fails is never written, and the reported issue carries the YAML line or the document path:

  • id must be unique and look like group.name;
  • canonical.symbol must be a plain identifier and unique across concepts;
  • terms must be non-empty and cannot be shared between two concepts;
  • every accepted entry needs a reason;
  • every glob must parse;
  • a YAML syntax error is reported with its line and column, and the file is left untouched.

Saving is canonical and idempotent. Hand edits in the raw editor keep their own formatting.

Detectors

DetectorConfidenceSignal
duplicate-typehighsame members and same values in two units: a real copy, and merging it is a safe suggestion
highderived copy: same member names, different values, one shared base type — a parameterized derivative, never a merge candidate
highsame names, different values: no shared base, so the two sides disagree about what those names mean
contract-drifthighthe same type in two units with different members, or with different values for the same members. Skipped when one type shadows its own base, or when both are private nested helpers
symbol-variantmediuma spelling variant of canonical.symbol (case/separator form, a known confusable, edit distance ≤ 2), or same contract, other name: same base, members and stable literal as the canonical type
mediumvocabulary spelling is not in the code: canonical.symbol appears nowhere as a code token while another case form is declared or heads a declaration
term-unmappedlowa declared term appears in comments or resources, but the canonical symbol never appears in code

Every finding also carries a stable rule id in detail.rule, which is what the panel localizes:

ruledetectormeaning
identical-membersduplicate-typesame members and the same values
derived-copyduplicate-typesame members, different values, one shared base
literal-variantduplicate-typesame members, different values, no shared base
diverged-memberscontract-driftmembers or their values differ
normalizedsymbol-variantsame spelling after removing case and separators
confusablesymbol-varianta known misspelling of a token in the symbol
edit-distancesymbol-variantwithin two edits of the canonical
contract-aliassymbol-variantsame contract, another name
canonical-casesymbol-variantcanonical spelling absent, another case present
canonical-missingterm-unmappeda term is used, the canonical symbol is not

Member values are compared when they are simple single-line literals: two enums whose members swapped values used to look identical when only names were compared. A copy declared as a struct on one side and a class on the other says so in the message.

Two filters keep the list short: a variant only fires when the file also mentions a term of the concept, or both spellings share the same leading token; a contract-drift pair must share at least one member.

Deliberately excluded: entry-point classes (Program/Startup with a Main), partial declarations, generated files (*.Designer.cs, *.g.cs, auto-generated headers), declarations with fewer than two members, subclasses that shadow a base of the same name, and private nested helpers.

Agent tools and prompt injection

ToolPurpose
semantic_listlist concepts; hasDrift runs a scan and filters to concepts with findings
semantic_getone concept by id or symbol, plus its accepted exceptions; includeDrift adds a scan
semantic_upsertcreate or update a concept (merge keeps omitted fields, replace rebuilds it)
drift_scanstructured findings with detector, confidence and citation
semantic_acceptadd (default), update scope or reason, remove one, clear a concept; reason is required to add or update. previousPath locates the entry to change

With announceToAgent on, every session receives one prompt section: the concepts of the workspace it runs in and the rules that go with them. The section is capped at 200 lines and summarized past 120 concepts. Turn it off in the panel to stop the recurring token cost; the tools stay available.

A refusal is always a value ({ ok: false, code, message, issues }), never an exception. A vocabulary file that cannot be parsed is reported as valid: false with its first issues.

The loop this is built for:

  1. the agent receives a task and calls semantic_get for the concept it is about to touch;
  2. a missing concept is registered with semantic_upsert before any code is written;
  3. after editing, drift_scan shows whether the change introduced a variant or a divergence;
  4. a finding that is intentional is accepted with a reason and a narrow scope;
  5. the vocabulary diff is reviewed like any other change.

The panel

  • Left tree — concepts grouped by id prefix, a finding count per group, a group add button, search, and a quick-create button.
  • Concept detail — the fields, the findings attributed to the concept, and its accepted exceptions with Edit, Remove and (when there is more than one) Clear all. A row reads "mutes N now"; 0 means the scope matches nothing, which is worth seeing.
  • Toolbar — icon-only scan, new concept, raw YAML and settings; every icon describes itself immediately on hover and to a screen reader. The toolbar holds the only scan button; the footer reports.
  • Workspace mode — a crosshair while the panel follows the session's workspace, a pushpin while it is pinned; clicking switches.
  • Scan memory — re-opening the panel shows the report this tab already has for that workspace (default 10 minutes, configurable). The footer dates it; past the retention it raises an amber badge, and so does an edited vocabulary file. Both badges are the rescan control.
  • Remembered page — the panel returns to the concept (or unclassified list) it was on, only if that concept still exists.
  • Unclassified — findings no concept owns; they exist before the first concept.
  • Settings — four groups: workspace following (follow on or off, rescan on follow), scanning and cache (how long a report is reused), display and notices (low-confidence findings, notice duration), and agent prompts (the prompt injection switch). Every change applies at once: the browser preferences go to localStorage, the injection switch to the plugin row. There is no save button — the dialog closes with the × in its title bar. Project-level settings are not here: one line at the bottom of the dialog points at DSH's Configuration block for this bundle (see Configuration).

Configuration

The panel configures how it looks and behaves; the project configures what is scanned and which file is the vocabulary.

FieldDefaultMeaning
vocabularyPath.dsh/semantics.yamlvocabulary file, relative to the workspace root
announceToAgenttrueinject the vocabulary section into agent prompts
citationStylefile+symbolpath/File.cs::Symbol or path/File.cs:123
minConfidencemediumlowest confidence the tools report; the panel receives every level
timeoutMs30000wall-clock budget for one scan
maxFindings5000hard cap per scan
maxFileBytes1048576larger files are skipped and counted
maxFiles50000hard cap on files visited
detectorsall fourwhich detectors a scan runs

Every field in this table is plugin-row configuration, and all of it except announceToAgent is edited in DSH: Plugins → Installed Plugins → dsh-semantic-drift (the bundle) → Configuration. The plugin registers that page into the plugins.bundle.config seat and brings the field table (from the schemastery schema), the labels and the controls; the form itself — the values and the writes — is DSH's own live config form, served by its configForms service under this plugin's profile entry id, semantic-drift. The plugin keeps no save channel of its own: the page posts nothing, GET /semantic-drift/config answers the field table alone, and the values never travel over HTTP.

Every field here is volatile: the only kind DSH shows as editable, and the kind the Loader commits in place instead of unmounting the plugin row. A change is therefore in force from the next read — no save button, no reload, nothing to toggle off and on.

announceToAgent is the exception: it belongs to the panel's agent-prompt group, so the Configuration block leaves it out. The panel writes it through the Host's config editor — POST /semantic-drift/settings carries that one field and refuses a patch — and because the field is volatile the prompt section stays registered and returns an empty text while the switch is off: one click is the whole gesture, and the next prompt assembly already reflects it.

Everything else in the panel's settings dialog is a browser preference kept in localStorage — not in the vocabulary file, not in the plugin row.

How it works

Token cost

Measured on a real 18-concept vocabulary:

PartSizeEstimated tokensVaries with
5 tool schemas5,474 chars~1,400–1,800never
Prompt section1,749 chars~500–700concept count
Prompt section, empty vocabulary~250 chars~80–120—
Prompt section, 120-concept cap~8,000 chars~2,500–3,500cap

So a session in a small-vocabulary project costs roughly 2,000–2,500 extra tokens per request, and a full vocabulary up to 4,000–5,000. System-prompt caching usually discounts the stable part, but a workspace switch or a vocabulary edit invalidates it.

What you can do about it:

  • Turn the injection off in the panel settings: one click, no reload, removes the section (~500–3,500 tokens) and keeps the tools.
  • Keep the vocabulary small: it is a vocabulary of concepts, not a dictionary of every field.
  • Disable the plugin row to remove even the tool schemas.

Guarantees

  • The scan never writes. The vocabulary is the only file the plugin ever writes.
  • One write path. Panel and tools share the store: per-file serialization, validate-before-write, atomic replacement.
  • No daemon, no watcher, no index. A scan is computed from disk when asked for.
  • Bounded. A deadline and a finding cap always end a scan and the result says which one did.
  • Cheap to repeat. Parsed declarations of unchanged files are reused (path, size, mtime; a file touched in the last second is always re-parsed); identical overlapping scans share one computation. Findings themselves are never cached.
  • Workspace-scoped. Reads and writes stay inside a registered DSH workspace (or the Host's default directory). A write must name its workspace, otherwise it is refused rather than falling back to the default directory.
  • One deliberate exception to "compute on demand". The browser keeps the last scan per workspace in sessionStorage for a bounded time. It never enters the repository, a closed tab forgets it, the tools never read it, and the footer dates it.
  • Diagnosable. GET /semantic-drift/health reports what this activation mounted (five tools, nine routes, one prompt section) and the effective settings; GET /semantic-drift/config reports the field table the settings form is built from — kinds, defaults, bounds, options — and no values: DSH's form holds those.

Limits

This is a lexical tool. It knows identifiers, member names and comment text, not meaning.

  • A name is not a contract; the shared-member filter removes most false positives, not all.
  • Member lists are parsed with regular expressions; an exotic declaration is skipped and counted, never guessed.
  • Edit distance is blunt: declared type names of at least six characters, together with a shared leading token or a term in the same file.
  • term-unmapped is a heuristic (low confidence, folded by default).
  • A rename across tokens (SetTemp vs TargetTemperature) is not a misspelling; record it as a concept with terms.
  • The panel cannot open a file; it copies a citation in the configured style.
  • The prompt section resolves the workspace by the session's registered workspace. If the session runs in a directory that is not a registered workspace, the section falls back to the first registered workspace; the tools still act on the session's own directory.

Development

pnpm install
pnpm test      # typecheck + node --test
pnpm build     # esbuild -> lib/index.js (host) + lib/client.js (browser)

Three layers of tests, each for a failure the previous one cannot see:

  • test/*.test.ts — store, scanner, detectors, service and locale dictionaries, against hand-made fixtures;
  • test/fiber.test.ts — mounts the built host artifact on a fake context and drives its tools, routes and prompt section;
  • test/*.test.mjs — renders components and drives the built browser bundle in jsdom, stubbing fetch with real payloads.

tsc covers only the browser half: it catches a helper renamed in one place but called in another — a class of bug a bundler ships happily.

Contributions follow CONTRIBUTING.md, including the rule that no real project may be identifiable anywhere in this repository.

License

MIT

Comments

Loading…

Similar plugins

dsh-design-review

Mandatory cross-review for design proposals and lessons-learned: auto-detects design doc writes and enqueues them (tier=review) into the task queue, delivers the external reviewer verdict back to the

Development & InfrastructureManifest valid

★ 0

dsh plugin --profile web add dsh-design-review

by joekytc

Run multi-agent task pipelines on DSH like a team — plan, execute, review, and deliver code through a visual kanban with provable completion.

Workflow & AutomationManifest valid

★ 6

↓ 233/wk

MIT

TypeScript

Sep 30, 2026

dsh plugin --profile web add @joekytc/dsh-swarm

by Lohaslee

Product-thinking companion for DeepSeek Harness: clarifies negative boundaries first, separates facts from assumptions, routes through seven product lenses, and persists confirmed decisions to project

Tools & CapabilitiesManifest valid

★ 0

MIT

JavaScript

Sep 11, 2026

dsh plugin --profile web add dsh-super-pm

by hoyyang

思维导图式项目规划可视 + 最强防跑偏:计划→模块→任务树/DAG、执行序号、Agent GPS 站位、改图人审门、git 交叉核对、阻断级漂移防护(DeepSeek Harness 插件)

Workflow & AutomationManifest valid

★ 0

BSD-3-Clause

TypeScript

Sep 16, 2026

dsh plugin --profile web add @dsh-external/dsh-plan-board

by ZSeven-W

DeepSeek Harness (DSH) plugin: a read-only ledger for the plugins you already have installed — a capability inventory with file:line evidence, declared-vs-detected reconciliation, cross-profile versio

Security & AuditManifest valid

★ 25

↓ 101/wk

MIT

JavaScript

Oct 26, 2026

dsh plugin --profile web add @zseven-w/dsh-harbor

by beartackler

Slash commands ported from other coding agents (setup, connect, install, trust, browse, doctor, status, model, memory, compact, resume, review, mcp, init, suggest, improve, refactor), a zero-dependenc

Tools & CapabilitiesDevelopment & InfrastructureManifest valid

★ 1

↓ 506/wk

MIT

TypeScript

Aug 30, 2026

dsh plugin --profile web add dsh-bridge