Claude Code Mods and DSH Plugins
Claude Code Mods vs DSH Plugins: Bridge & Migration
- Author
- DeepSeekAgent.io Editorial Team
- Published
- Updated
DeepSeek Harness v0.2.1-alpha.1 introduces an experimental Claude Code Mods bridge. It does not turn DSH into Claude Code or provide one-click compatibility with every Mod. It tests a narrower architectural claim: a useful subset of the Claude Code Mod hook API can run as a higher-level interface over DSH Plugins.
That boundary determines whether a Mod can be wrapped directly, needs a focused rewrite, or depends on Claude Code internals that the bridge does not currently provide.
How the two extension models meet
A Claude Code Mod enters through register(on, options). It subscribes to engine events through on and calls Session, tool, filesystem, and UI capabilities through $. A native DSH extension is a Cordis Plugin composed by a Profile and connected to Harness services and event pipelines.
The bridge adapts the two with defineMod:
import { defineMod, type ModOn } from '@deepseek-ai/dsh-experimental-claude-code-mods'
declare const register: (on: ModOn, options: Readonly<Record<string, unknown>>) => void
export default defineMod({
name: 'token-weather',
version: '0.1.0',
root: import.meta.dirname,
register,
})
The wrapped Mod loads as a Cordis Plugin. Configuration comes from defineMod defaults plus cordis.yml overrides. Mount the bridge first, followed by Mods in hook-chain order.
Capabilities mapped today
| Claude Code Mod capability | DSH bridge behavior |
|---|---|
session.start / session.end | Raised for root-agent creation and disposal, not subagents |
prompt.submit | Can rewrite user text, append context, or drop a prompt |
turn.start / turn.complete | Mapped onto the Agent turn lifecycle |
tool.call | Can observe, deny, answer directly, or rewrite a result after execution |
command.run | Supports Mod-registered commands |
ui.render | Supports the AbovePrompt band only |
$.tool / $.command | Register, call, and list tools or commands |
$.fs / $.process / $.http | Bridge-backed file, process, and HTTP operations |
$.state / $.store | Per-Session state and durable per-plugin storage |
The three official examples cover distinct layers. Token Weather reads usage and renders state. Blast Radius holds a command for risk confirmation. Replay Theater records Edit and Write calls and presents diffs. Together they demonstrate an observe–intercept–interact loop.
Why this is not full compatibility
The bridge does not implement the complete Claude Code engine. Migration is affected by several explicit differences:
- DSH raises
tool.callafter its permission decision, so a Mod cannot rewrite an already logged tool name or arguments; - Pane, focus, scrolling, input controls, and most UI events are not implemented;
agent.spawn,prompt.context,tool.check,engine.create, and Telemetry events are never raised;- namespaces such as
$.model,$.agent,$.settings, and$.telemetryare unavailable; - Claude Code user/project/managed tiers are treated as user;
- a built DSH install does not transpile a
.tshooks module, so packages must ship JavaScript Node can load; - the bridge does not read
plugin.jsonorhooks.json; identity and config move intodefineModandcordis.yml.
The official source review reaches the same conclusion for larger Mods: projects centered on Pane, Telemetry, agent.spawn, or managed policy do not run unchanged.
Security matters more than interface compatibility
A Mod executes inside the DSH Host process and is not protected by the Agent command sandbox. Although many operations use $, the hooks module itself still has Node process authority:
$.envreads and writes the Harness environment;$.http.fetchreaches the network;$.fsand$.tool.callact with the current Session's authority;- module code can use additional Node capabilities directly.
“The bridge loads it” is therefore not a security verdict. Review a Mod as local application code, not as a constrained prompt extension. Do not test an untrusted Mod in a Profile that contains production credentials.
Evaluate migration with two inventories
Start by extracting an event inventory:
Which on(event) registrations exist?
Which events does the bridge raise?
Is their ordering equivalent?
Does a hook attempt to rewrite tool arguments?
Then build a $ inventory:
Which $.namespace.method calls are used?
Does the bridge serve each one?
Are returned structures equivalent?
Does the design require Pane, Telemetry, Managed Tier, or complete message history?
A Mod centered on prompt.submit, tool.call, commands, files, and AbovePrompt UI is a good wrapping candidate. When its core behavior depends on events that never fire or namespaces the bridge does not serve, write a native DSH Plugin rather than accumulating compatibility patches.
A maintainable migration path
- Pin DSH
0.2.1-alpha.1; do not follow a floating alpha tag. - Wrap the original
registerwithdefineModand move identity and defaults into the spec. - Mount the bridge before the Mod in
cordis.yml. - Replay events with
createModTestKit, covering allow, deny, timeout, and error paths. - Define explicit degradation for events that do not fire and
$methods that are absent. - Validate real tool permissions, Session recovery, and plugin disposal in an isolated Profile.
- Rewrite as a native Plugin when DSH-specific adaptation becomes the majority of the code.
When a native DSH Plugin is the better choice
Prefer the native API when a project needs:
- full Sidebar pages, configuration pages, or several Client Slots;
- Sub-agent, Compaction, Provider, or Session Projection services;
- tool-input handling before the permission decision;
- precise lifecycle, HMR, and dependency ownership;
- no shared hook module with Claude Code.
The bridge lowers the cost of validating existing hook logic; it does not replace the DSH Plugin API. Its architectural value is showing the common subset between the two systems and turning every remaining difference into an explicit engineering decision.
Related reading
- DeepSeek Harness v0.2.1-alpha.1 Update
- DeepSeek Harness Plugin Manager Source Analysis
- DeepSeek Harness Plugin, Preset, and Native Agent Explained
- DeepSeek Harness Security Guide