Skip to content
dsh.fish
Bundle

deepseek-harness-desktop

macOS (Apple Silicon) desktop shell for the DeepSeek Harness Web GUI — double-click to run, no terminal needed.

Source
Evan1u
stars
1 stars
Updated
Updated 5 days ago

Readme

<div align="center">

# 🐋 DeepSeek Harness — Desktop

**A native macOS desktop shell for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) — double-click, no terminal.**

[![version](https://img.shields.io/badge/version-0.1.4-4c7dff?style=flat-square)](https://github.com/Evan1u/deepseek-harness-desktop/releases)
[![platform](https://img.shields.io/badge/macOS-arm64-888888?style=flat-square)](#)
[![license](https://img.shields.io/badge/license-MIT-4caf50?style=flat-square)](LICENSE)
[![stars](https://img.shields.io/github/stars/Evan1u/deepseek-harness-desktop?style=social)](https://github.com/Evan1u/deepseek-harness-desktop)

*[English](README.md) · [中文](README.zh.md)*

</div>

---

## ✨ What this is

DeepSeek Harness is powerful, but starting it means opening a terminal and typing `dsh web`. This app wraps it in a **thin Electron shell** — double-click, and it boots `dsh --profile web --no-open --port 0`, waits for the local URL, and renders the **exact same Web GUI** in a native window. Every web feature, zero divergence, zero terminal.

<div align="center">

| 🖥️ No terminal | 🐋 Live tray | 🎯 Busyness-aware | 🌗 Light/dark | 🔄 Auto-update |
|:---:|:---:|:---:|:---:|:---:|
| Double-click to run | Two switchable icon styles | The icon reacts to real workload | Adaptive icons | GitHub Releases |

</div>

## 🐋 The tray icon — alive and switchable

The menu-bar icon is **not a static glyph**. It reflects what DeepSeek Harness is doing:

- **Idle** → a calm, still icon.
- **Working** → an animated icon whose **speed** follows how busy the backend is (running sessions + running jobs).

Right-click the icon to switch between **two styles**:

<table>
<tr><th>Style</th><th>Idle</th><th>Working</th></tr>
<tr><td><b>🐟 Fish Swing</b> <i>(default)</i></td><td>Still whale</td><td>Swinging whale — faster with more work</td></tr>
<tr><td><b>🔮 Thinking Orb</b></td><td>Search globe</td><td>Listening orb — a rippling dot sphere</td></tr>
</table>

Both styles adapt to light/dark menu bars automatically, and your choice is remembered across launches.

<div align="center">
<table>
  <tr>
    <td align="center"><img src="assets/demo.gif" width="220" alt="Fish Swing"><br><sub>🐟 Fish Swing</sub></td>
    <td align="center"><img src="assets/demo-orb.gif" width="220" alt="Thinking Orb"><br><sub>🔮 Thinking Orb</sub></td>
  </tr>
</table>
</div>

### Busyness → animation

| Busyness | State | Frequency |
| --- | --- | --- |
| 0 | Still | — |
| 1 | Light | Slow (~1.8 s/cycle) |
| 2 | Medium | Medium (~1.2 s/cycle) |
| 3 | Heavy | Fast (~0.8 s/cycle) |

> Busyness = running sessions + running jobs, read live from the harness's own event streams.

### Swing amplitude

Right-click the menu-bar icon → **Swing Amplitude** → pick a preset:

| Preset | Subtle | Default | Strong | Stronger | Strongest |
| --- | --- | --- | --- | --- | --- |
| Rotation | 6° | 9° | 12° | 15° | 18° |

## 🚀 Getting Started

<kbd>double-click</kbd> the `.app` — or drop it into **Applications**. If macOS warns on first launch (unsigned build), *right-click → Open*.

- **Left-click** the tray icon → show the window
- **Right-click** → Open / Quit / Icon Style / Swing Amplitude
- **Red close button** → hides to the tray; the app keeps running in the background

<details>
<summary><b>🔧 How it works</b></summary>

```
DeepSeek Harness.app
  └─ Electron main process
       ├─ resolve dsh (DSH_BIN override → /opt/homebrew/bin/dsh → … → PATH)
       ├─ spawn: dsh --profile web --no-open --port 0
       ├─ parse stdout:  "dsh web: http://127.0.0.1:<port>"
       ├─ BrowserWindow.loadURL(that URL)
       └─ lifecycle: SIGTERM on quit · retry dialog on backend crash
```

The backend binds `127.0.0.1` on an OS-assigned port, so the `/api` loopback trust fence passes with no extra configuration and there is no fixed-port conflict.

> ⚠️ **Do not** open the same session in a separate terminal `dsh web` at the same time — the session store is single-writer, so two live backends writing one session log can corrupt it (history then fails with `corrupt session log: seq gap in committed region`).

</details>

<details>
<summary><b>📦 Develop / package</b></summary>

```sh
npm install          # installs electron + electron-builder
npm start            # run from source
npm run pack         # build the .app (release/mac-arm64/DeepSeek Harness.app)
npm run dist         # also build .dmg and .zip
```

Output lands in `release/`. If a **Developer ID Application** certificate is in your Keychain, electron-builder signs automatically; otherwise the app is left **unsigned** for local use.

</details>

<details>
<summary><b>🔏 Code signing & notarization (remove Gatekeeper)</b></summary>

Signing + notarization require an Apple Developer Program membership and a Developer ID certificate. The toolchain and build config are already wired up — you only supply the credentials.

**One-time setup**

1. Join the [Apple Developer Program](https://developer.apple.com/programs/) (paid).
2. Create a **Developer ID Application** certificate: Xcode → Settings → Accounts → Manage Certificates → `+` → Developer ID Application. Verify with `security find-identity -v -p codesigning`.
3. Create an **App Store Connect API key** (Developer role): [App Store Connect](https://appstoreconnect.apple.com/) → Users and Access → Integrations → App Store Connect API → Team Keys → generate → download the `.p8` → note the **Key ID** and **Issuer ID**.

**Build + notarize**

```sh
npm run pack    # signs automatically once the cert is in Keychain

APPLE_API_KEY_PATH=~/.appstoreconnect/AuthKey_XXXXXX.p8 \
APPLE_API_KEY_ID=XXXXXXXXXX \
APPLE_API_ISSUER_ID=00000000-0000-0000-0000-000000000000 \
./scripts/notarize.sh
```

</details>

<details>
<summary><b>🔄 Auto-update (GitHub Releases)</b></summary>

The app checks for updates on launch (then hourly) and offers **Restart now** when a newer version is out. Publish a new release with a GitHub token:

```sh
GH_TOKEN=github_pat_xxx ./scripts/publish.sh
```

> Note: reliable macOS auto-update is best with a signed app; for an unsigned personal build it is best-effort.

</details>

## ⚙️ Configuration

| Variable | Purpose |
| --- | --- |
| `DSH_BIN` | Absolute path to the `dsh` executable (defaults to `/opt/homebrew/bin/dsh`). |
| `DSH_HOME` | Inherited from the environment; shares `~/.dsh` profiles, credentials, and sessions with the CLI. |

<details>
<summary><b>🗺️ Roadmap</b></summary>

- [x] v0.1 — Electron shell wrapping `dsh web` (full web parity)
- [x] Appearance-adaptive Dock icon (light/dark)
- [x] Busyness-aware animated tray + close-to-tray
- [x] Two switchable tray icon styles (Fish Swing / Thinking Orb)
- [x] Auto-update (GitHub Releases)
- [ ] Code signing + notarization — config ready, pending Apple Developer credentials
- [ ] Native IPC transport — load `dist` over `file://` and bridge `/api` over `ipcRenderer`

</details>

<div align="center">

*Made with ❤️ for the DeepSeek Harness community.*

</div>

Install

dsh plugin --profile web add github:Evan1u/deepseek-harness-desktop

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source