midtown 0.5.4

Midtown - a multi-Claude Code workspace manager, inspired by Gastown
Documentation
# Dockerfile — Production image for running Midtown
#
# Multi-stage build: compile with Rust toolchain, ship only the binary
# with runtime dependencies (tmux, git, gh CLI).
#
# Usage:
#   docker build -t midtown .
#   docker run -it --rm -v /path/to/repo:/repo -w /repo midtown start
#
# For persistent state, mount the midtown config directory:
#   docker run -it --rm \
#     -v ~/.midtown:/home/midtown/.midtown \
#     -v /path/to/repo:/repo \
#     -w /repo midtown start

# syntax=docker/dockerfile:1

# ─── Stage 1: Chef planner ──────────────────────────────────────────────────
# Analyzes the project and creates a "recipe" of dependencies
FROM rust:bookworm AS chef
RUN cargo install cargo-chef
WORKDIR /app

# ─── Stage 2: Recipe creation ───────────────────────────────────────────────
FROM chef AS planner
COPY . .
RUN cargo chef prepare --recipe-path recipe.json

# ─── Stage 3: Build ─────────────────────────────────────────────────────────
FROM chef AS builder

# System dependencies for building
RUN apt-get update && apt-get install -y --no-install-recommends \
        pkg-config \
    && rm -rf /var/lib/apt/lists/*

# Build dependencies from recipe (cached layer)
COPY --from=planner /app/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json

# Now copy source and build the actual application
COPY . .
RUN cargo build --release

# ─── Stage 4: Runtime ───────────────────────────────────────────────────────
FROM debian:bookworm-slim AS runtime

# Runtime dependencies:
# - tmux: process model for lead/coworker sessions
# - git: worktree management
# - curl: general use, Claude CLI install
# - procps: process inspection (ps)
# - jq: JSON parsing in scripts
# - ca-certificates: HTTPS connections
RUN apt-get update && apt-get install -y --no-install-recommends \
        tmux \
        git \
        curl \
        unzip \
        procps \
        jq \
        ca-certificates \
    && rm -rf /var/lib/apt/lists/*

# gh CLI via GitHub's apt repo
RUN 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" \
        > /etc/apt/sources.list.d/github-cli.list \
    && apt-get update && apt-get install -y gh \
    && rm -rf /var/lib/apt/lists/*

# Non-root user for security and proper $HOME handling
RUN useradd -m -s /bin/bash midtown

# Install CLI tools as midtown user BEFORE copying the binary so these
# layers are cached even when source code changes.
USER midtown
WORKDIR /home/midtown

# Bun (JavaScript runtime, also used for npm packages)
RUN curl -fsSL https://bun.sh/install | bash \
    || echo "Bun install failed (may not be available in all environments)"

ENV PATH="/home/midtown/.bun/bin:${PATH}"

# Claude Code CLI
RUN curl -fsSL https://claude.ai/install.sh | bash \
    && echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc \
    || echo "Claude CLI install failed (may not be available in all environments)"

ENV PATH="/home/midtown/.local/bin:${PATH}"

# OpenAI Codex CLI
RUN bun install -g @openai/codex \
    || echo "Codex CLI install failed (may not be available in all environments)"

# Default git config (can be overridden via environment)
RUN git config --global user.email "midtown@docker.local" \
    && git config --global user.name "Midtown Docker" \
    && git config --global init.defaultBranch main

# Copy the binary from builder LAST so code changes don't invalidate
# the CLI install layers above.
USER root
COPY --from=builder /app/target/release/midtown /usr/local/bin/midtown
USER midtown

ENTRYPOINT ["midtown"]
CMD ["--help"]