DeepSeek Harness development container on Arch Linux.
This repository builds a development container for
deepseek-ai/deepseek-harness.
The image uses Arch Linux, installs Node.js, Python, pnpm, and optional
code-server, builds dsh from source, and compiles the node-pty native module
inside the image using only tools available in the image.
- Base image: official Docker
archlinux:latest - pacman mirror: Tsinghua TUNA with Aliyun fallback
- npm/pnpm mirror:
https://registry.npmmirror.com - node-gyp headers mirror:
https://npmmirror.com/mirrors/node - Python package mirror:
https://pypi.tuna.tsinghua.edu.cn/simple - Node.js, npm, pnpm 11.7.0, Python, pip
- Default user
deepseek(uid/gid 1000, home/home/deepseek) with passwordlesssudo - Production dependencies only by default;
DSH_DEV_MODE=truekeeps devDependencies for deepseek-harness plugin development - Multi-stage build:
node-ptyis compiled in a dedicated builder stage; the final image keeps no C/C++ toolchain and no package caches - Rust intentionally not installed: the x86_64 build of
dshdoes not need it, and dropping the Rust toolchain keeps the image noticeably smaller - Full source checkout at
/opt/deepseek-harness, pinned to commit47f943859bef60e4160492346772ded9b24f765a node-ptycompiled in-place and verified with a real PTY smoke test- Optional code-server 4.132.0, served on port
8443
GitHub downloads use
socks5h://host.docker.internal:1080by default. If your local proxy is elsewhere, changeGITHUB_PROXYindocker-compose.ymlor pass--build-arg.
make buildEquivalent plain command:
docker compose buildThe default image installs production dependencies only, so dsh runs from the
prebuilt CLI (apps/cli/lib/bin.js). When you want to develop plugins for
deepseek-harness inside the container (keeping devDependencies such as
TypeScript and tsx so you can build and lint in place):
make build-dev
# or
docker compose build --build-arg DSH_DEV_MODE=trueIf Docker Hub is blocked and archlinux:latest cannot be pulled, import the
base image from the Tsinghua TUNA mirror first:
powershell -ExecutionPolicy Bypass -File scripts/import-archlinux-base.ps1
docker compose buildThe import script uses Python zstandard and WSL to repack the official Arch
bootstrap tarball into a Docker rootfs. Pass -Force if you want to replace an
existing local archlinux:latest.
To disable code-server:
docker compose build --build-arg INSTALL_CODE_SERVER=falsedocker compose up -dThen open:
- DeepSeek Harness Web UI: http://127.0.0.1:3080
- code-server: http://127.0.0.1:8443
The Web UI starts without an API key, but a key is needed when you actually run an agent against DeepSeek's API.
First startup can take a few minutes with no obvious log output while
dshinitializes itswebprofile. Wait fordsh web: http://127.0.0.1:13080indocker compose logs dsh, then open port3080.
Pull the published image and run it directly:
docker pull ghcr.io/cupen/dsh-workbench:latest
docker run -d --name dsh-workbench --init --restart unless-stopped -p 127.0.0.1:3080:3080 -p 127.0.0.1:8443:8443 -v dsh-workbench-home:/home/deepseek -e DEEPSEEK_API_KEY=sk-... ghcr.io/cupen/dsh-workbench:latestThe image does not bake in any API key. DEEPSEEK_API_KEY is only passed when
you actually run an agent; drop the -e line if you are not ready to provide a
key yet.
On the mainland, pull through the domestic GHCR mirror instead:
docker pull ghcr.nju.edu.cn/cupen/dsh-workbench:latestAt container start, the DSH_REGION environment variable switches user-level
mirror configuration:
DSH_REGION=cn: mainland mirrors (npmmirror, Tsinghua pip, node-gyp headers) and GitHub proxysocks5h://host.docker.internal:1080DSH_REGION=global(default): official npm/pypi/node sources and no GitHub proxy
docker run -d --name dsh-workbench --init --restart unless-stopped -p 127.0.0.1:3080:3080 -p 127.0.0.1:8443:8443 -v dsh-workbench-home:/home/deepseek -e DSH_REGION=cn -e DEEPSEEK_API_KEY=sk-... ghcr.io/cupen/dsh-workbench:latestIf your SOCKS proxy port is different, override it:
-e GITHUB_PROXY=socks5h://host.docker.internal:7890Pushes to main and v* tags trigger
.github/workflows/publish-ghcr.yml,
which publishes the image to:
ghcr.io/cupen/dsh-workbench:latestThe workflow runs without the local SOCKS proxy, so it passes
GITHUB_PROXY= explicitly and relies on GitHub runners' direct network access.
docker compose exec dsh bashInside the container:
node --version
python --version
dsh --helpThe repository is at /opt/deepseek-harness. A host directory ./workspace is
mounted at /workspace for scratch work.
node-pty@1.1.0 ships no Linux x64 prebuild. The repository has
patches/node-pty@1.1.0.patch and allowBuilds entries, so pnpm install
runs its source build. The Dockerfile compiles it in a dedicated builder stage
(node-gyp header mirror pointed at npmmirror, gcc/make/pkgconf and Python
installed there), then copies the built workspace into the runtime image.
The runtime image intentionally ships no C/C++ toolchain to stay smaller. To rebuild native modules inside the container, install the toolchain first:
sudo pacman -S gcc make pkgconf pythonThe build loads pty.node and spawns a real /bin/sh PTY to verify the copied
addon works.