qiqll/dsh-task-suite: A verifiable task suite to run in DSH

Preface

When agents deliver multiple tasks continuously in real projects, three common problems arise: task states only exist in the conversation, completed tasks cannot be verified for changes, and no one checkpoints acceptance in loop dispatching. qiqll/dsh-task-suite ported Claude’s task-* task system to DeepSeek Harness (DSH), providing a disk-based task pool, along with a state machine, main session scheduling, background workers, and machine acceptance.

It has no Web task board; backlog.md is the board. It also doesn’t force git; when there’s no git repository, it uses file snapshots for baseline comparison, change attribution, and rollback. Below is an introduction to its installation, directory structure, usage, and acceptance logic.

I. What is it

qiqll/dsh-task-suite is a local plugin for DSH, maintained by qiqll, licensed under MIT (see package.json), and requires Node >= 20.

It splits four roles into a task pool and a set of tools: The main agent handles dialog with the requester, scheduling, dispatching, and acceptance; the background subagent completes a single task in a fresh context and outputs a structured report. The task pool is Markdown on disk, directly viewable and editable by the requester.

Differences from existing approaches: Claude’s task-* ecosystem state directories are in .claude/, while this plugin only uses .dsh/tasks/ and does not touch the .claude/ pool by default. It has no built-in heartbeat or cron; long loops need an external timer to remind the main session to tick; it also has no Web task board.

II. Installation and Enablement

Install from GitHub source code, the current recommended way:

dsh plugin add qiqll/dsh-task-suite

After the npm package is released, you can also install directly by package name:

dsh plugin add dsh-task-suite
# or specify profile
dsh plugin --profile web add dsh-task-suite

On the desktop version, search for dsh-task-suite in Settings → Plugins to install. After the first installation, tools and three skills (task-admin / task-loop / task-worker) are automatically registered; no restart is required.

The plugin follows the inclusion format of awesome-dsh-plugin; market cards, installation, and updates are driven by that directory and npm versions. This is a community directory with no official affiliation with DeepSeek / Synthflow.

When developing locally, link this directory to the profile’s dependencies using link:; after changing code, disable and re-enable the plugin to complete hot reload.

III. State Directory and State Machine

The task pool lands in .dsh/tasks/:

.dsh/tasks/
├── backlog.md          # Requester entry: P0-P3 tables, pending decisions, manual blocking, ID rules
├── dev-plan.md         # AI maintained: current batch, in progress, technical prerequisites
├── dev-progress.md     # Completed archives (by month)
├── inbox/              # Requester/scheduler delivery (task_*.json), moved to .merged/ after merge
└── auto/               # Runtime state, entire directory gitignored
    ├── current.json    # Current task: nonce / startSha / dirty files / stage
    ├── session.json    # Loop session: active / max / hours / done / noprog
    ├── run.log         # Runtime log
    ├── STOP            # Halt marker
    └── snapshots/      # Non-git mode: start snapshot + manifest (deleted after confirmation)
        └── T-001-<nonce>/
            ├── manifest.json
            └── files/

task_init adds .dsh/tasks/ to .gitignore in a git repository; it doesn’t create that file in non-git directories. Each workspace has an independent pool; the task pool is a runtime state, not committed to business commits.

State machine:

Pending -> In Progress -> Pending Verification -> Completed
             └→ Blocked / Pending Decision -> Pending
             └→ Rejected -> In Progress

Only one “In Progress” is allowed at a time; P0 can be interrupted, and old tasks record checkpoints.

IV. Pool Creation and Entry

First use task_init to create the directory, then task_add to enter tasks:

task_init                                   # Create .dsh/tasks/ (also writes .gitignore in git repos)
task_add items=[{title, module, priority, deps, acceptance, note}]
task_status                                 # Global view / Pending decisions / Blocked / Log

task_add can enter 1..N items at once, automatically deduping, assigning IDs, checking dependencies and acceptance fields; parameters are items[] and source. task_status gives a global view and next step suggestions.

Manual mode:

task_pick mode=manual task_id=T-001         # Claim and implement yourself
task_accept report="<report block>"         # Machine acceptance
task_confirm task_id=T-001 conclusion="..." # Archive after requester confirmation

V. Automatic Loop and Background Worker

Automatic looping is the recommended usage:

task_loop action=start max=10 hours=8
task_loop action=tick        # Returns worker_prompt
# Hand the worker_prompt to the subagent tool as is; then end the round and wait for completion notification
# After receiving the worker's last message:
task_accept report="<entire report block>"
# Pass -> Pending Verification; Requester confirms -> task_confirm; Fail -> task_reject
task_loop action=tick        # Dispatch next

Actions for task_loop are start / tick / stop / halt / resume / requeue / status. Use task_loop action=stop reason="..." for normal shutdown; to stop midway, call interrupt_agent first, then task_loop action=halt. Halt preserves commits but doesn’t rollback. After halting, continue using action=resume (re-dispatch same task with checkpoint) or action=requeue to put it back in the queue.

No built-in heartbeat; for long loops, use schedule_create to periodically remind the main session to tick.

VI. Tool Overview

Tool Function Key Parameters
task_init Initialize pool + .gitignore —
task_add Enter 1..N items, auto dedup/ID/dep/acceptance items[], source
task_status Global view and next step suggestions —
task_list Filter by status/priority/keywords status, priority, query
task_show Complete single-task brief task_id
task_pick Claim task; auto returns worker_prompt mode(auto/manual), task_id, interrupt
task_accept Machine acceptance of worker report report, rollback
task_confirm Requester confirmation -> Archive task_id, conclusion, gate
task_reject Requester rejection -> Pending task_id, reason
task_answer Reply to pending/decision/blocking, back to Pending task_id, answer
task_inbox Delivery of requirements/decisions (used when worker is running) type, text, title, ref
task_merge Immediately merge inbox —
task_loop Loop state machine action, max, hours, reason
task_verify Read-only re-run tests + baseline comparison + weakening audit test_cmd, start_sha
task_audit Read-only audit of commit attribution/out-of-bounds/dirty files/weakening start_sha, task_id

VII. Worker Report Contract

The worker’s last message only outputs a structured report block:

=== TASK-AUTO REPORT ===
NONCE: <nonce from current.json>
RESULT: DONE | NEEDS_DECISION | BLOCKED | BASELINE_RED | FAILED | GATE_PENDING_REVIEW
TASK: T-001
START_SHA: <start SHA>
COMMITS: <sha...>
TEST_CMD: <[cd dir &&] single test command path...>
TEST_RESULT: Baseline x passed, y failed → after delivery z passed, w failed; existing failures: ...
TEST_CHANGES: Only new / No changes / Modified (explain)
GATE: <code-reviewer H×n M×n; reason for skip; ...>
ACCEPTANCE: <compare to acceptance criteria>
ASSUMPTIONS: — / ...
DECISION: — / Issue / Options / Recommendation
BLOCKER: — / ...
DERIVED:
- [P2] Title | Files involved ... | Source ...
BRIEF:
1-3 sentence plain language explanation for the requester
=== END REPORT ===

task_accept validates nonce, task attribution, stage, task ID in commit messages, dirty files, test scope and baseline failure sets, whether tests were weakened, and high-risk paths. Upon passing, the task moves to “Pending Verification” and generates derived tasks; upon failing, it enters Pending Decision / Blocked / Auto-fail count based on RESULT.

When GATE_PENDING_REVIEW, acceptance pauses at review_pending: the scheduler checks start_sha..HEAD themselves; if pass, call task_accept again with review="pass: ..." (same report is fine); if fail, send findings back to worker for fixing and resubmit.

VIII. Two Baseline Modes

mode defaults to auto: uses git mode if git HEAD is available, otherwise automatically uses file mode; can also force mode: file / mode: git.

Git Mode File Mode (Non-git directory)
Start Baseline START_SHA auto/snapshots/<T-NNN>-<nonce>/ full snapshot + manifest.json
Change Attribution commit message contains task ID Snapshot vs current directory diff (added/modified/deleted)
Baseline Test git worktree back to START_SHA Copy snapshot to temp directory, replay code from start
Rollback git reset --keep START_SHA + ref Restore files from snapshot, backup current tree before restoring
Commit Requirement Each commit has task ID No commit; COMMITS: —
Limitations Requires HEAD Cannot distinguish “who changed it”; snapshot takes disk space; dependent directories/build artifacts are excluded

Snapshots default to excluding .git, node_modules, .venv/venv, __pycache__, dist/build, .dsh/tasks, etc. For large projects, use snapshotIgnore to exclude more directories, or increase snapshotMaxBytes / snapshotMaxFiles. Snapshots are deleted after task confirmation/rejection; by default, only the last 10 snapshots are kept.

TEST_CMD, test weakening audit, nonce, and legacy file checking are consistent with git mode in file mode; only “commit attribution” is replaced with “snapshot diff attribution”.

IX. Acceptance and Anti-Cheat

  1. Nonce: A one-time token is generated for every claim; old reports/duplicate notifications are discarded.
  2. Commit Attribution (git): The message of every commit in git log START_SHA..HEAD must contain the task ID; if someone else’s commit appears, stop and do not auto-process.
  3. Change Attribution (file): Compare with the start snapshot; list added/modified/deleted; alert if report CHANGES mismatches reality.
  4. Baseline Comparison: When current tests fail, re-run the same command on git worktree’s START_SHA (git) or snapshot copy (file); only cases where “baseline also failed” count as existing failures; new failures -> Reject.
  5. Test Scope: TEST_CMD must be a single command; forbidden chars: ; | & $( > < and flags -k/--deselect/--ignore/--lf/--collect-only/--passWithNoTests; test files added/removed must fall within the command path parameters.
  6. Weakening Audit: Deleting test cases, moving files, skip/xfail, commenting out assertions, net assertion reduction, test config ignores all generate alerts; DONE with alerts ->转为 “Pending Decision”.
  7. High-Risk Paths: Authentication, payment, migration, deployment, CI, dependency manifests, etc.; when hit, the report is required to write GATE and ASSUMPTIONS, otherwise it transfers to manual review.

Machine acceptance is rewritten from the original verify_tests.sh / check_test_weakening.sh to a Node implementation, with consistent judgment criteria.

X. Configuration

Plugin config is written in the config of cordis.patch.yml, overriding the following defaults:

Key Default Description
stateDir .dsh/tasks Relative to project root
testTimeoutSec 900 Single test timeout
defaultMaxTasks 10 Max number of tasks delivered in a loop
defaultMaxHours 8 Max hours in a loop
maxNoprog 3 Auto-shutdown after continuous no progress
maxDerivedPerParent 3 Upper limit for single task derivation
maxDerivedDepth 2 Upper limit for derivation hierarchy
mode auto auto / git / file; forcing file mode allows git repos to use snapshots too
snapshotIgnore [] Additional relative paths or * glob to exclude
snapshotMaxBytes 536870912 Single snapshot size limit (512MB)
snapshotMaxFiles 20000 Single snapshot file count limit
snapshotKeep 10 How many recent snapshots to keep

XI. Use Cases and Notes

Suitable for DSH users who need to do multiple tasks continuously in a local project and want every delivery to have acceptance and archiving. Also suitable for scenarios without a git repository but still needing to distinguish “which task this change belongs to”.

Note a few points: The plugin runs with the permissions of the current dsh process, writes .dsh/tasks/, and performs snapshots, git worktree, and test command replay as configured. Before installation, read the source code and license to ensure test commands, process spawning, and file operation scope meet project requirements.

Self-test can be run directly:

cd dsh-task-suite
node selftest.mjs

Self-test covers two modes: pool creation/entry/parsing, claiming, report parsing, DONE acceptance/archiving, FAIL_NEW baseline comparison, test weakening, inbox, pending decisions, loop start/stop, halt/resume/requeue; non-git claiming, snapshot diff attribution, DONE acceptance, FAIL_NEW baseline, test weakening, rollback on failure.

Conclusion

dsh-task-suite puts scheduling, dispatching, and acceptance of task-* onto disk: backlog.md is readable and editable, acceptance is done by machine based on baseline comparison and weakening audit, and both git repositories and non-git directories can run. The directory page is at https://www.skillhub.cn/plugins/qiqll/dsh-task-suite, source code at https://github.com/qiqll/dsh-task-suite.

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye