dsh-python-env
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.
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
dsh-multi-folder (optional, zero dependency) — when the dsh-multi-folder plugin is also installed, its configured secondary working directories automatically become valid roots for every pyenv_* tool: environments there can be discovered, created, installed into, uninstalled from, and removed under the same session mode multi-folder's interception grants (workspace-write sessions can write, read-only sessions are still refused by the policy gate). The integration is a silent capability probe — without multi-folder nothing changes: no extra context, no dependency, no user-visible difference.
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.
No comments yet. Be the first to write one.