Skill: polylith-migrate-convert-package-manager
⚠ Opinionation gate. This skill is explicitly opinionated about uv. It does not generalize to Poetry, PDM, or Hatch workspaces. If your Polylith workspace uses one of those, do not run this skill — align the project to the workspace's manager via a manual step instead, and leave CONVERT_PACKAGE_MANAGER=no in state.md.
Goal
Convert the project's pyproject.toml to PEP 621/uv format and register it as a uv-workspace member. This makes the project share the workspace's single lock file and virtual environment, preventing version skew.
When to Skip
Skip this skill if any of the following holds:
PACKAGE_MANAGER=uv already in migration/<PROJECT>/state.md (nothing to convert).
- The workspace root does not use uv (this skill does not apply — see the opinionation gate above).
CONVERT_PACKAGE_MANAGER=no in state.md (user opted out during polylith-migrate-discover).
Verify the workspace uses uv before proceeding
Open the workspace root pyproject.toml and look for [tool.uv.workspace] and/or a sibling uv.lock. If neither is present, stop: this skill does not apply.
Inputs
From migration/<PROJECT>/state.md:
PROJECT_DIR
PACKAGE_MANAGER
RUN_TEST_CMD (optional: RUN_LINT_CMD, RUN_TYPECHECK_CMD)
All inputs from state.md are assumed to satisfy the validation rules in polylith-migrate-discover (### Validation rules). Validate before proceeding.
Steps
1. Ask for User Approval
2. Rewrite pyproject.toml to PEP 621/uv Format
- Move
[tool.poetry.dependencies] to [project] dependencies. Keep only runtime (non-dev, non-test) dependencies in the project, listed without version constraints.
- Remove Poetry-specific sections:
[tool.poetry], [tool.poetry.group.*], [[tool.poetry.source]], and [build-system] with poetry-core.
- Add a
[build-system] with hatchling (or the workspace's build backend).
- Preserve
[tool.*] sections for other tools (e.g., pytest, ruff, mypy).
- Add
[tool.uv] only if project-level uv configuration is needed.
3. Register as a Workspace Member
4. Consolidate Dependencies
- Add all third-party runtime dependencies with version constraints to the workspace root
pyproject.toml [project] dependencies.
- Move all dev/test/tooling dependencies to the workspace root
[dependency-groups] (e.g., dev = [...], test = [...]).
- Ensure the project's
pyproject.toml lists runtime dependencies without version numbers.
5. Lock and Sync
- Run
uv lock from the workspace root to regenerate uv.lock with the new member.
- Run
uv sync to install all dependencies into the shared .venv.
- Resolve any version conflicts that arise during
uv lock.
6. Delete Old Lock Files
- Remove
poetry.lock, Pipfile.lock, and generated requirements*.txt from the project directory.
7. Update Verification Commands
Verify
- Run the updated
RUN_TEST_CMD and confirm the same pass/fail counts as before the conversion.
- If set, run
RUN_LINT_CMD and RUN_TYPECHECK_CMD.
- Ensure
uv lock and uv sync succeed from the workspace root.
Common failure modes
| Symptom |
Likely cause |
Remediation |
Workspace root does not use uv (no [tool.uv.workspace], no uv.lock) |
This skill does not apply — the opinionation gate at the top of this file rules it out. |
Stop. Set CONVERT_PACKAGE_MANAGER=no in state.md. Align the project to the workspace's actual manager (Poetry/PDM/Hatch) via a manual step instead. |
uv lock fails with "no version satisfies …" after adding the project as a workspace member |
Project's old version constraints conflict with the workspace root's pins. |
Relax the workspace root's range, or, if the project legitimately needs a different version, pin it explicitly in the project's pyproject.toml. As a last resort, exclude the project from the workspace and use a separate environment. |
| Project depends on a private/internal package that the workspace root doesn't know about |
Private index or path-dependency not declared at the root. |
Add the dependency (and its source — [tool.uv.sources] or [[tool.uv.index]]) to the workspace root pyproject.toml. |
Done When
- The project is listed as a workspace member in the root
pyproject.toml.
uv lock and uv sync succeed from the workspace root.
- Old lock files (
poetry.lock, Pipfile.lock, generated requirements*.txt) are deleted from the project directory.
PACKAGE_MANAGER=uv is recorded in migration/<PROJECT>/state.md.
- Verification commands in
state.md use uv run.
- Tests pass via
uv run.
Commit
After verification passes, commit this phase to the migration branch:
git add -A && git commit -m "migrate(<PROJECT>): phase optional — convert-package-manager"
Substitute <PROJECT> from state.md. This is an optional skill off the numbered main line, so the commit uses the literal phase optional label (no <N>). Do not proceed without a clean commit — the per-phase commit is the rollback point for the next phase's failure-mode tables.
1---2name: polylith-migrate-convert-package-manager3description: [Internal sub-skill of `polylith-migrate-orchestrator` (optional, runs only when opted in during `polylith-migrate-discover`). Do not load directly — load `polylith-migrate-orchestrator` first.] Convert the project's `pyproject.toml` to PEP 621/uv-workspaces format and register it as a uv-workspace member. **Opinionated about uv** — only applies when the workspace itself uses uv. Skip otherwise.4---56# Skill: polylith-migrate-convert-package-manager78> ⚠ **Opinionation gate.** This skill is **explicitly opinionated about uv**. It does not generalize to Poetry, PDM, or Hatch workspaces. If your Polylith workspace uses one of those, **do not run this skill** — align the project to the workspace's manager via a manual step instead, and leave `CONVERT_PACKAGE_MANAGER=no` in `state.md`.910## Goal11Convert the project's `pyproject.toml` to PEP 621/uv format and register it as a uv-workspace member. This makes the project share the workspace's single lock file and virtual environment, preventing version skew.1213## When to Skip14Skip this skill if **any** of the following holds:15- `PACKAGE_MANAGER=uv` already in `migration/<PROJECT>/state.md` (nothing to convert).16- The workspace root does **not** use uv (this skill does not apply — see the opinionation gate above).17- `CONVERT_PACKAGE_MANAGER=no` in `state.md` (user opted out during `polylith-migrate-discover`).1819### Verify the workspace uses uv before proceeding20Open the **workspace root** `pyproject.toml` and look for `[tool.uv.workspace]` and/or a sibling `uv.lock`. If neither is present, **stop**: this skill does not apply.2122## Inputs23From `migration/<PROJECT>/state.md`:24- `PROJECT_DIR`25- `PACKAGE_MANAGER`26- `RUN_TEST_CMD` (optional: `RUN_LINT_CMD`, `RUN_TYPECHECK_CMD`)2728> All inputs from `state.md` are assumed to satisfy the validation rules in `polylith-migrate-discover` (`### Validation rules`). Validate before proceeding.2930## Steps3132### 1. Ask for User Approval33- Ask the user if they want to convert the project's `pyproject.toml` to PEP 621/uv format.34- Record their choice in `state.md`:35 ```text36 CONVERT_PACKAGE_MANAGER=<yes|no>37 ```3839### 2. Rewrite `pyproject.toml` to PEP 621/uv Format40- Move `[tool.poetry.dependencies]` to `[project] dependencies`. Keep only **runtime** (non-dev, non-test) dependencies in the project, listed **without version constraints**.41- Remove Poetry-specific sections: `[tool.poetry]`, `[tool.poetry.group.*]`, `[[tool.poetry.source]]`, and `[build-system]` with `poetry-core`.42- Add a `[build-system]` with `hatchling` (or the workspace's build backend).43- Preserve `[tool.*]` sections for other tools (e.g., pytest, ruff, mypy).44- Add `[tool.uv]` only if project-level uv configuration is needed.4546### 3. Register as a Workspace Member47- Add the project path to the workspace root `pyproject.toml` under `[tool.uv.workspace] members`.48 Example:49 ```toml50 members = ["projects/example-service-b"]51 ```5253### 4. Consolidate Dependencies54- Add all **third-party runtime dependencies with version constraints** to the workspace root `pyproject.toml` `[project] dependencies`.55- Move all dev/test/tooling dependencies to the workspace root `[dependency-groups]` (e.g., `dev = [...]`, `test = [...]`).56- Ensure the project's `pyproject.toml` lists runtime dependencies **without version numbers**.5758### 5. Lock and Sync59- Run `uv lock` from the workspace root to regenerate `uv.lock` with the new member.60- Run `uv sync` to install all dependencies into the shared `.venv`.61- Resolve any version conflicts that arise during `uv lock`.6263### 6. Delete Old Lock Files64- Remove `poetry.lock`, `Pipfile.lock`, and generated `requirements*.txt` from the project directory.6566### 7. Update Verification Commands67- Replace any `poetry run`, `pipenv run`, or bare commands with `uv run` equivalents in `migration/<PROJECT>/state.md`.68 Example:69 ```text70 RUN_TEST_CMD=uv run pytest <test-dirs>71 RUN_LINT_CMD=uv run ruff check <dirs>72 ```73- Update `PACKAGE_MANAGER=uv` in `state.md`.7475## Verify76- Run the updated `RUN_TEST_CMD` and confirm the same pass/fail counts as before the conversion.77- If set, run `RUN_LINT_CMD` and `RUN_TYPECHECK_CMD`.78- Ensure `uv lock` and `uv sync` succeed from the workspace root.7980## Common failure modes8182| Symptom | Likely cause | Remediation |83|---------|--------------|-------------|84| Workspace root does not use uv (no `[tool.uv.workspace]`, no `uv.lock`) | This skill does not apply — the opinionation gate at the top of this file rules it out. | Stop. Set `CONVERT_PACKAGE_MANAGER=no` in `state.md`. Align the project to the workspace's actual manager (Poetry/PDM/Hatch) via a manual step instead. |85| `uv lock` fails with "no version satisfies …" after adding the project as a workspace member | Project's old version constraints conflict with the workspace root's pins. | Relax the workspace root's range, or, if the project legitimately needs a different version, pin it explicitly in the project's `pyproject.toml`. As a last resort, exclude the project from the workspace and use a separate environment. |86| Project depends on a private/internal package that the workspace root doesn't know about | Private index or path-dependency not declared at the root. | Add the dependency (and its source — `[tool.uv.sources]` or `[[tool.uv.index]]`) to the workspace root `pyproject.toml`. |8788## Done When89- The project is listed as a workspace member in the root `pyproject.toml`.90- `uv lock` and `uv sync` succeed from the workspace root.91- Old lock files (`poetry.lock`, `Pipfile.lock`, generated `requirements*.txt`) are deleted from the project directory.92- `PACKAGE_MANAGER=uv` is recorded in `migration/<PROJECT>/state.md`.93- Verification commands in `state.md` use `uv run`.94- Tests pass via `uv run`.9596## Commit9798After verification passes, commit this phase to the migration branch:99100```bash101git add -A && git commit -m "migrate(<PROJECT>): phase optional — convert-package-manager"102```103104Substitute `<PROJECT>` from `state.md`. This is an **optional** skill off the numbered main line, so the commit uses the literal `phase optional` label (no `<N>`). Do not proceed without a clean commit — the per-phase commit is the rollback point for the next phase's failure-mode tables.