Workbench Development Standard

Version: 2026-10-27 · The website is authoritative; DSH Desktop bundles a copy for offline use.

Official page: https://dshdesktop.com/workbench/docs/development-en/

Markdown source for agents: https://dshdesktop.com/workbench/docs/development-en.md

Six-step quickstart: https://dshdesktop.com/workbench/docs/quickstart-en/ (Markdown). 中文版.

This standard is intended for direct execution by an AI developing a workbench. For local development and personal use, this document is sufficient: build the package under Section 3, install it in the local DSH Desktop, and pass the Section 8 self-test. There is no requirement to publish code or upload anything.

If the author later wants to list the workbench in the Workbench Market, also read the Workbench Market Acceptance Standard. Its separate rules cover a public repository, releases, descriptions, screenshots, and listing PRs.

A workbench is a DSH plugin. It must first be a valid DSH plugin package that dsh plugin add can install and Harness can load. It then registers a business panel with Desktop and follows the rules for workbenches, sessions, and workspaces.

Rule levels are required (failure prevents installation or loading), recommended (strongly advised for usability and future listing), and optional.

1. Execution principles

Standard retrieval order: Before development, actually fetch and read the complete online Markdown above and record its URL and document version; prior knowledge or bundled documents do not count. Use a bundled offline copy only if online retrieval fails, and report the failure reason, offline source, and version. Offline copies are packaged snapshots, may be outdated, and must never silently replace the online standard. If the latest standard conflicts with the running version, explain capability differences and blocked steps; do not override it with an older standard.

Communication with users: Use business language for requirements discovery, layout suggestions, confirmation choices, and installation or completion status, such as “Show the business content on a full page and open AI conversation when needed” or “Talk while viewing supporting information.” Do not ask ordinary users to confirm code fields such as customFrame, register(), repository, dshHomePath, or reconcileLocalProviders, internal identities, or placeholder repository URLs; do not present lengthy implementation details as choices. The Agent handles technical fields during development under this standard. Missing publication identity must not block confirmed local development, and a real repository must never be fabricated. Ask only for practical information affecting the business or installation, such as “Which folder should hold the data?” Explain technical details briefly when the user asks. Lead completion reports with what works, actual operations tested, and items still pending verification; put changed files and technical checks in a short appendix, then end with the usage handoff required below.

After every workbench development handoff, the final response must end with a prominent three-point “What to do next” block, after all change descriptions, self-test results, file links, and technical appendices. Do not leave the reminder only at the beginning, and do not append any content after these three points:

  1. Development result: Use the actual workbench name and state the development and installation status. Say “Developed and installed locally” only when both actually succeeded; if development is incomplete or installation failed, explain the blocker honestly. Do not claim it loaded or all acceptance checks passed.
  2. How to restart: When installation succeeded and a restart is needed, ask the user to wait until the current task finishes, then click “Restart now” in the top banner or choose Harness → Restart Harness; normally only Harness needs restarting, without quitting DSH Desktop. Suggest fully quitting and reopening DSH Desktop only if Harness restart does not load the workbench and troubleshooting confirms this is needed. Do not close or restart the app the user is working in yourself. If no restart is needed or installation is incomplete, say so; do not present restarting as a fix for failed installation.
  3. Where to open it: After restarting, expand the sidebar and use the current name / switch area beside “Workbenches” at the upper left to select the newly created workbench (give its actual name). If missing, go to Workbench Market → Installed, find the entry marked “Local,” and check its running state; switch after it loads or is enabled. The user can try it directly, or optionally return to the original conversation and say “Restart complete” for continued verification; returning to the conversation is not required to use it. If installation is incomplete, state that this entry remains unconfirmed until installation and loading succeed.

Requirements conversation (before code): Discover the workbench through progressive conversation, asking only one necessary question at a time that affects the next step. Reuse the current request and confirmed context; do not repeat information the user already provided. If the name is unknown, first ask “What would you like to call this workbench?” A provisional name is fine and naming must not block implementation. Then fill gaps about the intended users, main functions, or business scenario as needed, without a fixed questionnaire or several questions bundled together. If the user cannot describe the core workflow, suggest a minimal flow based on their answers and ask them to confirm or adjust it; do not require a complete requirements form. Start once the business goal and smallest implementation scope are sufficiently clear and confirmed, without filling every formal field. Generic development instructions, directory names, existing code, or dependencies do not establish intent by themselves. While business intent or implementation scope remains unclear, wait for the current answer. Read-only checks of directories, versions, scripts, and host capabilities are allowed; creating or editing business code, UI, or package files, building, packing, installing, or submitting are not.

Once requirements are clear, read project name, author, version, description, and test commands from the project; ask only for necessary information that cannot be found and affects implementation. A development request does not authorize publication of code, business data, or credentials.

Before development, check:

One-page execution flow

  1. Confirm requirements: Reuse confirmed information and ask only one necessary follow-up at a time. Names may be provisional; suggest and confirm the flow. Start when the business goal and minimal scope are clear, without requiring every field. Generic instructions or a directory alone are not confirmation.
  2. Inspect project: Identify root; run pwd and, for a Git repository, git status --short; inspect code, package manager, uncommitted work, and target Desktop version. Preserve unrelated changes.
  3. Define the smallest business flow and layout: Write down entry point, main action, completion state, and failure recovery. Under Section 4, choose a standard split or customFrame and define the first-use path without a session before choosing host capabilities.
  4. Implement: Create the plugin package and registration under Section 3; follow Sections 4–7 for applicable responsibilities and capabilities.
  5. Verify package: Run pnpm pack; inspect package.json, declared entries, cordis.patch.yml, size, and sensitive files inside the tarball.
  6. Install and test locally: Check installation capabilities under Section 3.6, install that tarball, complete the required restart, and record real UI and loading evidence under Section 8. If the agent runs inside the target DSH Desktop, ask the user to restart it manually under the boundary below.

After building and verifying the archive, the model calls install_local_workbench({ path: "<absolute local .tgz path>", replace: false }) directly. This uses Plugin Manager installBundle; users do not enter paths or operate an installation page. Pass replace: true only for an authorized update of the same workbench. Inspect application: verify the UI for applied; only restart-required calls for restarting Harness. Failed, cancelled and overridden do not mean applied.

Restart boundary inside the target app: Do not close or restart DSH Desktop or Harness yourself or use process probes such as ps or pgrep to manage the restart; ask the user to restart manually. After the user restarts Harness, offer two optional paths: (1) Try it directly: expand the sidebar, click the current workbench name / switch area to the right of “Workbenches” at the upper left, and select the new workbench. If it is missing, check its entry and running state in Workbench Market → Installed, then switch after it loads or is enabled. New local workbenches are added to the switch menu automatically when loaded; there is no separate “Add” button. (2) Continue Agent verification: return to the original development conversation and tell the Agent “Restart complete”; the Agent then follows Section 8 to check loading, the installed list, the switch entry, and the real business UI. Users may try it independently without returning to the conversation. Checks the Agent has not actually performed remain pending verification; installation success does not mean all acceptance checks passed. An Agent outside the target app may follow the normal restart process.

Empty-directory exercise: If the directory is empty and the user only pasted generic development instructions or said “make a workbench,” reuse any context already provided. If the name is unknown, ask only “What would you like to call this workbench?” and allow a provisional name. On the next turn, ask the one business question that most affects implementation, such as “What should it mainly help you do?” If the purpose is already clear, skip that question and suggest a minimal flow for confirmation. Read-only directory and Desktop capability checks are allowed. Until the business goal and scope are sufficiently clear, do not create package files, business code, or pages, or build, install, or submit. A name alone is not a business brief.

2. What a workbench is

A workbench package is simultaneously:

The following identifiers have distinct purposes and must not be conflated:

IdentifierLocationPurpose
npm package namepackage.json nameInstallation, dependency resolution, cordis.patch.yml name:
Plugin entry IDid of an insert row in cordis.patch.ymlLocate that row in the Harness plugin tree
Local workbench identityDerived by the host from the actual client npm package namelocal:<npm package name>, such as local:my-workbench-package or local:@scope/name; shared by sidebar entry and session ownership
Repository workbench identityValid GitHub repository URL, market entry id, and existing attribution recordsLowercase owner/repository; existing identities stay compatible, shared by market card, sidebar entry, and session ownership
Legacy ID for compatibilityOld register({ id }) and catalog workbenchIdMigration of old data only; omit from new packages and submissions

Local development, installation, and use require no GitHub account, repository URL, repository creation, or code upload. Never fill a fabricated or placeholder repository. The host uses actual client package provenance; authors must not supply a local ID manually. Version upgrades and project-directory moves preserve local identity; renaming the npm package creates a new identity. Later market publication does not automatically migrate local sessions or silently replace local identity. Migration must be explicitly designed and confirmed; this standard provides no automatic local-to-market migration.

Desktop lowercases GitHub owner and repository, so https://github.com/Owner/Repo corresponds to owner/repo. A rename or transfer changes workbench identity; migrate existing sessions under the migration rules rather than changing only the URL. The legacy wb-owner-repo is only a compatibility mapping, not a registration ID for new packages.

3. Package format

3.1 Layout

Put one workbench in one package. Typical structure:

package.json          # npm and DSH plugin declaration
cordis.patch.yml      # insert the server entry in the plugin tree
dsh/index.js          # server entry (exports["."])
lib/client.js         # built client entry (exports["./client"])
README.md  LICENSE

3.2 package.json

FieldLevelRequirement
name, versionRequiredNormal npm fields; version is full SemVer such as 1.2.0
"type": "module"RecommendedAll official examples use ES modules
main and exports["."]RequiredPoint to the server entry imported by cordis.patch.yml
dsh.bundle.patchRequiredFor example "dsh": { "bundle": { "patch": "./cordis.patch.yml" } }, relative to package root. Without it, the package is an ordinary dependency and no plugin layer activates
dsh.client.platformRequiredMust be "web", or the client module will not load
dsh.client.injectRequiredString array that must contain dsh-desktop-workbenches so its service loads before the client; list other client packages used. This controls load order, not Cordis service injection
exports["./client"]RequiredA declared dsh.client must export the built client file, or startup fails
dsh.client.externalOptionalList modules (including subpaths) required by the client beyond the shared baseline; do not list itself
exports["./package.json"], exports["./cordis.patch.yml"]RecommendedMatch official packages
filesRecommendedInclude cordis.patch.yml, server entry, and built output
peerDependenciesRecommendedPut official @deepseek-ai/* packages such as @deepseek-ai/cordis and @deepseek-ai/dsh-client-connection here, not in dependencies, to avoid a second copy of host code. Explicitly include prereleases, for example ">=0.1.5-rc.2 <0.2.0-0", or prerelease Harness versions are excluded and installation fails with ERESOLVE
@deepseek-ai/schemasteryRecommendedUsed to define server Config; it is a runtime dependency
license, author, descriptionRecommendedProvide truthful values

Do not rely on undocumented dsh fields such as dsh.client.inline; they are silently ignored.

3.3 cordis.patch.yml

This file is a YAML array. A workbench normally needs one insert:

- insert:
    - id: my-workbench            # plugin entry ID
      name: my-workbench-package  # npm package name, so Node can resolve installed code
      config:
        root: !!js dshHomePath('my-workbench')   # optional business data directory

3.4 Server entry

import Schema from '@deepseek-ai/schemastery'

export const name = 'my-workbench'
export const inject = ['connection']
export const Config = Schema.object({ root: Schema.string().required() })

export function apply(ctx, config) {
  // Register local endpoints under this workbench, e.g. /api/my-workbench/...
}

3.5 Client entry

The client file must be a built single-file module registered through the module loader:

window.__ModuleLoader__.load({
  id: 'my-workbench-package',
  factory: (require) => {
    const React = require('react')
    function BusinessPanel({ service, entry }) { /* business panel */ }
    function apply(ctx) {
      ctx.effect(() => ctx.desktopWorkbenches.register({
        title: 'My Workbench',
        description: 'Describe the problem it solves'
      }, BusinessPanel))
    }
    return { apply, inject: ['desktopWorkbenches'] }
  }
})

3.6 Build and local installation

4. UI boundary

A workbench is a plugin for a specific business scenario. This standard governs its relationship and switching behavior with sessions and workspaces; it does not prescribe a uniform business panel design.

Authors or users may define business panel layout, content, toolbar, and operations. When integrating an existing workbench, reuse its existing UI and business binding flow where possible. A universal top toolbar, session dropdown, business-area collapse control, or “generic chat” button is not required.

4.1 Choose the layout for the primary task

When advising the user, say: “I suggest showing the business content on a full page and opening AI conversation when needed. If talking with AI is your main task, you can talk while viewing supporting information.” Confirm the experience tradeoff only; the Agent implements the APIs and layout parameters below rather than presenting them as confirmation choices.

Do not treat a persistent conversation pane as the default product design for every workbench. Confirm the user's primary task first; when requirements are unclear, suggest a business-first full page or a conversation split and explain the tradeoffs. Omitting customFrame still selects the standard split technically, but authors should choose deliberately rather than inherit that default.

In either layout, make the business UI respond to the actual width of its own container. Window-wide media queries alone do not reflect the space left by the sidebar, split, or embedding. Use container queries or measure the business root; rearrange columns, collapse secondary information, or provide bounded scrolling when space is tight. Long Chinese headings, English identifiers, numbers, and action buttons must stay readable and usable, without single-character vertical wrapping, clipped controls, or page-wide horizontal overflow.

DSH reserves shared entrances for the market, workbench switcher, and settings; the business panel must not cover them. A customFrame (Section 3.5) must stay within the host-assigned main content area. Its root should fill that area using normal flex layout. Internal absolute positioning, maximization, or drag-based repositioning must remain inside the host container's positioning and clipping boundaries, never cover Desktop's left session sidebar. Put the host-provided conversation node into the business layout for native sessions; do not build a second chat UI. Native conversation capabilities and mode switching continue to follow Desktop rules.

Header layout: default and compact

register() accepts headerLayout: 'default' | 'compact'; omission means default and other values fail registration. With the sidebar expanded, the host preserves the existing layout and adds no blank row. It makes only unoccupied pieces of the existing top band (--dsh-frame-top-clearance, normally 48px) draggable, subtracting actual rectangles for controls, menus, iframes and custom data-dsh-no-drag areas. Default mode reserves a separate system-controls row only on macOS outside fullscreen with the sidebar collapsed; business content starts below it regardless of nested header markup. Windows keeps its separate title bar; fullscreen adds no row. Existing providers default to this mode. The host does not infer the first <header> as a toolbar or clear provider-owned heading padding.

Any customFrame: true provider, or a standard split with layout.businessSide: 'left' (embedded is not required), can opt into compact mode:

ctx.desktopWorkbenches.register({
  title: 'Business tool',
  customFrame: true, headerLayout: 'compact'
}, BusinessPanel)
// Exactly one same-document toolbar rendered by BusinessPanel:
React.createElement('header', { 'data-dsh-workbench-toolbar': '' },
  React.createElement('span', null, 'Business tool'),
  React.createElement('button', { onClick: refresh }, 'Refresh'))

Ordinary left splits retain their side and bottom content gutters. Only valid compact mode removes the top gutter and makes the toolbar sticky while content scrolls. Toolbar ancestors must span the content height, without extra top margin/padding or an independent scroll container.

The marked toolbar must be the top row and span the host content width; nested wrappers are supported. For ordinary left splits, the host uses existing blank space above the right conversation without adding a row. For custom frames the toolbar must span the entire custom frame, including the conversation area, rather than only a business subpanel. The host sets minimum row height and leading clearance, makes blank space draggable, and excludes buttons, links, form controls and standard interactive roles. Add data-dsh-no-drag to custom interactions, expanded menus and popovers. data-dsh-compact-toolbar and data-dsh-compact-valid are host-owned internal markers. Do not duplicate system-controls padding or override the entire drag/no-drag policy.

Missing or multiple markers, right-side splits safely fall back to the default row. Iframe documents are outside this protocol: an iframe-based provider may place its unique toolbar in a same-document outer wrapper; marking the whole iframe does not make its contents a draggable toolbar. Reflow by business container width; truncate long titles, move descriptions below the toolbar, and keep actions usable.

Verify both modes with expanded/collapsed sidebar, narrow containers, realistic Chinese/English headings, entering/leaving fullscreen, and no duplicated space or covered controls. Click buttons, edit inputs, open menus and check keyboard focus. Verify actual native window movement from blank space; DOM/CSS checks do not replace native drag acceptance.

Existing-provider migration and compatibility limits

This is an explicit opt-in contract. The host cannot both prevent system controls from overlapping arbitrary legacy DOM and automatically preserve every legacy compact arrangement. Unmigrated providers remain loadable with the safe default layout. Only the collapsed sidebar on macOS outside fullscreen adds the default controls row; expanded layouts retain their original geometry.

Existing providerMigrationBefore migration
Default business heading and descriptionMay omit the declaration; review and remove provider-owned system-controls clearance while keeping normal business paddingOriginal expanded layout; separate row when collapsed
Custom frame or left split that should share the top rowDeclare headerLayout: 'compact', mark exactly one same-document data-dsh-workbench-toolbar, and remove duplicate system-controls clearanceOriginal expanded layout; separate collapsed row, no toolbar inference
Toolbar inside an iframe, right split, or multiple markersMove a single toolbar to a supported same-document position or retain default modeSafe fallback to default mode

Migration uses only the public registration field and toolbar marker, with no provider-name allowlist or semantic-header inference. External maintainers must publish their own migration releases; host updates do not modify installed external packages. Only valid compact declarations remove the host's 18px top gutter in ordinary left splits. Default mode and provider-owned header padding retain their existing values.

5. Workbenches, sessions, and workspaces

6. Using a workbench without a bound session

Open the business panel immediately, even without a session or workspace. Browsing, creating, and choosing business records or projects must not require a pre-existing native session or workspace.

Check whether the current session belongs to this workbench only when an action depends on a session, such as sending an agent request or writing a draft. If unbound, guide the user to create or open a session at that action; do not block unrelated business features.

Provide a clear action such as “New workbench session in this workspace” or “Choose a file location and start a workbench session.” A business record may be created first if it needs no filesystem. Once file storage or DSH workspace creation is required, call the host directory picker first; the user must choose an existing directory or explicitly create one in the system picker. Never silently create a folder in a default location, home directory, current repository, or guessed path. After confirming location, create workspace and session, register ownership, save business association, and populate an opening draft. On cancellation, leave no directory, empty project, workspace, session, or binding. Restore existing business records only from a location the user previously confirmed; if missing, ask for a new selection rather than recreating a same-named directory. On failure, retain retryable state and never silently choose an unrelated workspace.

If the user selects a business record or project before creating the first session, preserve that selection. When opening an existing session, restore its own business mapping first; do not let another session's latest selection overwrite it.

When integrating an existing workbench, retain its project-creation guidance and independent business flow. The user need not manually create a session first; the workbench requests creation or restoration through Desktop, which validates and records ownership. Keep user-written opening drafts for the user to send; preserve them for retry if creation fails or is delayed. Automatically run business flows only in a correctly owned session, never mix them with the opening draft or let a hidden workbench send accidentally.

7. Mode entry and switching

The host supplies one mode switcher at the top of the sidebar. Its button displays only the current mode; the expanded menu switches among “Native sessions” and added workbenches, with “Workbench management” always at the far right. A workbench must not duplicate, cover, or replace these shared entrances. Switching mode changes foreground display and session filtering only; it neither reinstalls a package nor stops background tasks.

“Native sessions” and each workbench are peer modes. Current mode determines visible sessions and new-session ownership:

Explicitly opening an unbound session switches to Native sessions; explicitly opening a bound session with an available owner switches to that workbench. If its owner is removed, uninstalled, or unavailable, treat it as an ordinary session without automatically activating or reinstalling the owner. If the user navigates, switches modes, or removes an owner during asynchronous creation, do not pull the UI back to an old mode, overwrite the later selection, or bind to an invalid owner.

Mode switching must not collapse or expand the left session sidebar automatically; the user controls its state across modes. A workbench session title has a small icon of its owner; an ordinary session does not. The icon indicates ownership and needs an accessible name or tooltip. Buttons, menus, selected states, and focus rings must not clip, overlap, or overflow in collapsed or expanded states.

First entry may show a home page, empty-session state, or initialize a session under workbench conventions, but the business panel must not depend on session initialization. Later entries restore that workbench's most recent session. Navigation and switching must not delete sessions, business records, project files, favorites, or notes.

8. Local self-test checklist

Verify a local package without repository (including a scoped npm package name): after installation and loading, its entry is marked “Local,” appears in the switcher, and opens the business panel. Reloads and version updates preserve identity and session ownership. Verify that registration failures show the package, stage, and reason in Workbench management and clear after a successful reload. Module HTTP 200, successful imports, and passing tests do not replace real UI acceptance.

Check each applicable responsibility after development. “Host responsibility” means observe current Desktop behavior and report issues; plugin authors must not copy host UI. For “only when using this capability,” mark “not applicable” with a reason if unused. Claim local self-test passed only with evidence for all applicable items.

Package and loading

Section 4: UI boundary

Sections 5–6: workspaces and sessions

Section 7: mode switching and preservation

9. Delivery when something fails

Final delivery must list actual results and evidence: changed files, package version, local installation and self-test outcomes, and unverified items. Identify anything missing; never invent success. If the toolchain is missing, installation fails, or host APIs are unavailable, keep completed code, explain why, and state the next step.

References