DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins
N

dsh-note

Note

Long-term markdown memory for DeepSeek Harness (dsh) agents — a writing-notes zone plus a memory bank with easy front matter, free local search, full edit/update and tail-first compact recall. Remember, so you don't re-send.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:jingchangzhao-gif/dsh-note#d053e49d9ccad3d8410c4ac0294aac98e852c67b
READMECompatibilityVersions

Compatibility and provenance

Note is published as dsh-note and currently resolves to version 0.5.1. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
any
Release source
github
Registry updated
10/7/2026

Versions

0.5.1stable
10/7/2026
0.5.0stable
9/30/2026
0.4.0stable
9/20/2026
Show 2 more versionsCollapse versions
0.3.0stable
9/19/2026
0.2.0stable
9/8/2026

Related plugins

Loading related plugins…

Latest
0.5.1
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
any
License
MIT
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
10/7/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in memory-context.

Experimental Session Search@deepseek-ai/dsh-experimental-session-searchGive Agents tools to search and read earlier sessions from the current workspace.Hindsight Coding Agents@vectorize-io/hindsight-coding-agentsReflect-only Hindsight long-term memory for coding agents (harness-pluggable: opencode, …), with automatic background ingestion (no setup CLI).Contextdsh-contextA DeepSeek Harness plugin for context insight and management, with context dashboard and context command, for understanding how the context is made of, and how it evolves.Memory Plugin@openviking/dsh-memory-pluginOpenViking memory and context bundle for DeepSeek Harness

README

dsh-note

Long-term markdown memory for DeepSeek Harness (dsh) agents — remember, so you don't re-send.

dsh-note is the coding agent's durable memory, written in TypeScript with zero runtime dependencies. Instead of carrying a long conversation (and re-paying tokens for it every turn), the agent keeps the important parts in local markdown files and recalls only the small relevant chunk later. Context stays small and on-demand, which saves tokens over a session.

dsh-note itself is token-free — that is its whole value. Every tool below is plain local file work (free). Tokens are only spent when the model is actually asked to think; the note layer just makes that thinking small: search, tail-reads and bounded context packets instead of whole-file dumps.

Two zones, never mixed

Storage is split into two directories under the session workspace, so article writing and long-term memory never get confused (each tool accepts a dir override):

ZoneDefault dirWhat lives there
writing./notesworking notes, drafts, articles, session logs
memory./memorythe long-term memory bank: per-topic files of timestamped entries

Memory bank files are topic files (e.g. decisions.md) whose body is a list of entries headed ## <ISO timestamp> [title]. Files can nest inside a zone (e.g. log/today.md); names can never escape the zone root, and a new note cannot be named with a leading dot in any folder (.draft.md, .cache/n.md) — every listing and search skips dot files, so it would be invisible. Files or subdirectories the process cannot read are skipped, so one bad permission never fails a whole listing, recall or search. Reading a zone never creates it — a missing folder simply reads as empty, and only a write makes one.

Easy front matter

Memory files (and any note) can start with a simple --- block:

---
title: decisions
tags: tooling, workflow
type: decision
created: 2025-01-03T08:00:00.000Z
updated: 2025-01-05T12:30:00.000Z
summary: compact one-paragraph digest (model-written, on request)
---

## 2025-01-05T12:30:00.000Z — merges

decided: use merge commits on paired PRs
  • created/updated timestamps are maintained for free on every write.
  • summary is optional and is what compact recalls show first.
  • aliases (or the legacy alias) is a comma separated list of other names a note answers to, used when resolving links (see note_links).
  • type: archive marks compaction archives, which recalls/search skip.
  • Unknown keys are preserved on rewrite; values are plain key: value lines.
  • YAML lists work too, the way Obsidian and basic-memory write tags and aliases: a block list (tags: then - coffee lines) under any key, and the flow form (tags: [coffee, brewing]) for tags/aliases/alias. They read as the same comma list and are written back in the style they came in.
  • A leading --- block is front matter only when it holds at least one key: value line. A note that opens with a --- rule keeps it as body text instead of having the block read (and then deleted) as metadata.

Tools

ToolWhat it doesCost
note_rememberAppend a snippet to a writing note (create if missing)free
note_recallRead a note back — full, tail, compact, one section, or outlinefree
note_writeFully replace a note's body (updates, rewrites, reordering)free
note_editIn-place body edits — literal text, or one section by its headingfree
note_listList a zone's notes; filter by tags / type / changed since, newest firstfree
note_searchFree keyword search across writing/memory/all zonesfree
note_forgetMove a note to the zone's .trash/ (restorable), or delete permanentlyfree
note_statsSize up a zone: files, archives, entries, bytes, largest file, tagsfree
note_mapOutline a zone: file lines + newest entry headings, under a budgetfree
note_linksFollow links between notes: out, back, broken, orphans, islandsfree
note_renameRename/move a note and rewrite the links that pointed at itfree
note_contextAssemble the small bounded context around a focus (tail-first)free
memory_addAppend a timestamped entry to the long-term bankfree
memory_recallRecall the recent/relevant small chunk (query/tags/type/date filters)free
memory_updateMerge front matter (summary/tags/…) and/or append an entryfree
memory_compact

The actual reasoning features — summarizing the context above, inferring what comes next, extracting key information, putting a draft in order — are agent workflows that combine these free tools with one deliberate thinking step. See docs/workflows.md for ready-to-use recipes.

How it saves tokens

  1. Small recall: note_recall with tail, and memory_recall which returns newest-first entries bounded by limit + a chars budget — never the whole history.
  2. Free search: note_search is plain local keyword search with snippets, so the model can find the right file without scanning everything itself.
  3. Compact fallback: note_recall with compact returns the summary field plus the recent tail. memory_compact keeps the active bank small by moving old entries into archives. When memory processing would be too long, grab the compact version instead.
  4. Edit, not just append: note_write/note_edit let the model rewrite a note in place — only the text it actually thinks about changes.
  5. Forget the rest: note_forget/memory_remove keep stored context small, so future prompts stay lean.
  6. Size before recall: note_stats reports how many files, entries and bytes a zone holds — free — so the model can pick a recall budget instead of guessing.
  7. Map before recall: note_map returns the outline — file lines, the newest entry headings and the zone's link structure — so the model can pick the right file without paying for entry bodies at all.
  8. Follow, don't search: note_links walks the links a note already has, so related context costs one hop instead of a keyword scan — and orphans shows which notes nothing reaches.

Installation

The package ships from this repository rather than npm, so install it by git specifier:

# CLI profiles (web, tui, …) — the CLI forwards the specifier to pnpm
dsh plugin --profile web add github:jingchangzhao-gif/dsh-note

lib/ is generated and git-ignored, so the install builds it through the package's prepare script. pnpm blocks dependency build scripts until they are allowed: dsh prints the exact key to put under allowBuilds in the profile's pnpm-workspace.yaml, then re-run the command.

Prefer to build it yourself? Clone, build, and add the checkout path instead — that also gets you the launchers and a CLI you can run without dsh at all:

git clone https://github.com/jingchangzhao-gif/dsh-note.git
cd dsh-note
pnpm install
pnpm build
dsh plugin --profile web add "$PWD"      # the checkout path, e.g. D:\dsh-note on Windows

The packed tarball carries lib/ (the plugin), cli.mjs (the CLI), cordis.patch.yml (bundle registration) and the docs; scripts/check-pack.mjs asserts exactly that in CI, because a git-ignored build directory is easy to forget. The checkout is also useful on its own: node cli.mjs help, ./run.command on macOS, run.bat on Windows.

The desktop app's profile is managed by the app itself: add github:jingchangzhao-gif/dsh-note from the GUI's plugin manager. dsh plugin --profile desktop … is refused — the CLI does not manage that profile.

Harness compatibility

dsh refuses to load a plugin whose @deepseek-ai/dsh* peer range does not satisfy the running runtime, comparing the runtime version with prereleases included, so the declared peers are ranges over the 0.1 line:

PeerRangeUsed for
@deepseek-ai/dsh-tools>=0.1.0-rc.8 <0.2.0-0defineTool, ctx.tools.register, exec.agent.session.header.cwd
@deepseek-ai/cordis^4.0.1the plugin entry (name / inject / apply)

Verified against dsh 0.1.0-rc.8, 0.1.5-rc.3 and 0.1.7-rc.2. pnpm test includes tests/compatibility.test.ts, which fails if the range stops accepting the @deepseek-ai/dsh-tools the suite installs.

Tool reference

These are the dsh plugin tool calls; outside the GUI every one of them has a direct CLI equivalent (see Usage), and docs/workflows.md shows the reasoning workflows in both forms.

note_remember

{ "name": "session", "content": "Decided: use pnpm + merge commits on paired PRs." }

Creates the note if missing, otherwise appends after a --- separator.

note_recall

{ "name": "session", "tail": 2000 }

Returns { name, content, truncated }. With tail, only the last N characters; with compact: true, the summary field plus the recent ~800 chars.

For a long structured note, read the map first and then only the part you need:

{ "name": "plan.md", "outline": true }
{ "name": "plan.md", "section": "Setup" }

outline returns the headings, indented by level, each with its section size ( ## Setup (240 chars)). section returns that heading and everything under it up to the next heading of the same or a higher level. Headings match loosely (case, spacing and leading #s don't matter). A missing heading names the ones that exist, and a heading that appears twice is refused rather than guessed. Use at most one of tail, compact, section, outline.

note_write

{ "name": "article.md", "content": "# New order\n\n…", "tags": "draft" }

Replaces the whole body; front matter keys given merge in, others are kept. When writing a new note, pass "createOnly": true: if a note of that name already exists the write is refused and the existing note left untouched, instead of being replaced and reported as created: false afterwards.

note_edit

{ "name": "session.md", "old": "pnpm install", "new": "pnpm i", "all": true }

Replaces literal text in the body (never inside front matter).

Or rewrite one section by its heading, without quoting its old text:

{ "name": "plan.md", "section": "Setup", "new": "pnpm 10", "mode": "replace" }

mode is replace (the default: everything under the heading, subsections included, which is what note_recall's section returns), append (at the end of the section) or prepend (right under the heading). The heading must match exactly one heading in the note; old/all cannot be combined with section. new is required here — a missing one would wipe the section — so pass "" explicitly to clear it.

note_list

{ "zone": "memory" }

Lists notes with title/type/tags; archives are hidden from the memory view.

Narrow it for free, e.g. "what changed since the last session?":

{ "since": "2025-01-05T09:00:00Z", "sort": "recent", "limit": 10 }
{ "tags": "work, urgent", "type": "plan" }

tags matches notes carrying any of them (any case), type is exact, since keeps notes modified at/after a date, and sort: "recent" puts the newest first. "Modified" is the file's modification time, so an edit made in another editor counts; those entries then carry modified. A plain listing is unchanged.

note_search

{ "query": "pnpm merge", "zone": "all" }

Returns ranked hits { name, title, snippet, score }. Zero tokens.

note_forget

{ "name": "session.md", "zone": "writing" }

Moves the note to the zone's .trash/ folder (the name Obsidian uses), keeping its relative path — log/today.md goes to .trash/log/today.md, or .trash/log/today-2.md if that is taken. Dot folders are skipped by every listing, search and stat, so the note is gone from view, and restoring it is moving the file back. "permanent": true deletes it for good instead.

note_stats

{ "zone": "memory" }

Read-only inventory of a zone: live files, archives, memory entries, total bytes, the largest file (name + size), and the zone's tags with how many live notes carry each, most used first (the top 20, plus moreTags for the rest). Nothing is returned to the model beyond these numbers and names, so it costs no content tokens — and the tag list tells it what to filter note_list and memory_recall by.

note_map

{ "zone": "memory", "chars": 1200 }

Free outline of a zone: one line per file (name — title (entries, bytes)) plus each file's newest entry headings, newest first, truncated to chars. Entry headings usually carry the gist (2024-06-01 — use pnpm), so a map is often enough to decide which file to recall without paying for entry bodies. total counts the files in the zone, omitted the ones the budget left out.

The outline also carries the zone's link structure — links, broken and orphans — rendered as a trailing links: 3 (1 broken) / orphans: … line, so one cheap call answers both "what is here" and "what relates to what". A zone with no links between notes says nothing extra (see note_links for the details of one note).

note_links

{ "name": "session.md" }

Free link graph. With a name: what that note points at (out), what points back at it (back), and its dangling targets (broken). Without one: the zone's links count, its orphans (nothing links to or from them), the linked islands cut off from the biggest cluster, and every broken target.

Both markdown links ([label](decisions.md), and <…> for names with spaces) and wikilinks ([[decisions]], optionally [[target|label]]) count. A target resolves the way the note-taking ecosystem resolves links: exact zone-relative path, then +".md", then a unique file basename, case-insensitively and shortest path first — so [[decisions]] finds decisions.md and [[today]] finds log/today.md. Failing all that, a bare name may match a front matter aliases: entry (aliases: adr, choices lets [[adr]] reach the note), which can never shadow a real file name. A name with two equally good candidates stays unresolved rather than guessing.

Not links between notes, so ignored: URLs, in-page anchors, absolute paths, image and media targets, ![alt](…) embeds, links inside fenced code blocks or inline `code` spans, and a note linking to itself (which would only hide that nothing reaches it).

note_rename

{ "from": "session.md", "to": "log/session.md" }

Moves the note and rewrites every link that resolved to it, so the graph does not break. Wikilinks keep their style (no extension), markdown links keep their extension, and #anchors, |labels and link titles survive. Links that reached the note through an alias are rewritten too.

dryRun: true returns the plan — which notes would change and how many links — without touching a file. A target name that already exists is refused rather than overwritten, and renaming a note to its own name is a no-op.

note_context

{ "focus": "what should I do next?", "notes": ["session.md"] }

Returns one bounded context packet: recent tails of the named notes, search snippets for the focus, and the recent/relevant memory tail. Older parts are dropped first when the chars budget (default 6000) is tight.

memory_add

{ "content": "user prefers dark mode", "tags": "prefs", "type": "preference" }

Appends a ## <ISO timestamp> entry to memory.md (or name when given).

memory_recall

{ "query": "dark mode", "limit": 5, "chars": 2000 }

Newest-first, bounded. Supports name, tags, type, newerThan, olderThan. Each matching file leads with its summary front matter field when set, then its entries. Without filters it returns just the recent tail of the bank.

memory_update

{ "name": "decisions.md", "meta": { "summary": "digest: …" } }

Merges front matter fields; content appends an entry.

memory_compact

{ "name": "decisions.md", "keep": 20 }

Keeps the 20 newest entries, moves the rest to decisions.archive.md (type: archive, invisible to recalls and search).

memory_remove

{ "name": "decisions.md", "match": "superseded idea" }

Usage — run.bat / run.command: point it at a folder, then operate

The launcher is the primary way to use dsh-note. One logic file (cli.mjs) runs on Windows and macOS alike; run.bat and run.command are thin shells that just forward every argument — so you give the tool a concrete folder address plus an operation, and the free file work happens locally. No model, no network, no tokens.

Build once before first use (cli.mjs drives the built lib/):

pnpm build

Basic shape:

run.bat <command> [dir] [--flags...]
  • <dir> is the folder the command operates on. Plain commands expect the notes folder; memory-* commands expect the memory-bank folder. When omitted, plain commands default to ./notes and memory-* to ./memory.
  • Run run.bat help (or run.bat --help) for the full reference.

Windows:

run.bat list "C:\Users\me\notes"
run.bat remember "C:\Users\me\notes" --name session.md --content "decided: pnpm"
run.bat recall  "C:\Users\me\notes" --name session.md --tail 2000
run.bat write   "C:\Users\me\notes" --name article.md --file new-draft.md --title "Article"
run.bat search  "C:\Users\me\notes" --query "pnpm merge"
run.bat memory-add "D:\memory" --content "user prefers dark mode" --tags prefs --type preference
run.bat memory-recall "D:\memory" --query "dark mode"
run.bat memory-compact "D:\memory" --name decisions.md --keep 20

macOS is identical with ./run.command instead of run.bat.

CommandWhat it does
list [dir] [--zone …] [--tags] [--type] [--since] [--sort recent] [--limit]List notes, optionally filtered and newest first
remember <dir?> --name f [--content | --file | -]Append a block (create if missing)
recall <dir?> --name f [--tail N | --compact | --section h | --outline]Full text, tail, compact view, one section or the outline
write <dir?> --name f (--content | --file) [--title/--tags/--type] [--create-only]Fully replace the body (or only create)
edit <dir?> --name f (--old x [--all] | --section h [--mode m]) [--new y]Literal body edit, or rewrite one section
search <dir?> --query words [--limit N] [--zone writing|memory]Free keyword search with snippets
forget <dir?> --name f [--permanent]Move a note to .trash/ (or delete it for good)
stats [dir] [--zone writing|memory]Zone inventory: files, archives, entries, bytes, tags
map [dir] [--chars N] [--zone writing|memory]Outline a zone: file lines + newest headings
mindmap [dir] [--chars N] [--zone ...] [--file out.md]The outline as a Mermaid mind map (renders)
links [dir] [--name <note>] [--zone writing|memory]Follow links: out, back, broken, orphans
linkmap [dir] [--zone ...] [--max N] [--file out.md]The link graph as a Mermaid flowchart
rename [dir] --from <old> --to <new> [--dry-run]Move a note and rewrite the links into it
export <dir?> --file f.jsonSnapshot the whole folder into one JSON file
import <dir?> --file f.json [--force]Write a snapshot back (skips existing files)
context <dir?> [--focus q] [--notes a,b] [--memory <dir>]Assemble a small bounded context packet
memory-add <dir?> (--content | --file) [--name] [--tags] [--type]Append a timestamped bank entry

Notes:

  • Append --json to any command to print the structured result.
  • A flag the command does not take is refused (unknown flag --…) rather than ignored, so a typo cannot quietly run the command on its defaults.
  • --zone memory makes list and search work on ./memory instead of ./notes and hides archives, the same rule note_list/note_search apply; a dir argument still points them at any other folder.
  • run.bat <dir> with a single bare argument keeps the legacy launcher form (list that directory).
  • A note file name typed alone is the note in the default folder: recall session.md is recall ./notes --name session.md (unless a folder called session.md exists).
  • Quote multi-word values. For Chinese or multiline content, pass --file <path> (UTF-8) or --content - and pipe stdin. "$@" on macOS/Linux forwards arguments byte-exactly; on Windows %* is re-parsed by cmd (%, ! and ^ are special), so prefer --file or stdin there for tricky text.
  • linkmap draws the graph as a Mermaid flowchart: hubs first, orphans dashed and island members outlined, so the picture says what links reports. --max N caps the nodes drawn (default 40, ceiling 500).
  • export/import move a whole folder as one JSON file (backup, another machine, another workspace). import skips files that already exist unless --force is passed, so a restore can never silently clobber newer notes. These two are CLI-only — the agent tools have no bundle equivalent.
  • The same package also works as a dsh plugin inside the DeepSeek Harness GUI (dsh plugin --profile web add github:jingchangzhao-gif/dsh-note, or the GUI's plugin manager for the desktop profile); its 17 tools cover the note and memory commands above.

Development

pnpm install
pnpm format:check
pnpm typecheck
pnpm build   # build first: the CLI and its end-to-end tests run against lib/
pnpm test
pnpm coverage  # same suite with a v8 report and a regression threshold
pnpm lint

CI runs the full check on Linux, macOS and Windows (the CLI ships run.bat and run.command). Node 22 is pinned because the build toolchain requires it — tsdown needs ^22.18 || >=24 and rolldown/oxlint need ^20.19 || >=22.12; the engines.node >=18 floor describes the published lib/ output, not the dev toolchain.

License

MIT

Keep the newest N entries; move older ones to *.archive.md
free
memory_removeDelete matching entries (deliberate discard, no archive)free
memory-recall <dir?> [--query] [--tags] [--type] [--limit] [--chars]
Recall the recent/relevant small chunk
memory-update <dir?> [--summary etc.] [--content | --file]Merge front matter / append entry
memory-compact <dir?> [--name] [--keep N | --older-than date]Move older entries to *.archive.md
memory-remove <dir?> --match text [--name]Delete matching entries