# syntax=docker/dockerfile:1.7 # # Two stages: a uv-based builder that resolves the venv, and a thin # python:3.13-slim runtime with bun + the `claude` CLI baked in. # # Alpine is intentionally avoided: @anthropic-ai/claude-code ≥ 2.1.113 # ships a glibc-only native binary (anthropics/claude-code#50270). # # This image is deliberately un-opinionated about ports and command — # the consumer's compose file decides what to publish and how to invoke. # ---- Builder: uv + Python deps ---- FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS builder ENV UV_LINK_MODE=copy \ UV_COMPILE_BYTECODE=1 \ UV_PYTHON_DOWNLOADS=never # `git` is required at build time: the `prod` extra resolves # raycast-api / claude-code-api from git URLs. RUN apt-get update \ && apt-get install -y --no-install-recommends git \ && rm -rf /var/lib/apt/lists/* WORKDIR /app RUN --mount=type=cache,target=/root/.cache/uv \ --mount=type=bind,source=uv.lock,target=uv.lock \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ uv sync --frozen --no-dev --no-install-project --extra prod COPY . /app RUN --mount=type=cache,target=/root/.cache/uv \ uv sync --frozen --no-dev --extra prod # ---- Runtime ---- FROM python:3.13-slim AS runtime RUN apt-get update \ && apt-get install -y --no-install-recommends ca-certificates git \ && rm -rf /var/lib/apt/lists/* # Bun native binary (glibc) — fast `npm install` replacement, only used # to drop the claude CLI into the image. Not invoked at runtime. COPY --from=oven/bun:1-slim /usr/local/bin/bun /usr/local/bin/bun RUN ln -s /usr/local/bin/bun /usr/local/bin/bunx # `--trust` is required: without it bun skips the postinstall step that # fetches claude's native binary (anthropics/claude-code#50203). The # postinstall itself is bun's smoke check — if it fails the layer # fails. We deliberately DO NOT run `claude --version` here: claude # touches `$HOME` on every invocation (creates `/root/.claude/`, # `/root/.claude.json`, sometimes `/root/.config/claude/`), and those # build-time artifacts seed the runtime named-volume `claude-home` # with stale "haven't onboarded" state, so the user gets re-prompted # for trust/bypass dialogs on every rebuild and the subscription auth # can land on a tainted credential file. ENV BUN_INSTALL=/usr/local/bun-global \ PATH=/usr/local/bun-global/bin:/app/.venv/bin:$PATH RUN bun install -g --trust @anthropic-ai/claude-code \ && test -x "$(command -v claude)" \ && rm -rf /root/.claude /root/.claude.json /root/.config/claude COPY --from=builder /app/.venv /app/.venv COPY --from=builder /app /app WORKDIR /app ENTRYPOINT ["python", "-m"] CMD ["beaver_gateway"]