# Timmy self-hosted vision worker (issue #15). # # Reproducible by construction: the llama.cpp revision and both model hashes are pinned here and in # deploy/worker/receipts.json, and tests/worker-container.test.js fails if either drifts from # scripts/bootstrap_selfhost_smolvlm.sh on the host. # # The weights are deliberately NOT baked into the image. They are mounted read-only at /models and # hash-verified against the pinned receipts by the entrypoint before the server starts. ARG LLAMA_CPP_COMMIT=6d05498314db1b57f81c271080018aa2d0b89be9 ARG MODEL_SHA256=0cf76814555b8665149075b74ab6b5c1d428ea1d3d01c1918c12012e8d7c9f58 ARG MMPROJ_SHA256=ae07ea1facd07dd3230c4483b63e8cda96c6944ad2481f33d531f79e892dd024 # Digest-pinned bases, recorded in deploy/worker/receipts.json. A tag alone can be repointed, so # the digest is what makes this build reproducible. FROM nvidia/cuda:12.4.1-devel-ubuntu22.04@sha256:da6791294b0b04d7e65d87b7451d6f2390b4d36225ab0701ee7dfec5769829f5 AS build ARG LLAMA_CPP_COMMIT RUN apt-get update \ && apt-get install --yes --no-install-recommends git ca-certificates cmake build-essential \ && rm -rf /var/lib/apt/lists/* WORKDIR /src RUN git init llama.cpp \ && cd llama.cpp \ && git remote add origin https://github.com/ggml-org/llama.cpp \ && git fetch --depth 1 origin "${LLAMA_CPP_COMMIT}" \ && git checkout --detach FETCH_HEAD RUN cmake -S llama.cpp -B llama.cpp/build -DCMAKE_BUILD_TYPE=Release -DLLAMA_CURL=OFF -DGGML_CUDA=ON \ && cmake --build llama.cpp/build --parallel "$(nproc)" --target llama-server FROM nvidia/cuda:12.4.1-runtime-ubuntu22.04@sha256:517da2300c184c9999ec203c2665244bdebd3578d12fcc7065e83667932643d9 AS runtime ARG MODEL_SHA256 ARG MMPROJ_SHA256 RUN apt-get update \ && apt-get install --yes --no-install-recommends curl ca-certificates \ && rm -rf /var/lib/apt/lists/* \ && mkdir -p /models COPY --from=build /src/llama.cpp/build/bin/ /usr/local/bin/ COPY deploy/worker/entrypoint.sh /usr/local/bin/timmy-worker-entrypoint COPY scripts/worker_ready.sh /usr/local/bin/timmy-worker-ready RUN chmod 0755 /usr/local/bin/timmy-worker-entrypoint /usr/local/bin/timmy-worker-ready && ldconfig # No credential is configured: the worker is a private service the app reaches over host loopback. # 0.0.0.0 here is the address inside this container's own network namespace; the run recipe decides # exposure and publishes on 127.0.0.1 only. ENV TIMMY_MODEL_DIR=/models \ TIMMY_MODEL_FILE=/models/SmolVLM2-2.2B-Instruct-Q4_K_M.gguf \ TIMMY_MMPROJ_FILE=/models/mmproj-SmolVLM2-2.2B-Instruct-Q8_0.gguf \ TIMMY_MODEL_SHA256=${MODEL_SHA256} \ TIMMY_MMPROJ_SHA256=${MMPROJ_SHA256} \ TIMMY_MODEL_ALIAS=SmolVLM2-2.2B-Instruct \ TIMMY_MODEL_HOST=0.0.0.0 \ TIMMY_MODEL_PORT=8080 USER 10001:10001 EXPOSE 8080 # Health is the post-load gate: the worker is not healthy until the pinned model is being served, # so an orchestrator cannot route to a worker that cannot answer. start-period covers a cold load. HEALTHCHECK --interval=30s --timeout=5s --start-period=600s --retries=3 \ CMD ["/usr/local/bin/timmy-worker-ready", "--host", "127.0.0.1", "--port", "8080", "--alias", "SmolVLM2-2.2B-Instruct"] ENTRYPOINT ["/usr/local/bin/timmy-worker-entrypoint"]