Files
agentic-mobile-control/openspec/changes/uv-workspace-packaging/design.md
T

5.7 KiB

Context

The root project currently discovers every Python package, including cloud, through one setuptools configuration and resolves dependencies without a committed lockfile. The cloud code depends inward on Runtime and workflow packages, while composition-safety tests prohibit those inner packages from importing cloud back. The packaging migration must preserve that dependency direction and all existing Python import paths while preparing the repository for separately runnable cloud and host applications.

Goals / Non-Goals

Goals:

  • Configure a uv workspace with one shared lockfile and explicit internal workspace dependencies.
  • Retain the existing root project as the device-agent-runtime member to minimize migration risk.
  • Move the existing cloud Python package into a packages/cloud-platform member published as device-cloud-platform.
  • Preserve cloud.* imports, tests, local Runtime commands, and current feature behavior.
  • Define repeatable workspace-aware commands for synchronization, tests, builds, and package selection.
  • Keep the dependency graph one-directional: cloud platform depends on device Runtime, never the reverse.

Non-Goals:

  • Creating a runnable distributed cloud control plane or host worker.
  • Adding remote dispatch, heartbeat endpoints, authentication, PostgreSQL, or scheduler processes.
  • Splitting cloud.sdk into a separate namespace distribution during this migration.
  • Moving the Vue/Vite console into the Python workspace.
  • Changing public REST/MCP contracts or Runtime execution behavior.

Decisions

D1: Keep the Runtime project at the repository root

The root pyproject.toml remains the device-agent-runtime project and becomes the workspace root. This avoids relocating all established inner packages at once and keeps existing developer commands and editable installs recognizable.

Alternative considered: move all Runtime packages under packages/device-runtime. Rejected for this change because it multiplies path, package-discovery, test, and documentation churn without being required to establish workspace isolation.

D2: Extract cloud as one distribution before splitting applications

The existing cloud package moves under packages/cloud-platform/cloud and is built by a new device-cloud-platform project. Its current cloud.sdk subpackage stays in the same distribution so the public import path remains stable and Python namespace-package coordination is unnecessary.

The subsequent cloud integration change may add apps/cloud-api and apps/device-host-agent as workspace members that depend on device-cloud-platform and, where needed, device-agent-runtime.

Alternative considered: create Runtime, cloud domain, SDK, API, and host-agent distributions in one migration. Rejected because package-boundary failures would be difficult to distinguish from new distributed behavior.

D3: Express internal dependencies as uv workspace sources

device-cloud-platform declares a normal project dependency on device-agent-runtime, with [tool.uv.sources] marking it as a workspace source. The Runtime project does not declare a dependency on the cloud project. The workspace uses a single committed uv.lock generated from all members.

D4: Preserve import paths and enforce ownership with tests

Moving package files must not rename cloud.* modules. Existing tests remain runnable from the workspace root. Packaging tests additionally verify that each member builds, imports resolve from the intended distribution, and forbidden reverse dependencies remain absent.

D5: Keep heavy optional concerns out of packaging scope

The migration does not change current dependency semantics merely to optimize installation size. Optional dependency groups can be introduced only when existing tests demonstrate that Runtime and cloud installations remain complete and documented; behavioral cloud work remains deferred.

Risks / Trade-offs

  • [Risk] Moving cloud/ changes source paths used by tests or tooling. -> Mitigation: preserve cloud.* imports, update only path-sensitive configuration, and run the full non-integration suite from a clean workspace environment.
  • [Risk] Editable installs can hide missing build metadata. -> Mitigation: build every member and test imports from built wheels in addition to editable workspace tests.
  • [Risk] A shared lockfile can resolve dependencies unused by a selected member. -> Mitigation: keep member dependency declarations accurate and verify member-scoped uv run --package commands.
  • [Risk] Existing developer environments may retain stale editable paths. -> Mitigation: document a clean uv sync migration and verify the workspace with a newly created environment in CI.
  • [Trade-off] cloud.sdk is not independently installable yet. -> Accepted to avoid namespace and API churn; it can be separated later under a deliberately stable top-level package name if distribution size becomes material.

Migration Plan

  1. Add workspace configuration to the root project and create the packages/cloud-platform project metadata.
  2. Move the cloud package without changing module names, then update setuptools discovery and path-sensitive tests.
  3. Declare the cloud-to-runtime workspace dependency and generate uv.lock.
  4. Update development and CI commands to use uv sync, root tests, member-scoped builds, and lock verification.
  5. Run the complete non-integration test suite and build/import smoke tests for both distributions.
  6. Roll back by restoring the cloud package to the root discovery set and removing workspace metadata and the generated lockfile; no data migration is involved.

Open Questions

  • None blocking. Separate cloud-api and device-host-agent members are intentionally owned by the follow-up cloud integration change.