Route eligible shell commands through rtk (Rust Token Killer) inside the DeepSeek Harness (
dsh) bash executor — compress tool output, save tokens, change nothing else.
- Quick Example
- Requirements
- Why
- How it works
- Install & enable
- API / Configuration
- Which commands are routed
- Development
- License
The plugin rewrites commands at the resolve() boundary — before anything runs:
Input (command) |
Resolved output | Reason |
|---|---|---|
git status |
rtk git status |
Simple + whitelisted |
cargo build --release |
rtk cargo build --release |
Simple + whitelisted |
git status | grep x |
git status | grep x |
Complex shell — passthrough |
ls -la |
ls -la |
Not whitelisted — passthrough |
git status (rtk absent) |
git status |
Binary missing — identity fallback |
Everything else — workdir, timeout, env, exit code, sandbox confinement — is inherited unchanged.
- Node.js: >= 20.0.0
- rtk:
rtk --versionmust exit 0 on PATH (install separately, e.g.cargo install rtk)
LLM agents burn tokens on verbose tool output (git log, cargo build, pytest trails…). rtk already knows how to shrink those for 30–90%. This plugin bolts that filtering onto dsh's bash executor so every eligible command is auto-routed through rtk — with zero semantic change to what actually runs.
model → dsh bash tool → RtkBashExecutor.resolve()
│
┌───────────────┴────────────────┐
eligible? not eligible
(simple + whitelisted) (complex / unknown)
│ │
rtk <subcommand> … command runs unchanged
(rtk compresses output) (byte-for-byte passthrough)
Three independent guards decide (see src/wrap.ts):
- Complexity — any shell metacharacter (
| & ; < > \$`) disqualifies the command. Wrapping those would silently alter what runs, so they pass through untouched. - Whitelist — only known dev tools that
rtkactually implements are eligible (map inwrap.ts). - Availability — if the
rtkbinary is absent onPATH, the transform is the identity: the deployment behaves exactly like the stock local executor.
The plugin does not bundle or pin rtk. At dsh startup it probes rtk --version on PATH (see resolveRtk() in src/index.ts). Therefore:
- When rtk ships a new release, any user who upgrades
rtkon their machine automatically gets the new behavior — no plugin update required. - The plugin version (this repo) and the rtk version are independent; keep them separate. This README states the minimum rtk version tested against, not a lockstep number.
Requires:
rtkonPATH(rtk --versionexits 0). The plugin does not install or manage rtk — you must install and update rtk yourself (e.g.cargo install rtkor download a release binary). When rtk is absent the plugin is a silent no-op passthrough.
The plugin is verified against dsh 0.2.1-alpha.1 and keeps the 0.1.x line working.
dsh gates the installation of every plugin: @deepseek-ai/dsh-app-boot reads the plugin's
peerDependencies and checks each @deepseek-ai/dsh / @deepseek-ai/dsh-* entry against the
running dsh version with semver.satisfies(runtime, range, { includePrerelease: true }).
A range whose branches cannot admit 0.2.1-alpha.1 — e.g. the 0.1.1 release's
… || >=0.1.1-rc.1 <0.2.0-0 — fails that check, and the plugin manager refuses the install with
is incompatible with dsh 0.2.1-alpha.1 (unless a manual dsh plugin allow-version exact-version
exemption is granted). The marketplace applies the same prerelease-aware reading of engines.dsh
and the host peers.
The ranges shipped now (see peerDependencies in package.json) add an explicit 0.2.x branch:
"@deepseek-ai/dsh-bash-local": ">=0.0.1-rc.1 <0.1.0 || >=0.1.0-rc.1 <0.1.1 || >=0.1.1-rc.1 <0.2.0-0 || >=0.2.0-0 <0.3.0-0"
"@deepseek-ai/dsh-bash-sandbox": ">=0.0.1-rc.1 <0.1.0 || >=0.1.0-rc.1 <0.1.1 || >=0.1.1-rc.1 <0.2.0-0 || >=0.2.0-0 <0.3.0-0"
"@deepseek-ai/dsh-shell": ">=0.0.1-rc.1 <0.1.0 || >=0.1.0-rc.1 <0.1.1 || >=0.1.1-rc.1 <0.2.0-0 || >=0.2.0-0 <0.3.0-0"
The prerelease-branch rule still applies: a broad >=0.0.1-rc.1 <0.3.0 would silently exclude
every 0.1.0-* / 0.1.1-* / 0.2.0-* prerelease under node-semver's default rules (a prerelease
only satisfies a range when some comparator shares its exact major.minor.patch tuple and also
carries a prerelease tag). Because dsh's gate — and the marketplace — evaluate ranges with
includePrerelease: true, those explicit <0.x.0-0 upper bounds are exactly what admit a running
prerelease such as 0.2.1-alpha.1.
package.json also declares the host requirement where discovery tools read it:
"engines": { "node": ">=20.0.0", "dsh": ">=0.1.0-rc.6 <0.2.0 || >=0.2.0-0 <0.3.0-0" }(dsh.plugin.json mirrors the same range for older readers; dsh itself reads package.json.)
All three @deepseek-ai/dsh-* peers stay optional in peerDependenciesMeta, so the plugin still
installs where they are absent (it then behaves as a passthrough). @deepseek-ai/cordis is not a
peer dependency — dsh injects it at runtime; it is only a dev dependency for typechecking.
What the 0.2 port changed. The execution seam is unchanged — the plugin still only overrides
resolve(), and the 0.2 ShellExecSpec merely gains a sandboxPolicy field that is spread through
untouched. The compile-time fixes are the module specifier (cordis → @deepseek-ai/cordis; the
unscoped alias no longer exists) and the executor surface the tests use (run()/start() were
replaced by execute() plus result(); SandboxProvider.confine() is now async and returns
Promise<ConfinedArgv>; SandboxPolicyService now requires ctx.sessionProjections).
Known version skew:
dsh(the aggregate, whatnpx @deepseek-ai/dshinstalls) and its@deepseek-ai/dsh-*sub-packages are on separate semver tracks — the aggregate can be0.1.1-rc.2while the published sub-packages are still0.0.1-rc.1. The ranges above pin to the published sub-package versions but are checked bydshagainst its own version, so every supported release line needs its own explicit branch. Watch the releases for a matching update.
The plugin is disabled by default — installing it does nothing until you opt in.
# 1) from a local checkout
dsh plugin --profile web add "<path-to-this-dir>"
# 2) or directly from the latest GitHub release tarball (no local clone needed)
dsh plugin --profile web add \
"https://github.com/DeepTrial/dsh-bash-rtk/releases/latest/download/dsh-bash-rtk-latest.tgz"
# enable it via an optional overlay — add to your profile's cordis.patch.yml:
# - id: bash-sandbox
# disabled: true
# - id: bash-rtk
# disabled: false
dsh web # restart to applyThe bundled overlay snippet lives in cordis.patch.yml. It swaps the stock sandbox executor for RtkSandboxBashExecutor (file confinement preserved) and leaves the unconfined RtkBashExecutor available for danger-full-access setups.
Both executors accept the same base config as their stock counterparts (LocalBashExecutor / SandboxBashExecutor) plus one optional field:
| Option | Type | Default | Description |
|---|---|---|---|
rtkAvailable |
boolean |
resolveRtk() result |
Force-enable or force-disable rtk wrapping. Useful for tests or deployments where the binary path is non-standard. |
All other options — cwd, timeoutMs, graceMs, etc. — are inherited unchanged from the upstream executors.
The set of commands eligible for rtk-wrapping is defined by rtk itself — see the rtk command reference / README.md for the authoritative, maintained list. This plugin mirrors that list; when rtk adds a new subcommand, upgrade rtk (not this plugin) to pick it up.
Complex commands — pipelines, &&/;, redirects, $( ), env assignments — always run natively regardless of the whitelist.
# 1. clone the plugin
git clone https://github.com/DeepTrial/dsh-bash-rtk.git
# 2. install the released harness packages the plugin builds against
cd dsh-bash-rtk && pnpm install --ignore-scripts
# 3. run checks
pnpm run check # typecheck + test + build
pnpm run test # tests only
pnpm run typecheck # tsc onlydevDependencies pin the published @deepseek-ai/dsh-* / @deepseek-ai/cordis releases the plugin
builds and tests against (currently the 0.2.1-alpha.1 line); no sibling deepseek-harness checkout
is required.
MIT