DSH HUB
HomePlugin StoreRankingsPublish Guide
Plugin source
Back to catalog

EricJiang0423 /

dsh-orchestrator

Verified

Local-first issue board for DeepSeek Harness: board data, model-facing tools, a fresh-agent planning loop, and a human approval queue for agent-proposed issues.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@e69a673d

English · 中文

dsh-orchestrator

Local-first issue orchestrator for DeepSeek Harness: one board per repository, a fresh session per issue, and a scheduler that works the queue itself
Cordis Plugin · Workspace-Scoped Board · Per-Issue Sessions · Auto-Pull Scheduler · Two Human Approval Gates

Quick Start License

TypeScript Node.js React Zod esbuild Cordis


Features

Feature Description
One Board Per Repository The board is bound to the session's working directory, not to the conversation: two sessions in the same repo share a board, and a session in another repo sees its own — the host resolves it, so the browser can never mix projects
Fresh Session Per Issue "Work on this" opens a brand-new session with the issue's brief and binds the issue to it, so every issue's transcript and cost are its own — and several can run at once
Auto-Pull Scheduler A scheduler keeps up to N issues in flight and refills from todo by itself — highest priority first — with live controls for concurrency and the auto-pull toggle in the board header
Three Human Gates An agent can never move an issue out of proposed, can never mark one done, and can never shelve one as archieved: proposals need your approval, finished work needs your acceptance, and archiving accepted work is yours too — all enforced in the service layer, not the UI
Durable Approval Queue Agent-proposed issues land in a proposed column and stay there until a human approves or rejects them — durable across restarts, unlike a one-shot approval prompt
Board as a Chat Peer The board registers into the conversation view ring, so it appears as a tab beside Chat and Trajectory instead of a separate page

Screenshots

The board rendered with sample data — no project details from any real deployment.

Board view: workspace-scoped board with the approval queue, the scheduler strip (auto-pull toggle, parallelism, live running/waiting counts), and the session chip on the in-flight issue:

Board view: proposed, backlog, todo, in progress, in review, and done columns

Issue detail, expanded from a card, showing the unified acceptance controls — Accept, or Send back with a reason that lands as a comment:

Issue detail expanded from a card, with the acceptance controls, description, labels, and comment trail


Quick Start

Prerequisites

  • Node.js 22.5+
  • A running DeepSeek Harness profile

Install from source (recommended)

Clone, build, and link the checkout into the profile. dsh plugin add . from inside the checkout registers the local build, so later npm run build runs are picked up without reinstalling:

git clone https://github.com/EricJiang0423/dsh-orchestrator.git
cd dsh-orchestrator
npm install && npm run build
dsh plugin --profile web add .

lib/ is gitignored build output. npm test builds it automatically when it is missing (a pretest hook runs npm run build first), so on a fresh clone you can run tests right after npm install without building by hand. Once lib/ exists, npm test skips the rebuild to stay fast — run npm run build explicitly to test your latest source changes.

Install from npm (registry)

⚠️ The unscoped dsh-orchestrator on the registry belongs to an unrelated project (zibo/dsh-agent-mesh). This project is published under a scope:

dsh plugin --profile web add @ericjiang0423/dsh-orchestrator

Run

dsh --profile web

Usage

Capture an issue without leaving the chat

/task Fix the flaky checkout test

Call the board from another plugin

import type {} from '@ericjiang0423/dsh-orchestrator'

export const inject = ['taskboard']

export function apply(ctx: Context) {
  const open = ctx.taskboard.listTasks({ status: 'todo' })
}

Call the RPC endpoint

const res = await fetch('/_dsh/taskboard/rpc', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({
    method: 'task.update',
    params: { id, patch: { status: 'in_review' }, expectedVersion: 3 },
  }),
})

Configure the scheduler and the planning loop

- id: taskboard
  config:
    scheduler:
      concurrency: 2
      autoPull: true
    plan:
      maxRounds: 16
      maxHandoffChars: 8192

Architecture

%%{init: {'theme': 'base', 'themeVariables': {'fontSize': '14px'}}}%%
graph LR
    UI[Board View<br/>React] -->|RPC + SSE| SVC[Taskboard Service<br/>Cordis Plugin]
    TOOLS[taskboard_* Tools<br/>Model-facing] --> SVC
    PLAN[taskboard_plan<br/>Workflow Engine] -->|fresh subagents| TOOLS
    SVC --> DB[(Storage Domain)]
    SVC --> WS[Workspace Registry<br/>cwd → workspace]
    SCHED[Scheduler<br/>session-link] -->|agents.create| ISS[Per-Issue Sessions<br/>ctx.agents]
    SVC --> SCHED
    ISS --> SVC

    classDef client fill:#3B82F6,stroke:#2563EB,color:#fff,stroke-width:2px
    classDef service fill:#10B981,stroke:#059669,color:#fff,stroke-width:2px
    classDef data fill:#8B5CF6,stroke:#7C3AED,color:#fff,stroke-width:2px

    class UI client
    class SVC,TOOLS,PLAN,SCHED,ISS service
    class DB,WS data

The browser half never talks to storage directly. Every read and write goes through ctx.taskboard, whether the caller is the board's own RPC route, a model-facing tool, the planning loop, or the scheduler — so the two human gates (no self-approval, no self-acceptance) live in one place and apply to every caller. The scheduler is the only thing that starts work on its own, and it draws exclusively from todo, which only a human can put an issue into.


Configuration

Key Default Description
scheduler.concurrency 1 How many issues may run at once; changeable live from the board header
scheduler.autoPull true Whether the board pulls from todo on its own; changeable live from the board header
scheduler.sweepIntervalMs 30000 Safety-net sweep that frees slots occupied by vanished sessions
plan.subagentProvider spawn Fresh structured-output subagent provider used for every planning round
plan.maxRounds 32 Default AND ceiling for one taskboard_plan run; a call may lower it, never raise it
plan.maxHandoffChars 16384 Maximum serialized characters in one round's structured report; an oversized report fails the run instead of being truncated
plan.maxIssues 16 Maximum issues admitted into one planning run

API

The browser half talks to the host half over one endpoint, POST /_dsh/taskboard/rpc, with { method, params } in the body, rather than one REST path per resource. DeepSeek Harness's typed RPC layer requires build-time code generation this plugin's build does not run, so the route is deliberately explicit — see docs/spike-findings.md for why.

Method Description
board.view The board this session belongs to (resolved from its workspace), with live scheduler state
project.list List every project
project.create Create a project
task.list List issues, optionally filtered by project, status, or session
task.get Read one issue with its comments and activity trail
task.create Create an issue
task.update Change an issue; refuses a stale expectedVersion
comment.create Add a comment to an issue
task.start Open a FRESH session for one issue and hand it the work
task.startNext Start the next todo issue — highest priority first — without naming one
task.accept Accept finished work (in_review → done) — the human gate no agent can pass
task.sendBack Send finished work back to todo with a reason (recorded as a comment), unbinding its session
scheduler.configure Change concurrency or the auto-pull toggle; returns the resulting state

Change notifications stream over GET /_dsh/taskboard/events as Server-Sent Events.


Directory Structure

src/
├── client/              # Browser half
│   ├── board.tsx         # BoardView: columns, cards, scheduler strip, approval + acceptance controls
│   ├── index.tsx          # Client plugin entry, slot registration
│   ├── rpc.ts              # fetch()-based RPC client + SSE subscription
│   └── styles.ts            # Layout-only CSS; every color is a theme token
├── domain.ts             # Zod schemas and the status machine
├── service.ts            # ctx.taskboard: reads, writes, version CAS
├── rpc.ts                 # Host RPC route + SSE change stream
├── tools.ts                # Model-facing taskboard_* tools
├── command.ts               # /task human command
├── plan-loop.ts               # taskboard_plan: the fixed planning loop
├── session-link.ts              # Workspace resolution, per-issue sessions, the scheduler
├── skill.ts                      # Registers the manage-taskboard skill
├── actors.ts                      # Actor identity
├── wire.ts                         # Shared browser <-> host RPC types
└── index.ts                        # Plugin entry: mounts every face
test/                    # node:test suites
skills/manage-taskboard/  # Bundled working-agreement skill
docs/                     # Extension-point research notes

Tech Stack

Runtime

Technology Purpose
TypeScript Source language for both plugin halves
Cordis Host plugin framework: services, effects, dependency injection
Zod Schema validation for the four storage-domain tables
Schemastery Plugin Config validation
React Board view rendering (peer dependency, supplied by the host at runtime)

Build & Test

Technology Purpose
esbuild Bundles the browser half into the client-module envelope the host serves
Node.js test runner node --test, no test framework dependency

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing)
  3. Commit your changes (git commit -m 'feat: add amazing feature')
  4. Push to the branch (git push origin feature/amazing)
  5. Open a Pull Request

License

Apache-2.0. The domain model and issue-flow rules derive from dashi-taskboard — see NOTICE.

DSH HUB

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

APIPublish GuideAbout
—/ 5

No ratings yet

Verified DSH bundle

Commit e69a673d2935

Community comments

No comments yet. Be the first to write one.