linhx1999
dsh-writing-pad
Markdown writing pad for the DeepSeek Harness web GUI: per-session editing, preview, and in-session AI-assisted rewrite.
- Stars
- 0
- Language
- TypeScript
- Created
- Aug 14, 2026
- Updated
- Aug 14, 2026
Introduction
dsh-writing-pad
Session-scoped writing pad for the DeepSeek Harness web GUI. It mounts a
right-details-column Markdown editor into the details slot, with:
- Markdown editing and a built-in preview pane (edit/preview toggle).
- AI-assisted rewrite: select a passage (in edit or preview), optionally add a
natural-language requirement, and send the request into the conversation;
the agent rewrites in-session and applies it through the
writing_drafttool. - A
writing_draftagent tool (action=read/action=rewritewithold+new) so the agent can read and locally rewrite the draft. - Workspace file save/load (relative
.mdfiles under the session workspace), per-session drafts, debounced autosave, and 2-second auto-sync so agent-side rewrites appear automatically.
Repository layout
dsh-writing-pad/
├── package.json # dsh.bundle + dsh.client manifests, exports, prepare
├── cordis.patch.yml # the bundle layer: inserts the `writing-pad` row
├── tsdown.config.ts # self-contained build (runs from `prepare`)
├── src/
│ ├── index.ts # Host: WritingPadService (@Remote) + writing_draft tool
│ ├── remote.ts # generated Remote client binding (see bridge section)
│ └── client/
│ ├── index.ts # Client: slot registration, store, bridge wiring
│ ├── WritingPad.tsx
│ ├── WritingToggle.tsx
│ ├── store.ts # shared per-session state
│ ├── markdown.ts # minimal Markdown renderer
│ └── writing-pad.css
├── README.md # English
└── README.zh-CN.md # 简体中文
Install
Requires the dsh CLI (dsh --profile web boots the web GUI). From a GitHub
host:
dsh plugin --profile web add github:you/dsh-writing-pad#<commit>
A git install fetches sources, so the package's prepare script (tsdown) must
build the entry points. pnpm ≥ 10 refuses to run a git dependency's prepare
until it is explicitly allowed: the first add fails and dsh prints the
exact package key — copy it into the profile's pnpm-workspace.yaml:
allowBuilds:
dsh-writing-pad: true
and re-run the add. Allow only source you trust, and pin a commit so a later
push cannot silently change what runs. Alternatives without the allowance:
publish to npm (prebuilt lib/) and run dsh plugin add dsh-writing-pad, or
ship a tarball from pnpm pack.
Verify without booting, then boot:
dsh --profile web --dump-config # shows a "# == dsh-writing-pad" layer
dsh --profile web
Build
pnpm install
pnpm build # tsdown → lib/index.js + lib/client.js
pnpm typecheck # tsc --noEmit (needs dev dependencies installed)
prepare runs pnpm build automatically after a git install.
Client→Host bridge
The client calls the host through a typert Remote service
(WritingPadService, @Remote methods). The generated client binding
(ctx.remote.writingPad) is produced by the typert generator and mounted with
ctx.remote.$mount(contribution), following the pattern in
@deepseek-ai/dsh-api-remotes/client. Until the generator runs, src/remote.ts
carries the interface the client casts to; keep it in sync with the @Remote
signatures.
If you prefer to avoid generation, an alternative is to contribute the service
to the dsh-api-remotes allowlist in the harness repo (a one-line assembly
change per remote namespace).
Porting notes (from the dynamic-plugin prototype)
This package is the static, installable form of a writing pad prototyped as a dynamic Cordis plugin. The conversion is mechanical:
| Dynamic plugin | Static bundle |
|---|---|
harness.defineTool / harness.registerTool | defineTool + ctx.tools.register from @deepseek-ai/dsh-tools |
harness.handle / host.call package-private RPC | @Remote methods on a TypertRemoteService; client calls ctx.remote.writingPad.* |
Dynamic client builtins (React, host, styles) | Normal imports (react, ctx.slots.register, CSS) |
| Draft held in Host memory keyed by session | Same, plus workspace-file save/load |
Known behavior of the prototype carried over unchanged: drafts live in Host
memory per session (a file write is the durable form), the rewrite request is a
real user message into the conversation (agent applies it via writing_draft),
and the details column replaces the shipped tool-details panel while this
plugin occupies it.
Open items
- Confirm the
@deepseek-ai/dsh-*rc packages resolve from npm (or install the harness checkout as a git dependency) beforedsh plugin addresolves. - Decide whether drafts should be file-backed (write the
.mdfile on every autosave and poll the file instead of Host memory) so agent-side file edits also sync into the pad automatically. - Run the typert generator for
./remote(or add the allowlist entry) to remove thesrc/remote.tsplaceholder cast.
License
MIT