Skip to content

Instantly share code, notes, and snippets.

@jtmcdole
Created June 5, 2026 00:26
Show Gist options
  • Select an option

  • Save jtmcdole/2ab7b98f0bcc1d89c2c9e3e6910ce2fa to your computer and use it in GitHub Desktop.

Select an option

Save jtmcdole/2ab7b98f0bcc1d89c2c9e3e6910ce2fa to your computer and use it in GitHub Desktop.
flutter + docker + antigravity
#
# Build:
# x86: docker build -t flutter_docker .
# Apple Silicon: docker build --platform linux/amd64 -t flutter_docker .
#
# Run:
# Apple Silicon: podman run --platform linux/amd64 --rm -it -v "${PWD}:/app" -v "dart_tool_cache:/app/.dart_tool" -v "dart_build_cache:/app/build" -v "/Users/codefu/.gemini:/home/codefu/.gemini" flutter_docker:latest
# x86: docker run --rm -it -v ".:/app" -v 'dart_tool_cache:/app/.dart_tool' -v "dart_build_cache:/app/build" -v "/Users/codefu/.gemini:/home/codefu/.gemini" flutter_docker:latest
#
# Doing something work worktrees?
# podman run --platform linux/amd64 --rm -it -v "${PWD}:/app" -v "dart_tool_cache:/app/.dart_tool" -v "dart_build_cache:/app/build" -v "${PWD}/.git_docker:/app/.git" -v "${PWD}/../.bare:/app/.bare" -v "/Users/codefu/.gemini:/home/codefu/.gemini" flutter_docker:latest
#
# Versions:
# * latest: permissions on ~/.gemini to fix tool calling
# * previous: better handling of .dart_tool - see run commands above! flutter 3.44.1. allow my user to sudo
# * previous: fix tmux key bindings. add less and rsync
# * previous: `agyolo`!, -homebrew, +vim dart plugin, native yq/gh/jq, less RUN steps
# * previous: zsh, omyzsh, homebrew.
# * previous: multi-stage build for flutter tooling. byobu/tmux, git, jq.
# ==========================================
# STAGE 1: The Heavy Downloader - flutter and its tools are heavy
# ==========================================
FROM ubuntu:24.04 AS flutter-fetcher
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl ca-certificates xz-utils git unzip && \
rm -rf /var/lib/apt/lists/*
RUN useradd -m builder && \
mkdir -p /opt && \
chown builder:builder /opt
USER builder
WORKDIR /opt
# This layer caches permanently until you change the URL.
# It is completely immune to changes in your main image.
RUN curl -fsSL https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.44.1-stable.tar.xz | tar -xJ
# 2. Lock in configuration and force the massive SDK downloads
ENV PATH="/opt/flutter/bin:${PATH}"
RUN flutter config \
--enable-web \
--no-enable-linux-desktop \
--no-enable-macos-desktop \
--no-enable-windows-desktop \
--no-enable-android \
--no-enable-ios \
--no-enable-fuchsia && \
# Precache pulls down the engine binaries, Dart SDK, and web tools
flutter precache --web && \
flutter --version
# ==========================================
# STAGE 2: The OS - which should mostly have an OCI layer already.
# ==========================================
FROM ubuntu:24.04
# 1. Environment Variables (Rarely change, define early)
ENV TZ=America/Los_Angeles \
DEBIAN_FRONTEND=noninteractive \
FLUTTER_ROOT="/opt/flutter" \
PATH="/opt/flutter/bin:/home/codefu/.local/bin:${PATH}" \
LANG="en_US.UTF-8" \
LANGUAGE="en_US:en" \
LC_ALL="en_US.UTF-8" \
TERM="xterm-256color" \
COLORTERM="truecolor" \
SHELL="/usr/bin/zsh"
# 2. OS Dependencies (Heavy layer, cache as much as possible)
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
ca-certificates curl dnsutils dos2unix git openssh-client unzip \
tmux byobu vim sudo xz-utils tzdata locales jq ripgrep \
fd-find fzf bat btop zsh build-essential procps file wget \
less rsync; \
# install github
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg; \
chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg; \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null; \
apt-get update && apt-get install -y gh; \
# binary yq
wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64; \
chmod a+x /usr/local/bin/yq; \
locale-gen en_US.UTF-8; \
ln -s $(which fdfind) /usr/local/bin/fd; \
ln -s $(which batcat) /usr/local/bin/bat; \
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone; \
rm -rf /var/lib/apt/lists/*; \
echo "codefu ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# 3. User setup and directory creation
# Using -m automatically creates the home directory securely.
RUN groupadd -r codefu && \
useradd -r -m -g codefu codefu && \
mkdir -p /app /opt/flutter /home/linuxbrew/.linuxbrew && \
chown -R codefu:codefu /app /opt /home/linuxbrew
# 4. Import the FULLY HYDRATED Flutter SDK from Stage 1
# This takes about 1 second and skips all network traffic.
COPY --from=flutter-fetcher --chown=codefu:codefu /opt/flutter /opt/flutter
# Switch context to the non-root user for the remaining installations
USER codefu
# or --disable-analytics if running as CICD
RUN flutter --enable-analytics && dart --enable-analytics
# 5. Install Oh My Zsh unattended so it doesn't halt the Docker build
RUN sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended
# Set these after USER
ENV PATH="/home/codefu/.pub-cache/bin:${PATH}"
# 6. User-specific CLI tools
RUN curl -fsSL https://antigravity.google/cli/install.sh | bash
# 7. User Configuration (Highly volatile, keep at the very bottom)
RUN mkdir -p /home/codefu/.config/byobu && \
touch /home/codefu/.config/byobu/.welcome-displayed && \
{ \
echo "unbind-key -n C-a"; \
echo "set -g prefix C-a"; \
echo "set -g prefix2 F12"; \
echo "bind a send-prefix"; \
echo "# Ensure tmux handles control modifiers correctly for xterm"; \
echo "set-window-option -g xterm-keys on"; \
echo "# Clear any existing bindings for these keys";\
echo "unbind-key -n C-Left";\
echo "unbind-key -n C-Right";\
echo "# Map Ctrl + Left/Right to switch bottom tabs (windows)";\
echo "bind-key -n C-Left select-window -t :-";\
echo "bind-key -n C-Right select-window -t :+";\
echo "set -g mouse on"; \
} > /home/codefu/.config/byobu/keybindings.tmux && \
{ \
echo "set -g default-terminal \"tmux-256color\""; \
echo "set -ag terminal-overrides \",xterm-256color:RGB\""; \
echo "set -g default-shell /usr/bin/zsh"; \
echo "# Automatically fix named volume permissions on startup"; \
echo 'run-shell "sudo mkdir -p /app/.dart_tool && sudo chown -R codefu:codefu /app/.dart_tool"'; \
echo 'run-shell "sudo mkdir -p /app/build && sudo chown -R codefu:codefu /app/build"'; \
echo 'run-shell "sudo mkdir -p /home/codefu/.gemini && sudo chown -R codefu:codefu /home/codefu/.gemini"'; \
} > /home/codefu/.config/byobu/profile.tmux && \
touch /home/codefu/.zsh_history && \
{ \
echo ": 1000000000:0;dart pub global activate melos; melos pub-get"; \
echo ": 1000000000:0;flutter pub get"; \
echo ": 1000000000:0;flutter analyze ."; \
echo ": 1000000000:0;dart pub get"; \
echo ": 1000000000:0;dart format ."; \
} >> /home/codefu/.zsh_history && \
touch /home/codefu/.zshrc && \
{ \
echo 'alias agyolo="agy --dangerously-skip-permissions"'; \
} >> /home/codefu/.zshrc
RUN mkdir -p /home/codefu/.vim/pack/dart-lang/start && \
git clone https://github.com/dart-lang/dart-vim-plugin /home/codefu/.vim/pack/dart-lang/start/dart-vim-plugin
RUN git config --global --add safe.directory /app
WORKDIR /app
ENTRYPOINT [ "/usr/bin/byobu" ]
#
# Build:
# x86: docker build -t flutter_docker .
# Apple Silicon: docker build --platform linux/amd64 -t flutter_docker .
#
# Run:
# Apple Silicon: podman run --platform linux/amd64 --rm -it -v "${PWD}:/app" -v "dart_tool_cache:/app/.dart_tool" -v "dart_build_cache:/app/build" -v "/Users/codefu/.gemini:/home/codefu/.gemini" flutter_docker:latest
# x86: docker run --rm -it -v ".:/app" -v 'dart_tool_cache:/app/.dart_tool' -v "dart_build_cache:/app/build" -v "/Users/codefu/.gemini:/home/codefu/.gemini" flutter_docker:latest
#
# Doing something work worktrees?
# podman run --platform linux/amd64 --rm -it -v "${PWD}:/app" -v "dart_tool_cache:/app/.dart_tool" -v "dart_build_cache:/app/build" -v "${PWD}/.git_docker:/app/.git" -v "${PWD}/../.bare:/app/.bare" -v "/Users/codefu/.gemini:/home/codefu/.gemini" flutter_docker:latest
#
# Versions:
# * latest: permissions on ~/.gemini to fix tool calling
# * previous: better handling of .dart_tool - see run commands
# * previous: bun + playwright install for gstack `install_gstack`
# * previous: `agyolo`!, -homebrew, +vim dart plugin, native yq/gh/jq, less RUN steps
# * previous: zsh, omyzsh, homebrew.
# * previous: multi-stage build for flutter tooling. byobu/tmux, git, jq.
#
# ==========================================
# STAGE 1: The Heavy Downloader - flutter and its tools are heavy
# ==========================================
FROM ubuntu:24.04 AS flutter-fetcher
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl ca-certificates xz-utils git unzip && \
rm -rf /var/lib/apt/lists/*
RUN useradd -m builder && \
mkdir -p /opt && \
chown builder:builder /opt
USER builder
WORKDIR /opt
# This layer caches permanently until you change the URL.
# It is completely immune to changes in your main image.
RUN curl -fsSL https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.44.1-stable.tar.xz | tar -xJ
# 2. Lock in configuration and force the massive SDK downloads
ENV PATH="/opt/flutter/bin:${PATH}"
RUN flutter config \
--enable-web \
--no-enable-linux-desktop \
--no-enable-macos-desktop \
--no-enable-windows-desktop \
--no-enable-android \
--no-enable-ios \
--no-enable-fuchsia && \
# Precache pulls down the engine binaries, Dart SDK, and web tools
flutter precache --web && \
flutter --version
# ==========================================
# STAGE 2: The OS - Using Playwright Noble (Ubuntu 24.04)
# ==========================================
FROM mcr.microsoft.com/playwright:v1.49.0-noble
# 1. Environment Variables (Rarely change, define early)
ENV TZ=America/Los_Angeles \
DEBIAN_FRONTEND=noninteractive \
FLUTTER_ROOT="/opt/flutter" \
PLAYWRIGHT_BROWSERS_PATH="/ms-playwright" \
PATH="/opt/flutter/bin:/home/codefu/.local/bin:${PATH}" \
LANG="en_US.UTF-8" \
LANGUAGE="en_US:en" \
LC_ALL="en_US.UTF-8" \
TERM="xterm-256color" \
COLORTERM="truecolor" \
SHELL="/usr/bin/zsh"
# 2. OS Dependencies (Heavy layer, cache as much as possible)
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
ca-certificates curl dnsutils dos2unix git openssh-client unzip \
tmux byobu vim sudo xz-utils tzdata locales jq ripgrep \
fd-find fzf bat btop zsh build-essential procps file wget \
less rsync; \
# install github
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg; \
chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg; \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null; \
apt-get update && apt-get install -y gh; \
# binary yq
wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64; \
chmod a+x /usr/local/bin/yq; \
locale-gen en_US.UTF-8; \
ln -s $(which fdfind) /usr/local/bin/fd; \
ln -s $(which batcat) /usr/local/bin/bat; \
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone; \
rm -rf /var/lib/apt/lists/*; \
echo "codefu ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# 3. User setup and directory creation
# Using -m automatically creates the home directory securely.
RUN groupadd -r codefu && \
useradd -r -m -g codefu codefu && \
mkdir -p /app /opt/flutter /home/linuxbrew/.linuxbrew && \
chown -R codefu:codefu /app /opt /home/linuxbrew
# 4. Import the FULLY HYDRATED Flutter SDK from Stage 1
# This takes about 1 second and skips all network traffic.
COPY --from=flutter-fetcher --chown=codefu:codefu /opt/flutter /opt/flutter
# 5. Import Bun directly from the official image (No curl | bash needed)
COPY --from=oven/bun:latest /usr/local/bin/bun /usr/local/bin/bun
RUN ln -s /usr/local/bin/bun /usr/local/bin/bunx
# Switch context to the non-root user for the remaining installations
USER codefu
# or --disable-analytics if running as CICD
RUN flutter --enable-analytics && dart --enable-analytics
# 5. Install Oh My Zsh unattended so it doesn't halt the Docker build
RUN sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended
# Set these after USER
ENV PATH="/home/codefu/.pub-cache/bin:${PATH}"
# 6. User-specific CLI tools
RUN curl -fsSL https://antigravity.google/cli/install.sh | bash
# 7. User Configuration (Highly volatile, keep at the very bottom)
RUN mkdir -p /home/codefu/.config/byobu && \
touch /home/codefu/.config/byobu/.welcome-displayed && \
{ \
echo "unbind-key -n C-a"; \
echo "set -g prefix C-a"; \
echo "set -g prefix2 F12"; \
echo "bind a send-prefix"; \
echo "# Ensure tmux handles control modifiers correctly for xterm"; \
echo "set-window-option -g xterm-keys on"; \
echo "# Clear any existing bindings for these keys";\
echo "unbind-key -n C-Left";\
echo "unbind-key -n C-Right";\
echo "# Map Ctrl + Left/Right to switch bottom tabs (windows)";\
echo "bind-key -n C-Left select-window -t :-";\
echo "bind-key -n C-Right select-window -t :+";\
echo "set -g mouse on"; \
} > /home/codefu/.config/byobu/keybindings.tmux && \
{ \
echo "set -g default-terminal \"tmux-256color\""; \
echo "set -ag terminal-overrides \",xterm-256color:RGB\""; \
echo "set -g default-shell /usr/bin/zsh"; \
echo "# Automatically fix named volume permissions on startup"; \
echo 'run-shell "sudo mkdir -p /app/.dart_tool && sudo chown -R codefu:codefu /app/.dart_tool"'; \
echo 'run-shell "sudo mkdir -p /app/build && sudo chown -R codefu:codefu /app/build"'; \
echo 'run-shell "sudo mkdir -p /home/codefu/.gemini && sudo chown -R codefu:codefu /home/codefu/.gemini"'; \
} > /home/codefu/.config/byobu/profile.tmux && \
touch /home/codefu/.zsh_history && \
{ \
echo ": 1000000000:0;dart pub global activate melos; melos pub-get"; \
echo ": 1000000000:0;flutter pub get"; \
echo ": 1000000000:0;flutter analyze ."; \
echo ": 1000000000:0;dart pub get"; \
echo ": 1000000000:0;dart format ."; \
} >> /home/codefu/.zsh_history && \
touch /home/codefu/.zshrc && \
{ \
echo 'alias agyolo="agy --dangerously-skip-permissions"'; \
echo 'alias btop="btop --utf-force"'; \
echo ''; \
echo 'install_gstack() {'; \
echo ' git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git /home/codefu/gstack || return 1'; \
echo ' pushd /home/codefu/gstack > /dev/null || return 1'; \
echo ' ./setup'; \
echo ' popd > /dev/null'; \
echo '}'; \
} >> /home/codefu/.zshrc
RUN mkdir -p /home/codefu/.vim/pack/dart-lang/start && \
git clone https://github.com/dart-lang/dart-vim-plugin /home/codefu/.vim/pack/dart-lang/start/dart-vim-plugin
RUN git config --global --add safe.directory /app
WORKDIR /app
ENTRYPOINT [ "/usr/bin/byobu" ]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment