dsh-tui
Discovered[WIP] TUI for DeepSeeh-Harness
dsh-tui
A lightweight terminal user interface for DeepSeek Harness (DSH). The TUI is a thin frontend client: it connects to a running DSH backend over the same HTTP/WebSocket protocol the Web UI uses, normalizes backend events into a small client-side model, and renders them in the terminal. The backend stays the single source of truth — the TUI never runs agents, tools, sandboxes, or models itself.
Browser Terminal
│ │
▼ ▼
DSH Backend ◄── HTTP RPC + WebSocket ──► dsh-tui
Features
- Attach to any existing DSH session and resume it later
- Live streaming: assistant text, reasoning (collapsible), tool cards, run state, session titles, token usage
- Interactive approvals and user questions answered through the backend
- Interrupt the current run (Esc)
- Session picker, new-session creation, command palette
- Reconnect with bounded backoff; dedup by backend identifiers
- Offline replay of captured event traces for development and regression tests
Requirements
- Node.js ≥ 20.18 (Node 22+ runs the TypeScript sources directly)
- A running DSH server:
dsh web(defaulthttp://127.0.0.1:3080)
Usage
npm install
npm run build # compile to dist/
# Attach to an existing session
node dist/cli.js --session <session-id>
# Create a fresh session in the current directory and attach
node dist/cli.js --new
# Point at a non-default server
node dist/cli.js --server http://127.0.0.1:8080 --session <id>
# No session argument → session picker on startup
node dist/cli.js
# Offline replay of a captured trace
node dist/cli.js --replay fixtures/pong-session.jsonl --speed 2
The npm bin is dsh-tui; after npm link (or installing the package) the
commands above become dsh-tui --session <id>.
Keys
| Key | Action |
|---|---|
Enter | send — next-step delivery while the agent is running (» prompt), native queue when idle |
Ctrl+Enter | steer — cancel the current step, continue with your message |
Ctrl+Shift+Enter | backlog — queue as its own turn after the current one |
Shift+Enter | new line in the composer (multiline input) |
Esc | interrupt the current run |
Ctrl+C / Ctrl+D | quit (press twice to force) |
Tab / Shift+Tab | expand/collapse tools |
Ctrl+T | toggle reasoning visibility |
Ctrl+O | toggle latest tool output |
Ctrl+P | command palette |
Ctrl+R | session picker |
PgUp / PgDn / Home / End | scroll conversation |
y / n | allow / deny a permission request |
1-9 + Enter | answer a question |
The three send modes follow the same semantics as the web UI's
queue-steer-button: Enter while running delivers the message with the next
agent step (session.prompt steer mode), Ctrl+Enter aborts the current step
first and then delivers, and Ctrl+Shift+Enter puts the message in the
whole-turn backlog.
Slash commands: typing / in the composer shows matching commands inline
(also available via Ctrl+P): /new, /sessions, /stats, /models,
/config, /permission, /reconnect, /reasoning, /tools, /clear,
/help, /quit. Any other /… text is forwarded to the backend's own
slash-command registry (e.g. /compact, /goal, /permission <preset>).
/stats— detailed session statistics from the live projections: turns, steps, LLM time, tool-call time, average TTFT, decode time, output tokens, throughput (TGS), input tokens (uncached + cache read), cache hit rate, and context pressure./models— browse provider groups and models;Enterapplies,rcycles the reasoning effort (session.selectModel)./config— read-only view of the deployment settings namespaces (settings.describe)./permission— shows the current sandbox permission and the available presets;Enterapplies through the backend/permissioncommand.
Architecture
src/
├── cli.ts CLI entry (args, TUI bootstrap, wiring)
├── test-client.ts headless smoke client (Milestone B)
├── client/
│ ├── types.ts normalized TUI event model (HarnessEvent, …)
│ ├── protocol.ts wire envelopes: /api RPC, respond, event streams
│ ├── events.ts raw frame → HarnessEvent normalization (once)
│ ├── harness-client.ts stable client boundary (interface)
│ ├── dsh-client.ts concrete DSH client (HTTP + WebSocket + reconnect)
│ └── reconnect.ts bounded-backoff helpers
├── state/
│ ├── state.ts DshTuiState
│ ├── reducer.ts pure reduceHarnessEvent / reduceUiAction
│ ├── fold.ts history folding (shares reducer semantics)
│ └── store.ts tiny observable store
├── components/ Pi-based rendering: app, header, conversation,
│ message, tool-call, interaction, composer, status-line,
│ session-picker, command-palette, help
└── testing/
└── replay-client.ts offline trace replay client
Design rules (from the implementation plan):
- The TUI depends only on the
HarnessClientboundary — never on transport, wire schemas, Cordis internals, or backend implementation details. - All backend-specific interpretation lives in
client/events.ts(normalize exactly once). - The state reducer is pure and unit-tested; rendering consumes state, not wire messages.
- Interactions are backend-authoritative: an approval is only settled when the
backend confirms it (
approval/resolved/question/resolvedframes). - Backend message/tool ids are preserved for dedup and reconnect.
Development
npm run typecheck
npm test # 46 unit + integration tests
npm run test:client # headless smoke client against a live server
npm run dev -- --replay fixtures/interaction.jsonl # live TUI on a fixture
Captured fixtures live in fixtures/:
live-trace.jsonl— 1336 frames captured from a live mux streampong-session.jsonl— a complete small run (user → stream → answer)interaction.jsonl— approval + question lifecycle (requested → resolved)interaction-pending.jsonl— approvals/questions left pending
Documentation
docs/tui/dsh-frontend-protocol.md— the DSH frontend protocol (transport, RPC map, event streams, session events, interactions, reconnect semantics), written from the shipped DSH package and verified against a live backend.deepseek-harness-tui-implementation-plan.md— the plan this project implements.
Non-goals (MVP)
No embedded terminal emulator, file explorer, diff editor, workspace management, model configuration, sandbox lifecycle, multi-session panes, local trajectory persistence, or direct LLM calls. The TUI is a client; the backend does the work.
License
MIT
Comments
Loading…
Similar plugins
by xiaoshihou514
DeepSeek Harness: TUI
★ 3
↓ 527/wk
MIT
TypeScript
Aug 22, 2026
dsh plugin --profile web add dsh-tuiby AncientMoon114
A light TUI plugin for Deepseek Harness.
★ 0
MIT
TypeScript
Sep 10, 2026
dsh plugin --profile web add @dsh-external/dsh-minituiby XMoon
A third-party TUI mode for DeepSeek Harness (dsh), built on a vendored fork of pi-tui
★ 19
↓ 823/wk
MIT
TypeScript
Oct 4, 2026
dsh plugin --profile terminal add @xmoon76/dsh-pi-tuiby liukj98
deepseek harness tools 插件
★ 0
MIT
TypeScript
Aug 19, 2026
dsh plugin --profile web add dsh-ui-toolsby cogine-ai
Claude-Code-Styled TUI for DeepSeek Harness
★ 8
↓ 126/wk
MIT
TypeScript
Sep 17, 2026
dsh plugin --profile web add dsh-claude-tuiby boxeryao
DSH-TUI: a lightweight and fast terminal plugin connected directly to the DSH runtime.
★ 10
↓ 129/wk
MIT
TypeScript
Aug 16, 2026
dsh plugin --profile terminal add dsh-mini-tui