DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

ChenYichener /

ChenYichener/dsh-book

Verified

DSH plugin: Markdown draft library + AI copywriting workspace for Xiaohongshu, WeChat Official Accounts and generic posts.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@e482fb04

dsh-book

English · 简体中文

License: MIT Node >= 20 DSH plugin Platform

A writing workspace for DeepSeek Harness: a Markdown draft library, platform-aware editors for Xiaohongshu / WeChat official accounts / generic posts, and an AI copywriting assistant that streams from your profile's default model.

Writing workspace: draft library on the left, editor in the middle, AI assistant on the right

Features

  • Draft library — one Markdown file per draft, in a folder you choose (default ~/Documents/DSH写作, created on first save); browse, search (title + body excerpt), create, refresh and delete; drafts are ordinary files, so Obsidian, Git and vim can share the same folder.
  • Editor — Xiaohongshu / WeChat / generic platform profiles with live title and body counters (soft limits: amber warnings, saving is never blocked); tag chips (Enter or , adds, Backspace in an empty field removes the last one); ~0.9 s autosave with a live status; copy the whole post (title + body + #hashtags) or just the body; renaming the title renames the file (a collision gets a (2) suffix); delete takes two clicks.
  • AI copywriting assistant — six modes (Draft, Polish, Expand, Tighten, Titles, Tags) streaming token by token with a Stop button, platform-aware prompts (Xiaohongshu hooks and hashtags, WeChat subheads, neutral generic tone) and one-click apply back into the editor; runs on the current DSH profile's default model through the host llm service, with no API key setup inside the panel.
  • Fit and finish — bilingual UI (Chinese / English) that follows the DSH locale, theme-aware styling on DSH design tokens so light and dark mode follow the app, no build step, no runtime dependencies and no background processes.

Install

Prerequisite: a working DeepSeek Harness install (dsh). The default profile is usually web.

From GitHub (recommended)

dsh plugin --profile <profile> add github:ChenYichener/dsh-book

From a local clone

git clone https://github.com/ChenYichener/dsh-book.git
dsh plugin --profile <profile> add /path/to/dsh-book

DSH desktop app

Open the Plugins page, install from a local directory, and point it at the cloned dsh-book folder (or paste the GitHub repo path). After installing, restart dsh web or refresh the page: a pen-icon Writing (写作) entry shows up in the sidebar panel list. To update, run the same add command again; to remove the plugin, run dsh plugin --profile <profile> remove dsh-book.

Requirements

Requirement Notes
DSH plugin-bundle support with the sidebar.panellist / main slots; tested on 0.2.2-rc.1
Node.js >= 20
Default model optional; required for the AI panel (uses the profile's default provider + model)
Runtime dependencies none — plain ESM on the host, plain browser JS on the client

Usage

Click the pen icon labeled Writing in the sidebar. The workspace has three columns: library, editor and AI assistant; the newest draft opens automatically once the library loads, and New work starts an empty one.

Edit a draft

  1. Pick a platform next to the title counter, then type the title and body (counters turn amber past the platform limit, but nothing is blocked).
  2. Add tags; they are stored in frontmatter and copied by Copy all. Everything autosaves.
  3. Use Copy all / Copy body to publish, or Delete → Confirm delete to remove a draft.
Platform Title limit Body limit Tag limit Assistant style
Xiaohongshu (xiaohongshu, default) 20 chars 1,000 chars 10 hook title, first-person short paragraphs, 8–10 hashtags
WeChat official account (wechat) 64 chars 4,000 chars 30 (assistant suggests none) clear value title, subhead structure
Generic (generic) none none 30 clear title, natural paragraphs, 5–10 tags

AI assistant

Mode What you need What comes back Apply action
Draft a brief (topic / material / key points) title + body + tags Apply to editor
Polish a non-empty body rewritten body Replace body
Expand a non-empty body longer body Replace body
Tighten a non-empty body shorter body Replace body
Titles body or brief 5 title candidates click one
Tags body or brief 8–10 hashtags click one, or Add all

An optional Extra requirements box (tone, audience, angle) is sent with every mode. Stop aborts the stream, and errors are shown inline in the output area.

Keyboard and interactions

Where Key Action
Title input Enter jump to the body
Tag input Enter, , or , add the tag
Tag input (empty) Backspace remove the last tag
Folder input Enter / Esc switch to that folder / cancel editing

There are no global keyboard shortcuts; everything else uses the buttons.

Draft format

---
title: A month of writing in public
platform: xiaohongshu
tags: 自媒体, 副业, 小红书运营
createdAt: 2026-11-03T01:00:00.000Z
updatedAt: 2026-11-03T01:20:00.000Z
---

Body text. Everything after the closing `---` is preserved verbatim.

The five keys are parsed line by line (a small frontmatter subset, not a full YAML parser); unknown keys are ignored and tags is a comma-separated list. Without frontmatter, the whole file is the body and the file name (minus .md) is the title. Only .md files directly inside the folder are listed — subfolders, dotfiles and files over 2 MiB are skipped.

How it works

  • Host half (index.js): exports inject: ['webServer'] and mounts one prefix route, /dsh-book/api, on the DSH host web server through ctx.effect + ctx.webServer.register.
  • Draft storage: plain node:fs; saves are atomic (temp file + rename), file names are derived from the title and validated against path traversal, and every operation is bounded (1 MiB request body, 2 MiB draft file, 500 listed drafts).
  • Generation: reads ctx.get('agentDefaultModel').currentSelection() for provider/model and streams through ctx.llm.stream(...), emitting Server-Sent Events (start → delta → done / error); closing the browser stream aborts the upstream request.
  • Prompts: a shared Chinese copywriting baseline (no fabricated facts or numbers, no medical or absolute claims, no ad tone) plus a per-platform style block; each author field is trimmed to 12,000 characters.
  • Client half (client.js): loaded by DSH's module loader, registers the sidebar.panellist entry (order 20, pen icon, localized label) and the main panel keyed writing; React comes from the shell module table. Draft CRUD goes through fetch; the folder override lives in localStorage under dsh-book.directory; styles are one <style data-plugin> element using DSW theme variables.

HTTP API

All endpoints are POST with a JSON body; /dsh-book/api/generate replies with text/event-stream.

Endpoint Request body Response
/dsh-book/api/info {} { ok, defaultDirectory, aiAvailable, provider, model }
/dsh-book/api/list { directory } { ok, directory, defaultDirectory, exists, docs: [...] }
/dsh-book/api/read { directory, name } { ok, directory, doc: { ...frontmatter, body, chars } }
/dsh-book/api/save { directory, name?, title, platform, tags, body } { ok, directory, doc, renamedFrom? }
/dsh-book/api/delete { directory, name } { ok }
/dsh-book/api/generate { task, platform, brief?, extra?, title?, body?, tags? } SSE events start, delta, done, error

name is always a bare .md basename. The route accepts only loopback Host headers and same-origin browser requests (non-POST gets 405, anything else 403), and JSON bodies are capped at 1 MiB.

Data & privacy

  • Your drafts stay local. Every draft is one .md file in the folder shown at the bottom-left of the panel (default ~/Documents/DSH写作; any absolute path, ~ accepted). No database, no sync.
  • The folder preference is browser-local (localStorage key dsh-book.directory), never written to disk by the plugin.
  • Only the AI call leaves the machine. A generation request sends the mode, platform, your brief / extra requirements and the current title, body and tags to your configured model provider through DSH's llm service; each text field is trimmed to 12,000 characters. Other drafts, file names, folder paths and any other local data are never sent.
  • No telemetry. The plugin makes no network calls of its own — no analytics, crash reporting or remote config. The route rejects non-loopback hosts and cross-site requests, so another site cannot read your drafts through the DSH web server.

Configuration

Setting Where Default
Draft folder bottom-left of the panel; absolute path, ~ accepted ~/Documents/DSH写作
Platform per draft selector next to the title counter Xiaohongshu
Model DSH model settings (the profile's default model) profile default
Autosave delay / prompt text cap fixed internals 900 ms / 12,000 chars per field

There is no plugin config file; the folder and platform live with the draft data.

Development

There is no build step — both halves are hand-written and loaded as-is. Syntax-check them, install a working copy into a throwaway profile, and restart dsh web after each edit:

node --check index.js && node --check client.js
dsh plugin --profile dev add /path/to/dsh-book

You can exercise the host route with curl while dsh web is running (use the port from its startup log; loopback requests without an Origin header are accepted):

curl -s -X POST http://127.0.0.1:<port>/dsh-book/api/info -H 'content-type: application/json' -d '{}'
curl -s -X POST http://127.0.0.1:<port>/dsh-book/api/list -H 'content-type: application/json' \
  -d '{"directory":"~/Documents/DSH写作"}'

The client half is a single bundle-registered file: window.__ModuleLoader__.load({ id: 'dsh-book', factory(require) { ... } }), React from require('react'), returning { inject, apply }.

Project layout

dsh-book/
├── index.js             # host half: /dsh-book/api route, Markdown storage, SSE generation
├── client.js            # client half: sidebar entry + main.writing workspace
├── cordis.patch.yml     # bundle patch that inserts the dsh-book plugin row
├── package.json         # dsh.bundle / dsh.client manifests, exports, npm metadata
├── icon.svg             # plugin icon
├── locale/
│   ├── en.json          # plugin-manager title + description (English)
│   └── zh.json          # plugin-manager title + description (Chinese)
├── docs/screenshot.png  # screenshot used by this README
├── README.md            # English (default) + README.zh.md (简体中文)
├── LICENSE
└── .gitignore

FAQ / Troubleshooting

Symptom Fix
No Writing entry after install Restart dsh web (or refresh the page), then confirm the plugin is in the profile you run: dsh plugin --profile <profile> list
AI panel says No model, Generate disabled Set a default model for the profile in DSH model settings; the assistant needs the llm service and a default model
Draft list is empty although files exist Check the folder at the bottom-left; only .md files directly in it are listed, and files over 2 MiB are skipped
Changes made in another editor do not appear Click the refresh icon in the library header
A title change created a second file Expected: the draft file name follows its title, and a collision gets (2)
The AI reply is cut off Each mode has its own token budget; shorten the source text or use Expand / Tighten in a second pass
Does the AI write in English? The built-in prompts are tuned for Chinese social platforms, so output is mainly Chinese; the UI language is independent
Windows / Linux support? Yes — the default folder resolves under your home directory, and the folder field accepts any absolute path

Compatibility

  • DSH / OS: the Web UI served by dsh web and the DSH desktop app (tested on 0.2.2-rc.1) on macOS, Windows or Linux — the host half only uses Node core modules, the client half browser APIs.
  • Plugin API caveat: this is an external plugin bundle (cordis.patch.yml + dsh.bundle / dsh.client manifests) that depends on the webServer, slots and locale services, the main and sidebar.panellist slots, and — for AI — the llm and agentDefaultModel services. If DSH renames those, the panel needs a matching update. Model providers work as long as they can be set as the profile's default model; the panel never talks to a provider directly.

Related DSH plugins

Plugin What it does
dsh-book Markdown draft library + AI copywriting workspace for Xiaohongshu / WeChat / generic posts
dsh-notify Native desktop notification when a session finishes while DSH is in the background
dsh-pomodoro Distraction-free Pomodoro timer in the sidebar
dsh-translate Chinese/English translation workbench with an always-on AI tutor and neural read-aloud
dsh-nce New Concept English Book 1 study panel (lessons, SRS flashcards, mistake notebook)

License

MIT © 2026 chenyichen

—/ 5

No ratings yet

Verified DSH bundle

Commit e482fb04e73d

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout