Introduction¶
DeepSeek Harness (DSH) is typically used to operate AI agent conversations on a desktop or in a browser. To view streaming replies, thinking processes, tool cards, and approvals on an iPhone or iPad using a native SwiftUI interface, without forking the client or publishing a self-built App, you need to provide a hermes-webui (HTTP + SSE) or Hermes host (REST + WebSocket JSON-RPC) service locally that Hermex can recognize.
dsh-hermes-facade is a DSH host plugin: it listens on a local loopback port, performs protocol conversion between Hermex and DSH’s Typer Gateway, and does not modify DSH’s native :3080 entry point. Maintained by Gnanesh Kunal, the source code is released on GitHub under the MIT license, and the current package version is 0.3.0.
Plugin Positioning and Architecture¶
In one sentence: make the local DSH appear as a Hermes series server that the Hermex free client (Hermex, App Store) can connect to.
The README data path schematic is as follows:
Hermex (iOS) --HTTPS/SSE--> tailscale serve :9443 --> 127.0.0.1:9120
|
dsh-hermes-facade
| in-process
dsh typertGateway
The plugin chooses a “Facade” over forking Hermex for a clear reason: Hermex’s main interface uses the hermes-webui contract; acting as a webui host is the approach with the least changes, requiring no maintenance of an Xcode project or a separate App Store entry.
Core Features¶
Below are only the capabilities explicitly stated in the README and package.json.
hermes-webui Listening (Default Port 9120)¶
- Session list, details, and history (latest 200; supports 50 per page pagination within the latest 800).
- Session search (id, title, message content; content matching with summaries).
- Chat: SSE streaming output, cancellation, token increments, thinking blocks, tool cards and results.
- Approval (once / session / always / deny) and clarification Q&A; command descriptions are preserved after reconnection, and stale prompts return
409 {"stale":true}. - Model selection and reasoning effort; usage telemetry (no cost field, as DSH has no pricing).
- Workspace: list is read-only; workspace file browser is read-only.
- Health checks, password authentication, and signed cookies.
Hermes-protocol Listening (Optional, Port 9121)¶
Hermex 2.x defaults to connecting to Hermes host. The plugin can provide both contracts in the same process:
| Port | Contract | Behavior in App |
|---|---|---|
| 9120 | hermes-webui (HTTP + SSE) | Legacy server; a prompt to migrate to Hermes may appear |
| 9121 | Hermes host (REST + WS JSON-RPC) | Native Hermes server |
The gateway listener does not re-implement DSH, but returns to the local webui facade via an internal token. The README lists coverage for chat attachments, Git inside sessions (read/write available when no turn in progress), Memory, Skills (read-only), Tasks/cron, etc. Bots and session import are not implemented (returns JSON-RPC -32601, App hides related controls). Details see docs/06-hermes-gateway.md in the repo.
Configuration example to enable the second listener (from README):
config:
gatewayEnabled: true # Only webui listener kept when false
gatewayPort: 9121
gatewayBindHost: 127.0.0.1
gatewayLanHost: auto # Provide plaintext HTTP on Wi-Fi LAN and Tailscale IPv4 simultaneously
Environment and Dependencies¶
package.json requires:
dsh:>=0.2.1-rc.1node:>=22.6
Installation and Enablement¶
First install the plugin, then write the bundle into the profile, and finally restart the host.
- Install the plugin (command must match README):
dsh plugin --profile web add dsh-hermes-facade
- Add the package name to the bundle list in
~/.dsh/profiles/web/package.json:
"dsh": { "profile": { "bundles": [ "... existing ...", "dsh-hermes-facade" ] } }
- Restart the host to load the plugin:
dsh web
On first startup, a one-time password will be printed in the logs, for example:
hermes-facade: FIRST RUN password = xxxxxxxxxxxx
The hash result is saved in ~/.dsh/hermes-facade/password.json (permission 0600). To reset, delete the file and restart.
Typical Usage: Connecting from Phone to Local Machine¶
Expose via Tailscale HTTPS (Tailnet only, no Funnel)¶
webui contract:
tailscale serve --bg --https=9443 http://127.0.0.1:9120
If the Hermes listener is enabled, you can expose the second port separately (the App determines the server type via GET /api/status, the same URL cannot serve both roles):
tailscale serve --bg --https=9444 http://127.0.0.1:9121
tailscale serve status
In Hermex, select Add server, fill URL with https://<machine>.<tailnet>.ts.net:9443, and fill password with the value printed at first startup.
When canceling exposure:
tailscale serve --https=9443 off
Note: Do not use serve reset, otherwise Funnel and :8443 will be closed as well.
LAN or Tailscale Plaintext HTTP¶
Hermex allows plaintext HTTP for local network hosts and Tailscale 100.64.0.0/10, so the first two methods do not need TLS configured:
| Scenario | URL Example |
|---|---|
| Same Wi-Fi | http://<mac-lan-ip>:9120 |
| Plaintext Tailscale | http://<mac-tailscale-ip>:9120 |
| Tailscale + serve | https://<machine>.<tailnet>.ts.net:9443 |
To check addresses:
ipconfig getifaddr en0 # Wi-Fi LAN
tailscale ip -4 # Tailscale IPv4
cordis.patch.yml only listens on non-loopback addresses when lanHost: auto; otherwise only 127.0.0.1, and the phone can only reach it via tailscale serve. iOS will request local network permission on first access, which must be allowed.
If the HTTPS address has no response for a long time, you can switch to Tailscale plaintext IP to skip MagicDNS and TLS handshake.
Development and Debugging¶
The host plugin is loaded when dsh web starts, and the plugin needs to be restarted after modification. If only iterating the HTTP/SSE contract, you can start a mock service separately:
node scripts/standalone.mjs --port 9120
This entry point is the same as npm test and can be covered by curl for the whole API surface.
When adding profile from source directory (excerpt from README):
dsh plugin --profile web add ~/self/dsh-hermes-facade
(You need to prepare the corresponding path checkout on the local machine first, and execute npm run check && npm test as per the repo instructions.)
Suitable Scenarios and Notes¶
Who is it for: Self-hosted users already running DSH who want to manage the same session flow (including approvals, tool cards, clarification) on mobile devices via Hermex; users already using or planning to use Tailscale to expose local services to personal devices, and who accept keeping the one-time password themselves.
Permissions and Security: The plugin is part of the DSH host and shares permissions with the current dsh process, reaching DSH’s opened workspaces and tool capabilities. Read the GitHub repository source code and MIT license before installation; do not use Funnel for Hermes facade scenarios explicitly opposed in the README.
Ecosystem Note: DSH follows “everything is a plugin”; Skillhub plugin directory is a community site with no official affiliation with DeepSeek or High-Flyer.
Conclusion¶
After the above steps, the local DSH can present sessions, streaming output, and approval workflows to the mobile side via Hermex without maintaining a forked client. For more information, see the directory page and the repository README: