v0.1.6 changelog (opens in a new tab)MIT · npm · macOS · Linux

One Workspace.
Multiple Roots.

Let a DSH agent read, edit and run commands across several repositories in a single session. The plugin widens the workspace sandbox from one root to a primary root plus N additional roots, and changes nothing else about how the agent works.

  • Native read, write, edit and bash tools
  • Kernel and in-process enforcement
  • Absent when you add no roots
Multi-root Workspace topologyAn agent session uses one scope enforced by an in-process fence and a kernel sandbox. The primary root web and the additional roots api and design-system are granted. The directory Documents is not granted write access.Agent sessioncwd = primary rootread · write · edit · bashWorkspace scopeIn-process fencefile toolsKernel sandboxbash · terminalweb~/code/web · primaryapi~/code/api · additionaldesign-system~/code/design-system~/Documentsno write access
Example topology with illustrative paths. Write access is decided by one scope; a directory outside it is not granted.

The problem

Real projects are several repositories. A session only had one.

DSH treats the session origin as the only writable root. Work that spans a service, its client and a design system meant juggling sessions.

Without the plugin

One session, one writable root

  • A change that spans repositories needs one session per repository.
  • You carry context between sessions by hand.
  • The agent cannot edit the API contract and its client in one turn.

With Multi-root Workspace

One session, a primary root plus N more

  • The agent reads, edits and runs commands across every registered root.
  • Each root keeps its own Git history and its own instruction files.
  • The session working directory does not change; only the writable scope widens.

Features

Wider scope. Same agent.

The plugin answers one question differently: which directories belong to this workspace. Everything built on that answer keeps working.

Multiple roots

A primary root plus as many additional roots as you register

The primary root is the session origin and cannot be removed. Additional roots are canonicalized, checked against the primary root and each other, and kept in an ordered list. Each one can be aliased, reordered, copied or revealed in your file manager.

  • Overlapping or nested roots are rejected at registration
  • A root that disappears or is swapped for a symlink stays listed but is not granted
  • With no additional root, behavior matches an uninstalled harness
Workspace folders dialog: primary working directory web, secondary directories api and design-system, with reorder, reveal and remove actions.
Workspace folders dialog in Rivetdeck (plugin v0.1.5, DSH 0.2.0-rc.2).

Native tools

No new tools to learn

The agent keeps using read, write, edit and bash. The plugin adds no workspace_* tools. It replaces the two sandbox provider rows with subclasses that consult one shared scope, so file tools, bash and the terminal all see the same roots.

  • bash and the PTY keep the primary root as their default working directory
  • Language servers treat each additional root as a separate workspace
  • The additional-root topology reaches the model as part of the sandbox policy context, so it needs no introspection tool
  • Sandbox modes still apply: read-only grants no additional root
  • On DSH 0.2.1 the session can move its working directory — grants and the registry stay keyed to the session origin

Unchanged for the agent

  • read
  • write
  • edit
  • bash
  • terminal

Not added

  • workspace_*

Widened

which directories belong to this workspace?

Workspace management

A command and a panel, one registry

Manage roots from a session with /workspace-folders, or from the Folders dialog at the sidebar foot of the Web GUI. Both go through the same validated registry, persisted per primary root, and both show the true state of every root.

  • Panel authority comes from the live session, never from a client-supplied path
  • Only one process per store may grant roots; a contending process fails closed
  • The dialog also browses an additional root’s files — expandable directories and text previews
  • The panel is bilingual and follows the interface language
session
# list the primary root and the additional roots /workspace-folders# register, name, remove or reveal a root /workspace-folders add ~/code/another-repo /workspace-folders alias 1 payments /workspace-folders reveal 1 /workspace-folders remove 1

Cross-repo workflow

Change an API and its client in one turn

The plugin’s journey test drives a real agent turn across two Git repositories in both the web and headless compositions, using a scripted model endpoint, so it needs no credentials.

  1. 1

    Register

    Add the other repositories to the session’s workspace.

  2. 2

    Ask once

    Describe a change that touches the service and its client.

  3. 3

    Edit across roots

    The agent edits files and runs commands in every granted root.

  4. 4

    Review per repo

    Each repository keeps its own Git state, so changes stay reviewable.

Workspace instructions

Each root’s own AGENTS.md reaches the model

Upstream discovery walks upward from the session directory, so it can never reach an additional root. The plugin adds exactly that missing path, with strict limits.

  • web/AGENTS.mdprimary · upstream discovery
  • api/AGENTS.mdadditional · injected by plugin
  • design-system/CLAUDE.mdadditional · injected by plugin
Example roots.

Accurate limits

  • Covers the top level of each additional root, plus subdirectories the session has successfully read, written or edited.
  • Delivered as a user-context message, never as system authority.
  • One shared byte budget across all additional roots (64 KiB by default).
  • Removing or redirecting a root sends an explicit revocation, because the earlier text is still in the conversation.
  • Delivery state lives in process memory, so after a resume an instruction may be told again.
  • Nested discovery for the primary root stays with upstream.

Security architecture

Widen the grant. Keep the mechanism.

Additional roots are granted by the same mechanisms the harness already uses, not by prompts and not by switching to full access.

Enforcement path of the released plugin (v0.1.6). The numbered controls below list what each part guarantees and what it does not.
  1. 01

    Re-resolving a path is not re-authorizing it

    A registration records the canonical directory it was granted for. The scope grants it only while the path still resolves to that directory; a swapped directory or symlink is reported as redirected and not granted.

  2. 02

    One scope, two enforcers

    The in-process fence and the kernel sandbox consume the same scope. A parity matrix test compares the fence’s write decisions with the paths each kernel profile grants.

  3. 03

    Fail closed

    If the upstream sandbox profile cannot be recognized, the plugin refuses to run the command instead of quietly granting only the primary root. An unsupported DSH release stops the gated rows from starting.

  4. 04

    Modes are inherited

    Read-only grants no additional root. Workspace-write grants the primary root plus the registered roots. Full access is upstream’s decision and bypasses the sandbox.

  5. 05

    One authority per store

    A store-wide kernel lease means only one process grants roots. A contending process publishes an empty scope and rejects changes. Panel requests are tied to a live session, not to a client-supplied path.

  6. 06

    Instructions are context, not authority

    Instruction files from additional roots arrive as user-role context and are recorded in the session log like any other model-visible input.

What this does not claim

  • It is not a new security boundary. It extends the harness sandbox and inherits that sandbox’s guarantees and gaps.
  • Enforcement covers writes. Read access follows the upstream sandbox.
  • On Windows a root-set ACL runner confines bash with a restricted token; it inherits upstream’s partial enforcement and the confined shell is pwsh.
  • Upstream DSH is pre-stable. The plugin depends on internals, which is why support is an exact list of tested releases.

Getting started

Two commands, then add a folder.

The plugin installs through the DSH plugin manager. It is published on npm and works with the web and desktop profiles.

  1. 1

    Install the package

    Run this with a supported DSH runtime. Replace the profile for Electron desktop.

    Recommended. Pre-built artifacts; the first add needs one allowBuilds answer.

    install · npm
    $ dsh plugin --profile web add @dsh-electron/dsh-plugin-multi-root-workspace$ dsh --profile web
  2. 2

    Approve the one-time build step

    The first install stops with ERR_PNPM_IGNORED_BUILDS. The plugin carries one native dependency, koffi, and pnpm 10 and later does not run dependency scripts unless you allow them. Set it to true in that profile’s pnpm-workspace.yaml, then run the install again. This lets that script run on your machine, outside the agent’s sandbox.

    pnpm-workspace.yaml
     allowBuilds:   koffi: true
  3. 3

    Add a folder

    The Folders action appears at the sidebar foot. In a session you can also use the command.

    session
     /workspace-folders add ~/code/another-repo /workspace-folders

    The agent now has the same write rights in that directory as in the session’s own workspace.

Other sources and notes

  • Commands above use the web profile. For Electron desktop, replace --profile web with --profile desktop. GitHub installs need two allowBuilds answers. See the README (opens in a new tab).
  • Running DSH from a source checkout? Use pnpm dsh instead of dsh.
  • The plugin is not bundled with Rivetdeck. It installs separately and appears in the app’s Installed plugins.

Compatibility

An exact list, not a range.

The plugin replaces sandbox providers whose internals carry no semver promise, so it supports exact DSH releases that CI has run — every row below is in the published v0.1.6 package.

DSH releases supported by plugin version 0.1.6
DSH releaseStatusAdded inNotes
0.1.5-rc.2Verifiedv0.1.1Baseline of the compatibility contract.
0.1.6-alpha.1Verifiedv0.1.1Sandbox confinement is asynchronous from this release.
0.1.6-alpha.2Verifiedv0.1.2Same shapes as 0.1.6-alpha.1; panel session lookup fixed.
0.1.7-alpha.1Verifiedv0.1.2Needs adapters: session format 4, in-process plugin packages, bash execute().result().
0.1.7-alpha.2Verifiedv0.1.3Same shapes as 0.1.7-alpha.1.
0.1.7-rc.1Verifiedv0.1.3Install enforces an exact peerDependencies match from this release.
0.1.7-rc.2Verifiedv0.1.4Same shapes as 0.1.7-rc.1.
0.2.0-rc.1Verifiedv0.1.5DSH 0.2 release candidate.
0.2.0-rc.2Verifiedv0.1.5The runtime inside Rivetdeck 0.2.0-beta.2.
0.2.1-alpha.1Verifiedv0.1.6Dynamic working directories; the registry stays keyed to the session origin.
0.2.1-alpha.2Verifiedv0.1.6Development pin of the plugin.
Any other releaseUnsupported—The gated rows do not start; the harness behaves as if the plugin were not installed.

Platforms

  • macOSVerified

    Seatbelt profile plus in-process fence

  • LinuxVerified

    bwrap or Landlock plus in-process fence

  • WindowsVerified

    Root-set ACL runner (restricted token) plus in-process fence; the confined shell is pwsh

Status is declared per release and never inferred from version order. A green CI run on an unlisted release is evidence, not support. Read the compatibility contract (opens in a new tab) for the rules.

Give your agent the whole workspace.

One command to install. No new tools to learn. Remove the roots and it behaves like it was never there.