DSH Plugins Marketplace

DSH Plugins

Plugins

/

Terminal & Clients

/

@noob-stupid/dsh-connection-card-host

@

@noob-stupid/dsh-connection-card-host

Manifest valid

Session Connection Card Host: Establishes stateful connections between DSH sessions, mounting connection-level card plugins

UI (client)hasBundlePatch

dsh-connection-card-host

中文 | English

Let your DSH sessions see each other, talk to each other, and share tools — without getting in each other's way.

Running several DSH sessions at once (one researching, one coding, one running experiments) is normal — but they're isolated: they can't see what the others are doing, and can't hand conclusions over.

This plugin makes a connection a first-class object in DSH: sessions are nodes, a connection is the container, cards are connection-scoped plugins.

In practice (screen recording)

Dragging a connection line out from the anchor beside the composer

Structure (diagram)

Drag-to-connect structure: anchor → session row → rail

Left: the real thing (source video) · Right: the same action as a diagram, showing the toggle semantics


Contents


What it does

See each otherLook up which files the other session is editing, how far its plan has got, what tools it last used — collected automatically, no effort required from the other side
Talk to each otherSend a message with one of three urgencies you choose: notify only (no interruption) / queue / interject
Share toolsMount cards on a connection: a card can provide tools to the sessions, even with tens of MB of real dependencies
Shared premisesA "convention box" holds what you agreed on: interfaces, units, naming, who owns what
Stay out of the wayAwareness is pull-based — zero cost unless the other side asks. Unrelated connections never interrupt you

Line colour shows the permission in that direction: grey = read-only, blue = can suggest, orange = can write; the two ends can differ


Quick start

  1. Connect: hold the circle to the left of the composer (or the … on a session row) and drag it onto a row in the session list.

Drag from the anchor (recording)

Dragging an arc out from the anchor beside the composer

Drag from a session row → after connecting (recording)

Dragging from a session row; after release a rail appears with per-end permission dots

anchor source video · session-row source video

  • Toggle semantics: drop on an unconnected row = connect; drop on an already connected row = disconnect (the hover hint tells you which)
  • You can also pick two sessions from the "Connections" panel in the sidebar
  1. Done. Both ends get one quiet notice (who you're connected to, what it enables) — nobody is interrupted.
  2. Want more detail? Open "Connections" in the sidebar, or have the session call connection_peer_work itself.

Once connected, a rail appears beside the session rows, with a coloured dot at each end — that's the permission for that direction:

Connections panel: permissions are set per direction, and cards, awareness and conventions all live under the same connection


Three layers: awareness / conventions / messaging

These are separate, because their costs differ enormously:

LayerMechanismEnters the other's context?Forces the other to act?Cost
A. Work statepull (the other asks)only when it asks❌ no0
B. Convention boxpull (the other asks)only when it asks❌ no0
C. Messagingpush (into its inbox)unconditionally✅ alwaysevery message

The key fact: in DSH, delivering a message forces the other session to run a turn — the agent loop has no "saw it but ignored it" state. So "talking" and "being aware" have to be built separately: to make the other side know, use A/B; only to make it act, use C.

A. Work state (automatic, zero cost)

Collected from runtime events — it asks nothing extra of the model:

【session-bd5ac1b1】
status: running a command (2s ago)
recently touched: water-boat/src/water.js
progress: turn 69 / step 39

B. Convention box (explicit, zero cost)

What you agreed on: interface signatures, units, coordinate systems, naming, who owns what. Editable in the panel; sessions read and write it with connection_conventions / connection_declare.

Why pull, not push: pushing slowly fills the other's context, and most of it is never needed. Keeping it in a box that the other queries on demand costs zero.

C. Messaging (three urgencies, chosen by the sender)

UrgencyUnder the hoodWhat the other sees
quietinjectplaced in context without waking it — it sees the message next time it works, uninterrupted
normalfollowupqueued — it sees the message once it finishes what it's doing
urgentsteerinterjected — inserted into the turn it's currently running, read immediately

urgent on an idle peer degrades to queued automatically (the next turn starts immediately, so the effect is the same), and never fails.

The rule (written into the tool description): interrupting has a cost — the other session has to drop its current line of thought. Most messages aren't urgent: default to normal, and use urgent only when it genuinely must change behaviour right now.


Cards on a connection

A card = a plugin mounted on a connection, with per-side visibility.

DSH pluginCard
Mounted onthe whole DSH (profile)one connection
Who can call itevery sessiononly sessions on that connection
Visibilityglobalper side: both / A only / B only
LifetimeDSH start/stopmounted and unmounted with the connection

A session uses one resident bridge tool to discover and call tools provided by cards, subject to visibility scope

Cards can provide tools to sessions

Tools registered with api.registerTool(name, fn) inside a card are reachable by sessions on that connection through one resident bridge tool:

connection_card_tool                                  ← the only resident one (1 schema)
  ├─ no `tool` argument → list the cards and tools visible to *your* side of this connection
  └─ with `tool`        → call it

Why one bridge instead of one schema per tool: the latter would make every session pay a resident cost for every card tool, while cards are mounted and unmounted dynamically. The bridge costs one schema, and it's the natural place to enforce visibility.

Visibility actually blocks:

Side A can see the card      ✅
Side B cannot see it         ✅
Side B calls it anyway       → 「这张卡片只对 A 端可见(你在 B 端)」

Cards can carry real dependencies

A card can carry real dependencies: wrapping a parsing core plus pdfjs-dist as a card, installed under $DSH_HOME/connection-cards/cards/, without touching the DSH profile. A session called it through the bridge and got real parse results back.

Install and update from the panel

Card picker: built-in cards install in one click; you can also give a package name, a repo tgz URL or a local directory

  • Install: package name / repo tgz URL / local directory → into our own directory, no pnpm, no profile changes
  • Update: installed cards get a "check for updates" entry with three distinct states
    「检查更新」→「↑ 更新到 x.y.z」/「已是最新」/「无法检查」
    
    "Couldn't check" is never shown as "up to date" — that would be lying.

What a card can and cannot do

Any ordinary DSH plugin can be mounted as a card on a connection. Three static conditions decide it:

ConditionSupportedNot supported
ScopeRegisters into a connection-level location (conversation, input area), or is capability-only (no client UI)Registers into an app-level location (sidebar, overall layout, settings page, theme, title bar, workspace) — those are meant to be installed into the app, not onto a connection
Host dependenciesEverything the entry actually loads can be resolvedA real runtime dependency is missing. Install reports it in two classes: missing host capability → the card needs a design change; missing third-party dependency → just add the dependency
Host capabilitiesUses only tools / effect / llm / promptNeeds other host services (credentials, web server, session control, commands, subprocess, …) — not provided; the mount is refused with a reason

Only files the entry actually loads count: tests, build scripts, CLIs and type declarations are not runtime dependencies.

Client UI: what works

Client shapeResult
Uses only slot registration and effect hooks (slots / effect)Renders, and stays interactive
Needs more client services (localization, config forms, connection, routing, settings pages)Mounts and registers slots, but cannot render — the panel shows the specific reason instead of a blank area
Client artifact sizeUp to 32 MB (self-contained bundles with inlined assets are fine)
Component propsComponents are called without props — ones that require slot props will error; the error is contained to that card

Badges in the candidate list

Each card carries one badge: adapter / capability / local / global / undecided. It tells you before mounting whether a plugin suits a connection — advisory only, nothing is blocked.


Architecture and cost

Three layers, with hard boundaries — each talks only to the one below:

┌─────────────────────────────────────────────────────────────┐
│  Card layer (connection-scoped plugins)                     │
│  Depends only on CardAPI; NEVER imports @deepseek-ai/*      │
│  → DSH upgrades don't affect cards; our CardAPI changes do  │
│    (guarded by a version declaration)                       │
├─────────────────────────────────────────────────────────────┤
│  Connection layer (this plugin)                             │
│  connections / permissions / awareness / conventions /      │
│  card host / message delivery                               │
│  → on a DSH upgrade, this is the only layer to change       │
├─────────────────────────────────────────────────────────────┤
│  DSH adapter layer (DSHAdapter + allowlist + audit)         │
│  the single exit point for all DSH interaction; we do not   │
│  rewrite DSH's transport, permissions or plugin system      │
└─────────────────────────────────────────────────────────────┘

Permissions are per direction

One line, one dot at each end; the colour is the permission for that direction — the two directions are independent, so you can have "A may send, B may only watch":

Line colour shows the permission in that direction: grey = read-only, blue = can suggest, orange = can write; the two ends can differ

Read-only does not affect awareness: work state and the convention box are both queried by the other side, independent of permission. Lowering a permission takes effect immediately; raising one requires confirmation from the side being granted it.

How card tools reach a session

Tools registered by cards do not each take a schema — a session sees one resident bridge, discovers on demand, calls on demand, and visibility is enforced at the bridge:

A session uses one resident bridge tool to discover and call tools provided by cards, subject to visibility scope


What it costs

ItemNumberNotes
Awareness (layers A + B)0 contextpull-based; costs nothing unless the peer queries
Card tools1 resident schemainstead of one per card tool
Automatic mirroring0 (disabled)mostly irrelevant content before it was turned off
Unrelated connections0 interruptionsconnecting doesn't wake anyone; unrelated sessions carry on

The one fixed cost: this plugin's five connection_* tools cost roughly 1,700 tokens resident — and only in sessions that have connections: sessions with none have them stripped automatically by system-prompt/assemble (a 0-connection session has 5 tools removed, logged as 按会话 scope 隐藏了 5 个感知工具).


Install

This plugin is not published to npm (DSH's peer dependencies aren't on the public registry, so npm install is guaranteed to fail — verified). Install from GitHub:

# Preview line (latest development build — the repo you're reading)
dsh plugin --profile web add github:Noob-stupid/dsh-connection-card-host-preview

# Stable line (the public facade, synced only at release time)
dsh plugin --profile web add github:Noob-stupid/dsh-connection-card-host

# Or a pinned tarball (grab the asset URL from the Releases page)
dsh plugin --profile web add https://github.com/…/releases/download/v1.0.0/noob-stupid-dsh-connection-card-host-1.0.0.tgz

The two github: commands above are verified working (161 files land in lib, using the profile's own settings: autoInstallPeers: false). The bare names dsh-connection-card-host and @noob-stupid/dsh-connection-card-host both 404 on npm and won't work for anyone else — don't use them.

Compatibility: peerDependencies declares @deepseek-ai/dsh >=0.2.0-rc.1 <0.3.0 — DSH gates on version at install time and refuses clearly, with a reason, rather than installing and crashing later.


Use

  1. Create a connection — pick two sessions in the panel; each direction has its own permissions.
  2. Mount a card — open a connection, choose a card from the candidate list. It takes effect on the side you pick (A / B / both).
  3. Talk to the peer — the card's tools become available to that session; messages carry the urgency you choose (quiet / normal / urgent / preempt).
  4. Unmount — remove the card from the connection; the card itself stays installed.

Configuration

SettingDefaultWhat it does
Adapter layeroffAllows ordinary DSH plugins to be mounted as cards. Nothing is touched until you turn it on.
Automatic mirroringoffAuto-forwarding session content to the peer. Kept off on purpose (it mostly sends noise).
View preferencesper connectionNumber of lanes shown on the connection track.

Uninstall

  • A card — the candidate list has an Uninstall entry for installed cards (a confirmation states how many connections it is mounted on). Built-in cards do not offer it: they ship with the plugin and come back on upgrade. What could not be removed is reported honestly.
  • The whole plugin — remove it from your DSH profile. Cards and connections live under $DSH_HOME/connection-cards/ and are left untouched.

FAQ

Do I need to install anything for cards? No. Cards install into the plugin's own directory; no pnpm runs in your profile and your DSH profile is not modified.

A plugin will not mount. Why? The refusal names the class: host capability (the card needs something this plugin does not provide) or third-party dependency (the dependency is missing). The first requires a change on the card side; the second can be fixed by shipping the dependency with the card.

A mounted card shows no UI. Its client half needs client services beyond slots/effect. The panel shows the exact reason — it is not a blank screen.

Does mounting a card change my DSH install? No. It does not rewrite DSH, does not touch your profile, and can be undone at any time.

License

MIT — see LICENSE.


Writing a card

A card is just an npm package with a dshCard manifest:

{
  "name": "my-card",
  "version": "1.0.0",
  "main": "index.js",
  "dshCard": { "id": "my-card", "name": "My card", "entry": "index.js", "api": 1 }
}
// index.js — NEVER import anything from @deepseek-ai/*; go through `api`
export function apply(api) {
  api.log(`mounted (scope=${api.scope})`)

  // provide a tool to sessions on the connection
  api.registerTool('greet', async (args) => {
    return `Hello, ${args?.name ?? 'world'}`
  })
}

// panel HTML (optional)
export function renderPanel(api) {
  return `<div>visible to: ${api.scope}</div>`
}
api memberMeaning
registerTool(name, fn)register a tool → sessions call it via connection_card_tool
send(kind, text) / read()send and receive connection messages as one side
on(event, handler) / emit(event, data)connection-scoped events
scopewhich side this instance serves (both / a / b)
log(...)write to the host log

dshCard.api declares the CardAPI version the card needs (defaults to 1):

  • Adding things does not bump the version — older cards keep working
  • Only removals or semantic changes bump it — the host refuses to mount a card that requires a newer version, and says why

This is our own compatibility guard: cards don't depend on DSH internals, so a DSH upgrade doesn't affect them; but changing our CardAPI does — and DSH's version gate can't see that layer.

See docs/card-protocol.md for details.


Docs

DocumentContents
docs/capabilities.mdCapability report: per-item measurements, total context cost, known limits
docs/card-protocol.mdCard protocol: manifest, CardAPI, install validation, distribution
docs/compatibility.mdCompatibility: how DSH's version gate works, the two lines of defence
docs/adapter-api.mdDSH adapter: the stable interface and its allowlist

BSD-3-Clause · not affiliated with the DSH project

Maintenance

Implemented

  • Connections: drag to connect (toggle semantics), three sessions fully interconnected, persistence and restore across restarts
  • Permissions: three levels per direction, asymmetric, upgrades need the other side's confirmation, refusals explain themselves
  • Awareness A: work state collected automatically (0 context)
  • Conventions B: the convention box (0 context)
  • Messaging C: three urgencies, with automatic degradation
  • Cards: template discovery / mounting / per-side visibility / in-panel install / update / crash isolation
  • Card tools: bridge invocation with enforced visibility
  • Card directories are versioned (so a mounted card can still be updated)
  • Per-session tool scoping: sessions with no connections do not carry the connection_* schemas (~1,700 tokens saved), via the official system-prompt/assemble waterfall; the whole chain is fail-open — behaviour introduced in v1.0.1 (v1.0.0 registers them globally)

Known gaps

ItemNotes
mountUI / requestRemoteInterface in place, implementation pending (mountUI currently only sets a dataset attribute)
Card tool schemasDeliberately take no separate schema; callers must list before calling
Rail layering trade-offThe rail is portaled onto document.body — decoupled from slot containers, which is the only way to keep someone else's skin/overlay from beating it via stacking context (z-index is only comparable within one stacking context). The cost: it always sits at body level, so a future "must be on top" full-screen modal would have the rail drawn over it. pointer-events: none keeps interaction unaffected, so the risk is low; if it ever needs tightening, the suggested fix is a minimal predicate — while [role="dialog"][aria-modal="true"] is present, drop the rail below that modal and restore when it closes (not an unconditional hide)

Comments

Loading…

From the same category

dsh-TUI

by ccch1mneyyy

DSH 官方公众号收录的 TUI 补位插件:Claude Code 风,鲸鱼顶栏/实时状态/流式思考/双击 Esc 回滚/上下文进度+TPS。npm 一键装。 DSH official WeChat featured TUI plugin — Claude Code style: whale bar, live status, streaming thoughts, double-Esc rol

Terminal & ClientsManifest valid

★ 4.3k

↓ 10.9k/wk

MIT

TypeScript

Oct 11, 2026

dsh plugin --profile terminal add @deepseek-harness-tui/dsh-tui

by strukto-ai

The World's First Virtual Terminal for AI Agents

Terminal & ClientsManifest valid

★ 3.7k

↓ 355/wk

Apache-2.0

TypeScript

Oct 11, 2026

dsh plugin --profile agent add @struktoai/mirage-dsh

by bowenliang123

The best DeepSeek Harness plugin for context insight and management, with context dashboard / browser / sidebar and context command, for context statistics, composition, breakdown, evolution details,

Tools & CapabilitiesTerminal & ClientsUI & ExperienceManifest valid

★ 2k

↓ 34.4k/wk

Apache-2.0

TypeScript

Oct 11, 2026

dsh plugin --profile web add dsh-context

by huiliyi37

官方 DeepSeek Harness 的交互式终端 UI 插件:自研 ANSI 极简交互渲染、流式 Markdown/工具卡、16+ 主题、slash 命令与选择器、输入历史与本地偏好持久化、LSP 诊断、memory记忆,很丝滑的开发体验。

Terminal & ClientsManifest valid

★ 287

↓ 462/wk

Apache-2.0

TypeScript

Sep 30, 2026

dsh plugin --profile terminal add @huiliyi37/dsh-tianshu-tui

by Hilbert-beinghappy

面向 DeepSeek Harness 的 Claude Code 风格终端界面,支持 Windows、macOS 与 Linux,兼容透明终端、VS Code 主题和自定义配色。

Terminal & ClientsManifest valid

★ 197

↓ 108/wk

MIT

TypeScript

Oct 1, 2026

dsh plugin --profile web add seektty

by T-Auto

deepseek-harness Plugin Access and Implementation Standards / deepseek-harness交互生态插件规范与实施标准

Terminal & Clients

★ 83

MIT

JavaScript

Oct 10, 2026

Index only — not installable