Introduction¶
In the pluginized workflow of DSH (DeepSeek Harness), many automation requirements are straightforward: sending notifications after a round of dialogue ends, logging when a specific tool is invoked, or displaying a desktop notification when an approval request arises. These actions typically require listening to events, parsing context, and then executing commands or notifications. dsh-hooks places this kind of logic in profile configuration: you can declare events, matching conditions, and the run or notify to execute in cordis.patch.yml without needing to write extra plugin code.
What is it¶
dsh-hooks is a DeepSeek Harness plugin maintained by PeterBon and licensed under the MIT license. Its positioning is config-driven lifecycle hooks: declaring event -> command/notify hooks via configuration.
It consists of two parts:
- Hook Engine: Listens to DSH events based on configuration and executes commands or built-in notifications.
- Web GUI Settings Page: After installation, the
dsh websettings panel adds aHookssection, providing a history timeline, manual testing, notify testing, hook editor, and Feishu connect.
Core Capabilities¶
Below are the main capabilities of dsh-hooks:
- Declare
event -> commandorevent -> notificationhooks in the profile’scordis.patch.yml. - No need to write plugin code; configuration can trigger commands or notifications.
- A single package provides both the hook engine and the Web GUI settings page.
- The Web GUI settings panel adds a
Hookssection, including history timeline, manual tester, notify tests, hook editor, and Feishu connect. - Built-in notification channels:
desktop: Platform bubble/notification.webhook: Send JSON to an HTTP endpoint;slack: truecan be configured to generate a summary line.
- Supports the following events:
turn/startturn/endtree/settledstep/endtool/calltool/resultuser/messageapproval/askedapproval/decidedsession/titlesession/createdsession/disposedagent/createdagent/disposedagent/erroragent/statushook/failed
- Context is passed via
DSH_HOOK_*environment variables; ifinput: stdinis configured, the full context JSON will be written to the command’s stdin.
Installation and Enablement¶
dsh-hooks requires Node.js:
node >=22
You can install the plugin via npm:
dsh plugin --profile web add dsh-hooks
You can also add it directly from the GitHub repository:
dsh plugin --profile web add github:PeterBon/dsh-hooks
After installation, you need to restart dsh web. Once the restart is complete, the settings panel will add a Hooks section for viewing and configuring hooks.
Basic Configuration¶
Configuration is written in the profile’s cordis.patch.yml. Below are several typical entries:
- id: dsh-hooks
name: dsh-hooks
config:
hooks:
- on: 'turn/end'
when: 'completed'
run: 'node examples/notify-feishu.mjs'
timeoutMs: 10000
- on: 'approval/asked'
notify:
channel: 'desktop'
- on: 'turn/end'
when: 'completed'
notify:
channel: 'webhook'
url: 'https://hooks.slack.com/services/…'
slack: true
- on: 'tool/call'
match:
tool: '^(rm|git|ssh)'
run: 'node examples/notify-webhook.mjs --slack'
The configuration above accomplishes four things:
- When
turn/endends withcompleted, executenode examples/notify-feishu.mjs. - When an
approval/askedevent occurs, send a desktop notification. - When
turn/endcompletes, send a notification via webhook with a Slack-style summary line. - When a model request invokes a tool matching
rm,git, orssh, execute the webhook notification script.
Configuration Fields¶
dsh-hooks’ hook fields cover event triggering, condition filtering, execution mode, notification, retry, concurrency, and debounce. Common fields are as follows:
on: The triggering event name, such asturn/end,tool/call,approval/asked.when: Filters the end reason ofturn/end, such ascompleted.match: Conditionally filters on context fields, such as regex matching on tool names.run: The command to execute. You must choose eitherrunornotify.notify: Built-in notification, supportschannel: desktopandchannel: webhook.input: Controls the context passing method. When usingstdin, the full context JSON is written to the command’s stdin.timeoutMs: Timeout for a single command, in milliseconds.retries: Number of retries for non-zero exit codes.retryDelayMs: Retry interval, in milliseconds.enabled: When set tofalse, the configuration is retained but not triggered.cwd: Command working directory, can besessionor an absolute path; only used forrun.maxConcurrent: Maximum number of concurrent processes for the same hook.debounceMs: Debounce window for high-frequency events, in milliseconds.
Typical Usage¶
1. Execute Command¶
When a certain event occurs, execute a local command:
- on: 'turn/end'
when: 'completed'
run: 'node examples/notify-feishu.mjs'
This configuration starts node examples/notify-feishu.mjs when turn/end occurs with the end reason completed.
2. Use Desktop Notification¶
When an approval request appears, send a platform bubble/notification directly:
- on: 'approval/asked'
notify:
channel: 'desktop'
This configuration does not require an extra script; it is handled directly by dsh-hooks’ built-in notification logic.
3. Use Webhook Notification¶
Post event information to an HTTP endpoint:
- on: 'turn/end'
when: 'completed'
notify:
channel: 'webhook'
url: 'https://hooks.slack.com/services/…'
slack: true
If the target is Slack, you can configure slack: true to send a summary line.
4. Filter by Tool Name¶
Only listen to tool/call events that match specific tool names:
- on: 'tool/call'
match:
tool: '^(rm|git|ssh)'
run: 'node examples/notify-webhook.mjs --slack'
Here, match.tool is a regular expression used to filter the tool names invoked by the model request.
5. Pass Full Context via stdin¶
By default, context is passed via DSH_HOOK_* environment variables. If your script needs the full JSON, you can use:
- on: 'turn/end'
input: 'stdin'
run: 'node my-hook.mjs'
After configuration, the full context JSON will be written to the stdin of node my-hook.mjs.
6. Control Retries¶
Perform limited background retries for non-zero exit codes:
- on: 'turn/end'
when: 'completed'
run: 'node examples/notify-feishu.mjs'
retries: 2
retryDelayMs: 1000
Retries here apply only to non-zero exit codes. Spawn failures and timeouts are not retried.
7. Control Concurrency and Debounce¶
For high-frequency events, you can limit concurrency and apply debounce:
- on: 'step/end'
run: 'node examples/log-step.mjs'
debounceMs: 500
maxConcurrent: 2
debounceMs: 500 merges high-frequency triggers within a 500-millisecond window; maxConcurrent: 2 limits the number of concurrent processes for the same hook. Triggers exceeding the limit are discarded and recorded as skipped.
8. Temporarily Disable a Hook¶
If you don’t want to delete the configuration, you can keep the declaration and disable it:
- on: 'turn/end'
enabled: false
cwd: 'session'
run: 'node examples/log-turn.mjs'
enabled: false means this hook will not trigger, but the configuration is retained. cwd: session means the command runs in the session’s working directory.
Behavior Description¶
dsh-hooks’ execution model leans towards “triggering external actions without blocking the main process”:
- Command execution is fire-and-forget.
- Command failures only generate a
console.warn; by default, they do not block DSH’s agent loop. runandnotifymust be one or the other.retriesis only used for background retries on non-zero exit codes; spawn failures and timeouts are not retried.maxConcurrentlimits the number of concurrent processes for the same hook; triggers exceeding the limit are discarded and recorded as skipped.cwdis only forrun; it can be set tosessionor an absolute path.
Dependencies and License¶
dsh-hooks’ package information contains the following peer dependencies:
@deepseek-ai/cordis
@deepseek-ai/dsh-session
@deepseek-ai/schemastery
react
Runtime requirements:
node >=22
The license is MIT.
Use Cases¶
dsh-hooks is suitable for the following scenarios:
- You want to connect DSH lifecycle events to local scripts or notification systems.
- You need to execute lightweight automation when events such as
turn/end,tool/call, orapproval/askedoccur. - You want to send desktop notifications, Slack-style webhook notifications, or invoke custom scripts.
- You do not want to maintain extra plugin code for event listening and wish to manage everything directly in the profile configuration.
Note: The run command in the plugin executes with the permissions of the current DSH process. It is recommended to check the source code, example scripts, and license before installation, and confirm that the commands to be executed will not perform dangerous operations.
Conclusion¶
The value of dsh-hooks lies in converting DSH lifecycle events into low-code automation entry points: after configuring cordis.patch.yml, you can execute commands or send notifications on events such as turn, step, tool, approval, session, and agent, and manage and test them via the Hooks settings page in dsh web.
Related Links:
- GitHub Repository:
https://github.com/PeterBon/dsh-hooks - Plugin Directory Page: The current documentation does not provide a separate URL; after installation, you can view the
Hookssection in the settings panel ofdsh web, or search fordsh-hooksin the current DSH plugin directory entry.