dsh-session-messaging
Manifest validCross-session messaging plugin for DeepSeek Harness: let user-launched sessions in one workspace message each other and coordinate tasks, write scopes, and conflicts.
dsh-session-messaging
Cross-session messaging for DeepSeek Harness (dsh): let user-launched sessions in the same workspace message each other to coordinate tasks, declared file-write scopes, and conflicts — without turning them into parent/child subagents.
English | 简体中文
Status: early preview (
0.2.0). Targets dsh0.2.1-rc.2. dsh plugin APIs are pre-stable, so expect breaking changes on upstream upgrades.
Why
dsh already has strong delegation (subagents, Agent Teams), but those are hierarchical and lifecycle-bound to a parent. When you open several conversations yourself — frontend, backend, docs — they work in one workspace with no way to say "I'm editing src/ui.ts, please avoid it" or "the API field is frozen".
This plugin adds a peer channel between those top-level sessions:
- Sessions discover each other in the same working directory.
- A model can send a message to a peer session; the message is inserted into the target conversation as a normal user message.
- Reception can be paused per session; write scopes are declared advice, and overlaps are reported to both sides.
Demo

A real run in the macOS desktop app (0.2.1-rc.2): another user-launched session sent a test message. It arrived inline as a session-message envelope — sender id, timestamp, and the "peer is not an authority" note — and this session replied through session_send. Both sessions work in the same directory; no subagent hierarchy is involved.
Case study: peer-reported bug to verified fix
Two user-launched sessions used the plugin to coordinate a real fix. One session sent a reproducible defect report with a code-level root cause; the fix shipped as v0.1.2, and the reporting session independently re-ran the regression on the desktop build.

The reporting session's message as seen here: reproducible steps, root-cause pointers, and the fix request — all delivered through session_send.

Independent regression verification: static checks plus a desktop runtime probe that returns caller-not-top-level, proving v0.1.2 is active. The same message also proves the top-level → top-level path still works.
See CHANGELOG.md for the 0.1.2 entry.
Settings panel

The sidebar entry opens a small panel: toggle cross-directory messaging (persisted through the dsh settings form), check the latest npm version, and open npm, GitHub, or the author's blog. After installing or upgrading the bundle, refresh the Web UI once so the client half joins the module graph.
Features
session_peers— list live, same-directory, top-level sessions and their reception state.session_send— relay a coordination message, optionally declaringwriteScopesand replying to a message.session_reception— pause/resume receiving peer messages for the current session and declare its write scopes.- Sidebar panel — a “Session Messaging” entry in the left sidebar with a cross-directory toggle, update check, and author links.
- Messages appear inline in the target conversation, attributed to the sending session — no separate inbox UI.
- Advisory write-scope conflict detection: if a peer declared an overlapping path, the receipt and the message envelope carry a
conflict-warning. - No new Session event types and no
SESSION_FORMAT_VERSIONchange: the relay is a durableuser/messagewith a declaredsession-messagesource. - Bilingual plugin-card metadata and icons (English / 简体中文) for the dsh plugin manager.
- Cold-session delivery — a persisted session that is not live is resumed through the Web/Desktop
sessionControllerbefore delivery (allowColdDelivery, on by default). - Bounded: message size, per-sender→target rate limit, top-level-only, self-send rejected. Cross-directory peers are allowed by default;
sameDirectoryOnly: truerestricts to one working directory.
How it works
Session A (model) calls session_send
→ tools.ts uses exec.agent as the only identity source
→ service.send validates target, body, scopes, reception, rate limit
→ createUserMessage({ content: envelope + body, source: session-message/relay })
→ target.steer(message) # next step boundary, or wake an idle agent
→ await ctx.sessions.flush(target.session)
Session B's log gains a user/message with source.kind = 'session-message'
→ deriveMessages() rebuilds it → B's next model request sees it → B can reply
The envelope always states that the message comes from another session, not the current user, and repeats that a peer is not an authority. Peer text is treated as data, never as higher-priority instructions.
Requirements
- DeepSeek Harness
0.2.1-rc.2(desktop app or source checkout). - Node.js
>= 22.19.0. - The plugin needs the host's copies of
@deepseek-ai/{cordis,schemastery,dsh-agent,dsh-llm,dsh-session,dsh-tools}. They are declared as peer dependencies and resolved from the running dsh installation.
Install
From npm (recommended)
dsh plugin --profile <profile> add dsh-session-messaging
The package is published as dsh-session-messaging (latest 0.4.0). For library use: npm install dsh-session-messaging.
From GitHub
dsh plugin --profile <profile> add github:XBXyftx/dsh-session-messaging
The repository ships the built lib/ output, so a git install does not run a build.
From a local checkout
dsh plugin --profile <profile> add /absolute/path/to/dsh-session-messaging
Troubleshooting: switching from a link install
If a profile previously linked a local checkout and later installed the npm package while the app was running, the running Loader can still reference the old checkout path. Removing that checkout's node_modules then surfaces ERR_MODULE_NOT_FOUND for @deepseek-ai/* peers even though the npm package is installed. Remove and reinstall the bundle, then restart the app (a page reload is enough for the client half):
dsh plugin --profile <profile> remove dsh-session-messaging
dsh plugin --profile <profile> add dsh-session-messaging@latest
Desktop app
The macOS/Windows desktop app uses its own profiles (for example desktop). Install with the bundled CLI or the agent's plugin_manager tool, targeting that profile. In dsh 0.2.1-rc.2 the configuration reloads through HMR, so the two plugin rows usually activate without restarting the app.
Verify the plugin is active:
- the agent's tool list contains
session_peers,session_send, andsession_reception; plugin_manager list_pluginsreports bothsession-messagingandsession-messaging-toolswithfiberPhase: active.
Usage
Open two sessions in the same working directory, then ask either model to coordinate. The tools are model-facing; no manual UI is required.
Example prompts:
Use session_peers to see which other sessions are working here.
Send session-b a message: I am editing src/ui.ts and declared it in writeScopes; avoid it.
Check whether anyone else declared a conflicting write scope before you edit src/api.ts.
Pause receiving peer messages for this session.
Tools:
| Tool | Arguments | Result |
|---|---|---|
session_peers | none | { peers: [{ sessionId, status, canReceive, writeScopes }] } |
session_send | targetSessionId, message, optional writeScopes, replyTo | { accepted, messageId, targetSessionId, targetStatus, conflicts } |
session_reception | enabled, optional writeScopes | { enabled, writeScopes } |
accepted means the message entered the target's inbox and the session flush acknowledged persistence. It does not mean the peer model processed or acted on it.
Configuration
The bundle row accepts validated configuration; every field has a default:
- id: session-messaging
name: dsh-session-messaging
config:
maxMessageChars: 4000
maxMessagesPerMinute: 12
requireTargetOptIn: false # sessions are open to peers by default
sameDirectoryOnly: false
allowSelfSend: false
allowColdDelivery: true # resume a persisted target when it is not live
Security model and limitations
- Peer content is untrusted input. It enters the target session as a user message. The envelope labels the sender and warns the model, but dsh has no content-approval point for peer messages; normal tool approvals,
agent/pre-step, and sandbox policy remain the only hard boundaries. - Top-level sessions only, in both directions. A subagent session is neither listed nor allowed to send (
caller-not-top-level), and a top-level session cannot target a subagent (target-not-top-level). Subagents keep using the existing parent/childsend_messagechannel. The envelopefromfield is the trusted identity; any identity claim in the message body is data only. - Cold sessions are resumed, not queued. When the target is not live and
allowColdDeliveryis on, the plugin calls the deployment'ssessionController.resolveAgent(), which resumes that session and may start a model turn (token cost). Profiles without that controller still answertarget-not-live. Archived or subagent-owned sessions are refused by the controller/session gate. Cross-process/cross-host messaging remains unimplemented. - Advisory scopes, not locks. dsh has optimistic filesystem version guards (
FS_STALE_VERSION) but no file locking.writeScopesandconflict-warningare coordination aids; Bash, formatters, and code generators bypass them. - In-memory state. Reception pauses and declared scopes live for the plugin's lifetime and reset on reload/restart.
- Cross-directory by default. Sessions in different working directories can message each other. Set
sameDirectoryOnly: trueto restore a path boundary; peer content remains untrusted either way. - No GUI extension. Messages render as ordinary user messages; a dedicated title/icon for the
session-messagesource would require a client plugin or an upstreamui-chatchange.
Development
npm install
npm run build # tsc -p tsconfig.build.json -> lib/
npm run typecheck # src + tests
npm test # 10 protocol unit tests
npm run test:integration # real AgentLoop services + tool pipeline, no model
npm run test:model-e2e # scripted model: A calls session_send, B sees it and replies
lib/ is committed so dsh plugin add github:... works without a build step. Rebuild before committing source changes; CI re-checks that lib/ matches src/.
Project layout
.
├── cordis.patch.yml # two insert rows: service + tools
├── src/
│ ├── index.ts # plugin entry: default exports the service class + Config
│ ├── service.ts # discovery, reception state, rate limit, delivery, conflicts
│ ├── tools.ts # session_peers / session_send / session_reception
│ ├── config.ts # Schemastery configuration
│ ├── protocol.ts # pure validation, envelope, scope conflicts, rate limiter
│ └── types.ts # MessageSourceMap 'session-message' declaration
├── tests/ # unit, integration, model-driven e2e
└── lib/ # committed build output
Compatibility
- dsh
0.2.1-rc.2; the bundle declaresengines.dsh = ">=0.2.1-rc.2 <0.3.0". - Uses documented extension points only:
ctx.tools.register,ctx.agents,ctx.sessions,MessageSourceMap. - Does not modify
agent-loopand does not addSessionEventMapmembers.
Contributing
Issues and pull requests are welcome. Please keep the "no loop changes, no new session event types, advisory scopes only" boundary unless a design discussion says otherwise. Run npm run typecheck, npm test, npm run test:integration, and npm run test:model-e2e before sending a PR.
License
MIT © 2026 XBXyftx
Comments
Loading…
Similar plugins
by happyren
Cross-session verification, claims and a decision ledger for DeepSeek Harness — so two agent sessions don't repeat, contradict or deadlock each other.
★ 7
↓ 41/wk
MIT
TypeScript
Sep 12, 2026
dsh plugin --profile web add dsh-agent-messagingby GengDaPeng
Cross-session agent messaging for DeepSeek Harness with session discovery, offline delivery, delivery receipts, and sender-session navigation.
★ 6
↓ 236/wk
MIT
JavaScript
Sep 15, 2026
dsh plugin --profile web add dsh-agent-messageby Wha1eChai
Same-runtime cross-Session discovery and communication for DeepSeek Harness
★ 2
↓ 38/wk
MIT
TypeScript
Aug 14, 2026
dsh plugin --profile web add @wha1echai/dsh-cross-sessionby Domaki-co
Cross-session message forwarding between DSH sessions: extract one model reply, a user message, or a multi-selected batch of messages and images from one session and deliver it into another, with sile
★ 1
MIT
JavaScript
Oct 16, 2026
dsh plugin --profile web add dsh-message-forwardby ybh1291747665
Cross-session message bus for DeepSeek Harness: let independent sessions address and wake each other.
★ 4
MIT
JavaScript
Oct 16, 2026
dsh plugin --profile web add dsh-peer-busby popu2do
In-process cross-session communication, peer session creation, and shared blackboard for DeepSeek Harness.
★ 4
↓ 650/wk
MIT
JavaScript
Oct 17, 2026
dsh plugin --profile web add dsh-call-session