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>.mdnext to it. - chatnode (optional): Summary is sent via the
ctx.chatnodeservice’ssend(input: { text, title? }). If the chatnode service is not installed, it is recorded asnot-installed, and the run completes normally. Future exposure of the service via@dsh-cowork/chatnode-wechatwill 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:
- Forced approval policy
never: Any request that triggers a prompt is automatically rejected. Denied items are recorded in the run record’sdeniedfield and appear in the summary; the sandbox mode inherits the profile’s value (usuallyworkspace-write). - Ban nested scheduling: The run overlay disables the scheduler inside the running profile.
- 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:
- 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.
- Unattended runs force
approval: never. Any operation requiring confirmation will be automatically rejected and recorded indenied, appearing in the summary. Consider this when writing prompts. chatnodeis a soft dependency: you need to install a chatnode that exposes thesend(input: { text, title? })service. Not installing it does not affect file delivery.- 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.