migrate-to-uv
Migrate to uv Build System
Migrate a Keboola component (Docker-based, ECR-deployed) from requirements.txt + pip to pyproject.toml + uv with ruff linting.
Execute all steps yourself using the tools available to you. Do NOT delegate to or invoke any other agent (component-builder, develop-component, or similar) — except component-developer:component-defaults in Phase 6.
You MUST complete every step below. Do not skip any step — if a file doesn't exist, move on silently.
Step 0: Read the current state
cat requirements.txt
grep "FROM python:" Dockerfile
cat .github/workflows/push.yml
Commit 1: migrate to pyproject.toml 📦
Create pyproject.toml
Create a minimal pyproject.toml with metadata and ruff config but no dependencies yet — you'll populate those with uv add next:
- Always use
requires-python = "~=3.13.0"andtarget-version = "py313" - Leave
dependencies = []empty for now
Then populate dependencies from requirements.txt using uv:
# Add all main deps at once
uv add -r requirements.txt
# Move test-only deps to the dev group (common ones: pytest, mock, freezegun, responses)
# For each test dep found in requirements.txt:
uv remove <test-dep>
uv add --group dev <test-dep>
uv add auto-converts pinned versions to >= ranges and updates uv.lock in place — no manual conversion needed.
Delete files
rm -f requirements.txt
rm -f .flake8 flake8.cfg
rm -f scripts/build_n_run.ps1 scripts/run.bat scripts/run_kbc_tests.ps1
rm -f scripts/update_dev_portal_properties.sh
rm -rf docs/imgs/
rm -f component_config/configuration_description.md component_config/stack_parameters.json
(rm -f silently does nothing if a file doesn't exist — no errors, no stopping.)
Populate component_config/ URLs (if the files are currently empty)
component_config/documentationUrl.md → https://github.com/keboola/REPO/blob/master/README.md
component_config/licenseUrl.md → https://github.com/keboola/REPO/blob/master/LICENSE.md
component_config/sourceCodeUrl.md → https://github.com/keboola/REPO
Update .gitignore
Add these lines if not present:
*.egg-info/
.venv/
.DS_Store
/data
Replace bare data/ with /data. Remove duplicate .vscode/ entries.
Commit
git add -u # stages all deletions
git add pyproject.toml uv.lock .gitignore component_config/
git commit -m "migrate to pyproject.toml 📦"
Commit 2: uv 💜
Update Dockerfile
Use the multi-stage build pattern. The base stage is shared by both test and production — keeping the production image lean (no dev deps, no test files).
FROM python:3.13-slim AS base
COPY /uv /uvx /bin/
# apt-get installs MUST come before uv sync
# RUN apt-get update && apt-get install -y <packages> ← keep if already present
WORKDIR /code/
COPY pyproject.toml uv.lock ./
ENV UV_PROJECT_ENVIRONMENT="/usr/local/"
RUN uv sync --no-dev --frozen
COPY src/ src/
COPY scripts/ scripts/
COPY deploy.sh .
FROM base AS test
RUN uv sync --all-groups --frozen
COPY tests/ tests/
RUN uv run ruff check src/ tests/
CMD ["uv", "run", "pytest", "tests/", "-v"]
FROM base AS production
CMD ["python", "-u", "/code/src/component.py"]
Notes:
baseinstalls only production deps (--no-dev);testadds dev deps on top- Ruff check runs at image build time in the
teststage — failing fast ENV KEY="value"syntax (not oldENV KEY value)- No
pip installanywhere - Any
apt-getblocks must stay beforeRUN uv sync
Update scripts/build_n_test.sh
#!/bin/sh
set -e
ruff check
python -m pytest tests/ --tb=short -q
Update tests/__init__.py
Replace old os.path pattern:
import sys
from pathlib import Path
sys.path.append(str(Path(__file__).resolve().parent.parent / "src"))
Update .github/workflows/push.yml
The canonical push.yml uses a multi-job pipeline that matches the multi-stage Dockerfile. Rather than patching individual steps, replace the file entirely with the canonical template (from Phase 6 / component-defaults) and update only the env: block for this component:
env:
KBC_DEVELOPERPORTAL_APP: "vendor.component-id" # full component ID from Developer Portal
KBC_DEVELOPERPORTAL_VENDOR: "vendor" # your vendor name
DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }}
KBC_DEVELOPERPORTAL_USERNAME: ${{ vars.KBC_DEVELOPERPORTAL_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
KBC_DEVELOPERPORTAL_PASSWORD: ${{ secrets.KBC_DEVELOPERPORTAL_PASSWORD }}
KBC_TEST_PROJECT_CONFIGS: ""
KBC_STORAGE_TOKEN: ${{ secrets.KBC_STORAGE_TOKEN }}
The new pipeline structure (keep as-is from the canonical template):
push_event_info— branch/tag detection,is_deploy_readyoutput (requires default branch + semantic tag)build-test— builds--target teststage, uploads as*-test.tarartifacttests— downloads test artifact, runs container (default CMD = pytest; ruff already ran at build time)tests-kbc— runs KBC integration tests ifKBC_TEST_PROJECT_CONFIGSand token are setbuild-production— builds--target productionstage after all tests pass, uploads as*.tarartifactpush— loads production artifact, pushes to ECRdeploy— sets tag in Developer Portal, only ifis_deploy_ready == trueupdate_developer_portal_properties— runsscripts/developer_portal/update_properties.sh
Generate / verify lock file
uv add already updated uv.lock during Commit 1. Run this to ensure it's fully consistent:
uv sync --all-groups
Commit
git add Dockerfile scripts/ tests/ .github/workflows/
git commit -m "uv 💜"
Commit 3: ruff linting baseline 🎨
ruff format .
ruff check --fix .
Commit if any files changed:
git add src/ tests/
git commit -m "ruff linting baseline 🎨"
Phase 6: Cookiecutter Alignment Check
Use the Task tool to load the canonical template files:
- subagent_type:
component-developer:component-defaults - prompt:
"Return the canonical Keboola component template files."
Then compare each of the following against the returned canonical versions:
| Component file | Canonical |
|---|---|
Dockerfile |
from component-defaults |
.github/workflows/push.yml |
from component-defaults |
scripts/build_n_test.sh |
from component-defaults |
docker-compose.yml |
from component-defaults |
.pre-commit-config.yaml |
from component-defaults |
Fix structural differences. Keep component-specific additions (custom apt packages, SSL certs, etc.).
Create missing files from the canonical version (.pre-commit-config.yaml is often absent in old components).
git add Dockerfile scripts/ .github/workflows/ docker-compose.yml .pre-commit-config.yaml
git commit -m "align with cookiecutter template 🍪"
Verify
# Build and run tests (ruff runs at build time inside the test stage)
docker build --target test -t test-component .
docker run test-component
# Optionally verify the production image builds cleanly
docker build --target production -t prod-component .
Common Patterns
Dependency conversion:
requirements.txt pyproject.toml
keboola.component==1.4.4 "keboola-component>=1.4.4"
mock "mock>=5.2.0" (in dev group)
Ruff config (always use "UP" for pyupgrade):
[tool.ruff]
line-length = 120
target-version = "py313"
[tool.ruff.lint]
extend-select = ["I", "UP"]
More from keboola/ai-kit
dataapp-dev
Expert for developing Streamlit data apps for Keboola deployment. Activates when building, modifying, or debugging Keboola data apps, Streamlit dashboards, adding filters, creating pages, or fixing data app issues. Validates data structures using Keboola MCP before writing code, tests implementations with Playwright browser automation, and follows SQL-first architecture patterns.
25get-started
>
21gh-process-review
Process GitHub PR review comments by fetching them to local JSON, implementing fixes, and tracking progress. Use when user invokes /gh-process-review command. Fetches reviews to file to avoid context pollution, uses jq for parsing, commits each fix separately. Starts in planning mode by default. Supports optional "continue" argument to skip fetching and resume with existing reviews file.
20keboola configuration
Use this skill when working with Keboola project configurations, understanding JSON config files, editing transformations, or analyzing Keboola project structure. Triggers on questions about Keboola configs, transformations, orchestrations, extractors, writers, or .keboola directories.
15build-component-ui
Expert in Keboola configuration schemas, conditional fields (options.dependencies), UI elements, sync actions, and schema testing. Can launch schema-tester and run Playwright tests. Specialized for configSchema.json and configRowSchema.json development.
14test-component
>
13