DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Add Assets — DSH Plugin for DeepSeek Harness
← Plugins
A

@achasoft/dsh-add-assets

Add Assets

Composer add-assets plate for the DeepSeek Harness Web Client: an options menu on the composer's + button (files, folders, slash commands) and a Claude Code-style draft attachment preview

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:navid-kianfar/dsh-add-assets#8de804548ce06b5509f6d4f3eee2ffa035aba906
READMECompatibilityVersions

Compatibility and provenance

Add Assets is published as @achasoft/dsh-add-assets and currently resolves to version 0.3.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
github
Registry updated
9/15/2026

Versions

0.3.0stable
9/15/2026
0.1.0stable
8/26/2026

Related plugins

Loading related plugins…

Latest
0.3.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
web
License
MIT
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
9/15/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in

Related plugins

More verified plugins in developer-tools.

Web App@deepseek-ai/dsh-web-appThe dsh browser-surface bundle: the web patch layer over dsh-base plus the runtime glue plugin (frontend dist serving, web-surface prompt, bash runtime variables, URL line)Sdk Minimal@deepseek-ai/dsh-sdk-minimalThe standalone minimal SDK profile bundle: JSON-RPC, one DeepSeek adapter, persistent shell, and JSONL sessionsSdk App@deepseek-ai/dsh-sdk-appThe dsh SDK profile bundle: stdio JSON-RPC serving and process lifecycle over dsh-baseSubagent Codex@deepseek-ai/dsh-subagent-codexOne-shot Codex subagent provider over the official app-server protocol

README

@achasoft/dsh-add-assets

A plugin for the DeepSeek Harness (dsh) Web Client. It replaces the composer's + button with a menu for adding files and folders, uploading images, or opening the slash-command menu. Files and folders come from a picker that can browse the project or the whole Host machine. Picked paths go into the draft as inline reference chips. Pending attachments show as cards, and images open in a full-size preview.

The composer with the + menu open, showing Add files, Add folders, Upload from this device, and Slash command with their shortcuts

Features

The + menu

The menu sits at the start of the composer's tool row. While replaceCommandButton is on, the harness's own + is hidden, so the row keeps one +.

RowWhat it doesDefault shortcut (macOS / other)
Add filesOpens the picker in files mode.⌘U / Ctrl+U
Add foldersOpens the picker in folders mode: only directories are listed, and they can be selected.⇧⌘U / Ctrl+Shift+U
Upload from this deviceOpens the browser's file chooser for PNG, JPEG, WebP, and GIF images. The composer validates them the same way it validates paste and drop. Shown only while deviceUpload is on.none
Slash commandOpens the composer's own slash-command menu.⌘/ / Ctrl+/

If neither picker scope is available, the two picker rows are disabled with a note. The same happens to the command row when the harness has no trigger pipeline (@deepseek-ai/dsh-client-ui-input-trigger). The menu is disabled while a message is being submitted.

The picker: Project and This machine

The Add files picker on the Project tab, with two files ticked and the footer reading "2 selected" and "Add 2"

When both scopes are available, tabs at the top of the picker switch between them:

  • Project lists the session's working directory through the harness's file-reference provider (@deepseek-ai/dsh-file-reference-local in the stock web profile). Typing a name at the root searches the whole workspace. Typing a path containing / lists that directory. Paths are workspace-relative.
  • This machine lists the Host filesystem through this plugin's own addAssets.browse endpoint. It opens at the Host account's home directory and shows one level at a time, with directories first. The breadcrumbs run from the filesystem root, and the home directory's crumb is labelled Home. Paths are absolute. The tab is offered only while outsideWorkspace is on.

In either scope, you can type a path into the search field to list that directory. Whatever follows the last separator filters the list. In This machine, /tmp/x lists /tmp filtered by x, and ~/Down lists your home directory filtered by Down. On Windows, only drive-letter paths (C:\Users\) and ~\ are accepted.

The picker on the This machine tab after typing a path: breadcrumbs from / down to the folder, and its folders listed

Your selection is kept when you change directories, filter, or switch tabs. You can collect files from both scopes and add them all in one step. Show hidden reveals dot-prefixed entries.

Key (in the search field)Action
↑ / ↓Move the highlight
EnterFiles mode: open the highlighted folder, or tick the highlighted file. Folders mode: tick the highlighted folder.
→ (caret at end of field)Open the highlighted folder
← (caret at start of field)Go up one level
Cmd+Enter or Ctrl+EnterAdd everything selected
EscClose without adding

During IME composition, Enter, the arrow keys, and Esc are left to the input method.

Reference chips

The composer draft with two file chips and a folder chip placed after some typed text

Each picked path becomes an inline reference chip. The chip shows the basename, with a trailing / for a folder. Its hidden value is the @path mention that the composer's own @ completion would write. Paths containing whitespace are quoted, as in @"My Files/a.txt". When the message is sent, the model receives that mention text. Copying a chip copies it too.

If the harness has no trigger pipeline, there is nothing to turn chips into text on send. In that case the plugin appends the plain @path text to the draft instead.

A path containing a double quote or a control character cannot be written as a mention. Such picks are skipped, and a notice under the + says how many were skipped.

Attachment previews

The attachment row with an image card showing a thumbnail and "PNG · 640×400 · 18KB", a text file card, and a draft with file and folder chips

The plugin takes over the composer's attachment row (conversation.input.attachments):

  • Image cards show a thumbnail, the file name, and a details line with format, pixel size, and byte size. Click a card to open the full-size preview. In the preview, ← and → (or the side buttons) move between images, the trash button removes the current image, and Esc, the close button, or a click on the dimmed backdrop closes it.

    Full-size image preview with the file name, details, a remove button and a close button above the image

  • File cards are for non-image attachments the composer accepts. While a file uploads, the card says so. If the upload fails, click the card to retry.

  • Every card has a remove button.

  • Dragging files over the page shows a drop target. The plugin handles the drop, because the shipped attachment row it replaces used to. If the composer cannot accept files at that moment, the target says so.

Settings card

The Add assets card expanded on Settings > Plugins, showing the Options plate, Browse scope, Shortcuts, and Attachment preview groups

The Add assets card on Settings → Plugins edits every configuration key. Edits are held until you click Save, and Discard drops them. Save stays disabled while a shortcut or number field is invalid. If the harness reports the section as not writable, the card is read-only.

Requirements

  • dsh 0.1.5-rc.2 with the web profile (dsh web). The plugin was built and tested against this release. Its composer integration depends on details of that release, listed under Known limitations.
  • Node.js ^22.19 || >=24 (engines in package.json).
  • pnpm on PATH, which dsh plugin uses to install packages.

The plugin declares @deepseek-ai/cordis, @deepseek-ai/dsh-file-reference, @deepseek-ai/schemastery, and @deepseek-ai/dsh-typert-protocol as peerDependencies. All four ship with the harness. Its browser half asks the harness to inject dsh-api-remotes, dsh-client-locale, dsh-client-ui-conversation, dsh-client-ui-input-trigger, dsh-client-ui-settings, and dsh-client-ui-settings-plugins (the dsh.client.inject field in package.json).

These harness services are optional, and the plugin works without them:

Harness serviceWithout it
File-reference provider (remote.fileReferences)No Project tab. The picker offers This machine only.
Input trigger pipeline (inputTriggers)The Slash command row is disabled, and picks are written as plain @path text instead of chips.
Settings provider (settings)The profile's values are used as they are, and the settings card cannot change them.

Operating systems. POSIX hosts use absolute paths. Windows hosts accept only drive-letter paths: UNC (\\server\share) and drive-less (\foo) paths are refused. The Windows path rules are covered by unit tests only and have not been tried on a live Windows host.

Install

dsh plugin --profile <name> runs the rest of the command as a pnpm command in that profile's directory. After a successful install, it adds any package that declares dsh.bundle to the profile's bundle list:

dsh plugin --profile web add @achasoft/dsh-add-assets

A packed tarball installs the same way:

dsh plugin --profile web add ./achasoft-dsh-add-assets-0.1.0.tgz

Restart dsh web afterwards. To confirm the plugin loaded, dump the composed configuration and look for its layer, # == @achasoft/dsh-add-assets:

dsh --profile web --dump-config

To uninstall:

dsh plugin --profile web remove @achasoft/dsh-add-assets

This also removes the package from the profile's bundle list. If your profile's cordis.patch.yml still has a patch targeting add-assets, the harness warns patch: entry "add-assets" not found and skips it. Delete that patch as well.

How the patch layers

The package's cordis.patch.yml becomes one layer of the profile. It inserts two rows:

Row idnameRole
add-assets@achasoft/dsh-add-assets/hostHost half: the settings section and the addAssets.browse endpoint. Carries the configuration.
add-assets-ui@achasoft/dsh-add-assetsBrowser half. Must stay the bare package name, because the Web Client finds a plugin's browser half by resolving <name>/package.json.

Layers apply in this order: bundle patches in bundle-list order, then $DSH_HOME/profiles/<name>/cordis.patch.yml, then $DSH_HOME/cordis.patch.yml, then any --patch files. To override the configuration, target the row by id in a later layer. A patch replaces the row's whole config, and the schema requires every key, so list all ten:

- id: add-assets
  config:
    replaceCommandButton: true
    deviceUpload: true
    outsideWorkspace: false
    browseMaxEntries: 500
    filesShortcut: mod+u
    foldersShortcut: mod+shift+u
    commandShortcut: alt+/
    pickerResultLimit: 20
    previewDensity: compact
    previewDetails: true

The patch file is a top-level list of patches, as above. Do not wrap it in a patch: key: the harness rejects that with patch: id is required for non-insert patches.

Values from the profile are only starting values. Anything saved from the settings card is stored by the harness settings provider and takes precedence over them.

Configuration

The schema defines no defaults, and a row missing any key fails at load. The defaults below are the values in the shipped cordis.patch.yml. The settings card can edit every key.

KeyDefaultAllowedMeaning
replaceCommandButtontruebooleanHide the harness's own +. With false, both buttons show: the harness's + still opens the slash-command menu, and this plugin's + sits beside it.
deviceUploadtruebooleanShow the Upload from this device row. Paste and drop work either way.
outsideWorkspacetruebooleanOffer the This machine tab. The endpoint checks this value on every call. See Security.
browseMaxEntries500integer 1–2000Most entries the Host returns for one directory level.
filesShortcutmod+ushortcut or ""Opens the picker in files mode.
foldersShortcutmod+shift+ushortcut or ""Opens the picker in folders mode.
commandShortcutmod+/shortcut or ""Opens the slash-command menu.
pickerResultLimit20integer 1–200Rows the picker shows per query. In Project scope the provider applies its own cap, maxResults (default 20), so raise that setting as well.
previewDensitycardcard, compactcard shows a thumbnail, name, and details line. compact shows a small thumbnail and name, with no details line.
previewDetailstruebooleanShow the details line in card density. Upload progress and failures are shown regardless.

Shortcut syntax

  • A shortcut is a +-separated, case-insensitive list of modifiers followed by exactly one key.
  • Modifiers: mod, cmd, command, ctrl, and control all mean the platform accelerator: Command on Apple devices and Ctrl elsewhere. alt and option mean Alt. shift means Shift.
  • Key: a single character, or one of enter, escape/esc, space, tab, backspace, delete, up, down, left, or right.
  • Every shortcut must include mod or alt. Shift alone does not count. Shortcuts listen on the whole page, so a plain-key shortcut would take that key away from every text field.
  • "" turns the shortcut off.
  • The Host refuses an invalid shortcut at load with an error that names the field, and the settings card will not save one.
  • Shortcuts are ignored during IME composition and while a message is being submitted. On macOS, holding Ctrl as well as Command stops a mod shortcut from matching.

RPC endpoints

The Host half registers one Typert Remote endpoint. The browser half mounts it as ctx.remote.addAssets and calls it through the harness gateway on the /api route. The wire format is the harness's own. This endpoint is not meant as a standalone HTTP API.

addAssets.browse(path: string, query: string) → AssetBrowseResult

ParameterMeaning
pathDirectory to list: "" or ~ for the Host home, ~/…, or a fully qualified path.
queryCase-insensitive substring filter on entry names, applied before the entry cap.

On success the result is { ok: true, listing }. listing contains:

  • path: the directory listed.
  • home: the Host account's home directory.
  • crumbs: { name, path } for each directory from the filesystem root down to path.
  • entries: { name, path, kind: 'file' | 'directory', hidden }, directories first, each group sorted by name.
  • truncated: whether the cap cut the level.

Failures are also returned as values, { ok: false, code, message }, with these codes:

codeWhen
disabledoutsideWorkspace is false
not-a-directoryThe path names something other than a directory
unreadableThe path is not fully qualified, does not exist, or cannot be read

The contract lives in generated/, and the types are exported from @achasoft/dsh-add-assets/host.

Security and trust model

  • Authentication. Browse calls use the harness's /api route, which rejects a request with 403 when its Host header is not trusted (loopback, a LAN IP address, or a configured trustedHosts entry) and with 401 when it lacks the browser session cookie. The cookie is issued from the launch token.
  • What browse can see. Any directory the Host process's account can read. It returns entry names, kinds, absolute paths, and the home directory path. It follows symlinks to report what they point to and omits broken ones. Other entry types (sockets, FIFOs, devices) are skipped.
  • What browse does not do. It never opens a file or returns file contents: it only lists directories and stats symlinks. A chip sends the model @path text, not the file. Whether the agent can then read that path depends on the agent's own tools and permissions.
  • outsideWorkspace is a preference, not a security boundary. Anyone using the Web Client can turn it back on from the settings card. The design assumes that person is the authenticated operator, whose agent can already run shell commands on the Host. If some browser users must not see the machine's directory tree, do not install this plugin for them, and do not give them a shell-capable agent either. Setting false in the profile will not stop them.
  • Limits. browseMaxEntries is capped at 2000 by the schema, so a write from the browser cannot raise it. A directory is read as a stream into a sorted window of at most that many entries, so a huge directory costs the Host only the window. At most 8 symlinks are resolved at a time. On Windows, UNC paths are refused, so the Host never connects to a network server named by the browser.

Known limitations

  • Chips are placed at the end of the draft, not at the caret. The slash-command menu also opens at the end of the draft, because the composer in dsh 0.1.5-rc.2 is a rich-text (Lexical) editor whose caret position the plugin does not read.
  • Picks can be dropped silently. If the draft changes while several chips are still being placed (for example, you type during that moment), the remaining picks are abandoned without a notice.
  • Unreferenceable paths are skipped. A path containing " or a control character cannot be written as a mention.
  • Cancelling a listing takes effect only between entries. A read blocked on a hung network mount may not stop when you move on.
  • This machine has no Home button. Once you browse outside your home directory, the breadcrumbs no longer include Home. Type ~ in the search field to go back.
  • This machine filters one level at a time. Only Project scope searches a whole tree.
  • Project scope has its own limits. The provider caps each answer at its maxResults (default 20) without saying it did so, so the picker cannot report the level as truncated. The provider also hides dot entries unless the typed name starts with ., and it skips excluded directories, so Show hidden reveals nothing there.
  • Picker titles say "Add workspace files" and "Add workspace folders" even on the This machine tab.
  • The harness's + is hidden, not replaced. The harness offers no slot for that button. The plugin finds it inside the composer card by button[aria-haspopup="listbox"] and marks it hidden. If a future harness changes that markup, both buttons show.
  • The attachment row replaces the shipped one. The slot renders only its lowest-priority entry, and this plugin registers at priority -1. Another plugin registering there at a lower priority would replace this plugin's row, including its drop handling.
  • The full-size preview does not trap focus. It sets aria-modal and restores focus when it closes, but Tab can reach the page behind it.
  • Windows path handling has not been tried on a live host.

Development

Development needs a sibling ../deepseek-harness checkout, because the link: devDependencies in package.json point into it. The build output (lib/, types/, tsbuild/) is not committed.

CommandWhat it does
npm run buildtsc -p tsconfig.build.json, then tsdown (writes lib/host.js, lib/client.js, and the other entries)
npm testChecks that generated/ matches src/host/ (check:typert), then runs vitest run
npm run check:typertThe Typert freshness check on its own
npm run typechecktsc --noEmit

Run npm run build before npm test. tests/client-bundle.spec.ts renders the built lib/client.js and fails, naming the fix, when that file is missing or older than src/:

npm run build && npm test

generated/ holds the Typert contract for addAssets.browse. Only the harness's generator can produce it, so it is committed. After changing the endpoint or any type it uses, regenerate it:

node scripts/regen-typert.mjs ../deepseek-harness

The script edits files in the harness checkout and restores them from git when it finishes. Never run two regenerations at the same time.

License

MIT. See LICENSE.