Tianbuyu-wwx/dsh-hermes-link
Bidirectional bridge between Hermes Agent and DeepSeek Harness (DSH). v0.2.4 — single-bundle Cordis plugin replacing the archived hermes-foundation/-oneshot-arbitrate/-dispatch-bridge triad.
项目介绍Project Overview
dsh-hermes-link 是 Hermes Agent 与 DeepSeek Harness 的双向桥接插件。Hermes 通过 POST /mcp/collab 的 JSON-RPC 派发一次性或可续接任务,DSH 启动子代理、回传实测 token,并支持把 Hermes 会话导入侧边栏续跑;还提供 SSE 事件流、会话镜像与咨询工具。适合需要让 Hermes 编排、DSH 执行编码任务时使用。注意 v0.2.2 起 amend nonce 与 consult reply_secret 为破坏性变更,Hermes 端需同步升级。
dsh-hermes-link is a bidirectional bridge between Hermes Agent and DeepSeek Harness. Hermes dispatches one-shot or continuable tasks via JSON-RPC on POST /mcp/collab; DSH spawns sub-agents, returns measured tokens, and can import Hermes sessions into the sidebar for native resume. It also offers SSE streams, session mirroring, and consult tools. Use it when Hermes should orchestrate while DSH executes coding work. Caveat: v0.2.2+ amend nonce and consult reply_secret are breaking changes requiring Hermes-side upgrades.
请帮我了解并安装插件:【dsh-hermes-link】【https://github.com/Tianbuyu-wwx/dsh-hermes-link】
把上面这条消息直接发给当前会话里的 DSH,让它帮你了解并安装。安装命令不一定准确,发给 DSH 更稳。Send this message to DSH in your current session. CLI install commands may not be accurate across systems — DSH will figure it out for you.
或使用命令行安装(适合开发者)Or use CLI install (for developers)
命令行安装CLI Install
dsh plugin --profile web add dshmarket
把 Tianbuyu-wwx/dsh-hermes-link 加入你的 DSH 配置(web profile)即可启用。
READMEREADME
dsh-hermes-link
Bidirectional bridge between Hermes Agent and DeepSeek Harness (DSH). Hermes dispatches focused tasks (one-shot or continuable) via JSON-RPC over
POST /mcp/collab; DSH spawns sub-agents, returns real measured tokens, and lets you continue any Hermes session as a native DSH session in the sidebar.
Table of contents
- Why dsh-hermes-link exists
- Features
- Quickstart
- Architecture
- Configuration
- Security model
- Roadmap
- FAQ
- License
- Related docs
Why dsh-hermes-link exists
Hermes is an agent-orch-estrator — it plans the work, picks the skill, loads the knowledge slice. DSH is a coding-runtime — it runs sub-agents, edits files, runs shells, talks to LLMs. Each tool does its job well in isolation; the question was always how to make them one system without dragging each one's concerns into the other.
Earlier we ran this as three separate plugins (hermes-foundation, hermes-oneshot-arbitrate, hermes-dispatch-bridge). That triad is now archived under dsh-hermes with an archive/hermes-legacy-2026-08-22 tag — dsh-hermes-link is the single plugin that replaced them, and this repository is the home of that replacement.
Features
Agent-communication line (Hermes → DSH)
POST /mcp/collab— JSON-RPC 2.0 endpoint Hermes posts to.dispatch_taskwithmode: one-shot | continuable. Continuable children are durable across DSH restarts (SQLite-backed).dispatch_followup/dispatch_interrupt/dispatch_list/dispatch_get/get_dispatch.dispatch_probe— zero-cost tool-name validation againstctx.tools.view().restrictableNamesso Hermes doesn't burn an LLM turn on a typo.dispatch_subscribe(v0.3.0) — discovery helper that returns the SSE URL.get_dispatch— readaudit.jsonlfor the most recent entries.
GET /mcp/collab/stream(v0.3.0 F1) —text/event-streamof real-time events for a continuable task (lifecycle / step / token / amend / followup / interrupt). Bearer-auth,?task_id=...&since_seq=N&timeout_ms=N.GET /mcp/collab/session-stream(v0.4.0) — SSE feed of newly mirrored DSH session events for an enabled session (?session_id=<sid>,since_seq/timeout_mssupported).GET /mcp/collab/session-mirror/status(v0.4.0) — mirror status for one session (?session_id=<sid>) or all enabled sessions.- Bearer auth via
HERMES_LINK_TOKENenv (open by default). - H4 amend nonce (v0.2.2+): amend files must be named
<ts>-<task_id>-<nonce>.json; nonce returned indispatch_taskmetadata. - Consult reply_secret (v0.2.2+): reply files must be named
<ticket>-<secret>.json; secret returned in the consult payload. - Persona envelope: SOUL injected (v0.2.2+);
include_project_memory: trueopts in cwd-scoped MEMORY; encoding rules prevent CJK mojibake; sentinel strings are never paraphrased. - Real measured tokens:
ctx.tokenMeter.measure(run.localAgent)populatestokens_usedon the dispatched result — no morenullin dispatch-result.
User-view line (DSH → Hermes)
| Tool | Purpose |
|---|---|
list_hermes_sessions |
enumerate Hermes archives enriched with title/model/cwd from Hermes state.db |
import_hermes_session |
convert a Hermes archive to a live DSH session — click-to-resume |
load_hermes_persona |
inject Hermes SOUL.md + config into the current session (v0.2.3: no longer reads MEMORY.md) |
load_hermes_project_memory |
cwd-scoped Hermes MEMORY.md loader (matches only this project's Hermes sessions) |
consult_hermes |
ask Hermes a question (file-based async; reply must carry secret suffix since v0.2.2) |
mirror_session_to_hermes |
opt-in V4 mirror with secret-pattern redaction (v0.2.2; cookies / JWTs / API keys / set-cookie / session_id redacted) |
session_mirror |
v0.4.0 opt-in automatic mirror switch: enable / disable / status for current DSH session (redacted, default OFF) |
hermes_inbox / hermes_inbox_append |
read / append to the shared conversation record (~/.dsh/hermes-inbox/session.jsonl) |
hermes_clear_injected |
audit-only: count turns auto-injected by an older hermes-foundation/dsh-hermes-link version, point at "open a new session" |
rotate_outbox_now |
v0.3.1 F2: force an immediate outbox file rotation pass (size-based usage.jsonl / session-mirror rotation + age-based heartbeat / memory-suggest archive + purge) |
dispatch_status |
v0.3.1 F4: snapshot of live continuable dispatch children (task_id, child_id, status, tokens, recent audit) — useful for inspecting what Hermes-dispatched tasks are running |
Auto-loop
- Startup auto-sync imports every Hermes session into DSH.
- fs-watcher polls
Hermes Home/sessions/and re-syncs on new dumps. - Import format compatibility: the converter accepts both Anthropic-style content blocks and OpenAI-compatible request dumps (
assistant.contentstring +assistant.tool_calls[]+role: 'tool'results), so Hermes AI replies and tool calls are preserved in imported DSH sessions. - heartbeat (60s), usage (per-task), memory-suggest all run in the background.
- amend watcher (H4 nonce-bound) delivers mid-task amendments from Hermes to running continuable children.
- session mirror is opt-in per session (v0.4.0). Once
session_mirror action=enableis called, every new DSH event is redacted and written toHermes Home/inbox/dsh/session-mirror/<sid>.jsonl; Hermes can also subscribe toGET /mcp/collab/session-stream?session_id=<sid>for real-time SSE. - Hermes Home auto-detect:
HERMES_HOMEenv →%LOCALAPPDATA%\hermeson Windows →~/.local/share/hermeson POSIX.
Security boundaries
| Risk | Mitigation | Since |
|---|---|---|
| Cross-project context pollution (Hermes injects project-A dialogue into DSH's project-B session) | main-session auto-injection disabled; MEMORY.md not broadcast; project-memory only matches cwd | v0.2.1 + v0.2.2 + v0.2.3 |
Adversary writes amend/* to hijack a running sub-agent |
nonce-bound filename (<ts>-<task_id>-<nonce>.json) |
v0.2.2 |
Adversary writes consult-reply/* to impersonate Hermes |
secret-bound filename (<ticket>-<secret>.json) |
v0.2.2 |
| Dispatched sub-agent inherits global MEMORY notes from unrelated projects | foundation = SOUL-only; include_project_memory: true is explicit opt-in per dispatch |
v0.2.2 |
Hermes state.db poisoned cwd → C:\Windows\System32 |
isSafeCwd() rejects 17 system roots + null byte + >1024 chars |
v0.2.3 |
Mirror filename >200 chars triggers ENAMETOOLONG silent failure |
sha1(12 hex) tail truncation with preserved uniqueness | v0.2.3 |
| Mirror leaks cookie / set-cookie / session_id | redact regex list expanded to 10+ secret shapes | v0.2.3 |
Imported sessions resume-unusable (turn:0 events fail DSH persistence validator) |
turn envelope rewritten to start at 1; corrupt artifacts auto-removed and rebuilt | v0.2.4 |
See docs/security-model.md for the full layered model.
Quickstart
Install from dsh-market (recommended)
# 1. Make sure dsh-market is installed in your profile
dsh plugin --profile web add dshmarket
# 2. Restart dsh web, open Settings → Plugin Market, search "dsh-hermes-link", one-click install
Install from npm directly
dsh plugin --profile web add @Tianbuyu-wwx/dsh-hermes-link
Install from a local checkout (dev loop)
git clone https://github.com/Tianbuyu-wwx/dsh-hermes-link.git
cd dsh-hermes-link
dsh plugin --profile web add ./packages/dsh-hermes-link
Then restart dsh web. Open Hermes-config.yaml (%LOCALAPPDATA%\hermes\config.yaml on Windows) and add:
mcp_servers:
dsh-bridge:
url: http://127.0.0.1:3080/mcp/collab
Optionally set HERMES_LINK_TOKEN in your DSH env to require a Bearer header (off by default).
Verify
node scripts/verify-install.mjs
Then in DSH:
/mcp/collab/health → { ok: true, version: "0.4.0", importer_ready: true, persona_ready: true, consult_ready: true, auth: "open|bearer-required", continuable_registry: "on", foundation_slice_chars: 1234, active_dispatchers: 0 }
Architecture
Hermes (orchestrator)
│
config.yaml mcp_servers.dsh-bridge
▼
POST /mcp/collab (JSON-RPC 2.0)
dispatch_task / followup / interrupt / list / get
dispatch_probe / get_dispatch
┌──────────────────────────────────────┐
│ dsh-hermes-link (Cordis bundle) │
│ ├─ HTTP routes /mcp/collab* │
│ │ ├─ POST /mcp/collab (RPC) │
│ │ ├─ GET /mcp/collab/health │
│ │ ├─ GET /mcp/collab/sessions │
│ │ ├─ POST /mcp/collab/import │
│ │ ├─ POST /mcp/collab/import-all │
│ │ ├─ POST /mcp/collab/rename-all │
│ │ ├─ GET /mcp/collab/persona │
│ │ ├─ POST /mcp/collab/consult │
│ │ └─ POST /mcp/collab/memory-suggest │
│ ├─ services/ │
│ │ ├─ importer request-dump → DSH SessionEvent[] │
│ │ ├─ watcher fs-poll Hermes Home/sessions/ │
│ │ ├─ personaLoader SOUL / MEMORY / config │
│ │ ├─ consultClient file-based Hermes consult │
│ │ ├─ outbox D3/D6/D7 + V4 mirror (opt-in) │
│ │ ├─ sessionMirror V4 opt-in auto mirror (redacted + SSE) │
│ │ ├─ continuations continuable child registry │
│ │ ├─ amendWatcher H4 nonce-bound delivery │
│ │ ├─ audit D4 audit JSONL │
│ │ └─ hermes-project-memory cwd-scoped MEMORY (opt-in) │
│ └─ tools/ │
│ ├─ list_hermes_sessions │
│ ├─ import_hermes_session │
│ ├─ load_hermes_persona │
│ ├─ load_hermes_project_memory │
│ ├─ consult_hermes │
│ ├─ mirror_session_to_hermes │
│ ├─ session_mirror (enable/disable/status) │
│ ├─ hermes_inbox / hermes_inbox_append │
│ └─ hermes_clear_injected │
└──────────────────────────────────────┘
│
DSH→Hermes files v Hermes→DSH files
────────────── ──────────────
dispatch-result/<task_id>.json amend/<ts>-<task_id>-<nonce>.json
consult/<ts>-<uuid>.json (reply_secret) consult-reply/<ticket>-<secret>.json
heartbeat/{ts}.json + latest.json (Hermes writes; DSH verifies)
usage.jsonl
memory-suggest/<ts>.json
session-mirror/<sid>.jsonl (opt-in via session_mirror or mirror_session_to_hermes)
See docs/ for component-level details.
Configuration
| Env var | Default | Purpose |
|---|---|---|
HERMES_HOME |
auto-detected (%LOCALAPPDATA%\hermes on Windows, ~/.local/share/hermes on POSIX) |
Hermes data root |
HERMES_LINK_TOKEN |
unset | When set, every /mcp/collab* (except /health) requires Authorization: Bearer <token> |
HERMES_LINK_TRUST_LEGACY |
unset (0) |
When set (1), legacy <ticket>.json consult-reply is accepted alongside the v0.2.2 <ticket>-<secret>.json |
Security model
docs/security-model.md walks through each layer in detail. TL;DR — every cross-project channel is explicit opt-in; every cross-process channel is authenticated; no null tokens, no unbounded system paths, no unredacted cookie/secret leakage.
Report vulnerabilities privately via GitHub Security Advisories on this repo. See SECURITY.md.
Roadmap
| Item | Status | |
|---|---|---|
| ✅ | L1/L2/L3 three-pack → single dsh-hermes-link plugin |
shipped 2026-08-20 |
| ✅ | v0.1 → v0.2: full bidirectional + continuable + amend nonce + mirror opt-in + foundation SOUL-only | shipped 2026-08-21 |
| ✅ | v0.2.1: disable main-session auto-injection; hermes_clear_injected audit |
shipped 2026-08-21 |
| ✅ | v0.2.2: S1–S4 (mirror opt-in / amend nonce / consult secret / project memory opt-in) | shipped 2026-08-21 |
| ✅ | v0.2.3: K.1–K.5 (persona SOUL-only / cwd whitelist / mirror filename cap / redact cookie+session_id) | shipped 2026-08-22 |
| ✅ | v0.2.4: turn envelope fix + corrupt-artifact auto-rebuild + tool output schema normalization + open-source | shipped 2026-08-22 |
| ✅ | v0.3.0: SSE realtime stream (F1) + error codes registry (E9) + HTTP layer split into 4 files (E1) | shipped 2026-08-25 |
| ✅ | v0.3.1: outbox file rotation (F2) + dispatch_status/tail observability (F4) + write-behind queue perf (E2) | shipped 2026-08-26 |
| ✅ | v0.3.3: dispatch_dry_run JSON-RPC pre-flight estimator (F5) for Hermes-side cost control | shipped 2026-08-28 |
| ✅ | v0.3.4: amend fs.watch + debounced batch (E3 perf) + globalThis cleanup (E5) | shipped 2026-08-29 |
| ✅ | v0.3.2: Prometheus /mcp/collab/metrics endpoint (F6) with 16 counters + 8 gauges | shipped 2026-08-27 |
| ✅ | v0.3.5: SSE first-event replay fix + HTTP surface end-to-end integration test | shipped 2026-08-26 |
| ✅ | v0.3.6: dispatch_task continuable HTTP 500 fix (sseBroker destructure) | shipped 2026-08-26 |
| ⏭ | Reverse tunnel (cross-machine / firewall traversal) | reserved |
| ⏭ | SSE real-time stream | reserved |
| ⏭ | File rotation for session.jsonl / mirror / usage |
suggested (Hermes-side cron) |
FAQ
Q: Does Hermes need to upgrade anything to talk to dsh-hermes-link v0.2.2+?
Yes. The amend nonce + consult reply_secret protocols are breaking changes. See docs/hermes-upgrade-v0.2.2.md and the reference gateway in scripts/hermes-gateway-demo.py.
Q: I imported a Hermes session — it shows in the sidebar but I can't open it.
That's the v0.2.4 bug (turn:0 envelope failing DSH persistence validator) — fixed in v0.2.4 by bumping turn/start..turn/end to 1 and auto-rebuilding corrupt artifacts. Update to v0.2.4 (auto-recovery runs on next sync) or dsh plugin update dsh-hermes-link.
Q: My import_hermes_session returns "invalid output" before v0.2.4.
Same issue — fixed by declaring firstUserSnippet / model / attach in the tool output schema and normalizing nullable fields. Update to v0.2.4.
Q: I imported a Hermes session, but only my messages appear — Hermes AI replies and tool calls are missing.
That was an import-converter bug for OpenAI-compatible Hermes dumps (assistant.content as string + assistant.tool_calls[] + role: 'tool' results). It is fixed in the current working tree: re-import the session (delete the persisted hermes-* DSH session first, then run import_hermes_session / auto-sync) to get assistant/message, tool/call, and tool/result events back.
Q: What's the difference between consult_hermes and Hermes' own consult?
Both end up at Hermes. consult_hermes is a DSH tool that any user can call inside their session; dispatch_task is the agent-comm RPC that Hermes initiates. They share the file-based reply protocol but live on different routes (POST /mcp/collab/consult vs POST /mcp/collab).
Q: Why not just one plugin instead of three (hermes-foundation / -oneshot-arbitrate / -dispatch-bridge)?
That's exactly what v0.2.0 did — those three are archived under dsh-hermes with tag archive/hermes-legacy-2026-08-22. Single-plugin form is less bookkeeping and easier to reason about; dsh-hermes-link is that consolidation.
License
MIT © 2026 Tianbuyu-wwx — see LICENSE.
Related docs
- docs/security-model.md — full layered security model
- docs/plugin-developer-guide.md — for Hermes-side gateway developers
- docs/plugin-install-guide.md — three install paths
- docs/dispatch-spec.md — JSON-RPC wire protocol
- docs/hermes-upgrade-v0.2.2.md — breaking-change upgrade guide for Hermes
- docs/delivery-v0.6.0-20260821.md — release notes (historical)
- CHANGELOG.md — version history
- CONTRIBUTING.md — development workflow
- SECURITY.md — vulnerability disclosure policy
- CODE_OF_CONDUCT.md — community standards
nexu-io/open-design
freestylefly/awesome-gpt-image-2
anywhere-labs/dsh-desktop
walkinglabs/learn-harness-engineering
awesome-dsh-plugin/awesome-dsh-plugin
MemTensor/MemOS