Docker dev environment
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.From its SKILL.md
npx -y skills add gotlougit/skills --skill docker-dev-environmentAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
10.2 KB, ~2.7k tokens by cl100k_base, as published. Nobody here has run it
Docker Dev Environment
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.
Why This Approach
- Isolation: transitive dependencies cannot access the host system beyond the mounted project directory
- Reproducibility: all build deps are captured in a Dockerfile, version-controlled in the wrapper repo
- Independence: the wrapper is separate from the upstream project; customizations don't pollute the original repo
- Simplicity: requires only Docker and bash knowledge; no exotic tooling
Workflow
Step 1: Create the Wrapper Repo Structure
Starting from the directory containing the target project (or where it will be cloned):
- Determine the project name (from directory name or git remote URL)
- Create a wrapper directory named
<project>-wrapper/ - If the project is already cloned elsewhere, instruct the user to clone/move it into the wrapper as a subdirectory. If a git URL is provided, clone it into the wrapper.
- The final structure MUST be:
<project>-wrapper/
├── <project>/ # the actual project repo (nested, gitignored)
├── Dockerfile
├── container.sh # executable (chmod +x)
├── .gitignore
└── README.md
- Create
.gitignorewith:
<project>/
.cache/
- Create a short
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
- Initialize git in the wrapper directory and make an initial commit with the README and .gitignore.
Step 2: Analyze the Project
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*- Any existing
Dockerfileordocker-compose*(to learn what deps the project already knows about) - Any
devcontainer.json flake.nix,shell.nix(to extract dependency lists)
Use this information to determine:
- Exact build, test, and run commands
- Required OS packages (apt)
- Required toolchain versions
- Language-specific cache directories
- Any ports that need forwarding
- Any environment variables required
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→ usepnpmyarn.lock→ useyarnbun.lockb→ usebunpackage-lock.json→ usenpm ci- Otherwise → use
npm install
Step 3: Generate the Dockerfile
Use reference/Dockerfile.base as the starting template. Rules:
- Base image:
ubuntu:24.04(preferred) ordebian:stable-slim - First layer:
RUN apt update && apt upgrade -y - Common essentials:
ca-certificates,curl,git,build-essential,pkg-config - Language toolchains (install ONLY what the project needs):
Rust:
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
- NO
ENTRYPOINT,CMD,WORKDIR, orUSERdirectives - Clean apt cache in the final layer:
rm -rf /var/lib/apt/lists/* - Add project-specific packages identified from docs/lockfiles
- Use separate
RUNlayers for clarity (one per logical group)
Step 4: Generate container.sh
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/activatefor 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__):
- Web projects:
-p 3000:3000(or whatever port docs specify) - Only add if the project serves HTTP or has a UI
The script MUST:
- Use
set -euo pipefail - Create cache directories if they don't exist (in
ensure_cache_dirs) - Use
--rm -itfor ephemeral interactive containers - Use
--cap-add=SYS_PTRACEfor debugging support - Warn (not error) if rootful Docker is detected
- Set container hostname
- Run all commands with
bash -cand prepend any env setup - Be marked executable (
chmod +x)
Step 5: Commit the Wrapper
After generating all files:
git addall wrapper files (Dockerfile, container.sh, .gitignore, README.md)- Commit with message:
auto: add Dockerfile + container.sh
Step 6: Verify
Run 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.
Handling Special Cases
Multiple languages in one repo (monorepo):
- Identify the primary language from docs or the root build file
- Install all detected toolchains in the Dockerfile
- Set build/test/run to the primary language's commands
- Add TODO comments for secondary language commands
Projects with existing Dockerfile/docker-compose:
- Read them to extract dependency information
- Do NOT reuse them as-is; generate a fresh dev-focused Dockerfile
- The existing Dockerfile is likely for production, not development
GUI applications (need display forwarding):
- Add Wayland/X11 socket passthrough only if the project is a GUI app
- For Wayland: pass
WAYLAND_DISPLAY,XDG_RUNTIME_DIR, mount the Wayland socket - For X11: pass
DISPLAY, mount/tmp/.X11-unix - Mount GPU render nodes:
/dev/dri/renderD* - This is advanced; add TODO comments and let the user customize
Projects needing services (databases, etc.):
- Out of scope for the basic wrapper
- Add a TODO comment in container.sh suggesting docker-compose for multi-service setups
Done Checklist
After applying this skill, verify:
- Wrapper directory exists with correct structure
-
.gitignoreignores the project subdirectory and.cache/ - Dockerfile installs only detected dependencies (no kitchen sink)
- Dockerfile has NO
ENTRYPOINT,CMD,WORKDIR, orUSER -
container.shis executable and implements all 5 commands (docker, build, run, test, sh) - Cache directories are mounted for the detected language
- Wrapper repo has an initial git commit
- Docker image builds successfully
-
./container.sh shopens a shell with project at/app
What ships with it: 2 files
3.6 KB alongside SKILL.md
reference/
- container.sh.generic3.4 KB
- Dockerfile.base237 B
Gives 0 of the 12 instructions most containers cloud skills give in ~2.7k tokens
Counted across 607 of the 657 authors here whose files we hold, read 2026-08-07
- Run containers as a non-root userin 66 of 607, across 46 files
- Use multi-stage buildsin 53 of 607, across 44 files
- Use Promise.all for independent operationsin 47 of 607, across 13 files
- Import directly instead of barrel filesin 46 of 607, across 12 files
- Use ternary instead of AND for conditionalsin 45 of 607, across 12 files
- Use Set or Map for O(1) lookupsin 42 of 607, across 10 files
- Create a .dockerignore filein 41 of 607, across 31 files
- Read individual rule files for detailsin 39 of 607, across 9 files
- Copy dependency files before source codein 36 of 607, across 23 files
- Authenticate server actions like API routesin 35 of 607, across 7 files
- Use next/dynamic for heavy componentsin 34 of 607, across 9 files
- Use React.cache for per-request deduplicationin 34 of 607, across 10 files
Said here and by no other author read
- create a wrapper directory around the target project
- gitignore the project subdirectory and cache
- detect the project build system automatically
- use placeholders for ambiguous commands
- generate a dockerfile from a base template
- generate an executable container script
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.