Preface

DeepSeek Harness (dsh) is an open-source agent runtime developed by DeepSeek, whose core philosophy is “everything is a plugin”: models, tools, sessions, scheduling, and interfaces can all be added or removed via plugins. When agents work, they often need to wait for certain events to happen—build artifacts being written to disk, HTTP interfaces recovering, a process starting or exiting, or a CI job pushing a result. Letting the agent poll on its own wastes tokens and breaks when the session is closed; staring manually defeats the purpose of handing off loops to the runtime.

The community plugin directory DeepSeek Harness Plugin Repository features the dsh-sentinel plugin designed for these waiting scenarios. This directory is an independent community site, not officially affiliated with DeepSeek / Horizon Robotics. Entries point to maintainer repositories, so you should verify the source code before installing. This article introduces what the plugin is, how to install it, and how to use it after cross-referencing the directory page, GitHub repository README, and source code.

The verification date of this article is 2026-08-18. The current released version of the repository is v0.11.0 (2026-08-17).

What It Is

dsh-sentinel is a DeepSeek Harness plugin maintained by fuhefei. The community directory categorizes it under “Interface Enhancement” because it provides dock cards, sidebar sections, and a global dashboard on the Web UI. Its core capability is condition-driven wakeup: an agent registers a persistent watch, after which it can hibernate or even close the session. When the condition is met, the sentry wakes the agent via the official followup channel, reviving the dormant agent in the session if necessary.

It is licensed under BSD-3-Clause and primarily written in TypeScript. As of the verification date of this article, the GitHub repository fuhefei/dsh-sentinel has 11 stars; the directory page previously showed 6 stars, so star counts should be referenced from the repository page. The npm package name is dsh-sentinel, and the runtime has no third-party dependencies.

The problem it solves is specific: moving the “wait for an event to continue” logic out of the conversation loop and handing it off to a daemon process with the same lifecycle as the server, while making every subscription and trigger visible as session events for users.

Core Capabilities

The repository README divides the sensors into six categories. The directory page lists file / command / HTTP / process / Webhook, while the repository adds an additional port (TCP reachability) category, which we will follow in this article.

  1. file: Takes a snapshot of a path and uses inotify push acceleration to trigger when the snapshot changes, with latency down to sub-second levels.
  2. command: Executes a read-only shell command at intervals, triggering when the output or exit code changes.
  3. http: Probes a URL at intervals, triggering when the status code or response body changes.
  4. process: Uses pgrep -f to detect processes matching a pattern, triggering when the matching set changes.
  5. port: Establishes a TCP connection to [host:]port, triggering when the reachability changes between open / closed / timeout.
  6. webhook: Pure push-based. After registration, you will receive a hook URL, and any POST request to it will wake the agent.

When a pattern is provided, the detection sensors trigger on the edge of “mismatch → match” of the regular expression, and the webhook only accepts matching payloads. When no pattern is provided, the detection sensors trigger on any changes to the baseline observation, and the webhook triggers on any POST request. The semantics of the first detection are also documented in the repository: a watch without a pattern treats the first observation as the baseline (no trigger); a watch with a pattern will trigger on the first detection if the target already matches.

Daemonized monitoring does not occur within a single conversation. On the Node side, the plugin’s own sidecar logs ($DSH_HOME/sentinel.jsonl) are aggregated into active subscriptions, and detection is performed at a shared heartbeat interval (default 5 seconds). When a match is hit, it is delivered via the official followup channel. Subscriptions can survive process restarts; if a condition becomes true while the server is down, it will be triggered on the next detection. Delivery is at-least-once: triggers that were recorded but not sent before a crash will be re-enqueued from the delivered watermark after restart.

Daemonized monitoring is the responsibility of a long-running process, usually dsh web. A one-time headless run can also load the plugin, create, list, or cancel watches, but no detection will occur after the process exits. When the next long-running process starts, these watches will automatically recover. Each $DSH_HOME has only one sentry owner, coordinated via the lease file sentinel.lease: the first process is responsible for detection and delivery, while a second DSH process on the same home runs passively. If the original owner dies, the second process will take over within one lease TTL.

There are three interface components on the browser side:
- Dock card above the composer (conversation.input.dock): Lists active watches for the current session, including sensors, targets, real-time detection status, trigger budget, and countdown to the next detection. Expanding it shows recent trigger history. It is not rendered when there are no watches.
- Global dashboard: A table of watches across all sessions, accessible at GET /plugins/dsh-sentinel/dashboard.
- Sidebar section under the session row (shows a count when collapsed, lists the session’s watches when expanded). The dock and dashboard work on the original host; the sidebar section relies on an as-yet-undocumented extension hole in the official tree, requiring you to patch the DSH source code with the patches/session-row-holes.patch included in the repository and rebuild the ui-workspace. This patch has different semantics from the one for the same hole in dsh-subagent-tree, so do not apply both.

If dsh-better-sidebar is installed in the same profile, sentinel will register the global watch table as a sidebar tab (dsh-sentinel:watches); otherwise, it will skip this silently. When used together with dsh-notification, the repository states that zero integration code is needed: the sentry wakes the agent, and after the agent completes its turn, a desktop notification is triggered at the end of the round.

There are only three tools for the model: sentinel_watch to register a watch, sentinel_list to list active watches and their real-time detection status for the current session, and sentinel_cancel to cancel a watch by ID.

Installation and Enablement

The installation command given on the community directory page, run in the DeepSeek Harness terminal:

dsh plugin add github:fuhefei/dsh-sentinel

For reproducible installations, the directory page recommends pinning the commit hash:

dsh plugin add github:fuhefei/dsh-sentinel#commit

Replace commit with the actual commit hash. The repository README also provides two additional installation methods: one using the npm package name, and one pinning the git source to the current release tag v0.11.0 (the build artifacts are committed directly to the repository, so no additional build is needed when installing from the git source):

dsh plugin --profile web add dsh-sentinel
dsh plugin --profile web add "github:fuhefei/dsh-sentinel#v0.11.0"

The v0.11.0 release notes state that the package name has been changed from @dsh-external/dsh-sentinel to the unscoped dsh-sentinel. If you previously installed it under the old name, replace the old line in your profile with dsh-sentinel; watches are stored in the sidecar logs and are not tied to the installed package, so subscriptions will persist after switching.

Deployment-related knobs are in the plugin config schema, which can be overridden in the cordis.patch.yml of your profile for the bundle entry. The default values given by the repository are as follows:

- id: dsh-sentinel
  name: dsh-sentinel
  config:
    heartbeatMs: 5000
    probeConcurrency: 8
    maxSubscriptionsPerSession: 16
    maxPendingWakeups: 8
    defaultIntervalSeconds: 30
    defaultCooldownSeconds: 60
    dutyLeaseTtlMs: 30000
    notifyWebhookUrl: ''

Invalid values will throw an error when the plugin loads, based on the schema, rather than failing silently at runtime. When notifyWebhookUrl is non-empty, each trigger will additionally send a JSON POST request to that address (the fields include plugin, event, sessionId, id, kind, target, note, fireNumber, maxFires, summary, after), which can be connected to Feishu, WeCom, Slack, or any receiving endpoint. This outgoing request is at-most-once: a failed POST will only warn in the logs and will not block wakeups within the harness.

Typical Usage

After installation, you can directly tell the agent what to monitor in the session, without writing a polling loop yourself. The parameters of sentinel_watch are subject to the tool definition in the repository source code: kind, target, and note are required; optional parameters include pattern, interval_seconds, max_fires, cooldown_seconds, and expires_in_seconds.

The corresponding relationships between kind and target are as follows:
- file: Absolute path
- command: Single-line read-only shell command
- http: URL
- process: Pattern passed to pgrep -f
- port: [host:]port, with port range 1–65535
- webhook: A short label for the expected caller, the actual push URL will be returned after registration

note will be delivered as-is with each wakeup, acting as a sticky note for the “awakened self”, and cannot be empty. max_fires defaults to 1, meaning one-time trigger; set it explicitly higher if you need repeated triggers. cooldown_seconds defaults to 60. The detection interval defaults to 30 seconds; the interval is ignored for webhooks, and file watches are accelerated by filesystem events. The source code clamps the interval to 5–86400 seconds (the README’s tools section previously wrote 1–3600 seconds, so refer to the source code). pattern uses JavaScript regular expressions (with the m flag); placeholder states such as file not existing, URL unreachable, or no matching processes will not be matched by the pattern, preventing “exhausting trigger quotas before the file even appears”.

After registration, you can use sentinel_list to view active watches and their latest detection status for the current session, and sentinel_cancel to cancel a watch by its ID, which takes the form watch-3. The Web UI’s dock, dashboard table, and the ✕ icon on each row also use the manual cancellation endpoint POST /plugins/dsh-sentinel/cancel?sessionId=…&id=watch-N. The host does not have a session-deleted event, so orphaned watches will continue to be detected after a session is deleted until manually canceled, making this cancellation endpoint a final fallback.

For webhook scenarios, the tool will return the full push URL:

POST /plugins/dsh-sentinel/hook?id=watch-N&s=

s is a session qualifier to avoid URL collisions when two sessions both have a watch-1 watch. The old URL without the s parameter is still available, and will resolve to the first matching webhook watch. The repository recommends embedding this curl command into CI jobs, git hooks, or scripts on other machines. Treat the full URL as a secret: anyone who obtains it can wake the agent in the corresponding session.

The read-only status API is GET /plugins/dsh-sentinel/state?sessionId=…, omit the sessionId parameter to return watches across all sessions, which is used by the dock and sidebar for polling.

Applicable Scenarios and Notes

It is more suitable for users who are already running dsh web and need to hand off “wait for an event to continue” to the runtime. Typical use cases include: waiting for a file or build artifact to appear, waiting for an HTTP health check to switch from failed to successful, waiting for a local process or port state to flip, and having CI / git hooks wake the agent from outside. It is not a general-purpose cron framework, nor does it replace notification plugins themselves.

There are several boundary cases to clarify before use:
1. The plugin runs with the permissions of the current DSH process, and may execute code during installation. You should review the source code repository and license before installing.
2. Detection and delivery depend on a long-running DSH process. If you run a one-time headless session and exit the process, watches will be written to the sidecar logs, but no detection will occur at that time.
3. The command sensor executes the configured shell command on each detection. Its trust boundary is the same as the host’s built-in shell tools, so do not include untrusted commands.
4. Treat webhook URLs as secrets; cross-site requests flagged by browsers and DNS rebinding attempts will be rejected with 403 by the four routes, while headless clients such as curl and CI jobs are not affected.
5. The default maximum number of active subscriptions per session is 16, and the default maximum number of pending wakeups per session is 8. Exceeding these limits will drop the oldest entries. The dashboard will show dropped pending wakeups.
6. The sidebar section is not out-of-the-box; you need to patch the DSH source code. The dock and dashboard do not depend on this feature.
7. The community directory is not an official app store. This plugin is a community open-source project and does not represent official endorsement from DeepSeek.

Summary

dsh-sentinel turns condition monitoring into persistent, visible, cancellable daemonized work: after registering a watch, the agent can go to sleep, and will be woken when the file, command, HTTP, process, port, or Webhook condition is met. The dock and dashboard in the UI make subscriptions no longer a black box behind the scenes. Refer to the directory page and repository for installation, source code, and licensing information, and review them yourself before deciding to install.

Directory page: https://deepseek-harness-plugin.com/zh-CN/plugins/dsh-sentinel/

GitHub: https://github.com/fuhefei/dsh-sentinel