English | 中文

DSH-Code is a terminal coding interface for DeepSeek Harness (dsh). It is composed as an out-of-tree bundle on top of the official @deepseek-ai/dsh-base and uses the same Agent, Session, tool, command, skill, permission, sandbox, context-compaction, and plugin services as the Harness Web UI.
DeepSeek Harness registers models, tools, storage, policies, and interfaces as plugins through Cordis. Durable session events record the information required to restore conversations and runtime state. DSH-Code preserves that architecture while adding a terminal workflow suited to coding tasks. The interface follows terminal conventions familiar to developers, while runtime behavior remains governed by DSH services and configuration.
Requires Node ^22.19 || >=24 and the preview dsh CLI (current release line: @deepseek-ai/dsh@0.2.1-rc.4). You can still enter the TUI, browse sessions, and use non-model features without configuring a model; press Tab in /model to manage API keys, OAuth, device-code sign-in, endpoints, and models.
Install from npm. Close all running dsh / deepseek sessions before installing or upgrading.
npm install -g --allow-scripts=@deepseek-ai/dsh-subprocess-local,koffi,node-pty,@google/genai,protobufjs @deepseek-ai/dsh@0.2.1-rc.4 pnpm
npm install -g dsh-code@2.1.0
deepseek repair-deps
dsh plugin --profile cli add dsh-code@2.1.0
Use /update or deepseek update --apply for later updates. See installation and upgrade troubleshooting for version alignment, dependency repair, and migration errors.
Available launch commands:
dsh --profile cli
deepseek
dsh-code
dsh --profile cli, deepseek, and dsh-code are equivalent launch commands. deepseek and dsh-code are global aliases for dsh --profile cli, and all additional arguments are forwarded unchanged, for example deepseek --resume abc123.
DeepSeek Harness is still a developer preview and may introduce compatibility-breaking changes. DSH-Code will continue to track the evolution of its plugin interfaces.
DSH-Code brings DSH Agents, models, tools, and durable sessions directly into the terminal, covering the complete workflow from writing code to reviewing changes.
/new, or restore existing sessions with /resume and --continue/fork while preserving the original session/history/usage reports the harness token meter's four disjoint buckets, the totals merged by model, and a per-turn breakdownin counts only uncached input, and cache shows both the cache-read volume and the hit share — together they are the billed prompt side

/mode to select standard, ptc, minimal, cordis, or a user-defined Preset (the legacy code id maps to ptc)/model to switch models and manage providers, API keys, OAuth/device-code sign-in, endpoints, available models, and context windows/model provider list, Enter manages a manual API key, l starts sign-in, and o logs out after confirmation/help to find them and /plugin to inspect extension status
The composer plays Wave, Aurora, or Pulse when the model or reasoning effort changes under the following conditions:
| Scenario | Trigger | Animation text | Effect tier |
|---|---|---|---|
| Official DeepSeek model | Switch to the model, or change its reasoning effort | deepseek | Flash uses the single-band tier; other DeepSeek models use the multi-band tier |
| Other models | After changing the model or reasoning effort, the effective effort is strictly above high | Into the Unknown | Uses the same multi-band tier as non-Flash DeepSeek models |
Levels above high include xhigh, x-high, very-high, max, maximum, and ultra. For non-DeepSeek models, high, medium, low, and off do not trigger an animation.
| Style | Flash | Other DeepSeek / Into the Unknown |
|---|---|---|
| Wave | One blue crest sweeps from left to right, about 1.2 seconds | Two offset blue crests sweep across in sequence with trailing · ✦ ✧ sparkles, about 1.5 seconds |
| Aurora | Two blue light bands drift across one another, about 1.5 seconds | Three differently hued light bands drift across one another, about 1.8 seconds |
| Pulse | One ring expands outward from the center of the composer, about 1.1 seconds | Two rings expand outward in sequence, about 1.45 seconds |
/animation off disables purely decorative effects such as Wave/Pulse, animated theme flow, and rainbow bursts. The input cursor, streaming caret, busy chase, Thinking/Deep Diving shimmer, and Deep diving... clock remain live so an active turn never looks frozen.
@ to reference workspace files or existing sessions; selecting PNG, JPEG, WebP, or GIF files attaches the real image automatically--image arguments, or by dragging one or more images into the terminal/diff, and start a read-only code review with /review (a range picker; diffs use full-row green/red)run_code lists nested tool calls as they run; workflow runs list their member agents until they finish/copy, and inspect history and full tool details with Ctrl+O; intermediate replies that contain reasoning but no final text do not occupy their own inspector entryWhile a turn is running you can keep typing. There are two ways to send what you type:
The difference is when the model sees it: a queued message is read once the turn has finished, a steered one before the turn makes its next move.
How to send each way:
Tab on an empty composer to switch between them. The prompt glyph (❯ / ↳), the placeholder text, and the notice shown on switching all say which one is selected. With text in the box, Tab still completes commands and references./queue opens the queue panel: press Enter on a message to send it as steering instead, e to edit its text (attachments are kept as they are), or d to remove it.Delete on an empty composer to cancel the newest queued message.Esc to cancel the turn keeps queued messages and sends them next, while steered messages are dropped with the turn.Every prompt in the transcript is a full-width coloured row, and the colour says how it was sent: the theme's bright brand colour for an ordinary message, its warning colour for a queued one, and its third accent for a steered one, each labelled with "queued" or "steered". The colour is computed from the theme, so switching themes or rerolling rainbow changes it too.
A message counts as queued or steered only when a turn was already running at the moment you sent it. A message sent while idle is an ordinary one even if the composer is set to steer, because it starts a new turn straight away.
See Queued and steered messages for the queue behaviour, the order the upstream queues are read in, and the colour values per theme.
Start the TUI:
dsh --profile cli # create a standard session
dsh --profile cli --mode ptc # start with the specified Agent Preset (standard/minimal/cordis/ptc)
dsh --profile cli --continue # resume the latest session for the current directory
dsh --profile cli --resume abc123 # resume by id or unique prefix
dsh --profile cli --session my-id # create a session with an explicit id
The following built-in commands are available inside the TUI. Additional Harness commands and user skills depend on the active profile and installed packages; use /help for the complete current list.
| Command | Purpose |
|---|---|
/new [preset] | Create a session, optionally selecting an Agent Preset |
/resume [id|prefix] | Search for or restore an existing session |
/search [query] | Full-text search across persisted sessions (Enter resumes the hit) |
/resume cancel | Cancel a pending session switch |
/fork [event-seq] | Create a session branch from the latest completed turn or a specified event position |
/delete [id|prefix] | Delete a session and its subagent sessions |
/title <text> | Change the current session title |
/export [path] | Export the current session as Markdown |
/history | Search and reuse previously submitted prompts and slash commands |
/clear | Clear the current terminal display without deleting the durable session |
| Command | Purpose |
|---|---|
/mode [preset] | Inspect or select the current session's Agent Preset |
/model | Switch models and manage providers, API keys, browser sign-in, endpoints, and available models |
/effort | Adjust the current model's reasoning effort |
/permission [preset] | Inspect or switch the permission Preset |
/subagent | Select the model used when a subagent performs a task |
| Command | Purpose |
|---|---|
/diff [--staged|ref] | Inspect the working-tree, staged, or specified-ref Git diff by file |
/review [note] | Bare /review opens a candidate picker (uncommitted changes / pick a branch / pick a commit / custom focus); any argument becomes a review note over the uncommitted diff (/review in Chinese). The diff is pasted into the current session under read-only permissions, and findings arrive with P0-P3 priorities and file anchors |
/todos | View the complete todo list for the current session |
/queue | See the messages waiting for the next turn: enter sends one as steering instead, e edits its text, d removes it; ↑↓/PageUp/PageDown/g/G move |
/usage | See this session's token usage: the four disjoint buckets (uncached input, cache write, cache read, output), the totals merged by model, and the per-turn breakdown |
/agents | View subagent sessions created by the current session |
/jobs | View background jobs and their runtime status |
/copy | Copy the latest complete assistant response |
| Command | Purpose |
|---|---|
/plugin [query] | Inspect loaded extensions and their status |
/update | Checks npm for a newer version and confirms the upgrade |
/statusline | Select the items displayed in the status bar |
/vscode-keys | Pass Ctrl+R through VS Code-family terminals (idempotent user-level keybindings.json write) |
/theme | Switch colors: dark / light / prismatic / rainbow / auto |
/rainbow [seed] | Reroll or pin the rainbow theme seed; a bare /rainbow rolls a new seed and switches to rainbow |
/language [en|zh] | Switch the interface language, default English; model prompts and factual status values stay in English |
/animation | Toggle decorative animations; input cursors and activity indicators stay live, /animation [on|off] |
/help | View key bindings, built-in commands, Harness commands, and user skills |
/quit | Exit DSH-Code |
| Action | Purpose |
|---|---|
Enter | Submit the current input |
Ctrl+J / Alt+Enter | Insert a newline in the composer (with the enhanced keyboard protocol, Shift+Enter / Ctrl+Enter work too) |
Up / Down | Recall the previous or next input-history entry |
Tab | Complete commands, skills, or @ references; on an empty composer, switch the next message between queue and steer |
@ | Reference workspace files or existing sessions; image files are sent as attachments |
Ctrl+O | Inspect history and full tool details; intermediate replies with reasoning but no final text do not occupy their own entry |
Ctrl/Alt+R | Fold or expand model reasoning; run /vscode-keys first in VS Code-family terminals to pass Ctrl+R through |
Shift+Tab | Cycle permission Presets, and the plan station when /plan is available |
Delete | Cancel the newest queued message when the composer is empty (steering is not in the queue; press Esc to end the turn instead) |
Ctrl+K | Delete from the cursor to the end of the line |
Ctrl+U | Clear the current input line |
Ctrl+A / Ctrl+E | Move to the beginning or end of the current line |
Esc | Close the current menu or interrupt the running turn; queued messages are kept and sent next, steered ones are dropped with the turn |
Ctrl+C | Cancel a task, clear the input, or exit, depending on the current state |
Ctrl+D | Exit DSH-Code |
| Indicator | Trigger |
|---|---|
✻ Deep diving... | The turn is running while nothing is streaming (waiting for the first token, gaps during tool runs); an elapsed clock appears after 15 seconds |
✻ Thinking… | Model reasoning is streaming; collapsed into the shimmer marker by default, expand with Ctrl/Alt+R |
DSH-Code reads the live Harness registries instead of maintaining a separate local copy. Model adapters, tool providers, skill sources, commands, permission policies, persistence backends, sandboxes, and subagent providers can all be added or replaced through DSH composition.
/plugin provides a read-only view of the current Cordis loader state.
The following official plugins ship with DSH-Code and are enabled in the composition by default:
session_search, session_event_search, session_trace, session_event_trace, session_event_read — over prior session logs (the index persists under the dsh home: the first search builds it once and later searches maintain it incrementally; cross-session access is scoped by exact working directory; on Node 22 the first search prints a one-time node:sqlite experimental warning, which is expected).The following official plugins are installed but opt-in (append rows in the user layer ~/.dsh/profiles/cli/cordis.patch.yml, or install as noted):
MCP servers (@deepseek-ai/dsh-mcp-client, one row per server; tools register as mcp__<server>__<tool>):
- insert:
- id: mcp-memory
name: '@deepseek-ai/dsh-mcp-client'
config:
transport: stdio
serverName: memory
command: mcp-server-memory
(HTTP transports use transport: streamable-http plus url; an unreachable server degrades to a reconnect loop and never breaks startup.)
Claude Code / Codex hooks bridges (@deepseek-ai/dsh-hooks-claude-code / -codex): run existing hooks configurations at the interception seams; a missing hooks file is a silent no-op. Since 0.2.1 the host no longer bundles the bridges: install a bridge with its protocol peer first (dsh plugin --profile cli add @deepseek-ai/dsh-hooks-claude-code@0.2.1-rc.4 @deepseek-ai/dsh-hook-protocol@0.2.1-rc.4; the Codex bridge needs the same peer). /hooks refuses to write a row while either package is missing and prints this command. Then add the row:
- insert:
- id: hooks-claude
name: '@deepseek-ai/dsh-hooks-claude-code'
config:
configPath: C:/Users/you/.claude/hooks.json
LSP navigation: the composition carries lsp / lsp-stdio / tool-lsp rows in a disabled state — language-server binaries resolve at mount, and a missing binary would fail the whole composition boot. The host CLI does not bundle the three packages: install them into the profile first (dsh plugin --profile cli add @deepseek-ai/dsh-lsp @deepseek-ai/dsh-lsp-stdio @deepseek-ai/dsh-tool-lsp), then flip the three rows to disabled: false in the user layer and configure lsp-stdio servers (extension to language to server command); the model then gets the lsp tool (goToDefinition / findReferences / goToImplementation / hover).
Persistent terminals: the PTY service and platform backends (pwsh dialect on Windows, bash on POSIX) mount by default, but the six model tools terminal_open / terminal_send / terminal_read / terminal_signal / terminal_close / terminal_list ship DISABLED — enabling them grants shell capability to every session, which the preset layer is supposed to gate, so deployments opt in explicitly. Since 0.2.1 the host bundles @deepseek-ai/dsh-tool-terminal, so enabling the row in the user layer is enough:
- id: tool-terminal
disabled: false
(Background sends appear in the /jobs panel.)
tmux pane context (@deepseek-ai/dsh-tmux-context): injects the current tmux pane into the model context when running inside tmux (config: { refreshIntervalMs: 60000 }); outside tmux every step degrades to a harmless no-op:
- insert:
- id: tmux-context
name: '@deepseek-ai/dsh-tmux-context'
config:
refreshIntervalMs: 60000
External CLI delegation: dsh plugin --profile cli add @deepseek-ai/dsh-subagent-claude-code (or -codex) installs the dormant provider; following the upstream contract, copy the preset and enable the tool-subagent-claude-code / tool-subagent-codex row to let the model delegate tasks to the claude / codex CLIs.
The Host owns the shared infrastructure—registries, persistence, session queries, permissions, and sandbox policies—while each session receives an isolated Agent scope composed by an Agent Preset:
standard — a full-featured general-purpose coding Agentptc — multi-operation workflows designed for PTC (formerly Code Mode); the legacy code id still worksminimal — a single-tool composition keeping only the persistent shellcordis — the full Agent plus runtime inspection and Preset-authoring guidanceUse /mode before the first turn, or start directly with --mode <preset>. The selected Preset is written to the session and restored when the session resumes.
Prompts, streaming chunks, tool calls and results, model selections, plan state, permissions, titles, and Preset selections are all projected from durable Session events. Session recovery, export, history inspection, context metrics, and terminal replay use the same record.
React state stores only temporary interface details such as the input draft, cursor, active panel, selection, and scroll position.
dsh profile
└─ Host plane: registries · persistence · queries · permissions · sandbox
├─ Agent session A + preset code
├─ Agent session B + preset minimal
└─ DSH-Code TUI
durable events → pure projection → append-only transcript
└→ bounded panels → composer → status bar
pnpm install
pnpm lint # type-aware ESLint over src, tests, scripts, and the root configs
pnpm typecheck # the build project (src)
pnpm typecheck:tests # the spec suite and scripts
pnpm test
pnpm test:coverage # coverage report (trend visibility; no percentage gate)
pnpm build
pnpm verify # lint + both typechecks + tests in one pass
pnpm run gen:whale # regenerate src/whale-glyph.ts from the vendored logo path
tsconfig.test.json puts the specs inside a TypeScript project, so a fixture that drifts from the interface it fakes fails pnpm typecheck:tests instead of surfacing (or not) at runtime.
For release packaging, see the packaging guide.
The whale glyph is generated from the DeepSeek FishLogo geometry vendored in scripts/fish-logo.ts (source: DeepSeek Harness, MIT).
For a local checkout:
dsh plugin --profile cli add file:C:/path/to/dsh-code
GitHub installation is available for source development:
dsh plugin --profile cli add github:unlinearity/dsh-code
The Git package builds during installation. If pnpm asks for an allowBuilds entry, copy the complete entry it prints into ~/.dsh/profiles/cli/pnpm-workspace.yaml, then run the command again. The key contains the Git URL and commit, so it cannot be replaced with only dsh-code.
dsh plugin --profile cli remove dsh-code # unmount the plugin from the cli profile
npm uninstall -g dsh-code # remove the global package and the deepseek / dsh-code commands
Both commands are required for a complete uninstall. The first only removes the profile mount, so the deepseek command still exists and reports "the cli profile does not mount dsh-code yet". The second removes the global npm package and its launch aliases. Uninstalling does not affect @deepseek-ai/dsh itself or any persisted session data.
DSH-Code is an independent MIT-licensed community project and is not affiliated with OpenAI or Anthropic.
Communities:
MIT. The vendored FishLogo geometry comes from DeepSeek Harness (MIT).
No reviews yet. Be the first to rate this tool.
Sign in to leave a review.