dsh-schedule

August 26, 2026 · View on GitHub

Part of the DSH plugin suite — six Apache-2.0 plugins for DeepSeek Harness.

Persistent scheduler for DeepSeek Harness: reminders and scheduled jobs that survive session restarts — SQLite archive, cross-session lease claiming, dual remind/job actions, full clock discipline. Built on schedule-core. Every claim carries an experiment number.

中文版见 README.zh-CN.md

license ci topic: dsh-plugin topic: dsh

Why this exists

The official dsh-schedule is a session-local reminder: state lives in the session event log, so when the session dies, the schedule dies with it. This plugin moves schedule state into a SQLite archive:

DimensionOfficial dsh-scheduledsh-schedule
State storageSession event log (session death = schedule death)SQLite archive + append-only event log (cross-session)
Due products[SCHEDULE REMINDER] follow-upDual-mode: remind (compatible) / job (timed command execution, archived task records)
Dispatch subjectSingle live ownerMulti-session lease claiming (atomic preemption + 60s lease-expiry re-claim)
Clock disciplineRFC3339 / IANA / DSTFully inherited, unchanged
Across restartsNoneCold-start lease release + due-flip unified sweep (EXP-1)

What you get

  • Scheduling across restarts — after a restart the dispatcher automatically claims due records and dispatches them (real-machine closed loop: offline write → restart → automatic dispatch → task archived as completed).
  • Automatic task archiving for scheduled jobsaction: 'job' spawns a recoverable task on schedule (detach-runner supervision + exit protocol + pid adoption); output joins the jobs archive, readable from any session.
  • Timed remindersaction: 'remind' sends a [SCHEDULE REMINDER] follow-up to the creating session when due; while the session is not live it stays overdue and retries next cycle (no reminder lost).
  • Multi-session safety — single conditional-UPDATE lease preemption; two sessions online at once cannot double-dispatch (fuzz I5: no double lease).
  • Three-platform job execution — the job runner is chosen per platform: Windows ACL sandbox / Linux chattr+bwrap / macOS uchg+sandbox-exec (protocols aligned; see dsh-cross-platform / dsh-macos).

Quick start

dsh plugin --profile <name> add "github:Wang-Lin-Chang/dsh-schedule#v0.1.1"

Three tools (names aligned with the official ones):

schedule_create { after_seconds | at | every_seconds, prompt, action?, job_spec?, time_zone? }
schedule_list
schedule_delete { id }

Examples: remind in 5 minutes / run a backup daily at 03:00 (IANA time zone) / probe every 300 seconds.

Acceptance evidence

LayerEvidence
schedule-core37 unit assertions + wall-clock disorder fuzz 200 seeds/0 violations + implementation×model differential 644 assertions/0 failures (see core's EXPERIMENTS.md)
This shell9 integration assertions (real job-bridge spawn + exit protocol + remind live/ghost + three tools + DST rejection)
Real machineOffline write → restart auto-claim dispatch → task archived as completed (full closed loop, real-machine logs)

Honest boundaries

  • at-least-once: a crash window may double-dispatch (by design).
  • every tracks only the latest, no Cron/calendar rules, every_seconds ≥ 300 — same as the official one.
  • remind stays session-local (the reminder target is a session); job is the cross-session one.
  • Job-runner sandbox semantics live in each backend's own honest-boundaries section.
  • Offline applicability: architecturally no network dependency (local SQLite archive + local timer; whether job execution needs the network depends on the task itself); multi-day offline runs are not measured, not claimed.
  • Windows CI environment: the GitHub Actions windows runner runs as administrator, where ACL deny sandboxes do not apply — CI asserts the runner's fail-closed protocol (EXIT:-998); sandbox capabilities are measured on non-admin Windows (same disclosure as dsh-witness).

Development

npm test   # shell integration acceptance (node --experimental-strip-types)

License

Apache-2.0