Back to home@seewhydee

dsh-emacs-bridge

Deepseek Harness to Emacs bridge

Stars
0
Language
Emacs Lisp
Created
Aug 23, 2026
Updated
Aug 27, 2026
GitHub repo

Introduction

dsh-emacs-bridge

This is a two-way bridge between Emacs and a Deepseek Harness session. The bridge moves text from Emacs to DeepSeek Harness (DSH), and vice versa, over loopback HTTP. This lets you type in Emacs and read DSH's replies without copy-pasting, while also avoiding streaming voluminous LLM outputs through Emacs.

It consists of two components:

  • dsh-plugin/ — a DeepSeek Harness plugin (dsh-emacs-bridge).
  • emacs/dsh-bridge.el — an Emacs package to interact with the harness.

Installation

Requirements

  • dsh, the DeepSeek Harness.
  • Node.js and pnpm to build the plugin.
  • Emacs 29 or later.
  • (Recommended) The markdown-mode Emacs package.

Manual compilation and installation

Here are the steps to build/install the DSH plugin and Emacs library manually:

Build the DeepSeek Harness plugin

From this repository's root directory:

cd dsh-plugin
pnpm install   # first time only
pnpm build     # emits lib/index.js (host) + lib/client.js (browser)

Note: if you have a dev setup where dsh-plugin/node_modules is a symlink to the harness checkout, and pnpm build aborts with “Aborted removal of modules directory due to no TTY”, invoke the builders directly:

./node_modules/.bin/tsdown && ./node_modules/.bin/tsdown --config tsdown.client.config.ts

Install the DeepSeek Harness plugin

If you have a global install with dsh on $PATH:

# global install, from this repo root:
dsh plugin --profile web add link:./dsh-plugin
dsh web

If you have a source checkout of DSH and run it as a pnpm script (pnpm dsh web), do the following instead (replace the link: path with the appropriate path into this repo):

# source checkout, from deepseek-harness root:
pnpm dsh plugin --profile web add link:/absolute/path/to/dsh-emacs-bridge/dsh-plugin
pnpm dsh web

Install the Emacs library

Put this in your Emacs init file (~/.emacs.d/init.el or ~/.emacs), replacing the path with the actual path to dsh-bridge.el.

(load "/path/to/dsh-emacs-bridge/emacs/dsh-bridge.el")

Alternatively, copy dsh-bridge.el into your Emacs load-path and do (require 'dsh-bridge).

Emacs package (EXPERIMENTAL)

Alternatively, the project can be bundled into a single Emacs package that also stores the DSH plugin. This requires both dsh and pnpm to installed on $PATH. First, build the package tarball from this repository's root directory:

make package

Then, in Emacs, run:

  1. M-x package-install-file RET /path/to/dsh-bridge-<version>.tar RET
  2. M-x dsh-bridge-install-plugin — install bundled plugin into DSH.
  3. Restart dsh web.

Usage

From Emacs, the main entry-points are these two commands:

  • M-x dsh-bridge — open a transient menu for DSH commands.
  • M-x dsh-bridge-list-sessions — show a list of DSH sessions.

Consider giving either of these a global keybinding, e.g.,

(keymap-global-set "C-c d" #'dsh-bridge)

Transient menu

The M-x dsh-bridge command opens a transient menu that prompts for the next command. The top line shows the session your next command will act on: the buffer's own session when the dispatcher is invoked from a DSH-View or DSH-Prompt buffer, otherwise the default target session if one is set, otherwise the last-active session.

The following commands are available from the transient menu:

  • q — exit the transient menu.
  • r — open a DSH-Prompt buffer for the session.
  • s — send the region or buffer as a prompt.
  • d — send the region or buffer as a draft (can still edit in DSH composer before submitting).
  • f — fetch the session's latest reply into the DSH-View buffer.
  • t — set the default target session.
  • u — clear the default target session.
  • l — open the DSH-Sessions buffer.

Sessions menu

The M-x dsh-bridge-list-sessions command opens a buffer with a list of DSH sessions. The default target session (if any) is marked by a * in the leftmost column.

The following commands are available from the DSH-Sessions buffer:

  • q — quit the window and bury the buffer.
  • f — fetch the last output for the session at point into a DSH-View buffer.
  • r or RET — open a DSH-Prompt buffer for the session at point.
  • t — set the session at point as the default target.
  • u — clear the default target.
  • v — cycle session display between live+saved (default), live, and live+saved+archived.
  • g — refresh the DSH-Sessions buffer.

For a full list, see the menu bar. Other tabulated-list-mode keys are also available.

DSH-View buffer

This read-only buffer contains the model output for a DSH session. It is fetched by f from the transient menu or the DSH-Sessions buffer, C-c C-f from the DSH-Prompt buffer, or pushed from the web UI's "Send to Emacs" button (see below). The session is displayed on the header line.

The following commands are available:

  • g — re-fetch the current session's latest reply.
  • r — open a DSH-Prompt buffer for the current session.
  • w — copy the reply (region, else the whole buffer) to the kill ring.
  • i — receive the latest "Send to Emacs" message (see below).
  • M-p/M-n — cycle the current session's assistant replies.
  • l — open the DSH-Sessions buffer.
  • q — quit the window and bury the buffer.

If markdown-mode is installed, and dsh-bridge-view-gfm is non-nil, the reply is font-locked as GitHub-Flavored Markdown.

DSH-Prompt buffer

This buffer is used to compose a prompt, or reply, for a DSH session. It is opened by r/RET from the DSH-Sessions buffer, and r from the transient menu or DSH-View buffer. The session affected is determined by how this buffer was invoked; for instance, r from a DSH-View buffer opens a prompt for the same session.

The following commands are available from the DSH-Prompt buffer:

  • C-c C-c — send the region, or the whole buffer, as a prompt.
  • C-c C-d — push it to the DSH composer as a draft instead.
  • C-c C-k — erase the buffer.
  • C-c C-f — open the DSH-View buffer for this session.
  • C-c C-l — open the DSH-Sessions buffer.
  • M-p / M-n — walk the session's prompt history.

When markdown-mode is installed, this buffer derives from it, so most markdown editing commands are also available.

Sending text from DSH to Emacs

The DSH plugin adds a "Send to Emacs" button that lets you push specific assistant messages to Emacs.

With dsh-bridge-notifications non-nil (the default), Emacs subscribes to the bridge's event stream and automatically updates the DSH-View buffer. If you disable this option, you can use i in the DSH-View buffer (or run M-x dsh-bridge-receive) to pull the latest message pushed by DSH. Receiving selects the DSH-View buffer unless dsh-bridge-receive-pop is nil.

Permissions, authentication, and failure bounds

The DSH plugin registers its routes on the DSH web server's loopback listener, and the browser plugin calls only same-origin /dsh-bridge/* routes. No third-party service is contacted.

Every /dsh-bridge route requires a shared bearer token stored at ~/.dsh/dsh-bridge-token, generated on first use in mode 0600. Emacs reads this file directly, while the browser plugin fetches it from the loopback-only GET /dsh-bridge/token route (peer- and origin-fenced).

HTTP request bodies are capped at 1 MiB; larger bodies get a 413 error. DSH-to-Emacs messages are held in a bounded outbox (100 unacknowledged entries); overflow evicts the oldest entries and is reported to the collector. Requests naming a non-live session fail with 404/409; a draft push fails with 409 when no browser client is subscribed.

License

This software is released under the terms of the GNU General Public License version 3, or later. See COPYING.