Skill: polylith-migrate-split-component-internals
📐 Scope vs sibling skills. This skill operates inside one already-extracted component, splitting its
core.pyinto multiple sibling Python files. No new components are created — only the internal file layout changes. Don't confuse with:
polylith-migrate-split-big-component— splits one component into multiple components. Use that when the unit being broken up is a component, not a file.polylith-migrate-isolate-shared-and-project-logic— separates shared vs project-specific code across components and projects; may create new components.polylith-migrate-extract-standalone-modules— pulls foundational modules out of the residual big component into new standalone components.
Goal
Split monolithic core.py files in shared components (e.g., models_shared, schemas_shared, or similar) into domain-focused modules. This skill ensures that shared components remain well-organized and maintainable.
Inputs
From migration/<PROJECT>/state.md:
TARGET_TOP_NS- Verification commands.
From migration/<PROJECT>/manifest.md:
- Current component list and structure.
All inputs from
state.mdare assumed to satisfy the validation rules inpolylith-migrate-discover(### Validation rules). Validate before proceeding.
Steps
1. Identify Candidates
- Scan components for large
core.pyfiles. - A component is a candidate if:
- The file contains definitions from multiple domains.
- The file contains helper/utility functions alongside class definitions.
- The file exceeds a reasonable size threshold.
2. Group Definitions by Domain
- Group definitions by the domain concept they serve.
- Example domains: ORM models, schema/dataclass clusters, helper functions.
3. Create New Modules
- Create domain-focused modules (e.g.,
merchant.py,transaction.py). - Move relevant definitions from
core.pyto the new modules.
4. Update __init__.py
- Re-export public names from the new modules in
__init__.py.
5. Handle core.py
- Delete
core.pyif all definitions have been moved. - Keep
core.pyif it serves as a composition point.
Verify
RUN_TEST_CMDsucceeds.- If set,
RUN_LINT_CMDandRUN_TYPECHECK_CMDsucceed.
Common failure modes
| Symptom | Likely cause | Remediation |
|---|---|---|
core.py is small (<100 lines) but mixes two domains |
The component itself is too small to warrant an internal split. | Leave it. Splitting adds indirection without benefit at this size; revisit when the file grows. |
After splitting, an import like from <ns>.<component> import <symbol> fails |
__init__.py was not updated to re-export the symbol from its new module. |
Add from <ns>.<component>.<new_module> import <symbol> to __init__.py. The component's public API must remain stable across the split. |
New files inside the component now circularly import each other (e.g., models/user.py ↔ models/transaction.py) |
Domain split was too aggressive; the two files genuinely share a concept. | Extract the shared concept into a third file (e.g., models/_base.py) and have both depend on it. |
Commit
After verification passes, commit this phase to the migration branch:
git add -A && git commit -m "migrate(<PROJECT>): phase <N> — split-component-internals"
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.