# Conflicts: # docs/config-catalog.md # docs/cordis-catalog/services.md # docs/core-data-structures/bash.md # docs/core-data-structures/core.md # docs/event-producer-consumer.md # docs/module-graph.md # docs/tool-catalog.md # examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl # examples/acp-agent/tests/snapshots/code-mode-turn/session.jsonl # examples/acp-agent/tests/snapshots/text-turn/session.jsonl # packages/README.md # packages/bash/README.md # packages/bash/bash-local/src/index.ts # packages/bash/bash/README.md # packages/bash/bash/package.json # packages/bash/bash/src/index.ts # packages/bash/bash/src/types.ts # packages/bash/bash/tests/service.spec.ts # packages/bash/bash/tsconfig.json # packages/bash/tool-bash/README.md # packages/bash/tool-bash/src/index.ts # packages/bash/tool-bash/tests/tools.spec.ts # packages/bash/tool-bash/tsconfig.json # packages/cordis/tool-cordis/src/api-catalog.ts # packages/core/agent-core/README.md # packages/core/agent-core/package.json # packages/core/agent-core/src/index.ts # packages/core/agent-core/tests/agent-core.spec.ts # packages/core/tools/tests/gen-tool-catalog.spec.ts # packages/hooks/hook-protocol/tests/runner.spec.ts # packages/ui/acp-agent/tests/acp-agent.spec.ts # packages/ui/stdio-agent/tests/stdio-agent.spec.ts # pnpm-lock.yaml # scripts/doc-budgets.manifest.json # scripts/gen-tool-catalog.ts
@deepseek-ai/dsh-bash-sandbox
Sandbox-consuming implementation of the @deepseek-ai/dsh-bash executor seam. Load it instead of @deepseek-ai/dsh-bash-local, together with a ctx.sandbox provider (e.g. @deepseek-ai/dsh-sandbox-local) — the model-facing tool layer (dsh-tool-bash) is untouched; that swap is exactly what the seams exist for.
Every command is confined by handing the provider the exact ['bash', '-c', command] argv this executor is about to spawn and spawning the returned (wrapped) argv instead. WHICH platform runner confines it — and whether one is usable at all (fail closed with a structured SANDBOX_UNAVAILABLE error, never a silent unconfined run) — is the provider's concern; this package owns the bash side only.
| Mode | File effects |
|---|---|
read-only (default) |
No writes anywhere (of /dev, only the /dev/null node is writable, so >/dev/null keeps working) |
workspace-write |
Writes only under workspaceRoot + /tmp (ephemeral under bwrap, the host /tmp under Landlock, /private/tmp plus the per-user temp dir under Seatbelt) |
danger-full-access |
No confinement; the provider is never consulted. Foreground results carry sandbox: { mode, denied: false }; background process handles carry no sandbox facts. |
Semantics:
- Denials are result facts. A failed run whose stderr carries the selected backend's own denial dialect — the signatures the provider stamps on every wrap (EROFS text under bwrap, EACCES under Landlock, EPERM under Seatbelt) — is reported as
BashRunResult.sandbox.denied: true(conservative classification, read from the collected stderr tail); every CONFINED run also carries the mode it executed under (result.sandbox.mode) and the provider's enforcement completeness (result.sandbox.enforcement:full, orpartialon an older Landlock ABI). - Runner failures are sandbox failures, never command failures. Foreground execution throws
SANDBOX_UNAVAILABLE; a settled background process stampsprocess.sandbox.runnerFailed, which the bash producer renders through generictask_output. - Config-time default, per-call policy. The DEFAULT mode is fixed by this entry's config for the executor's lifetime;
resolve()stamps it onto every spec, and an explicit request-levelsandboxModeoverride — set by the tool layer only for a call whose wider mode a human granted throughctx.approval(the sandbox RFC § Escalation) — makes THAT call run, classify, and report under its own mode while every neighbor keeps the default (background facts are stamped per task at settle). The capability factctx.bash.sandboxModereports the configured default so the tool layer advertises escalation only when this executor is mounted. The model learns of the sandbox only through result facts — the static bash tool description explains the denial marker; there is no current-mode statement in the system prompt. - File effects only. Network and process visibility are deliberately not restricted — the mode vocabulary does not pretend to cover what the backend does not enforce.
- Process mechanics (spawn, process-group kills, output collection/spill, background handles, credential scrub) are inherited from
dsh-bash-local; runner selection lives indsh-sandbox-local.
Deny-only at the seam: a denial is a reported fact, and this executor never negotiates permissions itself — the approval question lives in the tool layer (dsh-tool-bash), which drives the override this package honors.
- id: sandbox
name: '@deepseek-ai/dsh-sandbox-local'
- id: bash
name: '@deepseek-ai/dsh-bash-sandbox'
config:
mode: read-only
workspaceRoot: !!js process.cwd()
The keyless consumer-integration proofs are tests/bwrap.e2e.ts, tests/landlock.e2e.ts, and tests/seatbelt.e2e.ts (the real provider + real runner driven through ctx.bash, world-verified, each self-skipping where its runner is absent); see examples/sandbox-acp-agent for the runnable demo.