Preface

When developing agents with DSH, there is a common class of requirements: running tests daily at dawn, scheduled inspections of a project, and periodic task organization. The commonality of these tasks is a fixed cycle, a clear prompt, and a need for a single conclusion after execution. DSH’s philosophy is that “everything is a plugin,” but scheduling itself lacks a native solution. Relying on system crontab combined with shell scripts would lose the logs and audit capabilities of the agent sessions.

Below, we introduce dsh-routines, which makes “running a prompt on a schedule” a first-class citizen within DSH.

What is this

dsh-routines (npm package name @dsh-routines/bundle) is maintained by Jesse-njx, MIT licensed, version 0.1.0, and categorized as a “Workflow” plugin in the community directory.

One-sentence positioning: Provides scheduled agents for DSH — running a prompt based on cron, delivering summaries to where you are already looking (file summaries, chatnode delivery), and ensuring unattended safety.

A routine = named prompt + schedule + delivery channel, stored as a pure YAML file: human-readable diffs and git-commit-able. The scheduler launches each due run as an independent one-shot session via a headless runner. The full session log serves as the complete audit record and can be replayed with dsh-replay. Summary generation rules: if the last assistant message is short, it is used directly; otherwise, a one-time summarizer call is made on the session log.

Core Capabilities

Routine Files and Hot Reload

Routines are placed in two watched directories; changes trigger a hot reload. Illegal files are only reported and will not cause the storage to crash:

Directory Scope
<cwd>/.dsh/routines/*.yaml Project-level routines, can override global by name
~/.dsh/routines/*.yaml Global routines

Main fields and defaults:

Field Default Description
name Required [a-z0-9][a-z0-9-]*, max 64 characters
schedule Required "0 2 * * *", @daily, every 4h, etc.
timezone UTC Uses IANA timezone for scheduling calculations, not host timezone
prompt Required Task executed by headless run
cwd Current directory Working directory for run, also where summary is saved
profile headless DSH profile started by run
overlap skip skip / queue / cancel-previous
timeoutMin 45 Hard timeout (minutes)
deliver [{type: file}] Summary delivery channel

Scheduling Syntax

Cron is 5 fields, supporting *, step (*/15), range (9-17), list (0,30), ?, and month/day names; when both “Day” and “Weekday” are restricted, any match triggers (Vixie cron semantics). It also accepts shorthand forms like @daily, @hourly, @weekly, @monthly, @yearly, every 4h, every 30m.

overlap determines the behavior when a routine is due but the previous run hasn’t finished yet. The default is skip (don’t stack two agents on the same repository). timeoutMin is a hard stop, defaulting to 45 minutes.

Summary Delivery

  • file (always on): Run record + summary markdown written to .dsh/routines/runs/<runId>.json, with a readable <runId>.md next to it.
  • chatnode (optional): Summary is sent via the ctx.chatnode service’s send(input: { text, title? }). If the chatnode service is not installed, it is recorded as not-installed, and the run completes normally. Future exposure of the service via @dsh-cowork/chatnode-wechat will automatically enable this channel.

CLI

Use dsh --profile ops routines <command> in the hosting profile:

Command Purpose
list List routine’s schedule, pause status, and next run time
run <name> Manually trigger immediately, print summary then exit
pause <name> / resume <name> Pause / Resume scheduling
logs <name> [--limit n] Recent run logs: status, duration, summary, session id

Unattended Safety Defaults

Scheduled agents run without human supervision, so each run subprocess is patched:

  1. Forced approval policy never: Any request that triggers a prompt is automatically rejected. Denied items are recorded in the run record’s denied field and appear in the summary; the sandbox mode inherits the profile’s value (usually workspace-write).
  2. Ban nested scheduling: The run overlay disables the scheduler inside the running profile.
  3. Delivery, summary, and start failures are only recorded in the run record and not thrown outward.

Missed runs (e.g., computer sleep): Upon waking, the system will at most run once to catch up; it does not perform backlog replay.

Composition Structure

A bundle, three plugins, and a run driver, all installable by subpath:

Module Responsibility
@dsh-routines/bundle/store Watches .dsh/routines/*.yaml (project + global), validates, hot reloads, holds persistent state
@dsh-routines/bundle/scheduler Registers due routines to ctx.jobs (kind routine), handles overlap, missed runs, and timeout semantics
@dsh-routines/bundle/cli dsh routines ... command line
@dsh-routines/bundle/run Subprocess driver, injects each one-shot run via a generated --patch overlay, responsible for writing run records and summaries

Installation and Usage

The npm package @dsh-routines/bundle is marked as “when published” in the README (available after release), but can currently be installed directly from GitHub:

# 1. Create a profile to host the scheduler and CLI, and add this bundle
dsh plugin --profile ops add github:Jesse-njx/dsh-routines
# Also available after npm publish: dsh plugin --profile ops add @dsh-routines/bundle

# 2. Keep the process alive so scheduling can trigger (daemon mode, Ctrl-C to stop)
dsh --profile ops

dsh --profile ops without inner arguments is the expected daemon form: the CLI stays silent, and the scheduler takes over the process lifecycle. The scheduler runs inside the profile the bundle is installed into, so you can also load it into the main web profile; routines will trigger normally while the web application is running:

dsh plugin --profile web add @dsh-routines/bundle

Environment requirement: node >= 20; peerDependencies depend on DSH-related packages like @deepseek-ai/cordis, @deepseek-ai/cordis-plugin-timer, dsh-agent, dsh-cmdline, dsh-jobs, dsh-llm, etc. Routine runs default to DSH’s built-in headless profile, requiring no extra setup. If you need a different profile, set profile: <name> in the routine; that profile must support one-shot (includes the headless bundle, or installs this bundle itself—either way, the run overlay disables nested scheduling).

Scheduling bookkeeping (pause set, last run anchor) is stored in <cwd>/.dsh/routines/state.json.

Typical Use Case: Nightly Test Triage

The example routine provided in the README: run the test suite at 2 AM, diagnose the top failure if anything fails, draft a fix on a branch, and finally leave a summary of no more than 10 lines.

# ~/work/projectx/.dsh/routines/nightly-tests.yaml
name: nightly-tests
schedule: "0 2 * * *"        # 5-field cron; also accepts "@daily", "every 4h"
timezone: Asia/Shanghai       # Explicitly declared, not silently using host timezone
prompt: |
  Run the test suite. If anything fails, diagnose the top failure
  and draft a fix on a branch. Summarize in <10 lines.
cwd: ~/work/projectx
profile: headless              # Profile to use for running
overlap: skip                  # skip | queue | cancel-previous
timeoutMin: 45
deliver:
  - type: file                 # Always on: summary written to .dsh/routines/runs/
  - type: chatnode             # Optional: installed chatnode

Simply place this YAML in a watched directory; changes will hot reload. First, confirm the routine is recognized:

$ dsh --profile ops routines list
nightly-tests          active   0 2 * * *           tz=Asia/Shanghai next=2026-08-15T02:00:00.000Z

Check the recent run logs the next morning:

$ dsh --profile ops routines logs nightly-tests --limit 3
[completed] 2026-08-14T18:00:01.000Z 41213 ms session=session-2f7d…
  tests: 3 failed of 412; top failure: flaky wait in auth.spec.ts — drafted fix on branch fix/auth-wait

Before trusting a schedule, use dsh --profile ops routines run nightly-tests to manually trigger once for verification.

Suitable Scenarios and Notes

Suitable scenarios: Tasks with fixed cycles, clear prompts, and a need for a single summary result — nightly tests, scheduled inspections, periodic organization. The prerequisite is that the hosting process is alive at the trigger time; missed runs will only be run once to catch up, not replayed in a backlog.

A few notes:

  1. The plugin runs with the permissions of the current dsh process; check the source code and license before installing. This project is MIT licensed, and the source code is open on GitHub.
  2. Unattended runs force approval: never. Any operation requiring confirmation will be automatically rejected and recorded in denied, appearing in the summary. Consider this when writing prompts.
  3. chatnode is a soft dependency: you need to install a chatnode that exposes the send(input: { text, title? }) service. Not installing it does not affect file delivery.
  4. It is not confirmed whether the npm channel has been published; currently, the GitHub installation method takes precedence.

Summary

dsh-routines puts “running a prompt on a schedule and getting a summary” into a DSH bundle: routines are git-commit-able YAML, runs are independent one-shot sessions with audit-able logs, and delivery lands on files or installed chatnodes. If you have periodic task requirements in DSH, you can start with this bundle.

  • GitHub Repository: https://github.com/Jesse-njx/dsh-routines
  • Community Directory Page: https://www.skillhub.cn/plugins/Jesse-njx/dsh-routines

The directory is a community-maintained site with no official affiliation with DeepSeek / Hypoface.