Files
beaver-gateway/Dockerfile

71 lines
2.5 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
# ---- UI: SvelteKit SPA built with bun ----
FROM oven/bun:1-slim AS ui
WORKDIR /ui
COPY ui/package.json ui/bun.lock ./
RUN bun install --frozen-lockfile
COPY ui ./
RUN bun --bun svelte-kit sync && bun --bun run build
# ---- 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): `bunx` runs the stdio MCP servers declared in
# the user's config. The claude CLI itself ships inside the
# claude-agent-sdk wheel (`_bundled/claude`), nothing to install here.
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
# The model process runs as `beaver-runner`, not as the gateway: the
# adapter spawns claude under this uid with a whitelisted environment.
# `acl` lets the entrypoint grant it write access to the vault sub-mounts
# without chowning files that Obsidian Sync keeps rewriting as root.
RUN apt-get update \
&& apt-get install -y --no-install-recommends acl \
&& rm -rf /var/lib/apt/lists/* \
&& useradd --system --uid 1001 --create-home --shell /usr/sbin/nologin beaver-runner
ENV PATH=/app/.venv/bin:$PATH
COPY --from=builder /app/.venv /app/.venv
COPY --from=builder /app /app
COPY --from=ui /ui/build /app/ui/build
WORKDIR /app
ENTRYPOINT ["python", "-m"]
CMD ["beaver_gateway"]