Repository navigation
Releases
v1.0.1 — DeepSeek Harness 0.2.0-rc.2 compatibility + 16 robustness fixes
Install
Two gotchas in the plain command: the Harness CLI is not on PATH by default, and
<profile> is a placeholder (a literal < is shell input redirection). Adding a
release URL directly also fails pnpm's tarball-integrity check
(ERR_PNPM_MISSING_TARBALL_INTEGRITY), so download the asset first:
# 1) download the released artifact
curl -sSL -o /tmp/dsh-swarm-panel-1.0.1.tgz \
https://github.com/stephenlzc/dsh-swarm-panel/releases/download/v1.0.1/dsh-swarm-panel-1.0.1.tgz
# 2) install into an isolated profile (dswarm is any name you like; never desktop)
DSH="/Applications/DeepSeek Harness.app/Contents/Resources/runtime/cli/bin/dsh"
"$DSH" plugin --profile dswarm add /tmp/dsh-swarm-panel-1.0.1.tgz
# 3) verify and boot
"$DSH" --profile dswarm --dump-config | grep -A2 swarm
"$DSH" --profile dswarm
# uninstall
rm -rf ~/.dsh/profiles/dswarmAlternative that skips the download (pnpm resolves the repo at a pinned commit):
"$DSH" plugin --profile dswarm add 'github:stephenlzc/dsh-swarm-panel#path:dsh-swarm-plugin'
⚠️ Do not install into the reserveddesktopprofile - use an isolated profile.
See the upgrade notes below.
[1.0.1] — 2026-10-08
First release of the 1.0 line. This is a compatibility + robustness release:
the plugin now runs on the DeepSeek Harness 0.2.0-rc.2 runtime that the current
desktop app ships, and all 16 findings of an adversarial robustness audit are
resolved (or explicitly dispositioned).
⚠️ Upgrade notes (read before installing)
- Harness target moved from
0.1.0-rc.7to0.2.0-rc.2. Every peer range is
now^0.2.0-rc.2. A build prepared for0.1.0-rc.7does not load on the
0.2.0 runtime, and vice versa. - Reinstall is required.
dsh plugin --profile <profile> add file:<checkout>/dsh-swarm-plugin
(or re-addthe published/GitHub package). Updating in place is not enough: the
old bundle imports packages and APIs that no longer exist. - Never install this plugin into the reserved
desktopprofile
(dsh plugin --profile desktop add …). Installing there leaves a profile-local
node_modules/with duplicate@deepseek-ai/dsh-tools/dsh-brandcopies and a
pnpm-lock.yaml, which changes the app's module resolution and makes every
turn fail withCannot read properties of undefined (reading 'prepare').
Restarting the app, opening a new session, or unloading the plugin does not fix
it — only restoring the profile directory does. Verify plugins in an isolated
profile instead:# The desktop app launcher is not on PATH; adjust the path if needed. # Download the asset first: adding a release URL directly fails pnpm's # tarball-integrity check (ERR_PNPM_MISSING_TARBALL_INTEGRITY). DSH="/Applications/DeepSeek Harness.app/Contents/Resources/runtime/cli/bin/dsh" curl -sSL -o /tmp/dsh-swarm-panel-1.0.1.tgz \ https://github.com/stephenlzc/dsh-swarm-panel/releases/download/v1.0.1/dsh-swarm-panel-1.0.1.tgz "$DSH" plugin --profile dswarm add /tmp/dsh-swarm-panel-1.0.1.tgz "$DSH" --profile dswarm --dump-config | grep -A2 swarm rm -rf ~/.dsh/profiles/dswarm # when done
- Sessions written by this plugin contain
swarm/*events. They are readable
while the plugin is loaded; the Harness offers no way for an out-of-repo
plugin to mark its eventsignorable, so opening such a session without the
plugin is refused by the persistence layer. If you must temporarily disable the
plugin, setkeepEventVocabularyWhenDisabled: true(see Added).
Added
turnTimeoutMsconfiguration (default300000, i.e. 5 minutes). A group-chat
turn that gets no reply ends the chat withturn-timeoutinstead of leaving the
tool call pending forever.keepEventVocabularyWhenDisabledconfiguration. Withenabled: falsethe plugin
normally registers nothing; this switch keeps only the durableswarm/*event
vocabulary registered so previously written sessions stay loadable.SwarmRuntime.beginTurn()/endTurn()— an explicit single-turn mutex; a second
concurrentswarm_next_turnon the same swarm returns
unavailable: another turn is already in flight.SwarmRuntime.markChildSettled()— settles the role owning one child session
(available to hosts that can report a terminal child end).RoleTurnError— exposes why a turn stopped (interrupted|timeout) so the
engine can end the chat with a real reason.tests/robustness.spec.ts— 10 regression tests pinning the lifecycle fixes.docs/harness-0.2-compatibility.md— the full breakage/repair list for the
0.2.0 upgrade, plus the desktop-profile incident and reinstall guidance.docs/robustness-audit-2026-10-08.md(+…-probes/) — the adversarial audit:
16 findings with file:line references, raw reproduction output, minimal fixes,
and the repair status table.
Changed — DeepSeek Harness 0.2.0-rc.2 compatibility
| Area | Was (0.1.0-rc.7) | Now (0.2.0-rc.2) |
|---|---|---|
| Peer/dependency ranges | ^0.1.0-rc.7, dsh-brand ^0.0.1-rc.1 |
^0.2.0-rc.2 |
| Client context package | @deepseek-ai/dsh-client-runtime re-exported ClientContext |
package removed upstream; Context comes from @deepseek-ai/cordis, SessionId from @deepseek-ai/dsh-session/types |
| Session log read | session.events property |
session.snapshotEvents() (the synchronous readers are deprecated upstream) |
| Subagent delivery | ctx.subagents.followup() with a custom senderSessionId |
queueHostSubagentPrompt() from @deepseek-ai/dsh-subagent/internal (the public sendMessage() derives attribution from the live sender and cannot express peer routes) |
| Session projection | { schema, view } |
{ stateSchema, wire: { viewSchema, view } }, init(header, inheritedEventCount) |
| Client navigation | ctx.sessions.open(id) |
ctx.uiWorkspace.openSession(id); inject: ['uiWorkspace','slots'] |
| Client slot/types | runtime re-exports | explicit ui-renderer/client (ctx.slots) and ui-session/client (sessionId, useProjection) merges |
dsh.client.inject |
[dsh-client-runtime, dsh-client-ui-conversation] |
[dsh-client-ui-conversation, dsh-client-ui-workspace] |
| Web module table (tsdown) | included removed dsh-client-web-react/dsh-client-schema-form/dsh-client-ui-attachment |
the 0.2.0 platform table (react, cordis, client-store, ui-slots, ui-primitives, ui-dockkit) |
| Source workspace | CI linked the plugin into harness/plugins/ |
Harness 0.2.0 dropped both the plugins/* glob and linkWorkspacePackages: true; CI now restores them (without the latter the plugin resolves duplicate registry copies and branded-symbol identity breaks) |
Fixed — robustness (adversarial audit G4-01…G4-16)
High
- G4-01
awaitChildReplycould record the previous turn's reply as the
current one: the inbox accepts a delivery before itsuser/messageis appended,
and a watermark miss fell back to scanning the whole log. A miss is now
"not ready yet", bounded byturnTimeoutMs. - G4-02 (mitigated) Corrected the comment that contradicted the Harness design
and addedkeepEventVocabularyWhenDisabled; the upstream gap (noignorable
write path for out-of-repo events) remains and is documented.
Medium
- G4-03
terminate()/interrupt()are exception-safe: a rejected
subagents.interrupt(for exampleUNAUTHORIZED) no longer leaves the swarm
half-terminated.swarm/destroyedis written first, then children are
interrupted best-effort, and every interrupted role still gets its durable
swarm/role-exited. - G4-04 A terminated swarm accepts no new role:
assertActiveplus a
tool-levelinvalid_argument. - G4-05 Re-spawning a named role interrupts the child it replaces instead of
leaking it. - G4-06 A terminated swarm cannot park on HITL; a repeated
swarm_terminate
still cancels a late wait. - G4-08 A speaker interrupted mid-turn no longer drops the reply silently or
hangs the tool call: per-role cancellation plusRoleTurnErrorend the chat with
role-interrupted/turn-timeout/swarm-terminated, and
recordGroupMessagereports a vanished role instead of throwing. - G4-09 Cold resume re-spawns a role only when the host reports a genuinely
missing child (SubagentErrorcodeNOT_RESUMABLE); transient failures keep the
durable child and log a warning.
Low / informational
- G4-10 The in-process event vocabulary is reference counted, so unloading one
plugin instance no longer unregisters it for another. - G4-11
state()is memoized on (log length, topology, memory limit) and the
hitl-<n>/mem-<n>counters live in memory (reseeding once on hydrate) instead
of rescanning the whole session log on every tool call. - G4-12 Panel projection: a repeated HITL request id is upserted;
destroyed
closes the active chat; the group transcript is windowed like the flow; an
explicitpeerattribution only applies inmixedtopology. - G4-13
chat.startedAtis optional in the projection schema with an
asStringfallback, so a foreign writer cannot make restore fail hard. - G4-14
swarm/resumedis no longer appended afterswarm/destroyed. - G4-16 Explicit single-turn mutex (see Added).
Deliberately not wired
- G4-07 The audit suggested retiring a role when the host reports
subagent-settled. Measurement showed that notice marks the end of one
activation, not the end of the role — the same durable child can still be woken
by a followup. Wiring it broke the chat engine outright (7 regressions: the
speaker roster emptied after the spawn turn), so the plugin does not consume it.
The reasoning is recorded next to the code andmarkChildSettledstays available. - G4-15 (documentation only) The Harness has no human message source, so an
operator answer is delivered with the orchestrator'sagent-messageattr...