Upstream PR material: subagent worktree automatic isolation
August 14, 2026 · View on GitHub
dsh-worktree ships everything needed for manual and programmatic isolation.
The one-liner model experience — subagent(prompt: ..., worktree: true) creating
an isolated worktree per child run and cleaning it up afterwards — requires a
small upstream capability in the DeepSeek Harness core. This file collects the
exact changes; they are already implemented and tested in-tree
(456 tests, 33 worktree/subagent-specific) and can be lifted into a PR as-is.
The changes
1. packages/subagent/subagent/src/types.ts — optional cwd on the start request
Add to SubagentStartRequest (after persona):
/**
* Optional absolute working-directory override for the child session.
* In-process backends stamp it as the child's durable `header.cwd` instead of
* inheriting the parent's; out-of-process backends ignore it (see the
* `dsh-worktree` Known Limitations). A relative value rejects the start.
*/
readonly cwd?: string
2. packages/subagent/subagent/src/child-agent.ts — cwd override in session meta
childSessionMeta(parent, childDepth, lineageSeedLength, cwdOverride?):
export function childSessionMeta(
parent: Agent,
childDepth: number,
lineageSeedLength: number,
cwdOverride?: string,
): NonNullable<CreateAgentOptions['meta']> {
const parentHeader = parent.session.header
const agentPreset = parent.ctx.get('agentPresets')?.composedPreset(parent.ctx)
if (cwdOverride !== undefined && !isAbsolute(cwdOverride)) {
throw new Error(`subagent cwd override must be an absolute path, got "${cwdOverride}"`)
}
const cwd = cwdOverride ?? parentHeader.cwd
return {
...cwd !== undefined ? { cwd } : {},
...
}
}
(import { isAbsolute } from 'node:path' added.)
3. packages/subagent/subagent-in-process-driver/src/index.ts — pass the override
meta: childSessionMeta(parent, childDepth, activationBoundary, request.cwd),
4. packages/subagent/tool-subagent/src/index.ts — the model-facing parameter
- New optional parameter
worktree: { oneOf: [{ type: 'boolean' }, { type: 'string' }] }(true → auto slugagent-<7 hex>; string → that slug). - In
execute, before building the request: resolvectx.get('worktree')(optional service), reject the combination withbackgroundMode: continuable, acquire the lease from the parent'ssession.header.cwd, and stamprequest.cwd = lease.entry.path. - Prefix the child prompt with a
<worktree-context>notice (worktree path + branch, path-translation and re-read instructions). - After settlement:
lease.release()— a clean worktree is removed; a dirty one is kept and its path/branch appended to the tool result text ([Worktree kept at <path>, branch <branch>]). Background one-shot runs release inside the job producer's completion path.
Suggested PR structure
- PR 1 (core capability): changes 1–3 + the
child-agent-cwd.spec.tstests. - PR 2 (consumer): change 4 + the
tool-subagent/tests/worktree.spec.tstests, plus thedsh-worktreeplugin repo linked from the description.
Both PRs keep the default behavior byte-identical: without cwd/worktree,
child composition is unchanged (the regression suites prove it).