为 DeepSeek Harness 引入"独立会话的定时任务":在全新 Agent + Session 中按计划执行自包含任务,提供 Web 控制台与 Agent 工具双入口。
- 语言
- TypeScript
- License
- MIT
- 分支
- main
安装
$ dsh plugin --profile web add github:titanwings/dsh-automation在终端中运行以上命令,通过 dsh CLI 安装此插件。可在右上角切换 Profile。 第一次用 dsh?看这篇新手教程
一句话定位
dsh-automation 给 DeepSeek Harness 增加"独立运行的定时任务"能力。每当到点,它会在全新 root Agent + 新 Session 中执行一条自包含的 prompt,并把每次执行结果作为可审计记录留下来。和 DSH Core Schedule 那种"十分钟后回来这个会话"不同,它每次都是独立的新会话。
核心能力
- 支持四种调度:一次性、固定间隔(≥5 分钟)、每日、每周(按 IANA 时区),日常/周程会规范成 RFC 5545 RRULE 持久化
- 每次触发在全新 root Agent + 新 Session 中执行,prompt 显式标记 source.kind = "automation",便于审计
- 提供 Web 端"自动化"标签页,可在浏览器中创建、暂停/恢复、立即执行、删除、查看历史
- 提供 6 个 Agent 工具(automation_create / list / update / run_now / runs / delete),工具作用域绑定到当前工作区,不能跨工作区
- 每次执行都留下完整记录(定义版本、prompt 快照、目标快照、调度时间、结果 Session ID、摘要、结构化错误),状态含 queued / running / succeeded / failed / skipped / cancelled
- 安全护栏:只接受 read-only / workspace-write 两种权限;审批策略固定为 never;后台进程被拒;工具白名单在执行器层强校验
技术实现
- 语言: TypeScript(ESM,主入口编译到 lib/)
- 关键依赖: luxon(时区与 DST 计算)、zod(领域表与调度的模式校验)、@deepseek-ai/cordis(宿主插件运行时)
- 架构模式: 单 Cordis 插件,分两条线——Host 侧(src/index.ts / service.ts)持有唯一权威服务,Client 侧(src/client/index.ts)通过 conversation.view 槽位注入 Web 标签页;Agent 工具通过 agent/created 事件动态挂到每个 root Agent 上
- 入口文件: src/index.ts(Host 入口),src/client/index.ts(Web 客户端入口,由 package.json#dsh.client 暴露)
适用场景
适合需要让 DSH 在指定时间或间隔"独立地"完成一段编码/巡检/回归类工作的人,比如工作日 9:30 自动跑回归分诊、每周生成仓库健康报告、给一个不稳定的失败做延迟复测。任务必须写得自包含、能被独立验证,不适合依赖对话上下文的"接着上次聊"或"什么都修一下"。
前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| Node.js | ^22.19.0 | |
| React(可选) | ^18.2.0 | peerDependencies,可选;仅在 Web 客户端需要 |
| 平台 | 跨平台 | 未声明 os/cpu 限制,纯 TypeScript/Node 实现 |
| 原生模块 | 无 | 不依赖 node-pty、node:sqlite 等原生模块 |
安装方式
dsh plugin --profile web add github:titanwings/dsh-automation
配置项
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| maxConcurrentRuns | 整数 1-32 | 同一时刻允许同时执行的 run 总数;每个自动化内部仍互斥 | 2 |
| runTimeoutMinutes | 整数 1-1440 | 单次 run 允许运行的最长分钟数,超时会被取消并记为 failed | 60 |
| misfireGraceMinutes | 整数 0-10080 | Host 恢复后允许"补跑"最近 due 项的最大延迟分钟数;超过则记为 misfire 跳过 | 15 |
| historyLimit | 整数 1-5000 | 每个自动化保留的已结束 run 记录最大条数;正在运行或排队的永不裁剪 | 200 |
| archiveRunSessions | 布尔 | 是否把已结束的 run Session 从普通会话列表归档;当前 DSH 主机没有 unarchive API,归档后无法直接打开 | false |
常见问题
Q: 这个插件是不是给 DSH 加个 cron?
A: 比 cron 更严格也更安全。每次触发都会在全新 root Agent + 新 Session 中执行自包含 prompt,权限仅限 read-only 或 workspace-write,不接受 danger-full-access,也不会执行任意 shell。
Q: 自动化任务能继承当前会话的上下文、收件箱或历史审批吗?
A: 不能。每个 run 拿不到源会话历史、收件箱或历史授权;任务以 source.kind = "automation" 显式投递,行为可追溯。
Q: 主机宕机错过了执行时间,会重跑吗?
A: 不会。默认 15 分钟容错窗口内只补跑最近一个 due 项,更早的会被记为 misfire 跳过;可能产生副作用的 run 不会被悄悄补做。
Q: 执行超时或运行中崩溃会怎样?
A: 单次 run 默认 60 分钟后被取消并记为 failed;Host 重启时会把残留的 queued/running 记录统一标为 failed(host_interrupted),不会偷偷重做。
Q: 能在 Web 和 Agent 两个地方管理吗?
A: 能。Web 端有"自动化"标签页(创建、暂停/恢复、立即执行、删除、查看历史),任何 root Agent 可调用 6 个工具:automation_create / list / update / run_now / runs / delete。工具作用域绑定到调用者当前工作区,不能指向其他工作区。
Q: 删除任务会把历史记录也删掉吗?
A: 不会。删除只是把定义删掉,已结束的 run 记录会保留用于审计;只有最旧的已结束记录会被 historyLimit(默认 200 条/任务)裁剪,正在运行或排队的永不裁剪。
上手难度
进阶 — 需要理解 DSH 的工作区、Agent 预设、权限预设和会话模型,并写出"自包含、可独立验证"的 prompt;调度语法和时区/DST 规则也需要花点时间。
已知问题与限制
- 不提供同会话心跳式提醒,需要的话请用 DSH Core Schedule
- 不支持原始 cron 表达式或任意 shell 命令
- 不接受 unattended 模式下的 danger-full-access
- 对可能产生副作用的 run 不做自动重试
- 不提供 Git worktree 的创建或清理
- 不支持多工作区目标、DAG 依赖、跨 run 隐藏记忆
- 没有邮件、短信、推送等外部通知通道
- 不保证"恰好一次"的外部副作用,只承诺"至多一次"分发
- 仅本地执行,不支持多 Host 共享同一存储目录(README.md:230 明确说明)
- 0.1 版不实现操作系统级守护进程
- 工具白名单中 bash/pwsh 拒绝 run_in_background=true(src/executor.ts:33-42)
- 启用 archiveRunSessions 后,归档的 Session 在当前 Harness 版本无法重新打开
⏱️ dsh-automation
Run coding tasks on schedule. Manage them from Web or Agent.
|
🕒 Need recurring or one-shot coding work to run later without relying on an old chat? |
✨ dsh-automation turns all three requirements into one workflow.
Create and manage schedules from DSH Web or any eligible root Agent. Every dispatched occurrence starts in a fresh root Agent and Session, then leaves an auditable record.
Self-contained task + schedule + permission boundary → fresh root Agent + fresh Session + durable run history
Why automation · Features · Install · Quick start · Safety · Technical details
English · 简体中文


🎯 Why automation
DSH Core Schedule is the right tool for reminders in the current conversation: “come back to this Session in ten minutes.” dsh-automation handles a different job: “run this complete task independently every weekday and leave me a result I can inspect.”
| DSH Core Schedule | dsh-automation | |
|---|---|---|
| Execution context | Returns to the same live Agent | Starts a fresh root Agent and Session |
| Input | A follow-up inside existing context | A saved, self-contained task |
| Scope | Current Session Log | One canonical DSH workspace |
| History | Conversation events | Definition revisions and durable run records |
| Best for | Reminders and same-chat follow-ups | Repeated or one-shot standalone coding work |
If a task depends on unstated chat history, needs an interactive approval halfway through, or should react to a file, HTTP, or process condition rather than time, it is not a good automation yet.
✨ Features
🕹️ One control plane, two ways in
- DSH Web: use the Automations conversation tab to create a rule, pause or resume it, run it now, delete it, and inspect recent runs.
- Any eligible root Agent: ask in natural language. Six scoped tools let the Agent manage automations only for its exact workspace.
There is no separate bot, daemon UI, or third-party scheduler to operate.
📅 Schedules people can read
Create a one-shot, fixed-interval, daily, or weekly rule. Daily and weekly schedules use an IANA time zone; the friendly form is normalized into a validated RFC 5545 RRULE for persistence and inspection.

🧼 A clean execution boundary every time
Each dispatched occurrence receives:
- a new Session ID and fresh root Agent;
- the saved prompt, not the source conversation history;
- the captured workspace, cwd, Agent preset, model target, and permission preset;
- an explicit
automationmessage source containing the automation ID, run ID, and scheduled time; - a terminal result derived from the actual DSH turn end, not merely “message delivered.”
🧾 History that explains failure as well as success
Runs progress through queued, running, and a terminal state such as succeeded, failed, skipped, or cancelled. Each record keeps its definition revision, prompt and target snapshot, scheduled time, result Session ID, bounded summary, and structured error.

Updating a definition increments its revision, so each retained run still identifies what it executed. Deleting the definition does not immediately erase those run records. Retention removes only the oldest terminal records; queued and running records are never pruned.
Set archiveRunSessions: true in the Cordis plugin config to archive completed, failed, cancelled, and other terminal run Sessions from the ordinary DSH conversation list. Their logs are not deleted: the Automations run history keeps the Session ID, summary, and error as an auditable inbox. Current Harness releases do not expose an unarchive API, so an archived result is labeled instead of offering a broken Session-open action. The default is false and preserves ordinary Session navigation.
⚡ Install
Install the GitHub bundle into the DSH Web profile, then restart dsh web:
dsh plugin --profile web add github:titanwings/dsh-automation#v0.1.6
The version tag keeps the install reproducible; a reviewed commit SHA is equally valid. If you run DSH from its source checkout, use pnpm dsh in place of dsh.
Install from a local checkout
Node.js 22.19 or newer is required.
git clone https://github.com/titanwings/dsh-automation.git
cd dsh-automation
pnpm install
pnpm check
cd /path/to/deepseek-harness
pnpm dsh plugin --profile web add /absolute/path/to/dsh-automation
The repository ships its built Host and Web bundles. Git installation runs no
package build script and needs no allowBuilds entry.
🚀 Quick start
🖥️ From DSH Web
- Open a Session attached to the workspace you want to automate.
- Select Automations next to Chat and Trajectory.
- Enter a self-contained task, schedule, IANA time zone, and permission boundary.
- Use Run now once before relying on the schedule; inspect the resulting Session and run record.
💬 Ask an Agent
Once installed, eligible root Agents receive the management tools. For example:
Create a read-only automation called "Weekday regression triage" for this workspace.
Run it Monday through Friday at 09:30 in Asia/Shanghai. Inspect the latest local test
evidence, identify regressions, and return a short report. Do not modify files.
| Tool | Purpose |
|---|---|
automation_create | Create a workspace-bound standalone rule. |
automation_list | Read rules, next occurrences, and recent history. |
automation_update | Change name, prompt, cadence, permission, or active/paused state. |
automation_run_now | Queue one manual occurrence with the same boundary. |
automation_runs | Read bounded run history, errors, summaries, and Session IDs. |
automation_delete | Delete the definition while retaining durable run records. |
Plugin-level approval asks for human confirmation when an Agent creates or expands unattended future work. Read operations and a pause-only update do not add that extra approval step.
🧰 Good automation candidates
The best automations are repeatable, bounded, and easy to verify.
| Automation | Suggested boundary | Why it is useful |
|---|---|---|
| Weekday regression triage | read-only | Inspect local test evidence, group failures, and leave a concise diagnosis in a new Session. |
| Weekly repository health report | read-only | Review stale TODOs, dependency manifests, ignored failures, and test gaps without changing the tree. |
| One-shot verification | read-only | Recheck a flaky failure later and preserve evidence outside the current chat. |
| Generated-code refresh | workspace-write | Rebuild a known generated artifact, run focused checks, and report the exact diff. |
| Maintenance fix window | workspace-write | Reproduce one bounded issue, make the smallest verified fix, and stop when acceptance checks pass. |
A strong task states the goal, evidence to inspect, allowed changes, verification, and stopping condition. Avoid prompts such as “continue what we discussed” or “fix everything”: scheduled runs do not inherit the conversation that created them.
🛡️ A schedule is not permission
Unattended coding needs a smaller trust boundary than an interactive chat. dsh-automation makes these constraints explicit:
- No inherited authority. A run receives no source-chat history, inbox, grant, or past approval.
- Two permission modes only. Rules may use
read-onlyorworkspace-write; unattendeddanger-full-accessis not accepted. - Fail closed. Each fresh Session uses approval policy
never. A tool that still requires interactive approval fails instead of waiting forever or silently escalating. - Exact workspace scope. Agent tools bind to the caller's canonical registered workspace; callers cannot supply an arbitrary target path.
- Explicit capability allowlist. The fresh Agent admits a small coding-tool set. Interactive questions, plans, goals, nested Agents, runtime plugin mounting, terminal/background jobs, recursive automation management, and unknown third-party tools are denied by an Agent-scoped final guard.
- Loopback Web control. The management RPC channel accepts loopback authority only.
- Traceable origin. The task enters the Session with
source.kind = automation, plus the automation/run identity and scheduled time. It never impersonates a human message. - No blind retries. Once an Agent may have produced side effects, the plugin does not automatically retry it.
These boundaries do not turn every third-party DSH tool into a sandbox. Foreground shell and network behavior still depends on the selected Agent preset, tool set, and DSH guards. Review a task with Run now before enabling unattended writes.
🔧 Technical details
⏱️ Scheduling and recovery semantics
| Situation | Behavior |
|---|---|
| Interval | Minimum five minutes; the first run occurs after one full interval, not immediately. |
| Daily / weekly | Evaluated at local HH:mm in an explicit IANA zone; nonexistent DST wall times are skipped rather than shifted. |
| Overlap | One active run per automation. A due occurrence is recorded as skipped(overlap) if its previous run is queued or running. |
| Host restarts late | Within the grace window (15 minutes by default), only the latest due occurrence can catch up. Older work is not replayed as a write backlog. |
| Run timeout | The Agent is cancelled after 60 minutes by default and the run is recorded as failed. |
| Host crash | Persisted queued or running records become failed(host_interrupted) on recovery; they are not secretly re-executed. |
| Session list | With archiveRunSessions enabled, terminal run Sessions are durably archived after their run record is saved. Startup retries archival for an interrupted terminal record, and an archive failure never changes the run outcome. |
| Retry | Manual Run now only. There is no automatic side-effect retry. |
A deterministic occurrence key prevents the scheduler from dispatching the same recorded occurrence twice. This is an at-most-once dispatch policy, not a claim that external side effects are exactly once.
The DSH Host must be running for a task to start. Version 0.1 is not an operating-system daemon and does not coordinate multiple Hosts over one storage directory.
🏗️ Architecture
The product model is inspired by Codex Scheduled tasks, especially the distinction between returning to a chat and starting a standalone run. The implementation is native to DSH and Cordis; it does not copy Codex internals or patch DSH Core.
flowchart LR
UI["Web control center"] --> Service["Automation service"]
Tools["Agent-scoped tools"] --> Service
Service --> Definitions["Durable definitions"]
Clock["Cordis-owned clock"] --> Claim["Durable occurrence claim"]
Definitions --> Clock
Claim --> Executor["Run executor"]
Executor --> Agent["Fresh root Agent + Session"]
Agent --> Runs["Durable run history"]
Runs --> Service
| Layer | Owns | Does not own |
|---|---|---|
| Definition/run store | Durable facts and revision snapshots | Timers or Agents |
| Clock | Finding the next due occurrence | Prompts, permissions, or execution |
| Executor | One already-claimed fresh Agent run | Schedule mutation |
| Agent tools / Web RPC | Validated service calls | Tables, timers, or direct Agent construction |
| Web client | Native conversation.view presentation | Authoritative due state |
Cordis disposal stops the clock, cancels plugin-owned live handles, removes tools/RPC/UI, and closes storage without inventing a successful run. The full rationale and data model are in the design document.
⚙️ Configuration
The included cordis.patch.yml uses conservative defaults:
| Option | Default | Meaning |
|---|---|---|
maxConcurrentRuns | 2 | Global execution capacity for this Host. Per-automation overlap is still disabled. |
runTimeoutMinutes | 60 | Maximum wall-clock time for one fresh Agent run. |
misfireGraceMinutes | 15 | How late the latest due occurrence may catch up after downtime. |
historyLimit | 200 | Durable terminal-run retention per automation; active records are always kept. |
archiveRunSessions | false | Opt in to archiving terminal run Sessions from the ordinary conversation list while preserving their logs and durable Automation result metadata. Current Harness releases cannot directly reopen an archived Session. |
Edit the plugin row in the deployment profile if you need different values. Increasing concurrency or timeout expands the amount of unattended work; treat those changes as policy decisions.
🚧 Current limits
Version 0.1 deliberately does not provide:
- same-chat heartbeats — use DSH Core Schedule;
- raw cron or arbitrary shell actions;
- unattended full access;
- automatic retry of a run that may have side effects;
- Git worktree creation or cleanup;
- multi-workspace targets, DAGs, or hidden cross-run memory;
- external email, SMS, or push delivery;
- a guarantee of exactly-once external side effects.
Only local execution is implemented. A stable DSH worktree lifecycle service should exist before a UI toggle claims worktree isolation.
🧪 Development
pnpm typecheck
pnpm test
pnpm build
# or all three
pnpm check
The package builds a Host ESM bundle and a Web client bundle for DSH's window.__ModuleLoader__ contract. Tests cover recurrence and DST behavior, durable-domain invariants, Agent capability guards, scheduler overlap/recovery/retention, and client schedule/localization helpers.
📄 License
MIT. This is an independent community plugin for DeepSeek Harness. “Codex” is referenced only to describe the product pattern that informed the design.