# CI Requirements — FabledScribe > Spec lives in [`docs/process.md`](https://git.fabledsword.com/bvandeusen/CI-runner/src/branch/main/docs/process.md) > in the CI-Runner repo. ## Runtime image ``` git.fabledsword.com/bvandeusen/ci-python:3.14 ``` Used by all four jobs in `.forgejo/workflows/ci.yml`: typecheck (Vue/TS), lint (ruff), test (pytest), build (docker buildx). ## Image deps used - python 3.14 - node 24 (used for `npm ci` + `vue-tsc` in the typecheck job, and as the frontend builder stage inside the production `Dockerfile`) - ruff (lint job runs `ruff check src/` with zero install overhead) - docker CLI + buildx (build job pushes the production image to the Forgejo registry) ## Per-job tool installs Anything CI installs at job time that isn't in the image. Promotion candidates if more than one project needs them. - `uv` — installed inline in the test job (`curl -LsSf https://astral.sh/uv/install.sh | sh`). **Temporary**: belongs in the ci-python image so every consumer doesn't re-install on cold start. Tracked at [CI-Runner](https://git.fabledsword.com/bvandeusen/CI-runner). - `http-ece` is `--no-build-isolation`-installed before the editable package install because http-ece doesn't declare `setuptools` as a build dep and uv creates bare venvs without it. Not promotion-worthy (one project, one wheel). ## Notes - Production runtime image (`Dockerfile`) also tracks Python 3.14 — the CI image and runtime image stay aligned by design so test results are representative. - Build wall time: dominated by `pytest` (full async test suite). Cold ci-python pulls add ~30s; not a blocker. - Registry-backed BuildKit layer cache (`type=registry,ref=…:cache,mode=max`) gives ~80% speedup on warm builds — see the build job comment. - `pyproject.toml` pins `requires-python = ">=3.14"` to match the CI + runtime target; lockfile (`uv.lock`) is committed and resolves against Python 3.14.