Iteration 175 §9.6 — selection rationale and operating notes for the backend + bt_api_py monorepo wiring.
| Tool | Pros | Cons | Decision |
|---|---|---|---|
| uv workspace (selected) | First-class [tool.uv.workspace] declaration; resolves member packages into a single venv with one lock file; backed by Astral, same vendor as the project's existing uv adoption. |
Lock-file format (uv.lock) is uv-specific. |
✅ chosen for 175. |
| hatch workspace | Mature isolation per env; explicit env tables. | Heavier ergonomics; second tool on top of the existing pip/uv toolchain we want to keep small. | not chosen. |
| pdm workspace | PEP 517 native; supports multi-package mono-repos via [tool.pdm]. |
Adds yet another lock format alongside our SSOT pip lock. | not chosen. |
175 also explicitly rejected polyrepo splits and pnpm-style JS monorepo tooling: the project already enforces a clean Python/JS split at the top-level (
src/backendvssrc/frontend), so a single Python-side workspace is sufficient.
src/clientportal.gw/ is a vendored third-party tarball. It is not a
workspace member — it is built and shipped separately as part of the live
trading gateway. The 174 §A6 boundary discussion documented this; 175
inherits that decision unchanged. The workspace [tool.uv.workspace] members = ["src/backend", "src/bt_api_py"] list is intentionally the
complete set.
If a future iteration adds a third Python member (e.g. a CLI shipped from the repo), the steps are:
- Add the new directory to
[tool.uv.workspace] members. - Ensure that directory has its own
pyproject.toml. - Re-run
uv sync --workspaceto regenerateuv.lock. - Run
python scripts/dev/check_workspace_lock_conflict.pyto verify the new dependencies do not contradictconfig/requirements-dev.lock.
174 §A6 already declared:
src/backendandsrc/bt_api_pyare independent Python packages.src/backendis consumer-only ofbt_api_pybrokers; no business logic crosses the boundary other than via the public broker contract.src/clientportal.gw/is vendored (third-party), explicitly not part of the project's source tree under management.
175 §9 preserves all three of those rules. The workspace tooling does not
relax them; it only provides a single command (make check-all) that
exercises both packages with one venv resolution.
| What you want | Command |
|---|---|
| Install both packages into a shared venv | uv sync --workspace |
| Run lint + typecheck + tests across all members | make check-all |
| Verify uv.lock and config/requirements-dev.lock agree | make workspace-lock-check |
| Edit only the backend (legacy flow) | pip install -e ".[dev]" inside src/backend/ — still supported. |
The legacy single-package flow remains the documented default in
CONTRIBUTING.md "Dependency Management". The workspace flow is offered
as an opt-in convenience and is the path the 175 monorepo-check advisory
CI job exercises.
monorepo-checkjob in.github/workflows/ci.ymlrunsmake check-allwithcontinue-on-error: true. It surfaces failures as a⚠️ entry inci-summarybut does not block PR merge in 175.- Promotion plan: 176 considers flipping
monorepo-checkto a hard gate once it has stayed green onmasterfor one week.