Preface¶
When handing long-running tasks to DeepSeek Harness (DSH), the hardest part is not figuring out that it’s “slow”, but rather determining whether it’s “still running”. A single compilation might take ten minutes, while a long text generation could provide no new interface feedback at all; at the same time, hanging LLM requests, idle tool calls, and empty loop spins all look exactly like a frozen state. If a watchdog only kills tasks based on wall-clock time, long operations will be mistakenly terminated; if it does nothing at all, sessions will drag on in true silence.
That is exactly the problem dsh-stall-guard aims to solve: it tracks the last activity time of each session and pending operations, and only determines a true freeze when “it is running, has no events, and has no pending calls”. It then guides the Agent back with a tiered message flow of “diagnose → fix → redirect”. The repository README makes this very clear: No tasks will be terminated at any point during the entire process.
This article is organized by cross-checking the plugin directory page, GitHub repository README, package.json, and lib/index.js: what this plugin is, how it determines a freeze, how to install and configure it, and which files to check when viewing status.
What is this¶
dsh-stall-guard is a task watchdog plugin for DeepSeek Harness, maintained by GitHub user akira399, with the repository address at akira399/dsh-stall-guard. The community directory categorizes it under the “Sessions and Messages” section, with an MIT license and JavaScript as the primary language. As of writing (2026-08-18), GitHub shows 3 stars, the package.json version is 1.3.0, it requires Node.js >=20, and has zero npm dependencies.
It does not solve the problem of “adding a stop button for the Agent”, but rather addresses these three types of scenarios:
- Sessions show as running, but have not had any turn/step/tool/LLM events for a long time, and have no pending operations
- Long builds, long generations, and other tasks that “look like they take a long time but are actually still working” should not be treated as frozen
- When true silence occurs, reproducible guidance is needed instead of immediately killing the current task
The official DeepSeek Harness repository positions itself as “everything is a plugin”: capabilities such as models, tools, sessions, and loops are all composed of plugins. dsh-stall-guard is a community plugin, listed on the independent site DeepSeek Harness Plugin Repository; this directory has no official affiliation with DeepSeek / Magic Square, and you should treat it as third-party source code for review before installing.
One documentation discrepancy should be clarified upfront: the one-sentence introduction on the directory page still reads “only gently nudge or terminate when truly silent”. Cross-referencing the repository README, package.json description, and the 1.3.0 source code, the current implementation has no terminate option and will not send termination instructions; although the terminated field still exists in the status schema, the comment notes that it is only retained for compatibility and will no longer be set. The following content will use the repository’s primary source materials as the authoritative reference.
Core Features¶
Monitor → Judge → Continue / Fix / Redirect¶
The plugin hooks into agent/status and session/event, and maintains “last activity time” and “pending operation count” for each session. The interval of periodic scans is controlled by checkIntervalMs (default 5 seconds). The judgment logic can be summarized in a table:
| Task Status | Judgment | Behavior |
|---|---|---|
| Continual events (steps/tools/LLM streams are active) | In progress | No intervention; any activity resets the tier back to level 1 |
| Single long-running pending operation (e.g. 10-minute build, long text generation) | In progress (busy > 0) |
No guidance; only logs a LONG_RUNNING entry if it exceeds busyTimeoutMs |
No events + no pending operations, silent for longer than stallThresholdMs |
True freeze | Tiered guidance: diagnose → fix → redirect loop |
The default true silence threshold is 120000 ms (2 minutes). The default pending operation observation window is 600000 ms (10 minutes); setting busyTimeoutMs to 0 can disable LONG_RUNNING logging, but this will not trigger guidance—when there are pending operations, the source code directly returns.
Three-Tier Ladder, Only Injects Messages¶
The default policy is auto. After confirming a true silence, the plugin injects a user/message through the legitimate session channel, upgrading at a cooldown interval (default 30 seconds):
1. Level 1 DIAGNOSED (Diagnose): Ask the Agent to explain what it is waiting for, whether any operations failed or hung.
2. Level 2 FIXING (Fix): Ask it to retry the stuck point, complete pending calls, or fix errored steps, then continue.
3. Level 3 and beyond REDIRECTING (Redirect): Ask it to abandon the current approach, use an alternative solution, and retain the completed work. After level 3, it will loop at the same cooldown interval, with no termination tier.
The default messages are written in lib/index.js, and each will be appended with a diagnostic line from the watchdog itself, formatted similarly to:
[Watchdog Diagnostic] Last activity: tool/call; Step: Round 2, Step 5; Silent for 125000ms.
If you only want to log events without speaking to the Agent, change the policy to report.
Pending Operation Exemptions and Running State¶
“Having pending operations = in progress” relies on counting event pairs:
- tool/call, tool/code-dispatch, tool-workflow/run-start, request/header: busy + 1
- tool/result, tool-workflow/run-end, assistant/message: busy - 1 (will not go below 0)
- step/end, turn/end: Reset busy to 0 to avoid count drift
The running state is driven by turn/start / turn/end, and it also listens to agent/status. The README specifically notes: even if agent/status is missed, monitoring will start as soon as a turn opens. Covered no-progress scenarios include hanging LLM calls, hanging tool calls, and empty loop spins.
There is one critical design boundary you must know: if the Agent is stuck on an never-returning await, injected messages will queue until the step completes. The plugin will not kill the task, and will only continue to trigger tiered guidance at the cooldown interval.
Event Logging and Status Interface¶
Every detection or guidance event is appended to $DSH_HOME/stall-guard/events.jsonl (equivalent to ~/.dsh/stall-guard/events.jsonl if DSH_HOME is not set). The only event types are:
- STALL: True silence detection (capped at one log per 60 seconds by default to avoid spamming)
- LONG_RUNNING: Pending operation timed out, only logged
- DIAGNOSED / FIXING / REDIRECTING: Whether tiered injection was successful
The README emphasizes: There are never any termination-type events. If the Web UI is running locally, you can also check real-time status at:
GET http://127.0.0.1:3080/api/dsh-stall-guard/status
This returns the current configuration, each session’s ladderStage, and the most recent 50 events. GUI notifications are marked as a future enhancement in the README and are not included in the current version.
Installation and Activation¶
The installation command given on the directory page can be run in the DeepSeek Harness terminal:
dsh plugin add github:akira399/dsh-stall-guard
For a reproducible installation, pin the commit as specified on the directory page. As of writing, the latest commit on the main branch is db5b2147ccd60c0a0f9305f12402fb84491e919d (corresponding to version 1.3.0):
dsh plugin add github:akira399/dsh-stall-guard#db5b2147ccd60c0a0f9305f12402fb84491e919d
The repository README also provides a version with a profile flag, suitable for scenarios where you use npx to pull the CLI and explicitly install to the web profile:
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:akira399/dsh-stall-guard
After installation, you need to restart DSH. The cordis.patch.yml will insert the plugin into the current profile’s combined configuration, and it is enabled by default (opt-out). Modifying the stall-guard section in settings.yaml will take effect immediately without requiring a restart.
The security note on the directory page also applies: the plugin runs with the permissions of the current dsh process, and may execute code during installation. Please check the source code repository and license before installing.
Typical Usage Scenarios¶
1. Use default thresholds, only guide when truly silent¶
After installing and restarting, the default configuration is already “enabled, 2-minute true silence threshold, auto tiered guidance”. This works for most coding Agents that “occasionally hang but you don’t want long tasks to be interrupted”. You do not need to write any configuration first; as long as the session is in running state, the plugin will begin monitoring once the turn opens.
2. Shorten the silence threshold and confirm the auto policy¶
If your local tasks usually receive tool responses within a few minutes, you can adjust the threshold to 60 seconds and the scan interval to 3 seconds. The example given in the repository README is:
stall-guard:
stallThresholdMs: 60000
checkIntervalMs: 3000
policy: auto
Save the file and the configuration will take effect immediately. If you want to observe first without injecting messages, change policy to report.
3. View logs to confirm guidance instead of false termination¶
After a true silence occurs, open the event file to confirm that only STALL and tiered events appear, and that there are no actions taken on long operations:
tail -n 20 ~/.dsh/stall-guard/events.jsonl
You can also request the status API to verify busy, idleMs, and ladderStage:
curl -s http://127.0.0.1:3080/api/dsh-stall-guard/status
If a build has been running for a long time but busy > 0, there should be no tier upgrades in the status, and at most a LONG_RUNNING entry in the logs. This is exactly what the README states: “long task execution time does not equal ‘stuck’”.
4. Customize the three-tier messages (optional)¶
diagnoseMessage, fixMessage, and redirectMessage can all be modified. If left blank or omitted, the source code will fall back to the built-in default Chinese messages. Each message will still automatically append the [Watchdog Diagnostic] line, so you do not need to manually include the scene information in your custom text.
The repository provides a self-test command that covers syntax checking, default configuration, pending operation exemptions, tiered loop without termination, activity resetting tiers, STALL throttling, and status routing:
pnpm verify
Applicable Scenarios and Notes¶
Suitable for:¶
- Users who often hand compilation, testing, and long generation tasks to DSH and worry that sessions will quietly stop when there are no events
- Users who need an auditable stall record (JSONL + status API) instead of only checking the chat window
- Users who want intervention limited to “sending one more message to the Agent” and do not want the plugin to end tasks
Important Notes:¶
- The plugin runs with the permissions of the current dsh process and may execute code during installation. Read the source code of akira399/dsh-stall-guard and the MIT license before use; pin the commit in production environments.
- It does not perform hard termination. When stuck on an never-returning
await, messages will queue; you will still need to use the stop function in the host interface or manually intervene. - Pending operation counting relies on specific event types. If a tool or workflow does not use the event pairs listed in the README,
busymay be inaccurate, leading to incorrect exemptions or lack thereof. - The Web status route depends on the
webServerservice; without a Web UI, you can still viewevents.jsonland plugin logs. - The community directory is not an official app store. DSH is still in developer preview, and core APIs will continue to change. Plugin behavior will be subject to the commit you installed at that time.
Conclusion¶
dsh-stall-guard draws a clear line between “slow” and “dead”: it treats tasks with events or pending operations as in progress; only when true silence occurs does it gently nudge the Agent through a diagnose → fix → redirect loop, and logs every judgment. For DSH users who run long tasks and do not want their watchdog to mistakenly terminate them, this is a community solution with very clearly defined boundaries.
Directory page: https://deepseek-harness-plugin.com/zh-CN/plugins/dsh-stall-guard/
GitHub: https://github.com/akira399/dsh-stall-guard