Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    ilude

    devcontainer-workflow

    ilude/devcontainer-workflow
    DevOps
    6
    1 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    DevContainer configuration for consistent development environments with Docker, multi-stage builds, non-root users, environment management, Docker-in-Docker support, and Python with uv...

    SKILL.md

    DevContainer Workflow

    Guidelines for setting up and maintaining consistent development environments using DevContainers with Docker, featuring non-root user configurations, environment management, multi-stage builds, and Python-focused patterns.

    Quick Start Checklist

    • Create .devcontainer/ directory structure
    • Configure devcontainer.json with runtime settings
    • Create multi-stage Dockerfile for development environment
    • Set up non-root vscode user with proper permissions
    • Configure volume mounts (home, SSH, docker socket)
    • Create .env.example templates for configuration
    • Set up postCreateCommand with Makefile integration
    • Configure VS Code extensions in customizations
    • Test container build and entry
    • Verify all development tools are accessible

    Directory Structure

    project/
    ├── .devcontainer/
    │   ├── devcontainer.json       # Container runtime configuration
    │   ├── Dockerfile              # Multi-stage development build
    │   ├── .env.example            # Dev-specific config template
    │   └── .env                    # Dev-specific config (gitignored)
    ├── .env.example                # Shared config template (committed)
    ├── .env                        # Shared config (gitignored)
    ├── Makefile                    # Development task automation
    └── pyproject.toml              # Python project configuration
    

    Container Configuration

    Multi-Stage Dockerfile Pattern

    Use multi-stage builds to separate development, testing, and production stages:

    # Base stage with common dependencies
    FROM python:3.14-slim AS base
    
    RUN apt-get update && apt-get install -y --no-install-recommends \
        bash \
        curl \
        git \
        make \
        zsh \
        zsh-autosuggestions \
        zsh-syntax-highlighting \
        ca-certificates \
        && rm -rf /var/lib/apt/lists/*
    
    # Development stage with full tooling
    FROM base AS development
    
    ARG USERNAME=vscode
    ARG USER_UID=1000
    ARG USER_GID=$USER_UID
    
    # Create non-root user
    RUN groupadd --gid $USER_GID $USERNAME && \
        useradd --uid $USER_UID --gid $USER_GID -m $USERNAME -s /bin/zsh && \
        apt-get update && apt-get install -y --no-install-recommends \
        sudo \
        vim \
        && rm -rf /var/lib/apt/lists/* && \
        echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME && \
        chmod 0440 /etc/sudoers.d/$USERNAME
    
    # Install uv
    COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
    
    WORKDIR /workspace
    USER $USERNAME
    
    # Configure shell
    RUN echo 'source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh' >> ~/.zshrc && \
        echo 'source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh' >> ~/.zshrc && \
        echo 'eval "$(uv generate-shell-completion zsh)"' >> ~/.zshrc
    
    # Production stage (minimal footprint)
    FROM base AS production
    
    RUN useradd --create-home --shell /bin/bash appuser
    
    WORKDIR /app
    USER appuser
    
    COPY --from=development /workspace /app
    RUN /app/.venv/bin/pip install --no-cache-dir -e .
    

    Python 3.14+ with UV Installation

    Ensure uv is installed in development stage:

    # Install uv package manager
    COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
    
    # (Later in USER vscode section)
    # Copy project files for dependency installation
    COPY --chown=vscode:vscode pyproject.toml uv.lock* ./
    RUN uv sync --no-dev || uv sync
    

    Non-Root User Configuration

    User Setup in Dockerfile

    Always use a non-root user for security. Standard name is vscode:

    ARG USERNAME=vscode
    ARG USER_UID=1000
    ARG USER_GID=$USER_UID
    
    # Create user with home directory and shell
    RUN groupadd --gid $USER_GID $USERNAME && \
        useradd --uid $USER_UID --gid $USER_GID -m $USERNAME -s /bin/zsh && \
        apt-get update && apt-get install -y --no-install-recommends sudo && \
        echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME && \
        chmod 0440 /etc/sudoers.d/$USERNAME && \
        rm -rf /var/lib/apt/lists/*
    
    # Set user for all subsequent commands
    USER $USERNAME
    

    Permissions for Mounted Volumes

    Ensure proper ownership of workspace and home directories:

    # After copying project files
    COPY --chown=vscode:vscode . /workspace
    
    # Ensure workspace permissions
    RUN mkdir -p /workspace && chown -R vscode:vscode /workspace
    

    devcontainer.json User Configuration

    {
      "remoteUser": "vscode"
    }
    

    Environment Management

    .env File Strategy

    Use multiple .env files for different scopes:

    1. Project root .env - Shared across all environments (gitignored)
    2. .devcontainer/.env - Development-specific overrides (gitignored)
    3. .env.example - Template for shared config (committed)
    4. .devcontainer/.env.example - Template for dev config (committed)

    Root .env.example

    # Shared configuration (safe for version control)
    PROJECT_NAME=my-project
    LOG_LEVEL=info
    PYTHON_VERSION=3.14
    DEBUG=false
    

    .devcontainer/.env.example

    # Development-specific settings
    DEBUG=true
    LOG_LEVEL=debug
    PYTHONUNBUFFERED=1
    HOT_RELOAD=true
    

    Loading Environment in devcontainer.json

    {
      "runArgs": [
        "--env-file", "${localWorkspaceFolder}/.env",
        "--env-file", "${localWorkspaceFolder}/.devcontainer/.env"
      ]
    }
    

    Order matters: later files override earlier ones. Local .devcontainer/.env overrides shared .env.


    Docker-in-Docker Support

    When to Use

    • Building Docker images within the devcontainer
    • Running integration tests with containers
    • Testing Docker Compose configurations
    • Local CI/CD pipeline simulation

    Configuration

    Add Docker-in-Docker feature to devcontainer.json:

    {
      "features": {
        "ghcr.io/devcontainers/features/docker-in-docker:2": {
          "version": "latest",
          "moby": true
        }
      },
      "mounts": [
        "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
      ]
    }
    

    Security Considerations

    Mounting the Docker socket grants the container full Docker daemon access:

    • Use only in trusted development environments
    • Never use in untrusted code environments
    • Ensure user in container is trusted
    • Consider using Docker contexts for isolation if running sensitive containers

    Testing with Docker Compose

    .PHONY: test-integration
    test-integration:
    	docker compose -f docker-compose.test.yml up -d
    	uv run pytest tests/integration/ -v --tb=short
    	docker compose -f docker-compose.test.yml down
    
    .PHONY: build-image
    build-image:
    	docker build -t my-app:latest --target production .
    

    Development Tools

    Shell: Zsh Configuration

    Configure zsh with plugins for better development experience:

    RUN apt-get update && apt-get install -y --no-install-recommends \
        zsh \
        zsh-autosuggestions \
        zsh-syntax-highlighting \
        && rm -rf /var/lib/apt/lists/*
    
    USER vscode
    RUN echo 'source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh' >> ~/.zshrc && \
        echo 'source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh' >> ~/.zshrc && \
        echo 'setopt HIST_FIND_NO_DUPS' >> ~/.zshrc && \
        echo 'setopt SHARE_HISTORY' >> ~/.zshrc
    

    VS Code Extensions

    Configure recommended extensions in devcontainer.json:

    {
      "customizations": {
        "vscode": {
          "extensions": [
            "ms-python.python",
            "ms-python.vscode-pylance",
            "ms-python.black-formatter",
            "charliermarsh.ruff",
            "ms-azuretools.vscode-docker",
            "eamodio.gitlens",
            "ms-vscode.makefile-tools",
            "GitHub.copilot"
          ],
          "settings": {
            "python.defaultInterpreterPath": "/usr/local/bin/python",
            "python.linting.enabled": true,
            "python.formatting.provider": "black",
            "[python]": {
              "editor.defaultFormatter": "ms-python.black-formatter",
              "editor.formatOnSave": true,
              "editor.codeActionsOnSave": {
                "source.organizeImports": "explicit"
              }
            },
            "editor.formatOnSave": true,
            "files.trimTrailingWhitespace": true,
            "files.insertFinalNewline": true,
            "terminal.integrated.defaultProfile.linux": "zsh"
          }
        }
      }
    }
    

    Essential Development Tools

    Include in Dockerfile for all development environments:

    RUN apt-get update && apt-get install -y --no-install-recommends \
        build-essential \
        git \
        curl \
        wget \
        jq \
        && rm -rf /var/lib/apt/lists/*
    

    Volume Mounts

    Home Directory Persistence

    Preserve shell history, configurations, and VS Code data across container rebuilds:

    {
      "mounts": [
        "source=${localWorkspaceFolderBasename}-home,target=/home/vscode,type=volume"
      ]
    }
    

    Benefits of dynamic naming with ${localWorkspaceFolderBasename}:

    • Unique volume per workspace (supports multiple projects)
    • Prevents conflicts with other projects
    • Clear naming: project-name-home

    SSH Key Access

    Enable git operations and remote access with SSH keys:

    {
      "mounts": [
        "source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,readonly"
      ]
    }
    

    On Windows, use:

    {
      "mounts": [
        "source=${localEnv:USERPROFILE}\\.ssh,target=/home/vscode/.ssh,type=bind,readonly"
      ]
    }
    

    Configure SSH for git:

    # In devcontainer or post-create
    ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts 2>/dev/null
    git config --global core.sshCommand "ssh -i ~/.ssh/id_rsa"
    

    Docker Socket for DinD

    {
      "mounts": [
        "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
      ]
    }
    

    Add user to docker group in container:

    RUN groupadd docker || true && \
        usermod -aG docker vscode
    

    Post-Create Commands

    Makefile-Driven Initialization

    Use postCreateCommand to invoke a Makefile target:

    {
      "postCreateCommand": "make initialize"
    }
    

    Makefile Example

    .PHONY: initialize
    initialize: deps env-setup
    	@echo "Development environment initialized"
    
    .PHONY: deps
    deps:
    	@echo "Installing dependencies with uv..."
    	uv sync --extra dev
    
    .PHONY: env-setup
    env-setup:
    	@echo "Setting up environment..."
    	mkdir -p logs tmp .cache
    	test -f .env || cp .env.example .env
    	test -f .devcontainer/.env || cp .devcontainer/.env.example .devcontainer/.env
    	@echo ".env files created from templates"
    
    .PHONY: hooks
    hooks:
    	@echo "Setting up git hooks..."
    	pre-commit install || true
    
    .PHONY: clean
    clean:
    	find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
    	find . -type f -name "*.pyc" -delete
    	rm -rf .pytest_cache htmlcov .coverage .mypy_cache
    	uv pip cache prune
    
    .PHONY: test
    test:
    	uv run pytest tests/ -v --tb=short
    
    .PHONY: check
    check:
    	uv run pytest tests/ -v
    	uv run ruff check .
    	uv run mypy src/ --ignore-missing-imports
    
    .PHONY: run
    run:
    	uv run python -m myapp.cli
    

    Complete devcontainer.json Example

    {
      "name": "Python Development Environment",
      "description": "Development container with Python 3.14, uv, and Docker-in-Docker",
      "image": "mcr.microsoft.com/devcontainers/python:3.14",
      "dockerFile": "../Dockerfile",
      "target": "development",
      "context": "..",
    
      "runArgs": [
        "--env-file", "${localWorkspaceFolder}/.env",
        "--env-file", "${localWorkspaceFolder}/.devcontainer/.env"
      ],
    
      "features": {
        "ghcr.io/devcontainers/features/docker-in-docker:2": {
          "version": "latest",
          "moby": true
        }
      },
    
      "mounts": [
        "source=${localWorkspaceFolderBasename}-home,target=/home/vscode,type=volume",
        "source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,readonly"
      ],
    
      "customizations": {
        "vscode": {
          "extensions": [
            "ms-python.python",
            "ms-python.vscode-pylance",
            "ms-python.black-formatter",
            "charliermarsh.ruff",
            "ms-azuretools.vscode-docker",
            "eamodio.gitlens",
            "ms-vscode.makefile-tools"
          ],
          "settings": {
            "python.defaultInterpreterPath": "/usr/local/bin/python",
            "python.linting.enabled": true,
            "python.formatting.provider": "black",
            "[python]": {
              "editor.defaultFormatter": "ms-python.black-formatter",
              "editor.formatOnSave": true,
              "editor.codeActionsOnSave": {
                "source.organizeImports": "explicit"
              }
            },
            "editor.formatOnSave": true,
            "files.trimTrailingWhitespace": true,
            "files.insertFinalNewline": true,
            "terminal.integrated.defaultProfile.linux": "zsh",
            "terminal.integrated.profiles.linux": {
              "zsh": {
                "path": "/bin/zsh",
                "args": ["-l"]
              }
            }
          }
        }
      },
    
      "postCreateCommand": "make initialize",
      "postStartCommand": "git config --global --add safe.directory /workspace",
    
      "remoteUser": "vscode",
      "remoteEnv": {
        "PATH": "/home/vscode/.local/bin:${containerEnv:PATH}"
      }
    }
    

    Python with UV Patterns

    Project Setup with uv

    Initialize project with uv and modern Python:

    # In container or locally
    uv new my-project --python 3.14
    cd my-project
    uv sync
    

    Dependencies Management

    # Add production dependency
    uv add requests fastapi
    
    # Add development dependency
    uv add --group dev pytest pytest-cov black ruff mypy
    
    # Add optional group
    uv add --group notebook jupyter ipykernel
    
    # Sync all dependencies
    uv sync --extra dev
    
    # Run with uv
    uv run python -m myapp.cli
    uv run pytest tests/ -v
    

    pyproject.toml Structure for Development

    [project]
    name = "my-project"
    version = "0.1.0"
    description = "Project description"
    requires-python = ">=3.14"
    dependencies = [
        "fastapi>=0.104.0",
        "requests>=2.31.0",
    ]
    
    [project.optional-dependencies]
    dev = [
        "pytest>=7.4.0",
        "pytest-cov>=4.1.0",
        "black>=23.9.0",
        "ruff>=0.10.0",
        "mypy>=1.5.0",
        "pre-commit>=3.3.0",
    ]
    
    [tool.uv]
    dev-dependencies = ["pytest", "black", "ruff", "mypy"]
    
    [tool.black]
    line-length = 88
    target-version = ["py314"]
    
    [tool.ruff]
    line-length = 88
    target-version = "py314"
    
    [tool.mypy]
    python_version = "3.14"
    warn_return_any = true
    warn_unused_configs = true
    disallow_untyped_defs = false
    

    Makefile UV Integration

    .PHONY: install
    install:
    	uv sync --extra dev
    
    .PHONY: test
    test:
    	uv run pytest tests/ -v --cov=src --cov-report=term-missing
    
    .PHONY: lint
    lint:
    	uv run ruff check src/ tests/
    	uv run mypy src/
    
    .PHONY: format
    format:
    	uv run black src/ tests/
    	uv run ruff check --fix src/ tests/
    
    .PHONY: run
    run:
    	uv run python -m myapp.cli
    

    Installing from Dockerfile During Build

    COPY --chown=vscode:vscode pyproject.toml uv.lock* ./
    RUN if [ -f uv.lock ]; then \
          uv sync --no-dev; \
        else \
          uv sync; \
        fi
    

    Testing Support

    Unit Testing with pytest

    Configure pytest in pyproject.toml:

    [tool.pytest.ini_options]
    testpaths = ["tests"]
    python_files = ["test_*.py"]
    python_classes = ["Test*"]
    python_functions = ["test_*"]
    addopts = "-v --tb=short --strict-markers"
    markers = [
        "unit: unit tests",
        "integration: integration tests",
        "slow: slow tests",
    ]
    

    Integration Testing with Docker Compose

    Create docker-compose.test.yml:

    version: '3.8'
    services:
      postgres:
        image: postgres:15-alpine
        environment:
          POSTGRES_PASSWORD: testpass
        ports:
          - "5432:5432"
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U postgres"]
          interval: 5s
          timeout: 5s
          retries: 5
    
      redis:
        image: redis:7-alpine
        ports:
          - "6379:6379"
        healthcheck:
          test: ["CMD", "redis-cli", "ping"]
          interval: 5s
          timeout: 5s
          retries: 5
    

    Test Makefile Targets

    .PHONY: test test-unit test-integration test-all
    test: test-unit
    
    test-unit:
    	uv run pytest tests/unit/ -v -m "not slow"
    
    test-integration:
    	docker compose -f docker-compose.test.yml up -d
    	uv run pytest tests/integration/ -v || true
    	docker compose -f docker-compose.test.yml down
    
    test-all:
    	uv run pytest tests/ -v --cov=src --cov-report=html
    
    test-watch:
    	uv run pytest-watch tests/unit/
    

    Troubleshooting

    Permission Denied Errors

    Problem: Files owned by root, cannot write from vscode user.

    Solution in Dockerfile:

    RUN chown -R vscode:vscode /workspace /home/vscode
    

    Check in container:

    whoami
    ls -la /workspace
    ls -la /home/vscode
    

    Extensions Not Installing

    Problem: VS Code extensions fail to install in container.

    Solution: Use full extension IDs with version pins:

    {
      "extensions": [
        "ms-python.python@2024.0.0",
        "ms-python.vscode-pylance@2024.0.0"
      ]
    }
    

    Or rebuild container:

    # In VS Code: Dev Containers: Rebuild Container
    

    Environment Variables Not Loading

    Problem: .env files created but variables not available in container.

    Solution: Verify files exist and rebuild:

    # Check in container
    printenv | grep YOUR_VAR
    cat /home/vscode/.env
    
    # Rebuild container
    

    Ensure runArgs correctly references env files in devcontainer.json.

    Docker Socket Permission Issues

    Problem: Cannot access Docker socket from container.

    Solution in Dockerfile:

    RUN groupadd docker || true && \
        usermod -aG docker vscode
    

    In devcontainer.json:

    {
      "postCreateCommand": "newgrp docker"
    }
    

    UV Cache Issues

    Problem: Dependency resolution slow or caching issues.

    Solution:

    # Clear uv cache in container
    uv pip cache prune
    
    # In Dockerfile, use specific versions
    RUN uv sync --frozen  # Use uv.lock if available
    

    Volume Mount Issues on Windows

    Problem: Volume mounts not working on Windows with WSL2.

    Solution: Ensure Docker Desktop WSL2 integration enabled:

    # In devcontainer.json, use Windows paths correctly
    "mounts": [
      "source=${localEnv:USERPROFILE}\\.ssh,target=/home/vscode/.ssh,type=bind,readonly"
    ]
    

    Validation Guidance

    Pre-Build Validation

    Check before building container:

    # Validate JSON syntax
    python -m json.tool .devcontainer/devcontainer.json
    
    # Check file references
    ls -la Dockerfile pyproject.toml .env.example
    
    # Validate Makefile
    make --dry-run initialize
    

    Post-Build Validation

    After container builds:

    # Verify user and permissions
    docker exec <container> whoami
    docker exec <container> ls -la /workspace
    
    # Test uv installation
    docker exec <container> uv --version
    
    # Verify zsh and plugins
    docker exec <container> zsh -c "echo $ZSH_VERSION"
    
    # Check VS Code extensions installed
    docker exec <container> code --list-extensions 2>/dev/null || echo "VS Code not in container"
    

    Development Environment Check

    .PHONY: validate
    validate: validate-files validate-container validate-tools
    
    .PHONY: validate-files
    validate-files:
    	@echo "Validating devcontainer configuration..."
    	@python -m json.tool .devcontainer/devcontainer.json > /dev/null
    	@test -f Dockerfile && echo "✓ Dockerfile found" || exit 1
    	@test -f pyproject.toml && echo "✓ pyproject.toml found" || exit 1
    	@test -f .env.example && echo "✓ .env.example found" || exit 1
    
    .PHONY: validate-container
    validate-container:
    	@echo "Validating container setup..."
    	@whoami | grep -q vscode && echo "✓ Running as vscode user" || exit 1
    	@test -d /workspace && echo "✓ Workspace mounted" || exit 1
    	@test -d /home/vscode && echo "✓ Home directory mounted" || exit 1
    
    .PHONY: validate-tools
    validate-tools:
    	@echo "Validating development tools..."
    	@uv --version && echo "✓ uv installed" || exit 1
    	@python --version && echo "✓ Python available" || exit 1
    	@zsh --version && echo "✓ zsh available" || exit 1
    	@git --version && echo "✓ git available" || exit 1
    
    .PHONY: check-env
    check-env:
    	@echo "Environment variables:"
    	@printenv | grep -E '^(PYTHON|DEBUG|LOG_LEVEL|PROJECT_NAME)' || echo "No project vars found"
    	@test -f .env && echo "✓ .env file loaded" || echo "⚠ .env file missing"
    

    Best Practices Summary

    1. Always use non-root user (vscode by default) in containers
    2. Use dynamic volume naming with ${localWorkspaceFolderBasename}-home for persistence
    3. Prefer uv for Python dependency management in devcontainers
    4. Multi-stage builds separate development and production concerns
    5. Keep Dockerfile minimal - offload setup to Makefile targets
    6. Environment as configuration - use .env files for settings
    7. Document all tools - list in VS Code extensions and Dockerfile
    8. Test container builds - validate before committing devcontainer configs
    9. SSH access when needed - mount .ssh as readonly for git operations
    10. DinD with caution - only enable Docker socket when truly needed
    Recommended Servers
    Cloudflare Containers
    Cloudflare Containers
    Vercel
    Vercel
    Kernel
    Kernel
    Repository
    ilude/claude-code-config
    Files