FROM --platform=linux/arm64 debian:bookworm-slim ARG PYTHON_VERSION=3.11 ARG NODE_MAJOR=22 ARG JAVA_VERSION=17 ARG GO_VERSION=1.22.4 ARG GRADLE_VERSION=8.7 ARG TERRAFORM_VERSION=1.8.5 ARG ZIG_VERSION=0.16.0 ENV DEBIAN_FRONTEND=noninteractive ENV LANG=C.UTF-8 # Base system dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ curl \ wget \ git \ ssh \ make \ sudo \ build-essential \ unzip \ jq \ gnupg \ lsb-release \ software-properties-common \ libxml2-dev \ libxmlsec1-dev \ libffi-dev \ libpq-dev \ libssl-dev \ zlib1g-dev \ libbz2-dev \ liblzma-dev \ libreadline-dev \ libsqlite3-dev \ libncursesw5-dev \ xz-utils \ uuid-dev \ zsh \ fd-find \ ripgrep \ neovim \ less \ hugo \ xz-utils \ && rm -rf /var/lib/apt/lists/* \ && ln -sf /usr/bin/fdfind /usr/local/bin/fd # Set zsh as default shell SHELL ["/bin/zsh", "-c"] RUN chsh -s /bin/zsh root # Python 3.11 via deadsnakes-style build (bookworm ships 3.11) RUN apt-get update && apt-get install -y --no-install-recommends \ python3 \ python3-pip \ python3-venv \ python3-dev \ && ln -sf /usr/bin/python3 /usr/bin/python \ && rm -rf /var/lib/apt/lists/* # uv (fast Python package/project manager from Astral) RUN curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=/usr/local/bin sh # Keep sandbox-created Python project virtualenvs separate from the host/user .venv. # This avoids invalid interpreter symlinks when the same workspace is shared with macOS. ENV UV_PROJECT_ENVIRONMENT=".venv_sandbox" # Node.js 22 RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_MAJOR}.x | bash - && \ apt-get install -y --no-install-recommends nodejs && \ rm -rf /var/lib/apt/lists/* # Docker CLI (client only, expects host docker socket mount) RUN curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker.gpg && \ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/debian bookworm stable" > /etc/apt/sources.list.d/docker.list && \ apt-get update && apt-get install -y --no-install-recommends docker-ce-cli && \ rm -rf /var/lib/apt/lists/* # yq (mikefarah) ARG YQ_VERSION=v4.44.3 RUN ARCH=$(dpkg --print-architecture) && \ curl -fsSL "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_${ARCH}" -o /usr/local/bin/yq && \ chmod +x /usr/local/bin/yq # Zig RUN ARCH=$(uname -m) && \ case "$ARCH" in \ x86_64) ZIG_ARCH=x86_64 ;; \ aarch64) ZIG_ARCH=aarch64 ;; \ *) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;; \ esac && \ curl -fsSL "https://ziglang.org/download/${ZIG_VERSION}/zig-${ZIG_ARCH}-linux-${ZIG_VERSION}.tar.xz" -o /tmp/zig.tar.xz && \ tar -C /opt -xf /tmp/zig.tar.xz && \ mv "/opt/zig-${ZIG_ARCH}-linux-${ZIG_VERSION}" "/opt/zig-${ZIG_VERSION}" && \ ln -s "/opt/zig-${ZIG_VERSION}/zig" /usr/local/bin/zig && \ rm /tmp/zig.tar.xz # GitHub CLI (gh) RUN mkdir -p -m 755 /etc/apt/keyrings && \ curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | gpg --dearmor -o /etc/apt/keyrings/githubcli-archive-keyring.gpg && \ chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg && \ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list && \ apt-get update && apt-get install -y gh && \ rm -rf /var/lib/apt/lists/* # Rust RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y ENV PATH="/root/.cargo/bin:${PATH}" # Jujutsu (jj) - Git-compatible VCS RUN cargo install --locked jj-cli # Starship prompt RUN curl -sS https://starship.rs/install.sh | sh -s -- -y # Pi coding agent RUN npm install -g @earendil-works/pi-coding-agent # SelimovDE dotfiles RUN git clone https://forge.alexselimov.com/aselimov/SelimovDE.git /root/SelimovDE && \ cd /root/SelimovDE && \ git submodule init && \ git submodule update && \ ./deploy.sh # Global gitignore: lives on the host at ~/repos/dev_sandbox/.gitignore_global # (bind-mounted to /workspace/dev_sandbox/.gitignore_global). Symlinked into # place by entrypoint.sh so host edits take effect without a rebuild. RUN git config --system core.excludesfile /root/.gitignore_global # Pi wrapper script (optional, only applied if bin/pi exists in build context) COPY Dockerfile bin/p* /tmp/build-context/ RUN if [ -f /tmp/build-context/pi ]; then \ mv /tmp/build-context/pi /usr/local/bin/pi && chmod +x /usr/local/bin/pi; \ fi && rm -rf /tmp/build-context # Workspace directory (mount point for ~/repos) RUN mkdir -p /workspace WORKDIR /workspace # Pi state directory lives on a named Docker volume mounted at /root/.pi # (see docker run: -v pi-state:/root/.pi). This keeps pi's hot runtime state # (sessions, logs, caches) on the Linux VM's native ext4 instead of the # macOS bind mount (virtiofs), which is a major perf win for the agent loop. # # Config you want to persist/commit (settings, skills, themes, extensions, # etc.) lives in the workspace at /workspace/dev_sandbox/.pi/agent and is # symlinked into /root/.pi/agent at runtime by entrypoint.sh. RUN mkdir -p /root/.pi # Entrypoint script for runtime auth COPY entrypoint.sh /usr/local/bin/entrypoint.sh RUN chmod +x /usr/local/bin/entrypoint.sh ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] CMD ["/bin/zsh"]