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.0-rc.2). 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 (recommended). /update and deepseek update --apply both work afterwards: they check npm for a newer version and walk you through the upgrade.
npm install -g @deepseek-ai/dsh@0.2.0-rc.2 pnpm
npm install -g dsh-code@2.0.0
dsh plugin --profile cli add dsh-code@2.0.0When npm is unreachable (restricted network, a mirror outage), install the GitHub Release tarball instead. CI builds it on every tag and attaches it to the release; lib is prebuilt, so the installing machine needs no toolchain:
npm install -g @deepseek-ai/dsh@0.2.0-rc.2 pnpm
npm install -g https://github.com/unlinearity/dsh-code/releases/download/2.0.0/dsh-code-2.0.0.tgz
dsh plugin --profile cli add https://github.com/unlinearity/dsh-code/releases/download/2.0.0/dsh-code-2.0.0.tgznpm script prompts: npm 11.6+ may print
npm warn install-scriptsduring a global install (unapproved build scripts for node-pty, koffi, and friends). The host ships prebuilt artifacts, so common platforms can ignore the warning; if a native-module error appears after installing, follow npm's own hint and rerun withnpm install -g --allow-scripts=<package list>.Version alignment: dsh-code targets dsh
0.2.0-rc.2, with every Harness dependency pinned exactly to0.2.0-rc.2. A locallink:mount should be rebuilt withgit pull && pnpm install && pnpm build; do not run the updater against a checkout.Upgrade notes: sessions and startup arguments recorded under the legacy
codepreset map automatically to the upstream-renamedptc— no manual migration. The session-log reader follows upstream to format v4: older logs migrate in the kernel on read (v3 to v4), and the original files on disk stay untouched.Settings migration: on the first boot of a dsh 0.1.7-targeting build, the host imports the retired global
settings.yamlinto the active profile once (the file is then renamed tosettings.yaml.imported). Upgrade dsh and dsh-code together so no degraded boot falls in between. If provider/model configuration goes missing after an upgrade, the TUI detects it at startup and re-imports the stranded sections automatically through the host's own settings pipe — no manual steps, no re-login (credentials are unaffected). Only when the settings service is unwritable do you need the manual fallback: copysettings.yaml.importedtosettings.yamlunder the dsh home and restart.A GitHub tarball install can lead npm by one release (until the registry carries the same version). The updater only reads npm, so it reports that this install is newer and refuses to downgrade, instead of claiming everything is up to date; use
/updateonce npm catches up.
Available launch commands:
dsh --profile cli
deepseek
dsh-codedsh --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.
For installation, native-module, and plugin-loading issues, run deepseek doctor first, then see Troubleshooting.
DSH-Code brings DSH Agents, models, tools, and durable sessions directly into the terminal, covering the complete workflow from writing code to reviewing changes.
- Create sessions with
/new, or restore existing sessions with/resumeand--continue - Create a new work branch from a historical point with
/forkwhile preserving the original session - Search history by current directory, update time, and session scope
- Recall input history with Up/Down (typed slash commands included), or search previous prompts and commands with
/history - Use persistent titles, Markdown export, context occupancy, token, cache, TTFT, and elapsed-time metrics;
/usagereports the harness token meter's four disjoint buckets, the totals merged by model, and a per-turn breakdown - The status bar's
incounts only uncached input, andcacheshows both the cache-read volume and the hit share — together they are the billed prompt side - Restore the session's Agent Preset, model selection, and subagent list when resuming it; the welcome header shows both the dsh and dsh-code versions
- Select an independent Agent Preset for each session to compose tools, prompt sections, skills, context compaction, plan mode, and subagent capabilities
- Use
/modeto selectstandard,ptc,minimal,cordis, or a user-defined Preset (the legacycodeid maps toptc) - Use
/modelto switch models and manage providers, API keys, OAuth/device-code sign-in, endpoints, available models, and context windows - In the
/modelprovider list, Enter manages a manual API key,lstarts sign-in, andologs out after confirmation - Automatically load commands and skills available in DSH; use
/helpto find them and/pluginto inspect extension status - Use plans, goals, todos, permissions, sandboxes, subagents, and additional instructions while a task is running
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.
- Use
@to reference workspace files or existing sessions; selecting PNG, JPEG, WebP, or GIF files attaches the real image automatically - Attach images through the initial prompt, repeated
--imagearguments, or by dragging one or more images into the terminal - Inspect changes by file with
/diff, and start a read-only code review with/review(a range picker; diffs use full-row green/red) run_codelists nested tool calls as they run; workflow runs list their member agents until they finish- Copy the latest complete response with
/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 entry - Handle tool approvals, structured questions, plan reviews, multiple selections, and custom answers
- Control what the Agent may do with permission Presets and sandboxes; add instructions or interrupt while a task is running
While a turn is running you can keep typing. There are two ways to send what you type:
- Queue — it waits until the turn finishes and then runs as a new turn. Use it for "do this once you are done with that".
- Steer — it reaches the model before the next step of the running turn, as part of that request. Use it when the work has gone the wrong way and you want it corrected now.
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:
- Press
Tabon 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,Tabstill completes commands and references. /queueopens the queue panel: pressEnteron a message to send it as steering instead,eto edit its text (attachments are kept as they are), ordto remove it.- Press
Deleteon an empty composer to cancel the newest queued message. - Pressing
Escto 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 idThe 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. A GitHub tarball install can lead npm, in which case it says so and refuses to downgrade |
/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: the model gets five read-only tools —
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-timenode:sqliteexperimental 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 asmcp__<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-httpplusurl; 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:- 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-lsprows 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 todisabled: falsein the user layer and configurelsp-stdioservers(extension to language to server command); the model then gets thelsptool (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_listship DISABLED — enabling them grants shell capability to every session, which the preset layer is supposed to gate, so deployments opt in explicitly.@deepseek-ai/dsh-tool-terminalis likewise not bundled by the host: rundsh plugin --profile cli add @deepseek-ai/dsh-tool-terminalfirst, then enable in the user layer:- 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 thetool-subagent-claude-code/tool-subagent-codexrow 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 legacycodeid still worksminimal— a single-tool composition keeping only the persistent shellcordis— the full Agent plus runtime inspection and Preset-authoring guidance- user Presets — custom tools, prompt sections, skills, context compaction, plan mode, and subagent behavior
Use /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 pathtsconfig.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.
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-codeGitHub installation is available for source development:
dsh plugin --profile cli add github:unlinearity/dsh-codeThe 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 commandsBoth 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.
- Runtime services, events, plugin scopes, and the persistence model follow DeepSeek Harness.
- Session navigation, overlay sizing, scrollback, bottom layout, and resize handling refer to Codex CLI.
- Slash-command discovery, turn steering, reasoning folds, approvals, and question flows refer to Claude Code.
DSH-Code is an independent MIT-licensed community project and is not affiliated with OpenAI or Anthropic.
Communities:
- Linux DO: Learn AI at L Station!
- DeepSeek Harness: the official DSH website
MIT. The vendored FishLogo geometry comes from DeepSeek Harness (MIT).



