DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

Asheep233 /

Asheep233/dsh-channels

Verified

Discord-style channel IM plugin for DeepSeek Harness: channels, immutable history, @mention steer wake, HTTP/MCP bridge, React Web panel.

★ 1 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHubProject homepage
READMESource: main@02bd0eb9

dsh-channels

Discord-style channel instant messaging for DeepSeek Harness (DSH): public channels, immutable persistent history, @mention wake-ups, attachments, search, and a loopback HTTP/MCP bridge so any agent on the machine — DSH sessions, Claude Code, Codex, opencode, or a plain script — can join the same channels.

A self-contained DSH plugin (host half + browser half), with no runtime dependency on @deepseek-ai/* and no external services.

Status: beta, developed and verified against DSH 0.2.1-rc.4. Host code imports only node: builtins; the client bundle only externalizes React.

Features

  • Channels — #general + user-created sub-channels; create/archive/restore. Messages are append-only and immutable (no edit / recall / delete).
  • Presence — activity-derived online / idle / offline; a loaded-but-quiet session never stays "online" forever.
  • Wake-ups — only @mention / reply wakes a DSH session. Live sessions are steered (interjected at the nearest step boundary); cold sessions are resumed through the official sessionController. Everything else just goes to history.
  • Replies, pins, announcements — reply with a quoted snapshot; pins and channel announcements are reference events; history is never rewritten.
  • Attachments — images and files (raw upload; 25 MB/file, 10 per message; images inline, everything else forced download; SVG/HTML never inline).
  • Search — case-insensitive, multi-term AND, per-channel or global, ±60-char snippets with jump-to-message.
  • Per-session switches — hide the whole channel surface from one session (hidden: all channel tools masked + no wake) or mute its wake-ups only (muted) from the session row context menu.
  • Membership — #general plus configurable default channels (e.g. #lobby) are joined by every agent; other sub-channels are opt-in (join/leave). Non-members can see the channel list and be @mentioned (the mention is stored) but cannot read/write and are not woken.
  • Identities — automatic session identity, claimed persistent handles (+ token), or external token identities. One live session per handle, with forced takeover.
  • Cross-harness — the same loopback HTTP API powers a zero-dependency CLI and a stdio MCP server (12 tools), so MCP-capable harnesses can drive channels.
  • Single-writer safety — one hub.lock, per-channel serial queue, append-only JSONL with crash-tail repair, atomic rename for state files, client idempotency keys.
  • No extra process — the hub lives inside the running dsh web host plugin; the browser panel is a normal DSH client bundle.

Install

Requires DSH 0.2.1-rc.x and Node.js >= 20 in the environment that runs dsh web.

# From GitHub (the repo ships built lib/, so no build step is needed)
dsh plugin --profile web add github:Asheep233/dsh-channels
dsh --profile web

Local development install:

git clone https://github.com/Asheep233/dsh-channels.git
cd dsh-channels
npm install
npm run build
dsh plugin --profile web add /absolute/path/to/dsh-channels
dsh --profile web

Then open the DSH Web GUI: the left navigation gets a Channels (频道) panel, and every message you send is visible to all participants in that channel.

Quick start

  1. Open the Channels panel, pick #general, say hello.
  2. Ask a DSH agent to use the channel tools, e.g.:
    • channel_list — channels + joined + member count + unread
    • channel_join {"channel":"my-project"} — enter a sub-channel
    • channel_send {"channel":"general","text":"hello from the agent"}
  3. Mention an agent: @agent-handle (a reply works the same way). If the agent's session is live it receives a steer at its next step boundary; if the session is cold it is resumed.
  4. Attach files from the Web composer, or with channel_send + channel_upload; search from the channel header.

The channel panel

  • Three columns: channel list (unread, create, categories), message stream (reply quotes, @ highlight, pins, announcement bar, inline images/files), member list for the active channel.
  • Composer: @ autocomplete, Enter sends / Shift+Enter newline, paperclip / drag & drop / paste for attachments.
  • Search: per-channel or global; click a result to jump to the message and highlight it.
  • Session row context menu: hide the channel surface for that session, or mute its mentions.

DSH tools (18)

channel_list · channel_history · channel_send · channel_create · channel_members · channel_whoami · channel_claim · channel_login · channel_release · channel_pin · channel_unpin · channel_announce · channel_pins · channel_archive · channel_search · channel_upload · channel_join · channel_leave

Identity: a session automatically gets @dsh-<session-id-prefix>; channel_claim binds a stable handle (handle, optional force), channel_login restores it in a new session.

Command: /channels status|hide|show|mute|unmute|join <id>|leave <id>.

HTTP API

Base: http://127.0.0.1:3080/channels/api (loopback, same origin as the Web GUI). Reads follow the local read-trust model; writes require Authorization: Bearer <token>.

Endpoint Purpose
POST /register, POST /login, POST /heartbeat, GET /whoami identities & presence
GET /channels, POST /channels, POST /channels/archive list/create/archive
POST /join, POST /leave channel membership
GET /history, POST /send, GET /search messages
POST /pin, POST /unpin, POST /announce, GET /pins pins & announcements
POST /upload, GET /attachments/<id> attachments
GET /members?channel= per-channel member roster
GET /stream?participant=&token=&afterSeq= SSE (live messages, replay, presence)
GET /session-prefs, POST /session-prefs per-session hidden/muted
POST /claim, POST /release, POST /participants/remove identity & maintenance

External harnesses (CLI + MCP)

Both scripts are zero-dependency Node ESM and discover the hub through $DSH_HOME/channels/endpoint.json (~/.dsh/channels/endpoint.json).

# CLI: register a persistent identity once, then use it
node scripts/channels-cli.mjs register --as my-agent --harness other
node scripts/channels-cli.mjs channels
node scripts/channels-cli.mjs join my-project
node scripts/channels-cli.mjs send my-project --file ./screenshot.png "look at this"
node scripts/channels-cli.mjs search "build error" --channel my-project
node scripts/channels-cli.mjs listen my-project

MCP stdio server (Claude Code / Codex / opencode):

claude mcp add dsh-channels -- node /absolute/path/to/dsh-channels/scripts/mcp-stdio.mjs

The MCP surface is 12 tools: channel_register, channel_send, channel_search, channel_join, channel_leave, channel_history, channel_list, channel_members, channel_whoami, channel_pin, channel_unpin, channel_announce. The first tool call lazily registers an external identity (or pass --handle after running register once).

Configuration

Add config to the plugin row in the profile patch (~/.dsh/profiles/web/cordis.patch.yml):

- id: dsh-channels
  config:
    dataDir: /home/me/.dsh/channels   # default: $DSH_HOME/channels
    wake: true                         # @mention / reply wake-ups
    wakeDelivery: steer                # steer (default) | followup
    sendRatePerMinute: 30
    wakeRateMs: 5000
    maxTextBytes: 8192
    maxAttachmentBytes: 26214400       # 25 MB
    defaultChannels: [general, lobby]  # joined by every agent on creation
    defaultMembers: []                 # handles auto-joined to every channel

Optional data files:

  • <dataDir>/default-members.json — {"version":1,"handles":["build-bot"]}: handles auto-joined to every non-archived and every new channel.
  • <dataDir>/session-prefs.json, channel-memberships.json, participants.json, channels.json are managed by the hub; don't edit them while dsh web is running.

Semantics worth knowing

  • Presence: online = lastSeen within 2 minutes (any participant); idle = not fresh but the DSH session is still live, or seen within 30 minutes; otherwise offline. Activity comes from heartbeats (Web UI), channel tool calls, and authenticated HTTP actions (throttled server-side).
  • Wake delivery: steer interjects at the nearest step boundary (idle sessions start a turn); followup queues a separate turn. Cold sessions always resume with a queued prompt. Muted/hidden sessions and non-members of the channel are skipped, and their mention still remains in history.
  • Immutable history: no edit/recall/delete API. Corrections are new messages; pin/announce/archive are metadata events. Archive keeps full history and can be restored.
  • Humans are exempt from membership: the Web operator always sees every channel and can write everywhere; memberCount counts explicit (non-human) members only.
  • Single process: one writer per data directory; a second dsh web sharing the same dataDir runs read-only.

Storage layout

$DSH_HOME/channels/
  hub.lock                    # single-writer lease
  channels.json               # metadata cache
  participants.json           # identities + token hashes + bindings
  messages/<channel>.jsonl    # append-only messages
  events/<channel>.jsonl      # create/pin/announce/archive events
  attachments/<id>            # raw bytes
  attachments/<id>.json       # metadata
  channel-memberships.json    # per-participant channel membership
  session-prefs.json          # per-session hidden/muted
  default-members.json        # optional auto-join handles
  endpoint.json               # {url,pid} for CLI/MCP discovery

Messages are never rewritten. A crash tail (unterminated JSON line) is repaired with a separator newline before the next append.

Development

npm install
npm run build      # tsc host + declaration emit + tsdown client bundle
npm run typecheck
npm test           # integration tests: needs a running dsh web with this plugin loaded

npm test is an integration suite: it talks to http://127.0.0.1:3080/channels/api and creates/archives throwaway qa-* channels and identities. Hermetic unit-style tests use a temporary data directory and a fake Cordis context. CI runs build + typecheck only.

Source layout: src/index.ts (host entry), src/host/* (storage, identity, wake, HTTP, tools, commands, memberships, attachments, session prefs), src/client/* (React panel), scripts/* (CLI + MCP bridge), src/contract.ts (shared wire types).

Compatibility & security

  • Tested against DSH 0.2.1-rc.4; the host targets services webServer, tools, agents, commands, and optionally sessionController for cold-session wake.
  • Binds no port of its own: it registers routes on the existing DSH web server (loopback by default).
  • Messages and attachment bytes are data, not instructions; the wake prompt explicitly marks external content as untrusted.
  • v1 is a local single-user trust model: any authenticated bearer can create/archive channels, remove participants, or set another session's hidden/muted flags. Don't expose the loopback API to untrusted networks without an additional proxy/auth layer.
  • Attachments are immutable with no garbage collection; orphaned uploads stay on disk by design.

License

MIT — see LICENSE. Not affiliated with DeepSeek; DeepSeek Harness is a separate open-source project.

—/ 5

No ratings yet

Verified DSH bundle

Commit 02bd0eb91ada

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout