Agent Skills: UV Workspaces

|

UncategorizedID: laurigates/claude-plugins/uv-workspaces

Install this agent skill to your local

pnpm dlx add-skill https://github.com/laurigates/claude-plugins/tree/HEAD/python-plugin/skills/uv-workspaces

Skill Files

Browse the full folder contents for uv-workspaces.

Download Skill

Loading file tree…

python-plugin/skills/uv-workspaces/SKILL.md

Skill Metadata

Name
uv-workspaces
Description
|

UV Workspaces

Quick reference for managing monorepo and multi-package projects with UV workspaces.

When to Use This Skill

| Use this skill when... | Use another skill instead when... | |------------------------|-----------------------------------| | Setting up a Python monorepo with shared deps | Managing a single package (uv-project-management) | | Configuring workspace members and inter-package deps | Adding git/URL dependencies (uv-advanced-dependencies) | | Using --package or --all-packages flags | Building/publishing to PyPI (python-packaging) | | Creating virtual workspaces (root with no project) | Managing Python versions (uv-python-versions) | | Debugging workspace dependency resolution | Running standalone scripts (uv-run) |

Quick Reference

Workspace Structure

my-workspace/
├── pyproject.toml          # Root workspace config
├── uv.lock                 # Shared lockfile (all members)
├── packages/
│   ├── core/
│   │   ├── pyproject.toml
│   │   └── src/core/
│   ├── api/
│   │   ├── pyproject.toml
│   │   └── src/api/
│   └── cli/
│       ├── pyproject.toml
│       └── src/cli/
└── README.md

Root pyproject.toml

[project]
name = "my-workspace"
version = "0.1.0"
requires-python = ">=3.11"

[tool.uv.workspace]
members = ["packages/*"]

# Optional: exclude specific members
exclude = ["packages/experimental"]

Virtual Workspace (No Root Package)

When the root is purely organizational and not a package itself, omit the [project] table:

# Root pyproject.toml — virtual workspace (no [project] table)
[tool.uv.workspace]
members = ["packages/*"]
  • The root is not a workspace member
  • All members live in subdirectories
  • uv run and uv sync require --package or --all-packages (will error without them)

Member pyproject.toml

[project]
name = "my-api"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
    "my-core",       # Workspace member
    "fastapi",       # External (PyPI)
]

[tool.uv.sources]
my-core = { workspace = true }

Common Commands

| Operation | Command | |-----------|---------| | Sync workspace root | uv sync | | Sync all members | uv sync --all-packages | | Sync specific member | uv sync --package my-api | | Run in member context | uv run --package my-api python script.py | | Lock entire workspace | uv lock | | Upgrade a dependency | uv lock --upgrade-package requests | | Build specific package | uv build --package my-core | | Add dep to member | cd packages/api && uv add requests | | Add workspace dep | cd packages/api && uv add ../core |

Key Behaviors

Source Inheritance

Root tool.uv.sources apply to all members unless overridden.

Use case: Define workspace sources in root for all members, override only when a specific member needs a different version:

# Root pyproject.toml — applies to all members
[tool.uv.sources]
my-utils = { workspace = true }

# packages/legacy/pyproject.toml — needs pinned version
[tool.uv.sources]
my-utils = { path = "../utils-v1" }  # Overrides root entirely

Override is per-dependency and total — if a member defines a source for a dependency, the root source for that dependency is ignored completely.

requires-python Resolution

The workspace enforces the intersection of all members' requires-python:

# packages/core: requires-python = ">=3.10"
# packages/api:  requires-python = ">=3.11"
# Effective:     requires-python = ">=3.11"

All members must have compatible Python version requirements.

Editable Installations

Workspace member dependencies are always editable — source changes are immediately available without reinstallation.

Default Scope

| Command | Default scope | Override | |---------|---------------|----------| | uv lock | Entire workspace | — | | uv sync | Workspace root only | --package, --all-packages | | uv run | Workspace root only | --package, --all-packages | | uv build | All members | --package |

Workspace vs Path Dependencies

| Feature | { workspace = true } | { path = "../pkg" } | |---------|------------------------|------------------------| | Shared lockfile | Yes | No | | Always editable | Yes | Optional | | Must be workspace member | Yes | No | | --package flag works | Yes | No | | Conflicting deps allowed | No | Yes |

Use path dependencies when members need conflicting requirements or separate virtual environments.

Docker Layer Caching

# Install deps first (cached layer)
COPY pyproject.toml uv.lock packages/*/pyproject.toml ./
RUN uv sync --frozen --no-install-workspace

# Then install project (changes frequently)
COPY . .
RUN uv sync --frozen

| Flag | Effect | |------|--------| | --no-install-project | Skip current project, install deps only | | --no-install-workspace | Skip all workspace members, install deps only | | --no-install-package <name> | Skip specific package(s) | | --frozen | Skip lockfile freshness check |

Agentic Optimizations

| Context | Command | |---------|---------| | Sync all members | uv sync --all-packages | | CI sync (frozen) | uv sync --all-packages --frozen | | Test specific member | uv run --package my-core pytest --dots --bail=1 | | Test all members | uv run --all-packages pytest --dots --bail=1 | | Lock with upgrade | uv lock --upgrade-package <dep> | | Build one package | uv build --package my-core | | Docker deps layer | uv sync --frozen --no-install-workspace |

See Also

  • uv-project-management — Managing individual packages
  • uv-advanced-dependencies — Path and Git dependencies
  • python-packaging — Building and publishing workspace packages

For detailed workspace patterns (virtual workspaces, Docker integration, source inheritance, syncing strategies), CI/CD examples, and troubleshooting, see REFERENCE.md.