FROM python:3.13 ARG UID=1000 ARG GID=1000 # Create user with sudo support RUN groupadd --gid $GID dev \ && useradd --uid $UID --gid $GID -m dev \ && apt-get update \ && apt-get install -y sudo curl gnupg \ && echo "dev ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/dev \ && chmod 0440 /etc/sudoers.d/dev \ && usermod -a -G dialout dev # Install system packages RUN apt-get install -y \ bat \ fd-find \ git \ git-lfs \ graphviz \ iputils-ping \ libgl1 \ locales \ make \ micro \ mosquitto-clients \ net-tools \ picocom \ ripgrep \ rsync \ socat \ tree \ zoxide \ && rm -rf /var/lib/apt/lists/* # Install eza RUN mkdir -p /etc/apt/keyrings \ && wget -qO- https://raw.githubusercontent.com/eza-community/eza/main/deb.asc \ | gpg --dearmor -o /etc/apt/keyrings/gierens.gpg \ && echo 'deb [signed-by=/etc/apt/keyrings/gierens.gpg] http://deb.gierens.de stable main' \ > /etc/apt/sources.list.d/gierens.list \ && chmod 644 /etc/apt/keyrings/gierens.gpg /etc/apt/sources.list.d/gierens.list \ && apt-get update && apt-get install -y eza \ && rm -rf /var/lib/apt/lists/* # Install lazygit RUN LAZYGIT_VERSION=$(curl -s https://api.github.com/repos/jesseduffield/lazygit/releases/latest \ | grep '"tag_name"' | cut -d'"' -f4 | sed 's/v//') \ && curl -Lo /tmp/lazygit.tar.gz \ https://github.com/jesseduffield/lazygit/releases/latest/download/lazygit_${LAZYGIT_VERSION}_Linux_x86_64.tar.gz \ && tar -xf /tmp/lazygit.tar.gz -C /tmp lazygit \ && install /tmp/lazygit /usr/local/bin \ && rm /tmp/lazygit.tar.gz /tmp/lazygit # Set locale RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \ locale-gen ENV LANG=en_US.UTF-8 ENV LC_ALL=en_US.UTF-8 # Create user directories with proper ownership RUN mkdir -p /home/dev/.vscode-server/extensions \ && mkdir -p /home/dev/.local/bin \ && mkdir -p /home/dev/.claude \ && mkdir -p /workspace \ && chown -R dev:dev /home/dev/.vscode-server \ && chown -R dev:dev /home/dev/.local \ && chown -R dev:dev /home/dev/.claude \ && chown -R dev:dev /workspace # Switch to non-root user (only once, for the rest of the build) USER dev # create ssh keys RUN ssh-keygen -q -t ed25519 -N "" -f /home/dev/.ssh/id_ed25519 && \ printf "Host *\n StrictHostKeyChecking accept-new\n" > /home/dev/.ssh/config && \ chmod 0700 /home/dev/.ssh && \ chmod 0600 /home/dev/.ssh/id_ed25519 /home/dev/.ssh/config && \ chmod 0644 /home/dev/.ssh/id_ed25519.pub WORKDIR /home/dev # Add local bin to PATH ENV PATH="/home/dev/.local/bin:${PATH}" # Install uv RUN curl -LsSf https://astral.sh/uv/install.sh | sh # Install fzf RUN git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf && ~/.fzf/install --all # Install AI tools as user (frequently updated) # copilot cli RUN curl -fsSL https://gh.io/copilot-install | bash # claude cli RUN curl -fsSL https://claude.ai/install.sh | bash # User config (most frequently changed) COPY --chown=dev:dev CLAUDE.md /home/dev/.claude/CLAUDE.md COPY --chown=dev:dev aliases.sh /home/dev/.aliases.sh COPY --chown=dev:dev bash_helpers.sh /home/dev/.bash_helpers.sh # Customize bash prompt RUN echo 'export PS1="${PROJECT_NAME:+\[\e[35m\][$PROJECT_NAME]\[\e[m\] }🐍 \[\e[33m\]\W\[\e[m\] \[\033[1;36m\]# \[\033[0m\]"' >> ~/.bashrc \ && echo 'source ~/.bash_helpers.sh' >> ~/.bashrc \ && echo 'eval "$(zoxide init bash)"' >> ~/.bashrc \ && echo '[[ -f /workspace/init_container.sh ]] && source /workspace/init_container.sh' >> ~/.bashrc