Creates an isolated Docker-based development environment for any project. Wraps a repo in a scaffolding repo with a Dockerfile and container.sh script for building, running, testing, and shelling into the project. Use when asked to dockerize a dev environment, isolate a project, or set up a container-based workflow.
Creates an isolated, reproducible Docker-based development environment for any project. The approach wraps the target repo inside a "wrapper" repo that contains a Dockerfile and a standardized container.sh script to drive ephemeral containers for building, running, testing, and debugging.
Starting from the directory containing the target project (or where it will be cloned):
<project>-wrapper/<project>-wrapper/
├── <project>/ # the actual project repo (nested, gitignored)
├── Dockerfile
├── container.sh # executable (chmod +x)
├── .gitignore
└── README.md
.gitignore with:<project>/
.cache/
README.md:# <project> wrapper repo
Docker-based dev environment for <project>.
## Usage
./container.sh docker # Build/rebuild the Docker image
./container.sh build # Build the project
./container.sh run # Run the project
./container.sh test # Run tests
./container.sh sh # Open a shell in the container
Scan the project subdirectory to determine:
Build system detection — check for these files (in order of priority):
| File(s) | Language/System | Build Command | Test Command |
|---|---|---|---|
Cargo.toml | Rust | cargo build | cargo test |
package.json | Node.js | npm run build or pnpm build or yarn build | npm test or equivalent |
go.mod | Go | go build ./... | go test ./... |
pyproject.toml, requirements.txt, setup.py | Python | pip install -e . | pytest |
CMakeLists.txt | C/C++ (CMake) | cmake -S . -B build && cmake --build build -j$(nproc) | ctest --test-dir build |
meson.build | C/C++ (Meson) | meson setup build && ninja -C build | meson test -C build |
Makefile (without CMakeLists.txt) | C/C++ (Make) | make -j$(nproc) | make test |
configure.ac | C/C++ (Autotools) | ./autogen.sh && ./configure && make -j$(nproc) | make check |
pom.xml | Java (Maven) | mvn package | mvn test |
build.gradle or build.gradle.kts | Java/Kotlin (Gradle) | ./gradlew build | ./gradlew test |
Gemfile | Ruby | bundle install | bundle exec rake test |
mix.exs | Elixir | mix deps.get && mix compile | mix test |
composer.json | PHP | composer install | vendor/bin/phpunit |
Also read (if they exist, truncate at 4000 chars each):
README*, BUILDING*, CONTRIBUTING*, INSTALL*, DEVELOPMENT*Dockerfile or docker-compose* (to learn what deps the project already knows about)devcontainer.jsonflake.nix, shell.nix (to extract dependency lists)Use this information to determine:
If commands are ambiguous or unclear, use TODO placeholders rather than guessing. The user or a subsequent agent can fill them in.
Package manager detection for Node.js:
pnpm-lock.yaml → use pnpmyarn.lock → use yarnbun.lockb → use bunpackage-lock.json → use npm cinpm installUse reference/Dockerfile.base as the starting template. Rules:
ubuntu:24.04 (preferred) or debian:stable-slimRUN apt update && apt upgrade -yca-certificates, curl, git, build-essential, pkg-configRust:
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"
Node.js (via NodeSource):
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - \
&& apt install -y nodejs
# If pnpm: RUN npm install -g pnpm
# If yarn: RUN npm install -g yarn
Python:
RUN apt install -y python3 python3-venv python3-pip
Go:
RUN curl -fsSL https://go.dev/dl/go1.23.0.linux-amd64.tar.gz | tar -C /usr/local -xzf -
ENV PATH="/usr/local/go/bin:/root/go/bin:${PATH}"
(Adjust version based on go.mod if version is specified)
C/C++ (CMake):
RUN apt install -y cmake ninja-build
Java:
RUN apt install -y openjdk-17-jdk
ENTRYPOINT, CMD, WORKDIR, or USER directivesrm -rf /var/lib/apt/lists/*RUN layers for clarity (one per logical group)Use reference/container.sh.generic as the starting template. Customize it for the detected project:
Required substitutions:
__PROJECT_DIR__: name of the project subdirectory__IMAGE_NAME__: <project>-dev (lowercase, hyphens only)__CONTAINER_HOSTNAME__: <project>-dev-container__BUILD_CMD_PLACEHOLDER__: actual build command__TEST_CMD_PLACEHOLDER__: actual test command__RUN_CMD_PLACEHOLDER__: actual run command (or TODO)__ENV_SETUP_PLACEHOLDER__: any env setup needed before commands (e.g., . "$HOME/.cargo/env" for Rust, source /app/.venv/bin/activate for Python venvs)Cache directory mounts (__CACHE_DIRS_PLACEHOLDER__ and __MOUNT_PLACEHOLDER__):
| Language | Host Dir (in wrapper) | Container Mount |
|---|---|---|
| Rust | .cache/cargo | /root/.cargo |
| Rust (target) | .cache/target | /app/target |
| Node (npm) | .cache/npm | /root/.npm |
| Node (pnpm) | .cache/pnpm | /root/.local/share/pnpm/store |
| Python (pip) | .cache/pip | /root/.cache/pip |
| Python (venv) | .cache/venv | /app/.venv |
| Go (pkg) | .cache/go-pkg | /root/go/pkg |
| Go (build) | .cache/go-build | /root/.cache/go-build |
| C/C++ (ccache) | .cache/ccache | /root/.ccache |
| C/C++ (vcpkg) | .cache/vcpkg | /root/.vcpkg |
| Java (maven) | .cache/m2 | /root/.m2 |
| Java (gradle) | .cache/gradle | /root/.gradle |
Port forwarding (__PORT_PLACEHOLDER__):
-p 3000:3000 (or whatever port docs specify)The script MUST:
set -euo pipefailensure_cache_dirs)--rm -it for ephemeral interactive containers--cap-add=SYS_PTRACE for debugging supportbash -c and prepend any env setupchmod +x)After generating all files:
git add all wrapper files (Dockerfile, container.sh, .gitignore, README.md)auto: add Dockerfile + container.shRun these checks:
./container.sh docker — confirm the Docker image builds successfully./container.sh sh — confirm a shell opens in the container with the project mounted at /app./container.sh build — attempt to build (may need manual fixes)If the image build fails, read the error output and fix the Dockerfile (usually missing apt packages). Iterate until the image builds.
Multiple languages in one repo (monorepo):
Projects with existing Dockerfile/docker-compose:
GUI applications (need display forwarding):
WAYLAND_DISPLAY, XDG_RUNTIME_DIR, mount the Wayland socketDISPLAY, mount /tmp/.X11-unix/dev/dri/renderD*Projects needing services (databases, etc.):
After applying this skill, verify:
.gitignore ignores the project subdirectory and .cache/ENTRYPOINT, CMD, WORKDIR, or USERcontainer.sh is executable and implements all 5 commands (docker, build, run, test, sh)./container.sh sh opens a shell with project at /app