Introduction¶
The philosophy behind DeepSeek Harness (DSH) is “everything is a plugin.” In agent development, we often need to run unattended long-running tasks, such as overnight builds, model training, or batch rendering.
The dsh-schedule mechanism built into DSH can deliver messages, but it is passive: it delivers a message and leaves the decision to the model. However, if the model process crashes or the quota is exhausted, the built-in mechanism often cannot recover the situation in time.
We need an active mechanism: periodically check whether anyone is still working, and if nobody reports activity, directly execute a shell command to reclaim resources. This is the problem that the dsh-deadman plugin solves.
Plugin Introduction¶
dsh-deadman is the deadman switch plugin for DeepSeek Harness (DSH), maintained by user 0gl20shk0sbt36.
Its core logic is: after armed, it periodically checks for activity. If nobody “checks in,” it executes the command specified in advance. This is suitable for scenarios such as “the job finishes or crashes, then shut down automatically.”
Installation and Enabling¶
This plugin requires DSH version 0.2.0-rc.2 (strictly pinned dependency). On the Web or desktop client, enable dsh-deadman on the plugin page after installation.
Install it via CLI (using the web profile as an example):
dsh plugin --profile web add github:0gl20shk0sbt36/dsh-deadman
Uninstall command:
dsh plugin --profile <name> remove dsh-deadman
Note:
1. It only makes sense to install it in a long-running profile (such as web). The scheduler lives inside the dsh process; if it is a headless one-shot process, nobody will perform checks after the process exits.
2. Please review the source code and license before installing.
3. The plugin runs with the permissions of the current dsh process, and the commands executed are fully specified by whoever arms it.
Core Features¶
The plugin provides three tool commands and slash commands.
Tool Commands¶
-
deadman_arm
- Purpose: Arm. Set the task name, command to execute, first check time, interval, and so on.
- Mechanism: The first check happens afterafter_minutes; if checked in, it is rescheduled byinterval_minutes; after one successful execution, the task automatically finishes. -
deadman_hold
- Purpose: Check in. Tell the plugin “I am still working,” and skip the current execution.
- Behavior: Any session can check in (fail-safe semantics). -
deadman_disarm
- Purpose: Disarm. Available only to the arming session or its direct child agents; other sessions must explicitly setforce=true, and this will be logged.
Slash Commands¶
/deadman: Arm in the current session./deadman all: Arm in all sessions./deadman cancel <name>: Cancel the specified task.
How It Works¶
The plugin decides whether to execute the command based on “activity” rather than “state.”
- Resolve the owner session: First obtain the session. If the session is not open, it will try to recover it to avoid messages falling into a black hole.
- Deliver the check-in request: Send a message to the agent, requiring it to choose one of two options: check in or remain silent.
- Check loop and decision:
- If any agent has new events since the last check (session.seqadvances) ⇒ it is still progressing, so keep waiting.
- If all agents show no progress ⇒ start the grace periodholdWindowSeconds.
- If there is a question awaiting a user answer (state === 'open'in theuserQuestionsprojection) ⇒ run a separate timer and release after at mostquestionBlockSeconds.
- The total cap from the trigger time ismaxHoldMinutes; if reached, always release the hold (fail-open). - Execute the command: After release, execute the command. On success, the task automatically finishes and notifies the owner.
Check-in Channels¶
- Use the
deadman_holdtool. - Create a marker file
.deadman-hold-<name>in the current working directory. - Create a file named after the task name under the plugin data directory
hold/.
Configuration¶
The configuration is written in the profile’s cordis.patch.yml:
- id: deadman
config:
holdWindowSeconds: 60
| Key | Default | Description |
|---|---|---|
holdWindowSeconds |
60 | After all agents stop progressing, how long to wait before proceeding |
checkIntervalSeconds |
20 | Check interval |
maxHoldMinutes |
30 | Total cap from the trigger time; if reached, always release the hold |
questionBlockSeconds |
600 | Maximum wait time when blocked by an open question awaiting a user answer |
onUndeliverable |
execute | Behavior when the owner session is completely undeliverable: execute or skip |
progressScope |
global | Scope for the activity check: global (whole machine) or owner (owner only) |
serializeCommands |
false | Whether multiple action commands are queued and executed serially |
commandTimeoutSeconds |
300 | Execution timeout for a single action command |
dataDir |
$DSH_HOME/plugins/dsh-deadman | Data directory (tasks.json + hold/) |
Use Cases and Notes¶
Use Cases¶
- Long-running tasks such as overnight builds, training, and batch rendering.
- Scenarios where resources must be prevented from being left unclaimed after the model crashes or the quota is exhausted.
Notes¶
- Long-running dependency: The scheduler lives inside the dsh process. Arming in a headless one-shot process means nobody will check after the process exits (unless a long-lived instance later loads it when it starts).
- Single-writer assumption:
tasks.jsonis a plain JSON file; concurrent writes from multiple processes can overwrite each other. Do not arm simultaneously in multiple processes. - Permission control: Check-ins have no permission restriction (anyone can stop it), but disarming has permission restrictions.
- Data persistence: The data is retained across restarts, but executed task records are stored in
tasks.json.
Conclusion¶
dsh-deadman provides a capability complementary to the built-in dsh-schedule in dsh: it does not rely on the model to handle it, executes commands directly, and includes a “check-in gate” mechanism. It is suitable as the deadman switch for unattended tasks.
Plugin directory: https://www.skillhub.cn/plugins/0gl20shk0sbt36/dsh-timer-task
GitHub: https://github.com/0gl20shk0sbt36/dsh-timer-task