aboutsummaryrefslogtreecommitdiff
path: root/docker/Dockerfile
diff options
context:
space:
mode:
Diffstat (limited to 'docker/Dockerfile')
-rw-r--r--docker/Dockerfile62
1 files changed, 47 insertions, 15 deletions
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 89f2448..33b44eb 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -2,7 +2,8 @@ FROM debian:trixie-slim
ENV DEBIAN_FRONTEND=noninteractive
-# core tooling
+# ---- System packages ----
+
RUN apt-get update && apt-get install -y --no-install-recommends \
sudo \
curl \
@@ -24,44 +25,75 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
iputils-ping \
&& rm -rf /var/lib/apt/lists/*
-# Narrow sudo: senia can run apt/apt-get only, no password.
+# ---- Narrow sudo for senia (apt only, no password) ----
+
RUN echo "senia ALL=(root) NOPASSWD: /usr/bin/apt, /usr/bin/apt-get" \
> /etc/sudoers.d/senia-apt \
&& chmod 440 /etc/sudoers.d/senia-apt \
&& visudo -c -f /etc/sudoers.d/senia-apt
-# the visudo -c validates the file syntax; build fails if it's malformed
-# nodejs (for claude code) — using nodesource for a recent version
+# ---- Node + claude code ----
+
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*
RUN npm install -g npm@11.14.0
-# claude code itself
RUN npm install -g @anthropic-ai/claude-code
+# ---- Python MCP SDK (system-wide; used by MCP servers, not senia-managed) ----
+
RUN pip3 install --break-system-packages mcp
-# create non-root user matching common host uid (1000) so mounted volumes have correct ownership
+# ---- Non-root user ----
+
ARG USER_UID=750
ARG USER_GID=750
RUN groupadd --system --gid ${USER_GID} senia \
&& useradd --system --uid ${USER_UID} --gid ${USER_GID} -m -s /bin/bash senia \
&& echo "umask 002" >> /home/senia/.bashrc
+# ---- uv (the python project manager for the agent loop) ----
+
+# Single static binary, no python deps. The official image is the canonical install path.
+COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
+
+# uv config:
+# - put venvs in a known location, not next to pyproject.toml
+# - compile bytecode at install time for faster startup
+# - copy instead of hardlink for predictable docker layer behavior
+ENV UV_PROJECT_ENVIRONMENT=/opt/venv \
+ UV_COMPILE_BYTECODE=1 \
+ UV_LINK_MODE=copy
+
+# ---- User-level tools for senia (claude code, npm prefix) ----
+
USER senia
-# Install uv (the modern python package manager) system-wide so senia can use it
-# We install it as senia to avoid root-owned install paths.
-RUN curl -LsSf https://astral.sh/uv/install.sh | sh
-# uv installs to /home/senia/.local/bin/uv
-# Set up npm to install globally into senia's home (no sudo needed)
+# Set up npm prefix for any *other* user-level node tools senia might want
RUN mkdir -p /home/senia/.npm-global \
&& npm config set prefix /home/senia/.npm-global
-# Make sure her PATH includes the user-local bin dirs
-ENV PATH=/home/senia/.local/bin:/home/senia/.npm-global/bin:$PATH
+USER root
+
+# senia's PATH includes her user-local npm bins + the venv that uv populates
+ENV PATH="/opt/venv/bin:/home/senia/.npm-global/bin:$PATH"
+
+# ---- Agent project install (with layer caching) ----
+
+# Deps first; cached as long as pyproject.toml + uv.lock are unchanged
+COPY --chown=senia:senia agent/pyproject.toml agent/uv.lock /etc/senia/agent/
+WORKDIR /etc/senia/agent
+RUN uv sync --frozen --no-install-project --no-dev
-WORKDIR /workspace
+# Then the project code
+COPY --chown=senia:senia agent/ /etc/senia/agent/
+RUN uv sync --frozen --no-dev
+
+# ---- Runtime ----
+
+USER senia
+# WORKDIR /etc/senia/agent
+EXPOSE 8000
-CMD ["bash"]
+CMD ["uvicorn", "orchestrator.api:app", "--host", "0.0.0.0"]