Skip to content

dsh-tui

Recipe card from the charly-tools plugin (Images — the deployable catalog).

dsh-tui – the DeepSeek Harness terminal UI plugin

Section titled “dsh-tui – the DeepSeek Harness terminal UI plugin”

dsh-TUI (https://github.com/ccch1mneyyy/dsh-TUI, npm @deepseek-harness-tui/dsh-tui) is a pure DSH plugin, not a daemon. It is added to a dsh profile and launched by the shipped dsh-tui / dst launcher (or dsh --profile dsh-tui). The candy dsh-tui composes the dsh CLI candy and adds the plugin + a typed terminal channel.

Property Value
Install files charly.yml, package.json
Depends dsh (the CLI candy), layer-tmux
Env DSH_TUI_NO_LAUNCHPAD=1 (boot straight to the composer)
Channel terminal_profile: dsh-tui + agent_provide: tmux
Profile $DSH_HOME/profiles/dsh-tui (auto-bootstrapped on first launch)

The first-run wizard is pre-recorded at ~/.dsh-tui/onboarding.json ({"completed":true,"version":1}) and the launchpad is disabled (DSH_TUI_NO_LAUNCHPAD=1), so the process lands directly on the chat screen with no keyboard-owning dialog — the state a terminal channel can drive. Without both, an ordinary launch opens the wizard or the launchpad, which own the keyboard.

The candy publishes a terminal_profile (entrypoint dsh-tui) and an agent_provide: {provider: tmux, profiles: [dsh-tui]} capability. A disposable bed or a host controller drives it through charly agent terminal launch/snapshot/input/key/transcript. A terminal channel is on-demand, not a long-running service: a service-less box that carries it must be held at steady state by check-keepalive’s sleep infinity supervisord program.

The channel is a real terminal, so it must be driven the way a terminal behaves — not the way a service does:

  • Unique run-ids. launch/input/snapshot/close are keyed by --run-id. A hardcoded run-id collides when check-live and check-live-rebuild run the same plan in one session; derive a fresh id per step (a uuidgen/date +%s%N-style value), never a literal.
  • snapshot is a render of the viewport, so it is scroll/cursor dependent — a text that scrolled off is gone. To assert content, read the durable transcript (the full session log), not a snapshot taken at an arbitrary moment.
  • close closes the control channel, not the process. The TUI keeps running under tmux after a close; do not rely on close to reap it, and never launch a second session against the same target while a first is still attached — two concurrent control sessions on one pod contend for the same tmux server.
  • The interactive submit is keyboard-timing racy. Typing a prompt and injecting the submit key can race the TUI’s redraw, so a pass/fail that depends on the enter landing is flaky by construction. An interactive TUI’s liveness is proven by the channel (launch → non-empty transcript → close); the live model turn it fronts is asserted separately with a one-shot, non-interactive dsh --headless call in the same box.
charly.yml
my-tui-box:
candy:
- dsh-tui
Terminal window
charly start my-tui-box
# drive the TUI through the channel:
charly agent terminal launch '{"name":"dsh-tui","entrypoint":["dsh-tui"],"cols":140,"rows":44,"keys":["enter"]}' --target my-tui-box --run-id <uuid>