Install
Inside DeepSeek Harness, with dsh-market
dsh plugin --profile web add dshmarket
Or from the command line
dsh plugin --profile web add github:dsboylw/LazyNoobsCockloft#path:/dsh-session-notes
Installing runs third-party code with your own permissions — it can read your files, use your credentials and reach the network. Review the source first, and pin a commit (github:owner/repo#sha) when you can.
README
Session notes plugin for DSH (works on both DSH Desktop and Web; web platform client plugin). Attach multiple numbered notes (1 2 3… in creation order) to every conversation so you never have to dig through chat history to find your prompts.
✅ Built and tested on DSH Desktop 0.8.2 (current version); compatible since 0.7.x.
Why this plugin exists
While using DSH Desktop I kept hitting the same annoyance: in one session I'd reuse the same prompt over and over to pull data, and every time I had to scroll back through the chat history, copy the prompt, and paste it back in. Right-clicking the session offered no note field, so I decided to just write one myself.
I had previously installed fun-ticker, found it clunky and uninstalled it — it wasn't built for the desktop app in the first place, and the uninstall didn't clean up fully. So I ended up borrowing parts of its structure to build this notes plugin instead.
Sessions with notes show up in the overview: click a note to jump straight to that session, and one-click copy whatever you wrote — e.g. the prompt itself.
Lazy~~~~ that's just who I am ~ Noob and lazy, what can I do…
Features
- 📝 Header button (next to the conversation title): opens the edit popover; shows a label-colored dot when the current session has a note
- Edit popover
- Edit the current session's note, debounced autosave (400 ms), shows "Saved ✓"
- Copy button: one-click copy of the full note
- 📌 Pin toggle: pin right after writing; pinned state shows as a solid amber block
- 10 color markers (default / amber / rose / sky / lime / purple / pink / orange / teal / blue)
- All-notes overview: workspace badge + title + per-row copy button; the current session is included too (tagged "this session", pinnable right there, clicking just closes)
- 🔍 Filter box: live-filter by title / workspace / note text — scales when notes pile up
- Pinned-first sorting; capped list height with scrolling
- Bottom-bar toggle (persisted)
- Always-on bottom bar (always shown above the composer, note or not)
- Colored workspace badge (tinted by the note's label, text auto black/white for readability) + session title (20 chars)
- With a note: preview + copy button; clicking the preview opens the popover
- Without a note: a gray hint "no note for this session — click to write one" that opens the editor
- ☰ Session list: quick-switch menu of every session with a note — always reachable; pinned-first, includes the current session, mutually exclusive with the popover (only one overlay at a time)
- 📌 Pinning everywhere: pin from the list, the menu, or the editor; pinned rows sort first with a 📌 prefix; hover tooltips still show the full "workspace / title — note"
- Long-text truncation: titles 20 chars / workspace 10 chars, longer text ends with … — copy buttons always copy the full content
- Stability: the popover is wrapped in an error boundary (PopoverGuard) — a popover crash can never take down the bottom bar or the header button; the host API follows full PATCH semantics (omitted fields keep their old value, explicit empty text = delete)
- Data is stored in the host settings document (namespace
dsh-session-notes), persisted per session id, survives restarts - Clearing the note text deletes the note; limits: 2000 notes / 20000 chars per note
Changelog
- 0.3.1
- Bottom-bar preview now follows the selected note: pick a note in the popover and the bar shows that one (falls back to the latest-edited note when nothing is selected)
- 0.3.0
- Added: multiple notes per session (N prompts on one session, no more cramming into one) + sequence numbers (1 2 3… in creation order, never renumbered)
- Added: session-level color (color dots in the popover title row — one click repaints the whole group) + session-level pin (📌 in the title row, pins the group in the ☰ list)
- Added: copy picker (1 note = one-click copy; several = ▾ picker menu, click to copy, pinned-first sorting)
- Changed: slimmer bottom bar (+ removed; adding notes unified in the popover); stability fixes (locale-undefined defense, missing-rows defense, empty-draft survival, pin no longer shuffles order)
- 0.2.0
- Added: 📌 pinning everywhere (overview list / session menu / editor); 🔍 filter box; ☰ session-switch menu; always-on bottom bar (writable when note-less); current-session row in both lists
- Changed: palette 5 → 10 colors; header dot and workspace badge follow the label color; title 8 → 20 chars, workspace 5 → 10 chars; list rows show title only (hover for full text); popover widened to 480~640px with capped scrolling
- Fixed: pin wiped notes (host API now full PATCH semantics); wrong popover on new sessions (popover ownership split); popover crash took down the UI (PopoverGuard error boundary); horizontal scrollbar (box-model fix)
- 0.1.0 — first release: session notes, edit popover, all-notes overview, bottom bar
Install (DSH Desktop)
Option A: one-click script (recommended)
# inside the repo / extracted folder
powershell -ExecutionPolicy Bypass -File .\build.ps1 # build from source (skip for release zip)
powershell -ExecutionPolicy Bypass -File .\install.ps1 # copy into profile + patch
# restart DSH Desktop (fully quit, then reopen)
Option B: manual
Copy
package.json+lib\index.js+lib\client.jsinto%APPDATA%\dsh-desktop\harness\profiles\web\node_modules\@deepseek-ai\dsh-session-notes\(keep thelib\subdirectory)Edit
%APPDATA%\dsh-desktop\harness\profiles\web\cordis.patch.yml, inside the first- insert:block add:- insert: # ...existing rows... - id: session-notes name: '@deepseek-ai/dsh-session-notes'Restart DSH Desktop
Uninstall
powershell -ExecutionPolicy Bypass -File .\uninstall.ps1
# or manually: remove the two session-notes rows from cordis.patch.yml + delete the package dir from node_modules
The scripts back up cordis.patch.yml automatically (cordis.patch.yml.bak-<timestamp>). If the app fails to start, desktop safe mode auto-quarantines the plugin; restore from the backup afterwards.
Build
Requirements: Windows PowerShell, node ≥ 20, an esbuild binary (edit the $Esbuild variable in the script to your local path).
.\build.ps1
- Host side:
src/index.js→ ESM bundle (external@deepseek-ai/*; the closure is provided by the DSH app) - Client side:
src/client/index.tsx→ CJS bundle (externalreact/react-dom/@deepseek-ai/*), wrapped inwindow.__ModuleLoader__.load({ id, factory }) - Smoke tests: stubbed host services + ModuleLoader, covering the full host route flow and client slot registration
Architecture / Slots
| Side | Entry | What it does |
|---|---|---|
| Host | src/index.js |
Registers the settings namespace (callable schema + toJSON) and the API route |
| Client | src/client/index.tsx |
Slot registration, store, session-row projection; inject: ['slots', 'locale', 'sessions'] |
| Slot | Content |
|---|---|
conversation.session.header.actions |
📝 button + popover |
conversation.input.dock |
persistent bottom note bar |
API (/plugins/dsh-session-notes/api, host webServer service, prefix route):
| Method | Path | Description |
|---|---|---|
| GET | /settings |
Read everything (notes + barEnabled) |
| POST | /settings |
Replace wholesale (server-side validation/sanitizing) |
| GET | /notes |
Read the notes table |
| PUT | /notes/:id |
Upsert (PATCH semantics: omitted text/color/pinned keep the previous value; explicit empty text = delete) |
| DELETE | /notes/:id |
Delete one note |
Gotchas (for future DSH plugin authors):
- The host HTTP service is called
webServer(ctx.inject(['settings', 'webServer'], ...)+host.webServer.register(...)); there is nohttpServerservice - A slot entry's
sessionIdis not a component prop — it is the first argument of the inject factory:inject: (sessionId) => ({ ... }) - The client bundle must be CJS wrapped as
window.__ModuleLoader__.load({ id: "<package name>", factory: (require) => {...} });react/react/jsx-runtimeare provided by the loader's require - The settings schema must be callable (
resolveexecutesschema(merged)) and expose.toJSON()(used bydescribe())
Layout
src/index.js host entry: settings + API routes
src/client/index.tsx client entry: slot registration, store, session projection
src/client/ui.tsx popover + bottom bar UI
src/client/store.ts self-contained observable store + useSyncExternalStore hook
src/client/api.ts same-origin fetch wrapper
src/client/clipboard.ts copy (clipboard API + execCommand fallback)
src/client/locales.ts zh/en dictionaries
src/client/styles.ts style injection (dsw CSS variables, light/dark aware)
build.ps1 build + smoke tests
install.ps1 one-click install into the desktop profile
uninstall.ps1 one-click uninstall
test/smoke.mjs smoke tests (host + client)
test/host-drive.mjs host route direct-drive regression
License
MIT
Comments
Comments live in GitHub Discussions. Sign in with GitHub to post or react.