reinocheong
dsh-session-move
Manage DeepSeek Harness sessions from the Web UI: drag & drop / menu move to another folder, permanently delete, and AI-rename by summarizing the conversation. Includes agent tools.
- Stars
- 0
- Language
- JavaScript
- Created
- Aug 15, 2026
- Updated
- Aug 15, 2026
Introduction
dsh-session-move
Manage DeepSeek Harness sessions from the Web UI — move, delete, and AI-rename, with drag & drop.
A dual-face (host + browser) plugin for DeepSeek Harness (dsh). It fills the gaps the official UI leaves open:
| Feature | Official dsh | With this plugin |
|---|---|---|
| Move a session to another folder (workspace) | ❌ sessions are locked to the folder they were created in | ✅ drag & drop or menu → picker dialog |
| Permanently delete a session | ❌ archive only (hidden, never really gone) | ✅ menu → risk-consent dialog → full removal |
| AI-rename a session | ⚠️ auto-titles exist, but only from the first message | ✅ one-click: LLM summarizes the whole conversation |
Each feature also ships as an agent tool (workbench_session_move, workbench_session_delete, workbench_session_rename_ai), so your agents can organize sessions too.
Install
# from GitHub (recommended until published to npm)
dsh plugin --profile web add https://github.com/reinocheong/dsh-session-move/archive/refs/tags/v0.1.1.tar.gz
Restart the profile for the plugin to load:
# systemd-managed installs
sudo systemctl restart dsh
Note for manual installs (copying the package into
~/.dsh/profiles/node_modules/yourself): you must also register it in the profile'scordis.patch.yml:- insert: - id: session-move name: dsh-session-move
dsh plugin adddoes this automatically.
Usage
🗂 Move a session to another folder
Drag & drop — grab any session row in the sidebar and drop it onto the title of another folder. The target folder highlights while you hover; release to move.
Menu — open a session's ... menu → Move to folder… → pick the target folder → confirm.
Moving a session relocates its working directory: the session header's cwd is rewritten, the persisted log is moved to the target folder's storage slug, and the workspace accounting is updated — history travels with it, and the session keeps working in the new directory afterwards.
🗑 Delete a session
Open a session's ... menu → Delete session → tick "I understand the consequences" → confirm.
Deletion is complete and permanent: running agents are stopped first, then the log directory, projection-cache row, and workspace accounting are removed. Nothing lingers in "Ungrouped".
✨ AI rename
Open a session's ... menu → AI Rename — the LLM reads a representative sample across the whole conversation (evenly sampled to fit the token budget), fixes any typos, and writes a concise title in the conversation's language.
By default it uses the session's own model route. To pin a different provider/model, configure the plugin row:
- id: session-move
name: dsh-session-move
config:
renameAi:
provider: deepseek-official
model: deepseek-v4-flash
targetWords: 6
targetCjkCharacters: 14
maxInputBytes: 8192
maxOutputTokens: 96
timeoutMs: 60000
Agent tools
| Tool | Description |
|---|---|
workbench_session_move | Move a session to another workspace (by session id + workspace id). |
workbench_session_delete | Permanently delete a session. |
workbench_session_rename_ai | AI-rename a session. |
HTTP endpoints
These power the UI; they are also usable directly:
| Endpoint | Method | Body | Returns |
|---|---|---|---|
/__sessionmove/info | GET | — | all workspaces + the session's current workspace |
/__sessionmove/move | POST | { sessionId, workspaceId } | move result (old/new cwd, workspace ids) |
/__sessionmove/delete | POST | { sessionId } | what was removed |
/__sessionmove/rename-ai | POST | { sessionId } | the new title |
How it works (the short version)
dsh folders ("workspaces") are not free-form containers. A session belongs to the workspace whose path equals the session's working directory (cwd), which is frozen in the header line of the session's zstd-compressed log. Moving a session therefore means:
- stop/flush any live agent,
- rewrite the header line's
cwdto the target folder's path (decompress the first zstd frame, patch the JSON, recompress, keep the trailing frames byte-for-byte), - physically move the log directory to the target folder's storage slug,
- detach from the old workspace and attach to the new one through the workspace registry (which also refreshes the in-memory index, so the UI updates instantly — no restart needed).
All storage mutation goes through dsh's own storageDomain, keeping memory and disk consistent; nothing is left half-accounted.
Reliability (v0.1.1)
The move keeps every place a session's location is recorded in sync — not just the header and the log directory:
- Projection cache — the session's
identity.cwdin the projection cache (session_projcache) follows the move, so the web session list resolves the correct storage slug immediately (noENOENTon cold sessions and no "Ungrouped" residue after a move). - Boot reconciliation — on startup the plugin audits every stored projection-cache record against its on-disk header and repairs stale
identity.cwdentries left behind by earlier half-applied moves or manual reorgs, so the list shows real session titles from the first render instead of the folder placeholder. - Live sessions — a session that is loaded in memory when moved has a frozen header snapshot; the plugin detaches it from the live agents store before re-attaching it to the target workspace, so the attach validation never sees a stale
cwd(this was the cause of moves silently landing in "Ungrouped" while the physical move succeeded).
Each fix is fail-soft: if a repair can't run, the plugin logs a warning and leaves the state untouched rather than corrupting it.
Performance & footprint
The plugin is designed to be lightweight:
- Zero runtime dependencies — it only uses Node built-ins plus packages dsh already ships (
dsh-tools,dsh-llm,dsh-session-title,dsh-session-title-llm). Nothing new is installed. - No background work — no timers, polling, or resident connections. Move/delete/rename are purely request-driven: work happens while the request runs, then the plugin goes idle.
- Tiny footprint — the whole plugin is ~85 KB of source; its resident memory is negligible against a running dsh process.
- Fast operations — the stateless endpoints answer in ~1 ms (e.g.
/__sessionmove/info); the only potentially slow step is AI rename, which calls the LLM once on demand (a few seconds, timeout-configurable) and never runs otherwise. - Cheap client side — one DOM observer plus three dialogs that render only when opened; nothing runs in the browser while idle.
Requirements
- Node.js
^22.19.0 || >=24.0.0(same as dsh) - dsh
0.1.0-rc.6or newer - AI rename additionally needs the official
@deepseek-ai/dsh-session-title/@deepseek-ai/dsh-session-title-llmpackages (bundled with dsh)
License
MIT