diff --git a/openspec/changes/uv-workspace-packaging/.openspec.yaml b/openspec/changes/uv-workspace-packaging/.openspec.yaml new file mode 100644 index 0000000..8803b47 --- /dev/null +++ b/openspec/changes/uv-workspace-packaging/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-07-12 diff --git a/openspec/changes/uv-workspace-packaging/design.md b/openspec/changes/uv-workspace-packaging/design.md new file mode 100644 index 0000000..43159a3 --- /dev/null +++ b/openspec/changes/uv-workspace-packaging/design.md @@ -0,0 +1,71 @@ +## 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. diff --git a/openspec/changes/uv-workspace-packaging/proposal.md b/openspec/changes/uv-workspace-packaging/proposal.md new file mode 100644 index 0000000..e1299f6 --- /dev/null +++ b/openspec/changes/uv-workspace-packaging/proposal.md @@ -0,0 +1,29 @@ +## Why + +The repository currently publishes the local device runtime, cloud modules, and integration adapters as one flat Python distribution with no lockfile. Introducing a uv workspace now gives the runtime and future cloud applications explicit package ownership, reproducible dependency resolution, and independently runnable entry points before distributed cloud behavior is added. + +## What Changes + +- Configure the repository as a uv workspace with the existing `device-agent-runtime` project retained as the root member. +- Extract the existing `cloud` package into a dedicated workspace distribution without changing its public Python import paths or runtime behavior. +- Establish workspace conventions that allow the cloud API and device host agent to be added as independently installable members by the subsequent cloud integration change. +- Declare internal dependencies through uv workspace sources and generate a committed `uv.lock` for reproducible development and CI environments. +- Preserve the existing Vue/Vite console as an npm-managed project outside the Python workspace. +- Preserve existing Runtime, REST, MCP, and test behavior during the packaging migration. + +## Capabilities + +### New Capabilities + +- `workspace-packaging`: Defines the Python workspace membership, internal dependency direction, reproducible locking, and independently runnable project boundaries. + +### Modified Capabilities + +None. This change restructures packaging and dependency ownership without changing existing capability requirements. + +## Impact + +- Affects the root `pyproject.toml`, Python package locations, build metadata, import/package discovery configuration, development commands, CI commands, and the generated `uv.lock`. +- Existing local Runtime consumers continue to use the `device-agent-runtime` distribution and current import paths. +- Cloud code becomes an outer workspace dependency of the Runtime; inner packages such as `core`, `driver`, `device`, and `tools` remain unaware of cloud or transport concerns. +- No REST/MCP contract, task execution behavior, database schema, or frontend package-management behavior changes in this proposal. diff --git a/openspec/changes/uv-workspace-packaging/specs/workspace-packaging/spec.md b/openspec/changes/uv-workspace-packaging/specs/workspace-packaging/spec.md new file mode 100644 index 0000000..7da650c --- /dev/null +++ b/openspec/changes/uv-workspace-packaging/specs/workspace-packaging/spec.md @@ -0,0 +1,52 @@ +## ADDED Requirements + +### Requirement: Repository uses a uv workspace with a shared lockfile +The repository SHALL define a uv workspace containing the root `device-agent-runtime` project and the extracted `device-cloud-platform` project, and SHALL commit one generated `uv.lock` that resolves all workspace members. + +#### Scenario: Clean workspace synchronization +- **WHEN** a developer synchronizes the repository from a clean checkout using uv +- **THEN** uv installs the workspace members and their locked dependencies without requiring manual editable-install commands + +#### Scenario: Lockfile consistency check +- **WHEN** CI validates dependency metadata without updating dependencies +- **THEN** the committed lockfile is accepted as current for every workspace member + +### Requirement: Cloud packaging has an explicit one-way Runtime dependency +The `device-cloud-platform` project SHALL declare `device-agent-runtime` as a uv workspace dependency, and the `device-agent-runtime` project MUST NOT depend on `device-cloud-platform` or import the `cloud` package. + +#### Scenario: Cloud modules consume Runtime contracts +- **WHEN** the cloud platform is installed through the workspace +- **THEN** its imports of existing Runtime, workflow, storage, and driver contracts resolve through the declared Runtime workspace dependency + +#### Scenario: Runtime remains cloud-independent +- **WHEN** dependency-direction tests inspect Runtime-owned source packages +- **THEN** no Runtime-owned package imports `cloud` or requires the cloud distribution to execute existing local capabilities + +### Requirement: Existing cloud import paths and behavior remain compatible +The packaging migration SHALL preserve the existing `cloud.*` Python import paths and SHALL NOT change REST, MCP, scheduling, dispatch, persistence, or SDK behavior. + +#### Scenario: Existing cloud tests run after extraction +- **WHEN** the existing cloud test suite runs from the workspace root after the package is moved +- **THEN** the tests import the same `cloud.*` modules and retain their pre-migration behavior + +#### Scenario: Local Runtime runs without cloud application members +- **WHEN** a developer starts or tests the root Runtime project without starting a cloud application +- **THEN** existing Runtime entry points and local device behavior remain available + +### Requirement: Workspace members are independently buildable and selectable +Each Python workspace member SHALL contain valid build metadata, SHALL produce an installable distribution, and SHALL support member-scoped uv commands while root-level tests remain supported. + +#### Scenario: Build all distributions +- **WHEN** CI builds the Runtime and cloud platform workspace members +- **THEN** each build produces a wheel whose declared packages can be imported in an isolated environment + +#### Scenario: Run a member-scoped command +- **WHEN** a developer selects a workspace member with uv's package selection option +- **THEN** the command executes with that member's declared dependencies and workspace sources + +### Requirement: Frontend package management remains separate +The Vue/Vite `console` project SHALL remain managed by its existing JavaScript package manager and SHALL NOT become a Python uv workspace member. + +#### Scenario: Synchronize Python workspace +- **WHEN** a developer runs uv synchronization at the repository root +- **THEN** uv does not install or modify the console's JavaScript dependencies diff --git a/openspec/changes/uv-workspace-packaging/tasks.md b/openspec/changes/uv-workspace-packaging/tasks.md new file mode 100644 index 0000000..ff2596e --- /dev/null +++ b/openspec/changes/uv-workspace-packaging/tasks.md @@ -0,0 +1,33 @@ +## 1. Baseline And Workspace Metadata + +- [x] 1.1 Record the current non-integration test result and verify the existing root distribution builds before moving packages. + - Baseline: `uv run pytest -m "not integration"` -> 314 passed, 6 deselected. + - Baseline: `uv build` -> root sdist and wheel built successfully. +- [ ] 1.2 Add `[tool.uv.workspace]` membership to the root project while retaining `device-agent-runtime` as the root package. +- [ ] 1.3 Create `packages/cloud-platform/pyproject.toml` for the `device-cloud-platform` distribution with explicit build and package-discovery metadata. +- [ ] 1.4 Declare `device-agent-runtime` as a workspace source dependency of `device-cloud-platform` without adding any reverse dependency. + +## 2. Cloud Package Extraction + +- [ ] 2.1 Move the existing `cloud` package under `packages/cloud-platform` while preserving every `cloud.*` import path. +- [ ] 2.2 Remove `cloud*` from the root distribution's setuptools discovery and update path-sensitive composition tests or tooling. +- [ ] 2.3 Add packaging tests that identify the owning distribution for Runtime and cloud modules and reject reverse cloud dependencies. + +## 3. Locking And Developer Commands + +- [ ] 3.1 Generate and commit the shared `uv.lock` for all workspace members. +- [ ] 3.2 Verify clean `uv sync --locked` and lock consistency checks from the workspace root. +- [ ] 3.3 Verify member-scoped uv commands for both `device-agent-runtime` and `device-cloud-platform`. +- [ ] 3.4 Update README and relevant setup documentation with workspace synchronization, test, build, and package-selection commands while leaving console npm commands unchanged. + +## 4. Build And Compatibility Verification + +- [ ] 4.1 Build wheels for every workspace member and inspect them to confirm the expected packages are included once. +- [ ] 4.2 Install the built wheels into an isolated environment and smoke-test imports for existing Runtime and `cloud.*` modules. +- [ ] 4.3 Run the complete non-integration Python test suite from the workspace root and fix packaging-only regressions without changing behavior. +- [ ] 4.4 Verify the local REST and MCP factories still import and the console build remains independent of uv synchronization. + +## 5. OpenSpec And Project Records + +- [ ] 5.1 Run OpenSpec validation for `uv-workspace-packaging` and confirm all workspace-packaging scenarios are covered by automated checks. +- [ ] 5.2 Update the project index and runtime/package documentation to record the new workspace layout and canonical commands.