Wraps Python virtual environment management commands: reduces the network and permission problems agents hit when managing environments through terminal commands, works across operating systems, and routes installs automatically through mirrors and local proxies. The tools are strictly confined by the granted read/write permissions.
Install
# from npm (prebuilt)
dsh plugin --profile web add dsh-python-env
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:AngelosZou/dsh-python-env
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
English | 中文
Workspace-scoped Python virtual environment management for a DeepSeek Harness project — discover, create, install into, and remove virtual environments without sandbox, network, or subprocess pitfalls.
A DeepSeek Harness plugin that gives one project (workspace) agent-facing Python virtual environment management:
- Five model tools —
pyenv_discover,pyenv_create,pyenv_install,pyenv_uninstall,pyenv_remove— plus thepython-envskill and a system-prompt guidance section. - Runs the standard library
python -m venv/pipthrough the platform subprocess channel (host process) instead of the sandboxed shell, so venv creation,ensurepipbootstrapping, and package-index network access work where shell-side pip fails. - Mirror and proxy fallback — on a network-classified failure, installs retry across PyPI mirrors (TUNA, Aliyun, USTC) and probe common local proxy ports;
index/proxyarguments pin either. - Workspace confinement — every path resolves inside the session workspace (case-insensitive on Windows); caches and temp state live under
<workspace>/.dsh-pyenv/; commands are argv arrays (no shell); the global Python environment, host pip cache, and system temp are never touched. - Cross-platform — Windows / macOS / Linux layouts and interpreter chains (
Scriptsvsbin,py -3vspython3). - No third-party dependency — no uv, no virtualenv, no other plugin. A pip-less environment is repaired offline via
ensurepip. - Session policy parity — the mutating tools consult the session's sandbox policy and refuse to run in read-only sessions; discovery stays available everywhere.
Requirements
- Node.js >= 20
- A DSH profile composed from
@deepseek-ai/dsh-base(it provides thesubprocess,jobs,tools, andskillsservices the plugin uses) - Python >= 3.8 (on PATH, or passed explicitly) — only for the environments the plugin manages
Install
From npm:
dsh plugin --profile web add dsh-python-env
From a local checkout (development):
dsh plugin --profile web add link:<absolute-path-to-this-repo>
Then restart the DSH backend — the host composition loads at process start. The tools appear in new sessions: pyenv_discover, pyenv_create, pyenv_install, pyenv_uninstall, pyenv_remove, plus the python-env skill.
Usage
Agent side:
| Tool | What it does |
|---|---|
pyenv_discover |
Find environments up to two levels deep by the pyvenv.cfg marker or conventional names (.venv, venv, env, .env, virtualenv); report path, interpreter, version, pip availability. |
pyenv_create |
Create an environment with python -m venv — name / root_dir / base python arguments, idempotent on existing environments. |
pyenv_install |
Install packages and/or a requirements file into an environment (explicit venv / discovered / auto-created .venv); repairs missing pip via ensurepip; mirror/proxy fallback; upgrade flag; editable installs of local projects; run_in_background for long installs. |
pyenv_uninstall |
Remove packages from an environment (pip uninstall -y); offline; never auto-creates an environment. |
pyenv_remove |
Delete a real workspace environment only (refuses non-environments and workspace escapes). |
pyenv_create # -> .venv, interpreter path reported
pyenv_install { packages: ["pytest>=8"] } # installs into .venv
pyenv_install { requirements: "requirements.txt" }
pyenv_uninstall { packages: ["pytest"] } # removes packages again
pyenv_discover # inspect every environment
# run code with the reported interpreter:
# Windows: <venv>\Scripts\python.exe macOS/Linux: <venv>/bin/python
Behavior notes:
- The mutating tools (create / install / uninstall / remove) respect the session sandbox mode and refuse to run in read-only sessions; discovery still works.
- Common flows are all covered: pin versions (
"pkg==1.2.3"), upgrade (upgrade: true), install fromrequirements.txt(requirements), and editable installs of local projects (packages: ["-e", "."]— the editable path must stay inside the workspace; remote/VCS editable URLs are rejected). - Without a
venvargument,pyenv_installuses the single discovered environment (preferring.venv), auto-creates.venvwhen none exists, and asks for an explicitvenvwhen several exist. - Background installs register with the jobs registry — poll with
job_output, stop withjob_kill. - Two-minute budget. Every pyenv tool must finish within 2 minutes (discovery within 1). A tool that exceeds its budget terminates the running process tree and returns a detailed stop-reason — what was still running, the attempts tried, the last output, likely causes, and next steps — instead of hanging or reporting a bare timeout. Background installs share the same 2-minute cap; a per-call
timeoutMsoverride on install/uninstall is honored but capped at 120000 ms.
How it works
- Subprocess channel — the DSH shell sandbox blocks CPython's owner-only temp directories (Windows
[Errno 13]duringensurepip/wheel unpacking) and package-index network access. Plugin code runs in the host process, so every python/pip/venv invocation goes throughctx.subprocess(the same channel the graphlint plugin uses) with argv arrays, byte-capped collected output, and tree-scoped termination. The unrestricted token is compensated by the confinement model below — not by weakening the sandbox. - Confinement — every model-influenced path passes
guardWorkspacePath(absolute resolution + containment,..-safe); venv names are single-segment regex-validated and re-guarded afterjoin; children getPIP_CACHE_DIR/ TMP / TEMP / TMPDIR re-pointed into<workspace>/.dsh-pyenv/. - Install attempt chain — default index first; a network-classified failure (connection reset/timeout/DNS — never "No matching distribution found" or TLS errors) falls back across TUNA → Aliyun → USTC mirrors and, once, probes common local proxy ports (7890, 7891, 10809, 10808, 8888) to retry the same index through a live one.
- ensurepip repair —
<venv-python> -m ensurepip --upgradebootstraps pip offline from bundled wheels; when ensurepip itself is absent the error carries the Debian/Ubuntupython3-venvhint. - Concurrency — mutating tools declare
isConcurrencySafe: false, so the scheduler serializes them; discovery stays read-only. - Skill & guidance — the
python-envskill teaches tool-first usage and the "never escalate for pip" rule; one system-prompt section (dsh-python-env:guidance, order 120) reminds every session that the pyenv tools are the sanctioned path.
Project layout
| Path | Purpose |
|---|---|
cordis.patch.yml |
Profile patch layer inserting the dsh-python-env row |
lib/index.js |
Host plugin: registers the five tools, the skill, and the guidance section |
lib/tools/ |
The five model tools (discover / create / install / uninstall / remove) |
lib/guard.js, lib/venv.js, lib/layout.js, lib/paths.js, lib/python.js |
Workspace confinement, venv resolution, discovery, platform layouts, interpreter chains |
lib/runner.js, lib/pip.js, lib/envdir.js |
Subprocess seam, install chain, workspace caches |
test/ |
Runtime-free behavior tests (see Development) |
docs/ |
Design and analysis documents |
Development
No build step: the plugin is plain ESM and the tests run with Node directly
(the mock ctx stands in for the DSH services; the real defineTool validates
every schema):
npm test
# or: node --test --test-isolation=none "test/*.test.js"
See CONTRIBUTING.md for the development loop, including offline dependency resolution.
Compatibility
When DSH also has the dsh-multi-folder plugin installed, the Agent can use the tools provided by dsh-python-env to manage the secondary working directories specified by the user in dsh-multi-folder, even when those working directories are outside the main working directory. Environment management permissions for the secondary working directories are the same as for the main working directory; when the Agent runs in Read Only mode, the tools refuse any operation. This compatibility is automatic and optional — it takes effect automatically whenever both dsh-multi-folder and dsh-python-env are installed in the DSH environment. If dsh-multi-folder is not installed, dsh-python-env's functionality is unaffected. This compatibility introduces no additional performance burden or context overhead.
Security
Installing packages means executing third-party code: pyenv_install (including the auto-created .venv path) downloads and runs code from the configured index with the host user's privileges, and editable installs import in-workspace projects as-is. The plugin mitigates this with HTTPS-only indexes, workspace-only blast radius (a compromised environment is disposable via pyenv_remove), full routing transparency, session policy parity (read-only sessions cannot trigger any of it), and per-profile opt-in. See SECURITY.md for the complete threat model and mitigation list.
Documentation
- docs/design.md — architecture, confinement model, install chain, known limitations
- SECURITY.md — threat model and compensating controls
Contributing
See CONTRIBUTING.md. Issues and pull requests are welcome.
License
Links
More in this category
yjh051108/dsh-routing-suite★ 6993
One repository, three parts: a runtime injector for DSH plugin packages (inject, hot-reload, unload, promote a dev staging tool to the front, route self-heal, plus a settings-page plugin manager that lists, unloads and drags folders in to internalize), a task-aware reasoning-mode router agent preset (router-standard / router-spec / router-react), and a graded two-level task protocol whose six tools (commit_star, lock_stage, revise_do, edit_plan, mark_task, redteam_verdict) pin task state to disk. The injector implementation ships in-tree, so the install carries its own behaviour rather than a dependency list.
strukto-ai/mirage#dsh★ 3672
Swaps the filesystem and bash providers for a mirage virtual workspace: file tools and shell commands run over mounted resources (RAM, S3, Redis, Slack, Gmail, Notion, Postgres) instead of the host disk, with per-mount read/write/exec modes, per-command sandbox routing (monty, pyodide, quickjs in process; docker, e2b, daytona remote), and installed CLIs (git, gh, slack, linear, ntn, gws, or one you register) as head words in the virtual terminal.
hust-open-atom-club/oh-dsh★ 326
Community distribution: TUI, desktop, and Web UI as one bundle with layered installation.
weijiafu14/pi2dsh★ 210
Pi Host ABI compatibility engine: after one install, unmodified Pi extensions from npm mount as native DSH plugins with `dsh plugin add <pi-package>`. Verified end to end on stock DSH with pi-mcp-adapter (full MCP manager: OAuth, resources, prompts, MCP Apps, elicitation, sampling), @tintinweb/pi-subagents, pi-code, pi-hermes-memory and pi-background-tasks; `pi2dsh inspect` reports a package's compatibility before installing.
lire1131/dsh-undo-savepoint★ 169
Undo/redo & rollback system for DSH: every config change is auto-snapshotted; undo/redo/restore to any version from the WebUI or the offline CLI/GUI tools (works even when DSH fails to boot).
Fishquito7/dsh-skill-mcp-panel★ 166
Manages DSH skills and MCP servers from the web settings: skill cards with hot enable/disable, workspace scopes, groups, batch migration and drag-and-drop import, plus stdio/HTTP MCP CRUD with connection tests, secret redaction and the unified dsh-panel CLI.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.