From 04bef6320986d7bda7f90fbe382ddb91d8eb6d00 Mon Sep 17 00:00:00 2001 From: tegwick Date: Sun, 3 May 2026 01:43:50 +0200 Subject: [PATCH] Locked in cytoscape.js as visualization for dep graph --- .dockerignore | 18 +++++++++++++ Dockerfile | 49 ++++++++++++++++++++++++++++++++++++ docs/container-image.md | 56 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docs/container-image.md diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..7a5b430 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,18 @@ +.venv +.pytest_cache +__pycache__ +**/__pycache__ +*.pyc +*.pyo +*.pyd +.env +.env.* +!.env.example +dashboard/node_modules +dashboard/dist +dashboard/src/.observablehq/cache +dashboard/.observablehq/cache +kubectl +tests +docs +infra diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..534811e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,49 @@ +FROM python:3.12-slim AS runtime + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 \ + PATH="/app/.venv/bin:${PATH}" + +WORKDIR /app + +RUN apt-get update \ + && apt-get install -y --no-install-recommends curl ca-certificates \ + && rm -rf /var/lib/apt/lists/* \ + && pip install --no-cache-dir uv + +COPY pyproject.toml ./ + +RUN python - <<'PY' > /tmp/requirements.txt +import tomllib + +with open("pyproject.toml", "rb") as f: + project = tomllib.load(f)["project"] + +for dep in project["dependencies"]: + # llm-connect is currently a local editable test integration in this repo. + # The State Hub API/MCP runtime does not import it, and a container build + # must not depend on /home/worsch existing inside the image. + if dep == "llm-connect": + continue + print(dep) +PY + +RUN uv venv /app/.venv \ + && uv pip install --python /app/.venv/bin/python --no-cache -r /tmp/requirements.txt + +COPY alembic.ini ./ +COPY api/ ./api/ +COPY flows/ ./flows/ +COPY mcp_server/ ./mcp_server/ +COPY migrations/ ./migrations/ +COPY policies/ ./policies/ +COPY prompts/ ./prompts/ +COPY scripts/ ./scripts/ +COPY task_flow_engine/ ./task_flow_engine/ + +EXPOSE 8000 + +HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \ + CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/state/health', timeout=3).read()" + +CMD ["uvicorn", "api.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/docs/container-image.md b/docs/container-image.md new file mode 100644 index 0000000..b21414d --- /dev/null +++ b/docs/container-image.md @@ -0,0 +1,56 @@ +# State Hub Container Image + +The State Hub production image is built from `state-hub/Dockerfile`. + +## Build + +```bash +cd state-hub +docker build -t state-hub:local . +``` + +The image installs runtime dependencies from `pyproject.toml` and excludes the +local editable `llm-connect` dependency. `llm-connect` is currently used by the +test suite only; the API and MCP runtime do not import it. Removing that +workstation-local path from the image keeps cluster builds reproducible. + +## Runtime + +Required environment: + +```bash +DATABASE_URL=postgresql+asyncpg://USER:PASSWORD@HOST:5432/DB +API_BASE=http://127.0.0.1:8000 +``` + +The container starts: + +```bash +uvicorn api.main:app --host 0.0.0.0 --port 8000 +``` + +It includes Alembic migrations and can run migrations with: + +```bash +docker run --rm --env DATABASE_URL=... state-hub:local alembic upgrade head +``` + +## Verification + +After start, check: + +```bash +curl http://127.0.0.1:8000/state/health +``` + +Expected response: + +```json +{"status":"ok","db":"connected"} +``` + +## Registry + +The final registry target is intentionally not hardcoded yet. CUST-WP-0011 +still has an open human decision for Gitea registry versus an interim external +registry.