name: polylith-migrate-prepare-project
description: "[Internal sub-skill of polylith-migrate-orchestrator. Do not load directly — load polylith-migrate-orchestrator first, which drives all phases.] Clean up the project subfolder and consolidate dependencies after extracting application code into bases."
Skill: polylith-migrate-prepare-project
Goal
Clean up the project subfolder (projects/<PROJECT>/) and consolidate dependencies. After this step, the project subfolder should contain only:
- Project
pyproject.toml(with brick references). - Task runners (
Makefile,Justfile). - Project-specific config (e.g.,
alembic.iniand itsalembic/directory). - Compatibility shim (only when
SHIM_STRATEGY=shim).
Inputs
From migration/<PROJECT>/state.md:
PROJECT_DIRTARGET_TOP_NSALIAS(optional:GROUP)- Verification commands.
From migration/<PROJECT>/manifest.md:
- Infra files list.
All inputs from
state.mdare assumed to satisfy the validation rules inpolylith-migrate-discover(### Validation rules). Validate before proceeding.
Steps
1. Verify Project Subfolder
- Run
directory_treeonprojects/${PROJECT}/to confirm only infra and config files remain.
2. Update pyproject.toml
- Add brick references to
[tool.polylith.bricks]:[tool.polylith.bricks] "../../bases/${TARGET_TOP_NS}/${INITIAL_BASE_NAME}" = "${TARGET_TOP_NS}/${INITIAL_BASE_NAME}" - Register the project alias and group in
workspace.toml(if provided):[tool.polylith.projects.alias] ${PROJECT} = "${ALIAS}" [tool.polylith.projects.groups] ${GROUP} = ["${PROJECT}"]
3. Move Tests to Workspace Level
- Move
tests/totest/<test-dir>/, where<test-dir>is a valid Python package name. ⚠${PROJECT}frequently contains hyphens (e.g.order-management-api), which are illegal in a package name and break pytest's package-style import. Derive an underscore name — the workspace's<svc>_serviceconvention is a good default (e.g.order_management_service). Record<test-dir>instate.md. - If the moved tests import the old package by name (e.g.
from tests.fixtures import …/from tests.helpers import …), rewrite those to the new name (from <test-dir>.fixtures import …). Brick imports (<TARGET_TOP_NS>.*) are absolute and need no change. - Update
RUN_TEST_CMDinmigration/${PROJECT}/state.mdto point to the new location. - Update mock patch strings in test files if paths changed.
Per-brick test redistribution (
test/<theme>/<ns>/<brick>/) is handled later inpolylith-migrate-refactor-tests— this step only lifts tests to the workspace level. See that skill for the shared-helper / namespace-merge caveats before splitting further.
4. Move Infrastructure Folders
- Move deployment infra folders (e.g.,
helm/,k8s/,kustomize/,skaffold/) toinfra/<folder>/${PROJECT}/. - 🔒 Secret &
.gitignorecheck before the move. Infra folders frequently carry secret material (e.g.values-secret.yaml,*.env, sealed-secret sources, TLS keys). Two hazards when relocating them:.gitignorescope shifts. Ignore rules scoped to the old path stop matching at the newinfra/<folder>/${PROJECT}/path, so a previously-ignored secret file can become tracked after the move. Verify the destination is still covered by.gitignorefor anything that was ignored at the source.- Inline secrets. Scan the moved manifests/values for inline credentials before committing. Do not commit newly-tracked secrets; have the user move them to an ignored path or a secret manager first.
- Keep
alembic/together withalembic.iniin the project — do not split them.alembic.ini'sscript_locationpoints atalembic/relatively, andalembic/env.pyimports the project's bricks; separating them breaks migrations. (Alembic is project-specific config, which the project subfolder is allowed to keep.) ⚠alembic.inicommonly holds asqlalchemy.urlwith DB credentials — if it is not already tracked, do not newly commit it with a literal credential; reference an env var instead. - ⚠ Deploy-path breakage: moving infra breaks deploy scripts /
skaffold/ CI that hardcode the old paths. If you cannot verify the deploy in the migration environment (no deploy / manifest-diff cycle available), it is acceptable to defer the infra move and document it instate.mdrather than relocate blindly. Otherwise, update the referencing scripts and record the change. Prefer updating references over committing a symlink: a committed symlink can point outside the repo and behaves inconsistently across checkouts/OSes — if you must use one as a transition, keep it within the repo, record it instate.md, and schedule its removal.
5. Consolidate Dependencies
- Move third-party dependencies with version constraints to the workspace root
pyproject.toml. - Move dev/test/tooling dependencies to the workspace root.
- List runtime dependencies without version numbers in the project
pyproject.toml. - Sync the virtual environment with the project's package manager (e.g.
uv sync,pdm install,poetry install— matchPACKAGE_MANAGERinstate.md). - Verify dependencies, substituting your package manager's run prefix (
<RUN>=uv run/pdm run/poetry run/ bare in an activated venv):<RUN> pip list # Confirm all dependencies are installed <RUN> python -c "import <dependency>" # Verify key dependencies are available
Verify
RUN_TEST_CMDsucceeds against the new test location.- If set,
RUN_LINT_CMDandRUN_TYPECHECK_CMDsucceed. - Run
POLY_CMD_PREFIX checkto validate the workspace structure. - Run
POLY_CMD_PREFIX infoto inspect the workspace and confirm the project is correctly registered.
Common failure modes
| Symptom | Likely cause | Remediation |
|---|---|---|
RUN_TEST_CMD collects 0 tests after step 3 |
The command in state.md still references the old projects/${PROJECT}/tests path. |
Update RUN_TEST_CMD to the new test/${PROJECT}/ location. Also check [tool.pytest.ini_options].testpaths / rootdir / conftest.py discovery. |
Tests fail with ModuleNotFoundError on internal imports |
Tests use from tests.fixtures import … and the tests package name changed. |
Update test imports to the new test root path. If many tests reference the old name, consider keeping tests as the leaf directory and only renaming the parent. |
mock.patch("<old.path>") fails with AttributeError |
Mock patch strings reference moved modules. | Update patch strings to the new module paths. Use grep -r 'patch("' test/ to find them all. |
Infra folder move breaks deploy scripts that hardcoded paths (e.g., helm/<chart>/values.yaml) |
Deploy scripts haven't been updated to the new infra/<folder}/${PROJECT}/ location. |
Either update the scripts, or symlink the new location from the old one as a transitional step (record the symlink in migration/${PROJECT}/state.md). |
poly check complains about brick references after dependency consolidation |
A runtime dependency was moved to the workspace root but the project's pyproject.toml doesn't declare it. |
Add the dependency name (no version) back to the project's [project.dependencies]. The version stays only at the workspace root. |
| Verification fails and you can't quickly diagnose | Phase commit not yet made. | git reset --hard HEAD to roll back to the previous phase's commit and consult the user. |
Commit
After verification passes, commit this phase to the migration branch:
git add -A && git commit -m "migrate(<PROJECT>): phase <N> — prepare-project"
Substitute <PROJECT>, <N>, and <phase-name> from state.md and the orchestrator's phase table. Do not proceed to the next phase without a clean commit — the per-phase commit is the rollback point for the next phase's failure-mode tables.