jeremytenjo/dsh-plugin-backlog-md

dsh-plugin-backlog-md

Native Backlog.md task management for DeepSeek Harness

Uncategorizedbacklog-mddeepseek-harnessreact

Backlog.md for DeepSeek Harness

Native Backlog.md task management inside DeepSeek Harness. The plugin adds a Backlog launcher beside Source Control, renders the task view in Harness's native right-side panel, and starts and manages the official Backlog.md local server for the active workspace.

Backlog.md remains the single source of truth. The plugin never creates a second task database and never writes task Markdown itself.

Features

  • Native launcher — a ListTodo button beside Source Control, with the same dimensions, hover

treatment, tooltip, focus ring, and panel-toggle behaviour. It highlights while Backlog is active.

  • Native right-side panel — registered as a sidebar tab type, so it uses Harness's resizing,

collapse, fullscreen, focus, and per-session persistence. The chat and agent session stay mounted.

  • Zero server setup — detects the workspace's Backlog.md project, finds the installed CLI,

allocates a loopback port, starts backlog browser when needed, waits for health, and connects. Users never run backlog browser by hand.

  • Safe reuse and ownership — one managed server per canonical workspace; multiple Harness

sessions share it. A server the plugin did not start is never terminated.

  • Official API only — task and milestone reads and writes go through Backlog.md's HTTP API.
  • Live synchronization — the Host subscribes to Backlog.md's WebSocket notifications and relays

change scopes to the panel, which invalidates TanStack Query caches. No duplicate filesystem watcher.

  • Wide table and compact list — one TanStack Table instance drives both presentations. CSS

container queries switch at the panel's real content width, never the viewport. Filtering, sorting, selection, expansion, and detail navigation survive the switch.

  • Full task workflows — create, edit, change status or priority, assign, label, milestone,

dependencies, acceptance criteria, Definition of Done, subtasks, archive, and permanent delete.

  • Conflict-aware editing — unsaved edits survive background refreshes; external changes are

detected before saving, with explicit reload or merge choices. No silent overwrites.

  • Send to Chat — puts a ready-to-edit prompt into the current Harness composer. It never sends

the message automatically.

  • Agent-friendly — changes made by the Backlog.md CLI, MCP server, Codex, or another editor

appear through the same WebSocket notifications. No agent-side plugin integration is required.

Screenshots

Full table · Narrow panel ·

Task details · Filtered table ·

The launcher sits directly beside Source Control in the composer:

Requirements

Component · Supported DeepSeek Harness · 0.2.1-rc.3 tested. The plugin uses the public Cordis lifecycle, slots, locale, sidebarRightTabs, sidebarRight, webServer, subprocess, sessions, and workingDirectory services. Backlog.md · 1.55.3 tested; 1.54.0 also verified in the Harness UI. Supported range: >=1.30.0 <2.0.0. Node · 22 or newer on the Host. The shipped plugin has no runtime npm dependencies. OS · macOS, Linux, and Windows where Backlog.md's native CLI runs.

Backlog.md must be installed in the workspace (node_modules/.bin/backlog) or available on PATH. A workspace-local install wins. An initialized Backlog.md project is required; the panel shows the exact backlog init commands when it is missing.

Install

Desktop app (recommended)

  1. Open Settings → Plugins.
  2. Choose Add plugin and enter the local directory path (or the GitHub repository).
  3. Make sure the plugin is enabled, then reload the page or restart the Host.

The desktop profile is managed by the Electron application, so the Settings flow is the supported installation path there.

CLI

Clone the repository and add it to a profile:

git clone https://github.com/jeremytenjo/dsh-plugin-backlog-md.git
dsh plugin --profile <profile> add ./dsh-plugin-backlog-md

A GitHub spec also works:

dsh plugin --profile <profile> add github:jeremytenjo/dsh-plugin-backlog-md

Use the profile that serves your Harness instance (for example web). The package ships its built client.js, so installation does not need a build step.

First run

  1. Install Backlog.md in the workspace or on PATH:
npm install --save-dev backlog.md
   # or: pnpm add -D backlog.md
   # or: npm install -g backlog.md
  1. Initialize the project once, if it is not already:
backlog init
   # or non-interactive defaults:
   backlog init --defaults
  1. Open a Harness session in that workspace and click Backlog beside Source Control.

The panel starts the server itself. No backlog browser command is needed.

Usage

Launcher and panel

The Backlog button is registered in the composer's conversation.input.right slot at order 11, immediately after the Source Control trigger (order 10). Clicking it opens the backlog-md tab in the native right sidebar. Clicking again when Backlog is active follows Harness's native panel toggle. The panel is registered with keepMounted: true, so closing and reopening it preserves its state.

Filters

The status strip above the list shows a count per status and doubles as the status filter. Search narrows it further; Exclude status, Priority, Milestone, Label, and Assignee live behind the Filters control and combine without reloads. The header shows the filtered count; Clear filters resets everything. Filter, sorting, column visibility, and page size are persisted per workspace in localStorage; no task data is stored there.

Both presentations open in attention order: In Progress first, To Do second, Done last, with the Backlog.md ordinal then natural ID as the tie-breaker inside a status. Clicking a column header overrides that default for the current workspace.

Wide table

Columns: ID, Title (with subtask progress), Status, Priority, Ordinal, Labels, Assignee, Milestone, Created, and row actions. The table has sticky headers, compact rows, hover and focus states, column sorting, row selection (send selected tasks to the composer), expandable subtasks, and configurable column visibility. At narrower panel widths, fixed-layout columns leave the DOM and become available again as the container grows.

Compact list

Below the panel container's 640px breakpoint, the compact list shows the title, ID, subtask progress, status, priority, assignee, and relative creation time. It never requires horizontal scroll. Both presentations read the same TanStack Table instance, so switching widths keeps the same filter, sort, selection, expansion, pagination, and detail handlers.

Task details

Clicking a row drills into details inside the same panel. The header has a back button, task ID, editable title, and actions. Metadata includes status, priority, assignee, labels, milestone, parent task, dependency links, created and updated dates, and the server ownership/source. Content includes the Markdown description source, acceptance criteria, Definition of Done checklist, subtasks, and dependencies. Comments are shown read-only.

The footer shows unsaved state and provides Save/Cancel. The detail view:

  • keeps local edits through background refetches;
  • detects external changes before saving;
  • offers Reload latest or Merge my edits with a per-field explanation;
  • never silently overwrites an external change;
  • confirms archive and permanent deletion.

Send to Chat

The row menu and detail menu include Send to Chat. It identifies the current Harness session, builds a prompt such as:

Implement TASK-20.4 "Wire real-time sync" using its Backlog.md task definition. Follow AGENTS.md,
update task status as work progresses, and verify all acceptance criteria.

and calls the official composer inputActions.setDraft(...). It does not submit. The full prompt is visible and editable before the user sends it.

External agent changes

A coding agent can keep using the Backlog.md CLI or MCP server normally:

  1. The CLI edits the Markdown file.
  2. Backlog.md's ContentStore detects the change.
  3. The Backlog.md server broadcasts a WebSocket notification.
  4. The Host relay receives it and exposes the change scope to the panel.
  5. TanStack Query invalidates the affected task, milestone, task-detail, or config queries.
  6. The panel refetches and rerenders.

Rapid bursts are debounced. A reconnect requests a full resync so missed events are recovered.

Architecture

┌──────────────────────────── DeepSeek Harness ────────────────────────────┐
│                                                                          │
│  React panel (client.js)                  Host plugin (index.js)         │
│  ┌────────────────────────┐   same-origin  ┌──────────────────────────┐  │
│  │ BacklogPanel           │   POST /__dsh/ │ BacklogBridge            │  │
│  │  TanStack Query        │   backlog-md   │  session → workspace     │  │
│  │  TanStack Table        │ ─────────────► │  fixed action allowlist  │  │
│  │  shadcn/ui + Tailwind  │ ◄───────────── │  typed validation        │  │
│  └────────────────────────┘   JSON + long  └──────────┬───────────────┘  │
│             │                       poll              │                  │
│             │                                         ▼                  │
│             │                              ┌──────────────────────────┐  │
│             │                              │ BacklogServerManager     │  │
│             │                              │  one record per realpath │  │
│             │                              │  port allocation         │  │
│             │                              │  health + version gate   │  │
│             │                              │  crash budget + cleanup  │  │
│             │                              └──────────┬───────────────┘  │
│             │                                         │ spawn            │
│             │                                         ▼                  │
│             │                              ┌──────────────────────────┐  │
│             │                              │ backlog browser          │  │
│             │                              │ 127.0.0.1:<dynamic port> │  │
│             │                              └──────────┬───────────────┘  │
│             │                                         │                  │
│             │         WebSocket notifications         │                  │
│             │                              ┌──────────▼───────────────┐  │
│             └──────────────────────────────│ BacklogEventHub          │  │
│                                            │ ring buffer + long poll  │  │
│                                            └──────────────────────────┘  │
└──────────────────────────────────────────────────────────────────────────┘

                    Backlog.md Markdown files (single source of truth)

Host-side workspace resolution

The browser never sends a filesystem path. It sends the active Harness session ID. The Host resolves the Session with ctx.sessions.get, then the working directory with ctx.workingDirectory.get, canonicalizes it with realpath, and walks up to the nearest Backlog.md project (backlog/config.yml, .backlog/config.yml, backlog.config.yml, or backlog.json). The canonical project root is the server-ownership identity.

BacklogServerManager

  • Allocates a free loopback port with net and starts the official CLI:
backlog browser --port <port> --no-open
  • If the CLI selects a different port because of a race, the manager parses the URL it prints and

uses the actual port.

  • Probes GET /api/status and GET /api/version until healthy, validating the reported