DeepSeek Harness Plugin

PeterBon/dsh-hooks

Stars ★ 2 Category Notifications & Integrations Added 2026-08-15 npm dsh-hooks

Config-driven lifecycle hooks: event→command declarations in cordis.patch.yml, with Feishu card notifications and a QR scan-to-create bot setup.

Install

# from npm (prebuilt)

dsh plugin --profile web add dsh-hooks

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:PeterBon/dsh-hooks

Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time. Only install sources you trust, and pin a commit (github:owner/repo#sha).

README

Config-driven lifecycle hooks plugin for DeepSeek Harness (dsh).

Declare event -> command hooks directly in your profile's cordis.patch.yml — like Codex CLI / OpenCode hooks, but for dsh. No plugin code required.

中文文档 | Design | Feishu example

Install

dsh plugin --profile web add dsh-hooks           # from npm
# or straight from git:
dsh plugin --profile web add github:PeterBon/dsh-hooks

Restart dsh web.

Configure

Add a config block to your profile's cordis.patch.yml:

- id: dsh-hooks
  name: dsh-hooks
  config:
    hooks:
      - on: 'turn/end'
        when: 'completed'            # optional: only completed turns
        run: 'node examples/notify-feishu.mjs'
        timeoutMs: 10000             # optional, default 10000
      - on: 'approval/asked'
        run: 'powershell -Command "Write-Output approval-requested >> hooks.log"'

Events (v1)

Event When it fires Useful context
turn/start A turn begins session id, turn
turn/end A turn ends (completed / error / aborted / blocked / max-tokens / interrupted) reason, turn, duration
approval/asked A tool call requests user approval tool name, call id, reason
agent/created An agent is published session id
agent/disposed An agent leaves the registry session id
agent/error The agent loop reports an error error text
agent/status Agent status transition status

The when filter for turn/end matches the reason.kind value (completed, error, …). Hooks for other events run unconditionally.

Command execution

  • Each matching hook spawns run through the platform shell, fire-and-forget: failures only console.warn, never retried, never block the agent loop.
  • Context is passed via environment variables (no shell injection through data):
Variable Meaning
DSH_HOOK_EVENT event type, e.g. turn/end
DSH_HOOK_SESSION_ID session id
DSH_HOOK_SESSION_NAME readable session title (latest session/title log event, or first human prompt)
DSH_HOOK_TURN turn number (turn events)
DSH_HOOK_REASON turn end reason kind
DSH_HOOK_TOOL tool name (approval events)
DSH_HOOK_CALL_ID tool call id (approval events)
DSH_HOOK_DURATION_MS turn duration ms (turn/end)
DSH_HOOK_STATUS agent status (agent/status)
DSH_HOOK_ERROR error text (agent/error, and the failure message on turn/end error)
DSH_HOOK_CONTENT the turn's final assistant text (turn events)
DSH_HOOK_TIMESTAMP ISO timestamp
  • {{var}} placeholders inside run are substituted from the same context, e.g. run: 'echo {{DSH_HOOK_SESSION_ID}} >> log.txt'.

Feishu notification example

The fastest path is the one-shot setup CLI — it creates the Feishu app for you via a QR-code scan and writes all hook config:

dsh-hooks feishu-setup                 # default profile: web
dsh-hooks feishu-setup --profile work  # another profile
dsh-hooks feishu-test                  # send a test card with the stored credentials

feishu-setup prints a QR code (and opens it in your browser), waits for you to scan it with Feishu, then creates an app named 「DSH 通知机器人」 with message-send permission and writes:

File Purpose
~/.dsh/dsh-hooks/feishu-config.json app id/secret + your open_id as the notification target (0600, never committed); result_max_chars sets the card content truncation (default 300)
~/.dsh/dsh-hooks/notify-feishu.mjs stable copy of the notify script the hooks reference
~/.dsh/profiles/<profile>/cordis.patch.yml dsh-hooks block: turn/end (completed/error/aborted) + approval/asked + agent/error card hooks

Restart dsh web afterwards — you will get cards when turns finish, approvals are asked, or the agent errors.

Manual configuration

Prefer wiring it by hand? See examples/notify-feishu.mjs — a zero-dependency script that posts turn-completion / approval notices through the Feishu app API (works without a group custom bot). Configure it like:

- id: dsh-hooks
  name: dsh-hooks
  config:
    hooks:
      - on: 'turn/end'
        when: 'completed'
        run: 'node D:/path/to/examples/notify-feishu.mjs'
      - on: 'approval/asked'
        run: 'node D:/path/to/examples/notify-feishu.mjs --approval'

with DSH_HOOKS_FEISHU_APP_ID / DSH_HOOKS_FEISHU_APP_SECRET / DSH_HOOKS_FEISHU_TO in the process environment (never in config files).

Security

Hooks execute arbitrary commands with the dsh process privileges. Only configure commands you trust. Secrets belong in environment variables or the dsh credential store — never in cordis.patch.yml.

Design

Follows the dsh plugin conventions: dsh.bundle.patch mounts the plugin row, the plugin listens to the durable session/event firehose plus agent lifecycle events, and emissions are irreversible side effects that compensate rather than block (failures warn, never retry).

Development

pnpm install
pnpm run check     # typecheck + test + build

Releasing and CI operations (Trusted Publishing, security scanning, gotchas): see docs/RELEASING.md.

License

MIT

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →