Local Markdown notes as governable working memory for DeepSeek Harness agents: dual-mode source/WYSIWYG editor with images, convention or reference notes auto-inject into the system prompt with sensitive values masked, plus snapshot version history, recycle bin, undoable archiving, AI reorganization, backlinks and full-text search. Compatible with DSH 0.1.7-0.2.x.
Install
# from npm (prebuilt)
dsh plugin --profile web add dsh-notes-plugin
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:PPawnsir/dsh-notes-plugin#path:/packages/dsh-notes-plugin
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
English | 中文
📝 dsh-notes-plugin
Turn the decisions and conventions that agent sessions would otherwise "lose the moment the chat ends" into local Markdown notes
Auto-injected into the system prompt · Dispatch todos to live sessions · One-click selection capture · Pure local Markdown, never uploaded
Interactive demo
Version Compatibility (dsh-notes ↔ DSH)
DSH evolves quickly and each plugin version differs in capability and supported range — check the table below before upgrading the plugin. The declared range comes from peerDependencies (enforced by npm at install time); the "tested baseline" is the DSH version on which that plugin version was developed and regression-tested:
| Plugin version | Released | Declared DSH range | Tested baseline | Highlights |
|---|---|---|---|---|
| 0.6.5 | 2026-11-06 | ^0.1.7 | 0.2.0-rc.2 | 0.2.1-rc.2 | 0.2.1-rc.3 | 0.2.1-rc.5 | ^0.2.0 |
0.2.1-rc.5 | Feature patch (user-feedback driven): "injection scope" section in the mount modal — an already-mounted note can be re-mounted to other sessions right inside the mount / edit-mount modal (sessions grouped by workspace, existing scope pre-checked, untouched scope = parameter omitted = zero migration; notes-mount gains an optional injectTo — normalized to short ids, invalid values rejected wholesale, fail-safe); previously "re-mounting to another session" required a detour through the editor's scope chip; check 1319→1326 (new section 142, seven assertions) · e2e 645→649 (70→71 cases) |
| 0.6.4 | 2026-11-02 | ^0.1.7 | 0.2.0-rc.2 | 0.2.1-rc.2 | 0.2.1-rc.3 | 0.2.1-rc.5 | ^0.2.0 |
0.2.1-rc.5 | Host-adaptation + receipt-reliability patch: overflow "⋯" menu now fixed-positioned (folding the meta action row no longer lets the menu hide behind the sidebar — coordinates computed from the trigger's rect on open, flipping to left-alignment at the boundary, isomorphic on both ends with viewport clamping) + dispatch-receipt diagnostics and defensive fallback (rc.5 exhibited "execution succeeded but receipt never closed": four diagnostic line types in notes/_dispatch-diag.log (subscribed / subscribe-failed / event payload / no-sid, single-line JSON with a 200-line rolling cap) + six-shape sid fallback + a no-sid path that only closes when idle is positively confirmed — prefer missing over misfiring; two consecutive post-restart probes closed normally at 27.9s / 5.7s) + peer declaration explicitly enumerates rc.5; check 1314→1319 (new section 141, five assertions) · e2e 645 (70 cases) |
| 0.6.3 | 2026-10-24 | ^0.1.7 | 0.2.0-rc.2 | 0.2.1-rc.2 | 0.2.1-rc.3 | ^0.2.0 |
0.2.1-rc.3 | Host-adaptation patch: DSH 0.2.1-rc.3 verified end to end (API surfaces checked individually + four live probes — RPC / session enumeration / on-time scheduled fire / dormant wake + idle receipt + the fast-idle annotation behaving correctly in production) + peer declaration explicitly enumerates rc.3; feature surface identical to 0.6.2; check 1309 · e2e 641 (69 cases) |
| 0.6.2 | 2026-10-24 | ^0.1.7 | 0.2.0-rc.2 | 0.2.1-rc.2 | ^0.2.0 |
0.2.1-rc.2 | Maintenance patch (driven by live user reports + main-window daily audits): backlink overflow collapse (first 8 by default + a "show N more ▾ / collapse ▴" toggle row, collapse state anchored to the note id and never persisted — hub notes no longer squeeze the editor away, isomorphic on both ends) + fast-idle suspect annotation on dispatch receipts (a sub-60s idle close is recorded as idle-fast with a "⚠ Ns quick-close" line in the execution log — silent evaporations of scheduled tasks stop masquerading as successes; still closes normally, never blocks) + host 0.2.1-rc.2 adaptation (peer declaration explicitly enumerates it + adaptation note + a check anchor against future omissions); check 1295→1309 · e2e 641 (69 cases) |
| 0.6.1 | 2026-10-14 | ^0.1.7 | 0.2.0-rc.2 | ^0.2.0 |
0.2.0-rc.2 | Maintenance patch (robustness / safety gates / docs; no new syntax, no new surface): document-security write-side closure (masked-body write-back guard — writing the masked note_get body back is rejected wholesale with self-rescue guidance, never persisted; dual-form detection of whole-block secret-span placeholders and inline sensitive placeholders; driven by a real inspection self-injury incident) + secret-read audit viewer (a "Data & Storage" group entry in settings surfaces the reveal audit ring buffer, latest 100 entries, on both ends) + vector-layer hygiene (startup reconciliation self-heals missed indexing across restarts + the "last built" timestamp survives restarts + pendingErr split keys + indexable N≡M accounting) + search refinements (İ/ß/fi Unicode excerpt-offset fix + short-query suppression threshold kept per real-model evidence + legacy key cleanup) + bilingual "host capability dependencies" table (feature × host version × absence behavior, version numbers pinned by live verification); check 1269→1295 · e2e 624→641 (67→69 cases) |
| 0.6.0 | 2026-10-12 | ^0.1.7 | 0.2.0-rc.2 | ^0.2.0 |
0.2.0-rc.2 | Major release · secret spans (document-security batch S2-S6, six cards): fenced ```secret blocks as the secret-marking syntax (one-click wrap of a selection; toolbar / right-click / Ctrl+Shift+S entries, the panel trio isomorphic) + dual-mode editor masking (blur islands in rich text + opaque redaction blocks in source mode; click to reveal, auto re-blurs in ~10s, editable while revealed — masking is render-layer only: textarea.value always holds the true body, locked by byte-exact save-roundtrip assertions) + ten consumer pipelines evade secrets (injection / note_get (masked by default + spanCount) / search / excerpts / vector index / AI organize / export (incl. single-file + includeSecret switch) / dispatch payloads / health checks / selection — secrets never leak) + reveal gate (an agent must ask the user for consent via ask_user_question before reading secrets; every reveal is audited to the process log — a discipline gate, not a cryptographic boundary, honestly labeled) + on-save auto-detection of suspected credentials (one-click mark / ignore, never rewrites your body; a global toggle in the settings card "Data & Storage" group, on by default, governs only suggestions, never protection); check 1223→1269 · e2e 581→624 (61→67 cases) |
| 0.5.0 | 2026-10-10 | ^0.1.7 | 0.2.0-rc.2 | ^0.2.0 |
0.2.0-rc.2 | Major release · semantic search (four-card main batch + real-machine-driven P0-P2 fixes and R1-R3 architecture revisions): local semantic search (bge-small-zh vector embeddings fused with the text channel via RRF (k=60) — conceptual queries with zero literal overlap get recalled; embedding/indexing/querying all close the loop in the host process: onnxruntime-web pure wasm with zero native dependencies, the browser is a pure consumer, note bodies never leave the machine) + save means embed (2s debounced micro-batches, saved → searchable in <5s) + background async full-library rebuild behind "Build index" (returns immediately + status-row progress polling + sticky error on real failure) + search excerpt line + hit highlighting + "semantic" badge (note_search carries the excerpt too) + semantic settings section (master switch off by default with zero cost; the 23MB model downloads on demand host-side via the mirror chain hf-mirror→HF; sensitive and kind=sys machine notes are never indexed) + scheduled dispatch wakes dormant targets (agents.resume) + mount lines follow the target note's injectTo; check 1111→1223 · e2e 529→581 (61 cases) |
| 0.4.8 | 2026-10-08 | ^0.1.7 | 0.2.0-rc.2 | ^0.2.0 |
0.2.0-rc.2 | Seven cards (UX rework batch + test-net trust stamp, clearing UX-inspection R1/R2 findings): [[ wiki-link autocomplete (caret-following dropdown in source mode, in-memory zero-RPC search, keyboard boundary locks) + triple-classification convergence (topic merged into tags — read-side effTags virtual merge with zero migration risk, lazy write-side persistence, sidebar topic tree → multi-value tag tree, tag chip editor) + note-row context menu (Move to… folder-tree submenu / pin / dispatch / delete) + settings group navigation (seven-group rail + narrow-width chips + scroll-spy) + language toggle in topbar (🌐 zh/en instant switch; settings item retired) + mock/host contract alignment audit (17 drift fixes + standing gates: registration parity / live key-set diff with 36 probes / 12-group filter matrix / exemption list — adding a host RPC without mock now fails check) + injection-manager narrow-width overflow fixes; check 1050→1111 · e2e 359→529 (51 cases incl. real-browser panel harness) |
| 0.4.7 | 2026-10-08 | ^0.1.7 | 0.2.0-rc.2 | ^0.2.0 |
0.2.0-rc.2 | Seven cards (live-user testing surfaced 6 real bugs): scheduler stability (P0 hotfix for anchored first-fire never firing + same-title dedicated sessions now discriminated by note-id suffix) + dedicated-session permission preset (schedule 10th key preset — two explicit tiers, passed through to host permissionPresets + dispatch-modal dropdown and "headless session" hint) + AI-organize overhaul (busy veil / sticky failure banner / over-limit precheck + adaptive per-model configurable length cap organizeMaxChars) + conflict-check timeout 8s→120s + editor data safety (close-flush of in-flight edits + unified red "load failed" dot + source-mode in-flight lock) + panel e2e harness (mock-mounted React panel + vendored React, real-browser panel cases covering the kind-lag/group-paging paths) + UX polish (sticky settings save bar / collapsible descriptions / meta action overflow menu / keyboard-reachable group paging / tri-state ⓘ) + telemetry backoff & slow-RPC diagnostics hook; check 1007→1050 · e2e 231→359 (39 cases) |
| 0.4.6 | 2026-10-07 | ^0.1.7 | 0.2.0-rc.2 | ^0.2.0 |
0.2.0-rc.2 | Combined release (includes unpublished 0.4.5; 21 cards + 1 hotfix, driven by UX inspection R2 + live-user reports): stability hardening (RPC resilience — 20s timeout / non-blocking slow-bar / landing empty state + rich-text in-flight fake-green-sync root fix: edit lock + "body loading…") + governance surfaces to topbar (Suggest button with live count badge + conflict-check shortcut + "core concepts in 30s" in help) + @-mention notes in composer (notes candidate group, title search, body inlined) + convention health check (LLM pairwise conflict/supersede detection over injected conventions, sensitive masked, suggest-only) + one-click MD export + session-header 📎 injected-list badge + scheduling (edit-misfire root fix via declaredAt re-anchoring + dedicated sessions can pick a model) + grouped paging (pinned/folder/unfiled/topic each get "load more (N left)"; global window slice and scroll-load deadlock retired) + kind filter one-tick lag root fix (filtersRef ordering defect, explicit param) + dispatch no longer auto-resolves notes + 19 copy/consistency items + 6 suggester-flow breakpoints + check section auto-discovery; check 882→1007 · e2e 231 (31 cases) |
| 0.4.4 | 2026-10-06 | ^0.1.7 | 0.2.0-rc.2 | ^0.2.0 |
0.2.0-rc.2 | Eight cards (driven by live-use proposals): dispatch overhaul (dispatch receipts as notes — "执行记录 · title" kind=log companion in a dedicated folder, 📤/📥/✅ three views unified, clickable jump on both ends + dormant-session "deliver on next activity" with zero wake + periodic-schedule dedicated session created on first fire and reused after) + directory supplementary lines removed entirely (mount lines = sole directory source) + folder governance (folder expand = explicit sys entry to browse memory archives + hidden attribute as pure UI mask (show-hidden toggle / right-click hide / jump-to unaffected) + machine-sediment folders sys-hidden by default (work logs / memory archives / exec records, revealed via Machine filter or show-hidden)) + AI organize optional user-instruction modal (prompt byte-identical when empty) + panel-reopen empty-body fix (rich-text uncontrolled DOM rebuild hole, dual gate); check 824→882 · e2e 141 (22 cases) |
| 0.4.3 | 2026-10-05 | ^0.1.7 | 0.2.0-rc.2 | ^0.2.0 |
0.2.0-rc.2 | Combined release (includes unpublished 0.4.1/0.4.2 + 14-card main batch + 12-card acceptance-repair batch): note network kernel (graph kernel / RootNote hosted sections / onNoteChanged event bus / per-note serial chain / kind=sys) + three-layer injection pipeline (payload = injection-index §1 mount lines with human-editable "when to read me" / machine storage = telemetry.json with four disciplines / presentation = directory-section value-signal line) + catalog & reference buckets merged into a single directory section (mount lines as enhanced state, off by default) + whenToUse LLM-prefilled mount modal (modal-first on three entry points, 8s fallback to title) + work logs on par with regular notes (visible/searchable/editable/explicitly catalogable, injection hard-off; "file view" & overlay special-path removed, expand lag 64×→1×) + sys machine notes quiet by default (panel "Machine" filter to browse memory archives; archives filed into a real folder) + useCount unified into note-stats facet single source of truth (note_get hot path no longer rewrites .md) + utility ledger three layers (telemetry / signal line / per-memory archive details) + browser e2e suite (17 cases, 90 assertions); check 736→824 |
| 0.3.3 | 2026-10-04 | ^0.1.7 | 0.2.0-rc.2 | ^0.2.0 |
0.2.0-rc.2 | Agent memory r3 lane model (convention/memory parallel lanes — enabling no longer asks for overlap-conflict confirmation) + injection manager panel (library-wide injection three-state overview + per-row direct edit + multi-select batch) + settings card interaction feedback (permanent ✕ close + dirty save/revert + fallback flush on close) + internal modularization refactor (client 46 slices / app 40 slices / host dual manifests 45 slice entries, dual-package same-source assemblers byte-equivalent + zero-BOM assertion on the publish surface) + check --only section-scoped regression; peer declaration unchanged |
| 0.3.2 | 2026-10-03 | ^0.1.7 | 0.2.0-rc.2 | ^0.2.0 |
0.2.0-rc.2 | Pure README re-release (remedy for the 0.3.1 release accident where the README was not synced: filled in missing descriptions for version history / token statistics / nested folders and more), zero code changes |
| 0.3.1 | 2026-10-03 | ^0.1.7 | 0.2.0-rc.2 | ^0.2.0 |
0.2.0-rc.2 | Agent memory v0 (kind=log work-log sedimentation + memory-guide onboarding + log hygiene) + snapshot version history + token consumption statistics + virtual folder nesting (maxFolderDepth / recursive subtree / cascade delete) + trash batch & multi-select delete + list resilience; the npm-page README stayed on the 0.3.0 list (remedied in 0.3.2) |
| 0.3.0 | 2026-10-02 | ^0.1.7 | 0.2.0-rc.2 | ^0.2.0 |
0.2.0-rc.2 | Major release: dual-mode editor (source ⇄ rich text) + image support + ✨AI organize + explicit archive (preview/undo) + sensitive masking + injection enhancements (staleness/budget/previewer) + trash + usage telemetry + wiki-links/backlinks + single-file export + organize suggester + filter center (~20 items, see the feature list); peer declaration kept unchanged (upper bound ^0.2.0, conservatively not opening 0.3.x — unverified) |
| 0.2.4 | 2026-09-30 | ^0.1.7 | 0.2.0-rc.2 | ^0.2.0 |
0.2.0-rc.2 | DSH 0.2.0 compatibility: the declaration explicitly covers the 0.2.0-rc.2 prerelease (semver prereleases do not match wide ranges and must be enumerated); rename-race guard against body loss; verified loading on a local 0.2.0-rc.2 |
| 0.2.3 | 2026-09-30 | >=0.1.7 <0.2.0-0 |
0.1.7 | npm page README synced with the repo root (sync-pkg-readme + docs whitelisted) |
| 0.2.2 | 2026-09-30 | >=0.1.7 <0.2.0-0 |
0.1.7 | Declared range correction: lower bound tightened to the tested baseline 0.1.7 (0.1.5~0.1.6 dispatch list timed out in practice, and 0.2.1 still wrongly declared the old range) |
| 0.2.1 | 2026-09-30 | >=0.1.5-rc.1 <0.2.0-0 |
0.1.7 | Context injection dual roles (convention/reference) / injection scope drops the workspace dimension (defaults to all sessions) / entry button & color v2 polish |
| 0.2.0 | 2026-09-29 | >=0.1.5-rc.1 <0.2.0-0 |
0.1.7 | Virtual folders / UI v2 / catalog index injection / import & export / /dsh-notes-app / 0.1.7 dispatch performance fix |
| 0.1.2 | 2026-09-25 | >=0.1.5-rc.1 <0.2.0-0 |
0.1.5~0.1.6 | Basic panel: CRUD / quick capture / dispatch / convention injection / search |
| 0.1.0 | 2026-09-23 | >=0.1.5-rc.1 <0.2.0-0 |
0.1.5-rc | First npm release |
- Recommendation: always use the latest plugin version + a DSH at or above the table's "tested baseline"; below the baseline the RPC surface is not guaranteed complete (e.g. <0.1.7 has the dispatch-list timeout problem — 0.2.0 ships a mitigation, but behavior follows 0.1.7).
- semver prerelease note: a prerelease like
0.2.0-rc.2does not match a wide range like>=0.1.7 <0.3.0-0(semver rules), so prerelease branches must be enumerated explicitly in the declaration — done this way since 0.2.4. - 0.2.1-rc.2 / 0.2.1-rc.3 / 0.2.1-rc.5 adaptation confirmed (three rounds of live verification: RPC / panel slot / scheduled-wake agents.resume / agent-status event / session enumeration / dormant-wake receipt chain — all pass; the peer declaration enumerates all three rcs explicitly). On rc.5 one "scheduled dispatch executed but its receipt never closed" occurrence was observed; after a host restart two consecutive probes closed normally (27.9s / 5.7s), and a
_dispatch-diag.logdiagnostic probe now ships to pin down any future recurrence. - When DSH makes a major change (
0.xminor-version jump), this table is updated after the corresponding plugin adaptation release; thepeerDependenciesupper bound (currently<0.3.0-0/^0.2.0) is the conservative "not yet verified on the newer DSH" declaration, and lifting it happens with a new plugin release.
Host Capability Dependencies (feature × host version × behavior when absent)
The table above is the per-release history; this one switches the axis — it maps each feature to the host capability it depends on and what actually happens when that capability is absent. Every version below is pinned against the code of the published host npm packages, not written from memory:
| Feature | Required host version / capability | Behavior when absent |
|---|---|---|
Dispatch session list (session-metadata cache + titlesPending polling) |
DSH ≥ 0.1.7 | The list is slow / times out (0.1.5~0.1.6 verified unusable); plugin 0.2.0 ships a cache + polling mitigation, but behavior still follows 0.1.7 |
| Scheduled dispatch waking dormant targets | Host provides agents.resume (verified present in the dsh-agent package since 0.1.5-rc.1 — the entire declared range is covered) |
Probed per point at runtime: when absent, the schedule chain records lastError ("host does not support agents.resume"), never silently queues, never crashes the page; manual dispatch is unaffected |
| Notes panel & session-header entries | Host slots service + the built-in shell.overlay / conversation.session.header.actions seats (verified present since 0.1.5-rc.1) |
When the slots service is absent the client logs a console.error and skips mounting entirely — the entries and panel never appear, the rest of the host page is unaffected |
| Agent memory / injection / search / semantic search / secret spans | No extra host dependency (closed loop on the plugin side; semantic embedding runs in the plugin's own host-process code, note bodies never leave the machine) | — (nothing beyond the declared range is required, so there is no absence case) |
General principle: when a host capability is absent, degrade by capability instead of crashing the page — what can be probed at runtime is probed and degraded per point (the capability probes and guards in the rows above); what cannot is left to peerDependencies, enforced by npm at install time.
What Problem It Solves
Conclusions inside agent sessions are disposable: why a design was chosen, which hard conventions a project has, the todo that popped up this afternoon — all scattered across the conversation stream. Compress the context or close the session, and that knowledge is gone. The next session's agent doesn't know what was decided last week, and the user has to repeat conventions over and over.
dsh-notes turns this into an accumulable local asset:
| Problem | Solution |
|---|---|
| Conclusions vanish when the chat ends | Press Enter in the panel to store a local Markdown note (~/.dsh/notes); one-click capture for selected text; never leaves your machine |
| Notes get messier as they grow | An LLM asynchronously infers the topic and backfills title/category; two orthogonal dimensions — kind (note/decision/todo/link/quote) and status (active/pinned/resolved/superseded) — plus virtual folders for filing |
| Agents don't know your conventions and reference material | A three-state segmented control in the detail area — "⚡ Off / Convention / Reference": convention = behavioral rules that must be followed, reference = factual background material (agents pull it on demand); note content is injected into the agent system prompt bucketed by role (order 130); scope defaults to all sessions and can be limited to specific sessions |
| Agents don't know what's in the library | Directory section (merged into the single order 130 injection): mounted lines (- [[id]] when-to-use: …) are the sole content source — only explicit mounts enter the section, with a gentle planning nudge in the system prompt; note_get fetches the full text of relevant entries, note_search finds more (no full-library flat listing since 0.4.4-E) |
| Todos never get executed | One click dispatches a todo to any live session (Agent.send injects "recall context + concrete instructions" and wakes the target to start work); dispatch history can be marked done |
| Can't find it afterwards | Instant panel search + full-text fallback union search, the note_search tool filters by tag/topic/kind, archive merges by session or tag, soft delete is restorable |
Design Philosophy: The Note Network
dsh-notes is not just "a notes plugin with a panel" — the whole product is a continuously growing network of note references: nodes = notes (memory / reference / log / archive / index / todo…), edges = references. Features change endlessly, but their carrier is always a node on this network; every governance surface is a node, and high-frequency writes always land in root notes. Every new feature must first pass the design question: What are its nodes? What are its edges? (nodes first, then edges)
The four kinds of edges in the network:
| Edge | Form | Semantics |
|---|---|---|
| Wiki link | [[id]] in the body |
Evidence (log → memory) / association |
| Soft link | front-matter field (schedule.runLog, refNote) |
Association (companion note points to its host) |
| Index mount | Injection-index §1 line - [[id]] 何时查我:… |
Mount (index → reference; the primary recall channel) |
| Dispatch mount | dispatches[].sessionId |
Recall (task → reference = deterministic distribution) |
Root-index pattern: machine-produced artifacts never add a new panel — data concentrates in linked companion notes (the RootNote hosted-section framework: anchor section / line format / idempotence / tail trimming; the machine only performs line-level edits inside the section, zero touches outside it). Instances: scheduled-dispatch execution log, memory archive, and the injection index. The ruled exception (0.4.3 acceptance fix ⑤) covers recall metrics: high-frequency machine counters move out of note bodies into the notes/telemetry.json machine store (in-memory deltas + 2s debounced atomic flush + capacity gates; single writer = the host process), the legacy recall-telemetry note degrades to a human-readable mirror refreshed by the daily-evaluation cron (zero note writes on the hot path), and metrics surface to the panel through the notes-recall-stats RPC. The presentation layer (0.4.3 acceptance fix ⑥): injection assembly appends a value-signal line to the tail of the directory section ((本周引用:id×count|零引用候选:id|截至 HH:MM) — computed from the in-memory ledger snapshot, an atomic same-version snapshot with the directory rows, mentioning only surviving directory-row ids, silently omitted without a snapshot, ≤200 chars), and the injection-manager panel shows a compact mount-area stats row (mounted N|week Top|zero-ref M; click to expand full per-channel stats) — the signal line serves presentation only; correctness or cleanup decisions must go through the full notes-recall-stats output or human review (usage-grading red line). The original body is never touched — a convention's body is the dispatch payload; history always goes into the companion note.
Memory governance tiers (recall guarantee grading): inject full-text injection = strong guarantee; task mount (one whenToUse line in index §1) = medium guarantee · the primary channel. Reference notes are not injected by default — mounting is an explicit action. (The former weak tier — a flat full-library catalog index — was removed entirely in 0.4.4-E: flat listing conflicts with the explicit-mount model.)
Red lines: the convention bucket is injected verbatim and untouched; reference notes are not injected by default (mounting opts in explicitly); archive/metrics root notes are never injected (no recursion); work logs are first-class notes (visible / searchable / editable), with a single hard gate — injection is never available (no UI toggle + host-side enforcement).
Install
Host requirements: Node ≥ 22; DSH ≥
0.1.5-rc.1(declared viapeerDependencies; see package.json for the version range including prerelease branches)
dsh plugin --profile web add dsh-notes-plugin
Takes effect after restarting DSH: a "Smart Notes" button (✎, with a count badge) appears in the session header — click to open/close the panel; there is also a draggable floating bubble entry in the corner of the desktop.
Size note: since 0.5.0 the semantic-search embedding runtime ships with the package (onnxruntime-web pure wasm + transformers.js, about +25MB). The zero-native guarantee is structural: the host side always imports the transformers web build (where sharp/onnxruntime-node are webpack-ignored stubs that are never referenced), independent of install layout; npm overrides whole-package stubbing stays as defense-in-depth — this repo's install tree contains zero
.node/ zero@img/*binaries. The vector model itself (bge-small-zh-v1.5, ≈23MB) is not in the npm package: it downloads via the mirror chain (hf-mirror → huggingface.co) into~/.dsh/notes/models/on first enable. All inference is local; note bodies never leave the machine.
Upgrade / Uninstall
dsh plugin --profile web add dsh-notes-plugin@latest # upgrade (restart DSH)
dsh plugin --profile web remove dsh-notes-plugin # uninstall (data is kept)
Feature List
- Quick capture: the top-bar
+icon (orAlt+N) expands the input box —Entersaves,Shift+Enterinserts a newline; an LLM asynchronously infers the topic and backfills the title without blocking interaction - Selection capture: select any text on the page and a floating "quick capture" button appears — one click stores it as a
quotenote (you can also write a "remark" in the same popover and let the LLM extract tags/kind/injection intent) - Same-session merge: consecutive quick captures within a 10-minute window are auto-merged by timestamp into one note, avoiding fragmentation
- Kind & status:
kind= note / decision / todo / link / quote;status= active / pinned / resolved / superseded (pinned notes are grouped separately, resolved notes are dimmed) - Virtual folders (nestable): the sidebar note tree is organized as "📌 Pinned / 📁 Folder tree / Unfiled notes"; folders nest (right-click "New subfolder" or drag to re-parent; depth cap
maxFolderDepthdefaults to 3 levels, adjustable / 0 = unlimited, cycles auto-rejected); folder views and counts use the recursive subtree caliber (clicking a parent folder shows all descendant content); deleting a folder deletes its children with it (the confirm states "N subfolders + M notes move to the trash (restorable); the folder structure is not restorable", and restored notes whose original folder no longer exists fall back to unfiled); right-click offers rename / move up-down (swap among siblings) / move back to root; the manifest persists infolders.json(parentfield, zero migration for existing data), selection state inlocalStorage - Snapshot version history: before every save, the previous version is auto-snapshotted into
.history/<id>/(tiered retention: every version within 1 hour / hourly for the current day / daily within 7 days; 20-version cap per note + a global 50MB LRU); the detail area's "History" panel lists versions (time/bytes), opens read-only previews, and restores with one click — the current version is auto-snapshotted before restoring, so a restore is itself undoable (just roll back again) - Panel UI v2: two-column layout — left note tree (pinned / folders / unfiled grouped by topic; the "topic filter" applies globally across folders), right full-width editor (title + topic/tags/kind/status meta chips editable in place); SVG icon library + DSH design-token colors, light/dark theme adaptive; quick capture card v2 (selection preview + copy/save/cancel — a successful copy closes the card)
- Bilingual UI (Chinese / English): the settings card "Language" row switches the UI between 中文 and English (persisted in localStorage, Chinese by default, full re-render on switch); runtime flat dictionaries
src/i18n/zh.js+en.js(single source shared by both client states) witht(key, { name })interpolation — a missing key falls back to the Chinese original and never leaks a raw key; check.js runs a resident i18n guard (zh/en key-set equality + duplicate-key defense + two-way dictionary↔code reference coverage + product dictionary spot checks) and prints an advisory "uncovered list" of remaining inline-Chinese files at the report tail (non-blocking); host-side RPC error messages stay Chinese in this release - Context injection (dual roles): the detail area's three-state segmented control "⚡ Off / Convention / Reference" (independent fields
inject+injectRole, not tag-based) — convention = behavioral rules that must be followed (injected into the "user conventions" bucket every turn), reference = factual background material (the "reference material" bucket, pulled on demand when relevant to the current task); the scope popover is multi-select — inject into all sessions by default, tick specific sessions to restrict to them (sessions grouped by workspace and shown by name; sub-agents and archived sessions auto-excluded) - Directory section (since 0.4.3 merged with the reference bucket into a single directory section; mounted lines are the sole source since 0.4.4-E): a lightweight listing beside full-note injection = mounted lines (
- [[id]] when-to-use: …from injection index §1) — reference material = explicit mount; unmounted notes are no longer listed flat (0.4.4-E removed "directory supplements unmounted entries": a flat full-library listing conflicts with the explicit-mount model; thecatalogEnabledmaster switch / preview badge / catalog telemetry tap retired with it, and a leftover key in settings.json is an inert dead key, never migrated; therecallfield lost its last consumer and stays dormant with read/write compatibility); mounted lines ride in the sameorder 130injection as conventions (the former standaloneorder 131block is retired) with a gentle planning nudge and anote_getmount hint; when the injection budget squeezes, mounted lines drop oldest-first; the section tail carries a work-log count line and a value-signal line (0.4.3 acceptance fix ⑥:(本周引用:id×count|零引用候选:id|截至 HH:MM), computed from the in-memory ledger snapshot as an atomic same-version snapshot with the directory rows, silently omitted without a snapshot) - Injection manager panel: settings card "Injection Manager → Manage…" — a library-wide injection three-state overview (convention N / reference M / not-injected K stat chips that filter on click + 250ms debounced search); per-row three-state segmented direct edit (semantics exactly identical to the detail-area control; since 0.4.3 acceptance fix ⑪, switching a single row to "Reference" first opens the whenToUse edit dialog — LLM draft prefill, the index line lands and the note flips to reference only on confirm, cancel is side-effect free; the detail-area three-state control uses the same flow); multi-select batch "Set as convention / Set as reference / Turn off injection" (confirm-gated, per-item failure counting does not interrupt; batch "Set as reference" stays silent with default mount lines whenToUse = title); injecting entries first (convention > reference), sorted by update time descending within groups; logs are inject-hard-gated (no per-row injection toggle — a static "logs never inject" label instead — and not batch-selectable; host-side injectForcedOff enforcement as a second guard), sensitive-note rows hint that injection auto-masks, and an ever-injected badge shows the sticky flag; a mount-area stats row (0.4.3 acceptance fix ⑥: mounted N|week Top|zero-ref M, reusing the
notes-recall-statsledger snapshot, click to expand full per-channel recall rates, silently omitted without a snapshot) - Settings card interaction feedback: a permanent ✕ close in the title bar + dirty-state "Save" (explicit confirmation: all numeric fields are validated first, then only keys whose "control value ≠ persisted value" are written serially) / "Revert" (rolls back to the snapshot taken on open); closing via ✕/Esc/mask click with unpersisted changes auto-flushes as a fallback and confirms via toast; the existing save-on-select / save-on-blur auto-save is unchanged
- Task dispatch: one click dispatches a todo to a live session or a new session, with optional concrete instructions; dispatch records (session name/instructions/time/done) live in the note's
dispatchesfield without polluting the body; the target session's system prompt keeps injecting the todo until it is marked done; DSH 0.1.7 adaptation — the live-session list goes through the session metadata cache (on a miss it returns a placeholder +titlesPending, and the frontend polls every 1.5s to fill in), cutting load time from 128s to 0.2s - Scheduled dispatch (a convention is a schedule): a
contractType: dispatch-scheduleconvention note + a structured front-matterscheduledeclaration ({at|every, target, action, enabled, anchor?, dow?}— natural-language parsing is forbidden) — the host runs a resident 30s cron tick (unrefso it never holds the process, reload-safe against double runs, catch-up evaluation on startup), and when due it reuses the full dispatch pipeline to auto-dispatch (the dispatch card's source is labeled "Scheduled @title", and receipts close the loop through the existing chain); three-layer state = front-matterschedule.lastFiredAt/lastRun/lastError(machine read/write) + the existingdispatcheshistory array; execution-record companion note (runLog soft link, 0.4.4-A three-tables-in-one): on dispatch success a "执行记录 · @title" note is lazily created (kind=log work-log type — injection hard-disabled, still visible/searchable/editable as usual, filed in the dedicated「执行记录」folder), the convention's front-matterschedule.runLogstores its id as a soft link (non-schedule dispatch sources use a top-levelrunLogfield; manual dispatch 📤 / receipt 📥 / manual close ✅ lines append line-wise into the same note), and both the detail plan block and the meta dispatch-history rows offer a "Run log ↗" jump — the convention body is never touched (the body is the dispatch payload; appending history would pollute the next dispatch context), entries newest-first trimmed to ≤50, idempotent dedupe by msgId, and deleting the convention does not cascade-delete the run log (kept for the record); the idempotency lifeline =lastFiredAtis persisted before dispatching — a one-shotatmissed while stopped fires once on startup, a missed recurring tick aligns to the next cycle without catching up; anchored time (recurring mode optionally takesanchor: 'HH:MM'local time + weeklydow: 0-6): first fire = the next local anchor time, and the firing sequence is pinned to that time of day without drifting from creation/fire times — existing declarations withoutanchorkeep pure-interval semantics (zero migration); write red lines:atmust be in the future / recurring interval ≥5min /anchorstrictly HH:MM and requires a whole-day interval /dow0-6 and weekly only / target session alive /runLogmust be an existing note id or empty / unknown fields rejected - Search: the panel search box (instant local filtering + 250ms debounced full-text fallback, unioned), the filter center (a "Filter(N)" button + grouped popover — the status group pinned/injected/ever-injected/sensitive and the kind group of five kinds are all multi-select, OR within a group and AND across groups, active-condition chips individually removable, ever-injected feature-detected via the slim field; an independent sort control time/references/relevance, conditions and sort persist), and the
note_searchtool - Semantic search (0.5.0, off by default with zero cost): flip the master switch at the tail of the settings card's "Search & Injection" group — embedding / indexing / querying all close the loop inside the host process (the onnxruntime-web pure-wasm runtime ships with the package at about +25MB, zero native dependencies; the browser is a pure consumer and note bodies never leave the machine); the bge-small-zh vector model (≈23MB) is not in the npm package — on first enable the host downloads it on demand via the mirror chain (hf-mirror → huggingface.co) into
~/.dsh/notes/models/(safe to delete — it re-downloads on next enable); saving embeds (2s debounced micro-batches — saved → searchable in <5s), and the "Build index" button starts a background async full-library rebuild (the RPC returns immediately, the status row polls progress, and real failures stick as an error banner); retrieval fuses the text and semantic channels with RRF (k=60) (one chain across the panel search / the full-window page /note_search), recalling by meaning even with zero literal overlap; result rows carry an excerpt + hit highlighting, purely semantic hits wear a "semantic" badge, andnote_searchexposes the excerpt too; sensitive notes and kind=sys machine notes are never indexed; when the model is not ready or no index exists, search silently falls back to plain text (no errors, no blocking) - Keyboard flow:
Ctrl+Ksearch (↓inside the box jumps straight to the first hit in the list, keeping the filter context),Alt+Nnew note (Ctrl+Nis the browser-reserved "new window" key and has been dropped),j/k/↑↓move the focused row (visible highlight),Enteropens,Esclayers (close popover → clear search and refocus the list → close the panel); typing in inputs never gets hijacked; same behavior in the floating panel and the full-window page (/dsh-notes-app) - Explicit archive: the title-bar "Archive" first runs a dry-run preview (
notes-archive-preview, with an onboarding bubble), and quick-capture groups merge only after you tick them (notes-archivewhitelisted groups — the host fully validates before acting; the toast can undo once vianotes-archive-undo); manual notes are excluded from auto-grouping (mis-merge protection) — use the list's "Select" multi-select to merge them; original notes are soft-deleted (.bakbackup) and restorable - Organize suggester: settings card "Organize Suggestions" —
notes-suggestdry-run, zero writes, nominates six candidate classes: quick-capture archive groups / stale unreferenced (kind=note/link older thanstaleDaysand never hit bynote_get) / orphan notes (ordinary notes with no[[wiki-link]]outlinks or backlinks, not injected, zero references) / log hygiene (agent memory v0: weekly aggregation beyond 7 days + monthly aggregation beyond 90 days) / zero-signal mounts (0.4.5-C telemetry-driven: §1 mounted notes with zero events across the five channels — inject/dispatch-mount/search/get/catalog — in the last 14 days, mounts younger than the window exempt; actions: unmount (note kept) or edit text) / hot but unmounted (0.4.5-C: active notes/links fetched+searched ≥3 times in the last 14 days and not mounted, same exemptions as orphans; action: mount with LLM-prefilled text); it only nominates, never executes — jump straight to archive preview / batch soft-delete (no confirm, toast-undoable) / orphans are display-only with per-item jumps / log hygiene only expands details / the two telemetry classes reuse existing channels (unmount = turning injection off which removes the mount line; mount = MountModal) and silently degrade to empty when telemetry is unavailable - Agent memory v0 (work-log sedimentation, r3 lane model): the settings card "Agent Memory" section "Enable sedimentation guide" — creates a prefilled convention note (
inject=true,contractType: memory-guidecontract identity marker (withtag memory-guideas a compatible discovery key), three scope tiers), guiding agents to write session conclusions askind=logwork logs when a task wraps up or when you say "jot down today's work" (four-section template: what was done / changes / leftovers & follow-ups / linked notes); the lane model: agent memory is a parallel lane independent of note conventions — conventions govern how you take notes (for humans to read), memory governs what the agent sediments for itself (self-recall); both may apply to the same event with no overlap check / conflict confirmation; logs produced while the guide is active getorigin: memory-guidein front-matter for provenance; logs are first-class notes (since 0.4.3⑦: visible in default lists/search, openable and editable like any note),injecthard-off (no panel toggle + host enforcement), and never nominated by stale/orphan cleanup; out-of-window old logs are nominated for aggregation by workspace×week/month in the suggester's "log hygiene" section (nominate only, window adjustable in the settings card); disabling = turning off that convention's injection (spec:design/agent-memory-v0.md) - Dual-mode editor (source ⇄ rich text): toggle via the two-segment switch on the meta row or
Ctrl+/— rich text is a restricted WYSIWYG (whitelist: h1-h3 / lists / quotes / fenced code blocks / bold-italic / inline code / links (http/https only) / images / wiki-links; render ⇄ serialize round-trips losslessly, writing back to source with a 900ms debounce); rich-text toolbar (bold/italic/link/image) + paste-HTML whitelist sanitizing (h4-6 demoted to paragraphs, script/style dropped); when the body contains syntax outside the whitelist, the rich-text entry is greyed out with a banner explaining why, and recovers once cleaned - Relaxed rich-text gate: inline HTML (
<b>/<i>etc.) renders literally, GFM tables render read-only (contenteditable=falseatomic islands, serialized back verbatim) — no more whole-document downgrade; only ambiguous structures like multi-line HTML blocks / nested quotes disable rich text - ✨ Organize (AI rewrite by template): the "Organize" button on the editor meta row — the current draft goes through
notes-ai-organize(the same LLM channel asnotes-quick-instruct) and is structurally rewritten perkindtemplate (decision → background/conclusion/rationale, todo → checkboxes, link → link/description, quote → quote block/source, machine/ops info → environment/machine list/accounts/portals); after replacement it flows through auto-save, and the toast can undo once; bodies over 12000 characters error out with guidance to split - Kind template skeletons: new notes are prefilled per kind (same templates as above;
noteis free-form empty) — the panel's new-note modal lets you pick a kind, and the full-window page follows the filter center's kind group (prefills with that kind when exactly one is selected) - Image support: bodies reference
relative paths (files land inassets/), with three upload entries — paste / drag-drop / toolbar button (notes-asset-upload: mime whitelist png/jpeg/gif/webp, ≤5MB;GET /dsh-notes/assetserves<img>loads, path-traversal-proof); PNG/JPEG over 1MB are downgraded client-side on a canvas to JPEG before upload (long edge ≤2560px, quality ladder 0.85→0.45, transparent backgrounds painted white; GIF/WebP untouched to preserve animation/transparency), and the upload dialog shows "compressed: before → after"; archive backups and import/export carry assets along - Asset cleanup: settings card "Asset Cleanup" —
notes-assets-prunescansassets/for orphan files not referenced by any note body (references from deleted notes still count as protected — better keep than delete), and deletes only after you tick them in the dry-run preview; the published static package performs real deletion, while the dev build clears placeholders (0-byte tombstones) - Trash: the sidebar-bottom "Trash" (same entry in the panel and the full-window page) — lists soft-deleted notes (
notes-listparameterizedincludeDeleted), supporting select-all/multi-select + batch restore / batch permanent delete (the confirm states "not recoverable (including version history)", with re-entry protection while running); click a title for an inline read-only body preview (Markdown rendered, zero injection surface); per-item "Restore" (notes-restore) or "Permanently delete" (notes-purge, double-confirm "permanent deletion is not recoverable"); permanent deletion is limited to already-soft-deleted notes (host safety gate), and removes the.md, the archive backup.md.bak, and the.history/<id>snapshot history together — the published static package performs real deletion, the dev build clears placeholders (0-byte tombstones, treated as nonexistent across the whole chain) - Multi-select batch operations: the list's "Select" enters multi-select mode with a bottom action bar "N selected | Merge | Delete | Cancel" — merge goes through archive preview, delete soft-deletes into the trash (no confirm, toast-undoable; confirmation strength = irrecoverability: soft delete is light-confirm, permanent delete keeps the double confirm), buttons disabled at 0 selections
- Sensitive note masking: a 🔒 toggle on the editor meta row (
sensitive=true) — when injected into the system prompt, the body is masked line by line (keys and structure kept, values hidden as******(敏感,note_get <id> 获取), so the agent mustnote_getfor the original); password/secret patterns are auto-detected — quick captures land directly assensitive=true, manual creates return asensitiveSuggestedhint (not enforced) - Secret spans (0.6.0 document security): fenced ```secret blocks are the marking syntax (wrap a selection into a fence via the toolbar / right-click /
Ctrl+Shift+S), masked in both editor modes — blur islands in rich text + opaque redaction blocks in source mode (click to reveal, auto re-blurs in ~10s, "unmark secret" and editable while revealed; masking is render-layer only,textarea.valuealways holds the true body; the panel and the full-window page are isomorphic); they are masked or stripped uniformly across the ten consumer pipelines (injection / note_get / search / excerpts / vector index / AI organize / export / dispatch payloads / health checks / selection);note_getmasks by default (placeholder + count + guidance line), and the agent may passreveal:trueonly after asking
…
Links
More in this category
loopx-project/loopx#dsh-loopx-plugin★ 6537
LoopX, a provider-neutral, local-first state kernel and control plane for long-horizon agents: keeps Goal, Todo, gate, evidence, quota, recovery, and handoff state above DeepSeek Harness, while the plugin bootstraps the CLI and skills, admits bounded same-session continuation, and adds a loopback GoalBar for the exact bound loop.
Q00/ouroboros#integrations/dsh-plugin★ 6308
Config-only bundle that mounts Ouroboros through the DSH MCP client, exposing 36 interview, Seed, execution, evaluation, and evolution workflow tools in DSH.
chuspeeism/dashi-taskboard#deepseek-harness★ 3434
Embeds the active installed Codex Taskboard runtime in the DeepSeek Harness sidebar, using its launcher runtime descriptor instead of a fixed port.
NanmiCoder/dsh-agent-teams★ 2647
AgentTeams multi-agent teams.
EthanYoQ/AI-Novel-Writer#dsh-ai-novel-writer★ 2265
Installs a dedicated AI novel-writing preset and workbench: revisioned local project assets, a compact side drawer, and native approval-gated single-file changes.
Miaotofu01/Study-Mate★ 1307
Your AI learning companion: helping you plan your studies, understand concepts, and build projects to master a subject.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.