DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

lijian-ui /

lijian-ui/dsh-schedule-view

Verified

A cron-based scheduled task plugin for DeepSeek Harness (dsh) desktop: create / edit / delete / fire-now tasks from the settings panel, with cross-session agent follow-up and multi-level notifications. Zero LLM tools — purely human-driven scheduling.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: master@599d90d9

dsh-schedule-view · Scheduled Task Plugin

English | 中文

A cron-based scheduled task plugin for DeepSeek Harness (dsh) desktop: create / edit / delete / fire-now tasks from the settings panel, with cross-session agent follow-up and multi-level notifications. Zero LLM tools — purely human-driven scheduling.

Features

Feature Description
7 Schedule Types Interval / Daily / Weekly / Monthly / Yearly / Once / Cron
Cron Expression Full 5-field cron with live validation and human-readable preview ("every weekday at 09:00")
Cross-Session Fire Timer lives at host process level; fires even when the target session is closed
Agent Follow-up Injects a user-role prompt (请根据系统指令开始执行任务。) into the target agent via followup
Execution Lifecycle Tracks delivered → running → completed/failed via session/event with AI reply excerpt
Multi-Level Notifications Page toast (8s auto-dismiss) + WebAudio chime (zero files) + Electron desktop notification + unread badge
Model Selection Per-task provider / model override, falls back to deployment default
Working Directory Per-task cwd binding for context-aware execution
Catch-Up Policy Skip missed windows or run once on next tick (for app restarts / sleep)
Zero LLM Tools No schema overhead — purely UI-driven, no schedule_* tools registered

Background

dsh's official @deepseek-ai/dsh-schedule plugin has several limitations:

Limitation Official This Plugin
Schedule granularity after_seconds / at / every_seconds Full cron + 7 types
Session scope Session-local only Cross-session (host-level timer)
Notifications In-chat only Toast + chime + desktop + badge
UI management None (pure LLM tool) Full settings panel
LLM schema cost 3 tools (schedule_create/list/delete) Zero tools

Installation

Prerequisites

  • DeepSeek Harness (dsh) desktop
  • Node.js >= 18

Install

dsh plugin add @lijian-ui/dsh-schedule-view

Local Development

# Enter the plugin directory
cd extensions/dsh-schedule-view

# Install dependencies
npm install

# Build
npm run build

# Watch mode
npm run watch

# Type check
npm run typecheck

Build output goes to lib/ and is automatically synced to node_modules/@lijian-ui/dsh-schedule-view via junction. Restart the desktop app after each build to load the new bundle.

Usage

  1. Open dsh desktop
  2. Navigate to Settings → Scheduled Tasks
  3. In the task list:
    • Click New Task to create a scheduled task
    • Toggle the switch to enable/disable
    • Click Edit to modify schedule, prompt, or model
    • Click Fire Now to trigger immediately
    • Click Delete to permanently remove
    • Click Run History to view execution records

Task Fields

Field Required Description
Title Yes Task name
Schedule Rule Yes 7 types: interval / daily / weekly / monthly / yearly / once / cron
Prompt Yes Instruction injected into the target agent when fired
Target Session Yes The session where the agent will receive the prompt
Working Directory No Bound cwd for the task's agent (absolute path)
Model No Provider/model override; falls back to deployment default
Timezone No Local timezone for cron resolution (default: system tz)

Schedule Types

Type Example Description
Interval Every 60 minutes Fixed interval in minutes
Daily 09:00 every day Wall-clock time
Weekly Mon, Wed, Fri at 09:00 Selected weekdays
Monthly 1st day of month at 09:00 Day of month (1-31 or last day)
Yearly January 1 at 09:00 Month + day
Once 2026-09-01T09:00:00 One-shot, auto-disables after fire
Cron 0 9 * * 1-5 Full 5-field cron expression

Catch-Up Policy

When the app was closed or asleep and missed a scheduled window:

Policy Behavior
Skip Drop the missed window, wait for next scheduled time
Once Run once on the next tick to catch up (default for once-type tasks)

Execution Lifecycle

When a task fires:

delivered → running → completed/failed
Stage Trigger What happens
Delivered agent.followup succeeds History record created, desktop notification sent
Running user/message event matches injected messageId AI reply excerpt captured, duration tracked
Completed turn/end event Final status, endReason, toast + chime notification
Failed turn/end with error Status marked failed, persistent toast, error chime
Skipped Agent not live at fire time No followup, skipped notification, history marked skipped

Technical Architecture

Directory Structure

extensions/dsh-schedule-view/
├── src/
│   ├── index.ts                    # Host entry (install settings section + start timer)
│   ├── remote.ts                   # Host RPC methods (list/create/update/delete/fireNow)
│   ├── timer-runtime.ts            # Core timer engine (cron parsing + tick polling + fire)
│   ├── schedule-core.ts            # Schedule computation (next-fire calculation)
│   ├── lifecycle-tracker.ts        # Session/event listener for run lifecycle
│   ├── notify.ts                   # Multi-level notifications (toast + chime + desktop)
│   ├── guarded.ts                  # Fault isolation wrapper (try-catch for all callbacks)
│   ├── types.ts                    # TimerTask, RunRecord, TaskSchedule types
│   ├── schema.ts                   # Config schema (schemastery)
│   └── client/
│       ├── index.ts                # Client entry (settings section registration)
│       ├── TimerSettingsSection.tsx # Main settings UI (list + form + history)
│       ├── client-i18n.ts          # i18n (zh/en)
│       ├── config-api.ts           # Client-side RPC wrapper
│       ├── model-catalog.ts        # Model selection UI
│       └── chime.ts                # WebAudio chime synthesis
├── lib/                            # Build output
├── cordis.patch.yml                # Bundle patch declaration
├── package.json
└── tsdown.config.ts

Host Side (src/)

Module Responsibility
index.ts Plugin bootstrap: install settings section, start timer, sync on config change
remote.ts RPC API: list / create / update / delete / fireNow / runs
timer-runtime.ts Cron parsing, tick polling, agent followup injection, lifecycle tracking
lifecycle-tracker.ts Listens to session/event, matches injected messageId, updates run status
notify.ts Toast (React portal) + chime (WebAudio) + desktop notification (Electron IPC)
guarded.ts Wraps all callbacks in try-catch; plugin failure never crashes the host
schema.ts Config validation via schemastery

Client Side (src/client/)

Module Responsibility
index.ts Registers settings section via ctx.slots.inject
TimerSettingsSection.tsx React component: task list, create/edit form, run history panel
client-i18n.ts Chinese / English translations
config-api.ts RPC client wrapper for host methods
model-catalog.ts Model selection dropdown UI
chime.ts WebAudio dual-tone chime synthesis (zero audio files)

Persistence

Data Storage Notes
Task definitions dsh-settings UI-editable, revision conflict protection
Execution history dsh-storage-domain Structured KV, capped at 500 records

Tick Polling Strategy

Uses setInterval tick polling (default 15s) rather than per-task setTimeout:

  • Avoids setTimeout's 2^31 - 1 ms (~24.8 days) ceiling
  • Restart recovery: recalculates nextFireMap from persisted tasks
  • Missed windows: caught on first tick after restart, handled by catch-up policy
  • Trigger precision: bounded by tickSeconds (acceptable for scheduled tasks)

Known Issues & Solutions

Session ID collision after restart

Issue: After desktop restart, the persisted sessionId in task config may collide with existing agent sessions, causing agents.create to fail with "session already exists".

Root Cause: sessionId was persisted to settings; on restore, the old ID clashes with the agent's own session log on disk.

Our Solution: sessionId is not persisted. On each fire, a fresh session is created via agents.create with a new UUID. The sessionId in config is transient — only used to track the live agent handle during a session's lifetime.

Stale agent handle after agent disposal

Issue: Agent is disposed externally (e.g. user closes session), but the runtime still holds a stale handle.

Our Solution: ensureAgent checks if the handle is stale (disposed or not in agents.list()). If stale, it disposes the handle and rotates the sessionId to create a fresh session.

ENOENT when session log file is deleted

Issue: User deletes the session log file while the agent is still alive; agent can't write logs.

Our Solution: agent/error listener detects ENOENT → disposes agent → rotates sessionId → creates a new session.

Archived sessions

Issue: dsh archives sessions by marking archivedSessionIds but doesn't dispose the agent. agents.get() still returns the agent, and followup executes normally but the user can't see it in the UI.

Our Solution: ensureAgent checks workspaceRegistry.archivedSessionIds. If archived, it disposes the agent and rotates sessionId to create a fresh session.

Model selection without preset mount

Issue: agents.create without a setup callback doesn't mount the standard preset, so the agent has no tools and the prompt assembly can't resolve {{provider}} / {{model}} variables.

Our Solution: All agents.create / agents.resume calls include a setup callback that mounts agentPresets ('standard') and installs model selection before the agent is published.

Internationalization

Supports Chinese and English. Translation files are in src/client/client-i18n.ts. Language follows the dsh desktop language setting.

Tech Stack

  • Language: TypeScript
  • Build: tsdown (rolldown)
  • Frontend: React 18
  • Cron Parsing: cron-parser (~30KB)
  • Human-Readable Cron: cronstrue
  • Config Schema: @deepseek-ai/schemastery
  • Settings Persistence: @deepseek-ai/dsh-settings
  • Storage: @deepseek-ai/dsh-storage-domain

License

MIT

Related Links

  • DeepSeek Harness (dsh)
  • Design Document
—/ 5

No ratings yet

Verified DSH bundle

Commit 599d90d9fac0

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout