Files

66 lines
2.6 KiB
Docker

# 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"]