Tools & Capabilities

dsh-subagent-cwd

lynx-gt/dsh-subagent-cwd · ★ 2

lynx-gtCurated

Extends dsh-subagent-tools with a per-call cwd for subagents, shipped with the two in-process provider patches it requires.

License
MIT
Added
2026-08-14
Maintenance
active
Install kind
github
Manifest details
Manifest status
Declared
Manifest path
package.json#dsh
Manifest checked
2026-08-19
Lifecycle scripts
None found

Static manifest checks report declarations only; they are not compatibility or security review.

安装

dsh plugin --profile web add github:lynx-gt/dsh-subagent-cwd

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

For install and environment setup, plus plugin development tutorials, see DSH community docs ↗

README

Source README · body: en · Read Chinese README

Table of contents
  1. Choose one of the two packages — not both
  2. Why cwd needs patches (and the other features don't)
  3. persona × preset coexistence (patch v2)
  4. ⚠️ Limitation: persona is lost under router-style presets
  5. Installation
  6. Web sessions need the preset adapter
  7. Upgrading dsh
  8. Uninstall
  9. Example
  10. Design
  11. Verified
  12. Limitations
  13. License

Enhanced subagent delegation tools for DeepSeek Harness (dsh) with per-call working-directory control.

Everything in dsh-subagent-tools (per-call model / provider / persona / toolFilter overrides, @preset: references, provider/model composite ids) plus a per-call cwd parameter — shipped with the two small provider patches that make cwd actually work.

| English | 中文 |

Choose one of the two packages — not both

Package Per-call model/provider/persona/toolFilter @preset: cwd Patches
dsh-subagent-tools ✅ ✅ ❌ none (bundle only)
dsh-subagent-cwd (this) ✅ ✅ ✅ 2 provider patches

Install either one. Both expose the same tool surface (subagent / subagent_fork) and colliding installations would fight over the tool names.

Why cwd needs patches (and the other features don't)

SubagentStartRequest has no cwd field, and the in-process drive layer builds child session meta purely from childSessionMeta(parent, ...) — a per-call cwd is never forwarded. Two code paths create in-process children, and both must be patched or you hit the classic trap where the foreground path honors cwd while the background path silently ignores it:

Path Package to patch File
Foreground (one-shot) @deepseek-ai/dsh-subagent-in-process-driver lib/index.js
Background (continuable) @deepseek-ai/dsh-subagent lib/index.js (the BUNDLE — not lib/types/continuation.js!)

The second one is a bundle trap: package.json main/exports point at lib/index.js, which contains an inline copy of the continuation manager. Patching the source-shaped lib/types/continuation.js has no effect — always patch and verify the bundle.

persona × preset coexistence (patch v2)

When preset and persona are given TOGETHER (e.g. subagent(preset: "@preset:router-standard", persona: "@preset:翻译员")), the old patch registered the per-call persona as the deployment:persona section, which router-style presets then deleted by name on every assemble (applyPersona strips every section whose name matches /persona/i) — the role persona was silently lost.

Patch v2 (install.ps1 hunk 3 / hunk 5, three-state: raw / old-patch / new-patch all upgrade) instead:

  • skips the deployment:persona registration when preset AND persona are both given;
  • registers the per-call persona AFTER recompose as delegation:role (order 1, no "persona" in the name), which the router's filter cannot reach — so the preset's own reasoning persona and the delegated role persona COEXIST.

Passing only persona (no preset) keeps the old behavior: plain deployment:persona shadowing.

The patch v2 hunks (3–5) are currently implemented only in install.ps1 (Windows). The POSIX install.sh preset hunks will be added in a follow-up; on Linux the preset parameter is accepted but does not recompose until that lands.

⚠️ Limitation: persona is lost under router-style presets

Even with patch v2 in place, when a subagent/member uses a router-style preset (e.g. @preset:dsh-router-standard), the per-call persona still does NOT reach the system prompt. This is a mechanism-level behavior of router-style presets: their system-prompt/assemble hook deletes every section whose name matches /persona/i and injects the preset's own dynamic persona. As a result only the preset's built-in dynamic persona takes effect; your custom role persona is silently dropped.

Workarounds:

  • a) Use a non-router-style preset (e.g. standard) so the persona parameter is honored;
  • b) Inject the role definition through the message layer instead (first-turn prompt prefix / task-message prefix, e.g. the stitching mechanism used by agent-teams), which does not depend on cwd;
  • c) Or accept that the persona parameter is a no-op under router-style presets (the preset's own dynamic persona takes over).

Installation

# 1. install the plugin (npm / git / local)
dsh plugin --profile web add dsh-subagent-cwd

# 2. apply the two provider patches (required for `cwd`)
powershell -ExecutionPolicy Bypass -File patches\install.ps1    # Windows
# or: ./patches/install.sh                                       # POSIX

# 3. Web sessions: also run the preset adapter (see below)
powershell -ExecutionPolicy Bypass -File install-preset.ps1     # Windows
# or: ./install-preset.sh                                       # POSIX

Restart dsh --profile web and start a NEW session.

Web sessions need the preset adapter

In the web profile, agent tools are provided by the mounted agent preset (the default standard preset composes subagent / subagent_fork pointing at @deepseek-ai/dsh-tool-subagent), not by the host plane — a bundle patch is invisible to Web sessions. install-preset.ps1 / install-preset.sh copies standard to $DSH_HOME/.agent-presets/standard-plus, rewrites its delegation rows to point at this package, and switches the default preset. Presets are read at session creation, so you must start a NEW session (live sessions cannot switch). Revert: pick standard in the UI (General > Agent preset) and delete standard-plus.

headless and other non-web profiles do not need the preset adapter.

Upgrading dsh

A dsh upgrade rewrites node_modules and wipes both patches. After every upgrade:

# re-run the installer (it is idempotent; it also detects version-mismatched anchors)
powershell -ExecutionPolicy Bypass -File patches\install.ps1

If the installer reports "anchor not found", the target packages changed shape — check for a new dsh-subagent-cwd release or file an issue.

Uninstall

powershell -ExecutionPolicy Bypass -File patches\uninstall.ps1   # Windows
# or: ./patches/uninstall.sh                                     # POSIX
dsh plugin --profile web remove dsh-subagent-cwd

Example

Let a subagent work in a directory without the repo's AGENTS.md injected:
  subagent(description="Summarize this file", prompt="...", cwd="D:\\projects\\scratch\\notes")

Design

  • The tool surface is a bundle. The shipped tool-subagent / tool-subagent-fork rows are disabled and replaced by this package's rows; no official package file is modified for the tool surface itself.
  • cwd is the one capability that cannot stay a bundle-only feature. SubagentStartRequest has no cwd field, so a per-call cwd must be forwarded by the in-process subagent providers. That needs the two small patches (one hunk each) in patches/ — idempotent, backed up on first run, and node --check-verified. This is the entire reason this package exists separately from dsh-subagent-tools.
  • Version contract: peerDependencies pin the public dsh packages (0.1.1-rc.1). The patches target the same version; a dsh upgrade rewrites the dsh installation's node_modules and wipes both patches — re-run patches/install.ps1 / install.sh after every upgrade (see Upgrading dsh). The bundle itself lives in the profile's own node_modules and survives an upgrade, but a changed public API will make peerDependencies refuse to load.

Verified

Tested against a stock dsh 0.1.1-rc.1 install on Windows (headless + web):

  • Everything dsh-subagent-tools verifies (per-call model/provider/persona/ toolFilter, @preset:, presetHints) ✅
  • cwd on the foreground path ✅ — the child's pwd and its sandbox workspace both switch to the requested directory
  • cwd on the continuable (background) path ✅ — background children honor the same directory (the classic "foreground works, background silently ignores cwd" trap does not occur)
  • toolFilter scoping ✅
  • patches/install.ps1 and patches/uninstall.ps1 round-trip ✅ (backup, apply, node --check, restore, re-verify)

Limitations

  • Patches target rc.1 (0.1.1-rc.1). The two patches match exact anchors in the rc.1 official sources; if a future dsh upgrade moves the anchors, re-run patches/install.ps1 — "anchor not found" means the patches need a new adaptation. Since rc.1, the official driver natively consumes per-call persona / toolFilter (applyChildComposition reads request.persona); the patches only cover what the official code still lacks: per-call cwd forwarding and per-call preset recompose.
  • @preset: depends on the local preset layout — same caveat as dsh-subagent-tools.
  • Web sessions need the preset adapter (install-preset.ps1) for the same reason as dsh-subagent-tools.

License

MIT