home / skills / martinffx / claude-code-atelier / atelier-python-monorepo

This skill helps you set up and manage a Python monorepo with uv workspaces, ensuring consistent dependencies and cross-package collaboration.

npx playbooks add skill martinffx/claude-code-atelier --skill atelier-python-monorepo

Review the files below or copy the command above to add this skill to your agents.

Files (4)
SKILL.md
3.3 KB
---
name: python:monorepo
description: Python monorepo architecture with uv workspaces, mise, and apps/packages pattern. Use when setting up project structure, configuring workspaces, managing dependencies across packages, or designing multi-app Python repositories.
user-invocable: false
---

# Python Monorepo with uv Workspaces

Modern Python monorepo architecture using `uv` for workspace management and `mise` for Python version and task orchestration.

## Core Concepts

**Monorepo**: Single repository containing multiple related packages and applications

**uv workspace**: Python's answer to npm/pnpm workspaces
- Single lock file for entire repo
- Shared virtual environment
- Cross-package dependency resolution

## Directory Structure

```
my-monorepo/
├── .mise.toml           # Python version + task runner
├── pyproject.toml       # Root workspace config
├── uv.lock              # Unified lock file
├── apps/                # Deployable applications
│   ├── api/
│   └── worker/
└── packages/            # Shared libraries
    ├── core/
    └── utils/
```

## Workspace Configuration

**Root pyproject.toml:**

```toml
[project]
name = "my-monorepo"
version = "0.1.0"
requires-python = ">=3.12"

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

[tool.uv]
dev-dependencies = [
    "pytest>=8.0.0",
    "ruff>=0.8.0",
    "basedpyright>=1.0.0",
]
```

See `references/workspace-config.md` for detailed configurations.

## Package Linking

Workspace packages reference each other by distribution name:

**packages/utils/pyproject.toml:**
```toml
[project]
name = "my-utils"
dependencies = ["my-core"]
```

**apps/api/pyproject.toml:**
```toml
[project]
name = "my-api"
dependencies = ["my-core", "my-utils", "fastapi>=0.100.0"]
```

## Cross-Package Import

**packages/core/src/my_core/entities.py:**
```python
class User:
    def __init__(self, email: str):
        self.email = email
```

**apps/api/src/my_api/main.py:**
```python
from my_core.entities import User  # Import from workspace package

def run():
    # App code...
```

## Dependency Direction (Critical)

```
apps/ → packages/  (Apps depend on packages)
packages/ ⇏ apps/  (Never the reverse)
```

**Rules:**
- Apps can depend on packages
- Packages can depend on other packages
- Packages NEVER depend on apps
- Avoid circular dependencies

## mise Task Runner

**.mise.toml:**

```toml
[tools]
python = "3.12"

[tasks.check]
depends = ["lint", "typecheck", "test"]

[tasks.lint]
run = "uv run ruff check ."
```

**Usage:** `mise run check`

## Core uv Commands

```bash
uv sync                           # Install all packages
uv add fastapi --package my-api   # Add to specific package
uv add my-core --package my-api   # Add workspace package
uv run pytest                      # Run tests
uv lock --upgrade                 # Update dependencies
```

## Best Practices

1. Single lock file at root
2. Shared dev tools (ruff, pytest) in root dev-dependencies
3. Pin Python version with mise
4. Apps depend on packages only
5. Use namespace packages for logical grouping (optional)

## References

For detailed patterns:
- `references/workspace-config.md` - pyproject.toml patterns, dependencies, versions
- `references/docker.md` - Multi-stage Docker builds
- `references/namespace-packages.md` - PEP 420 namespace packages

Overview

This skill describes a modern Python monorepo architecture using uv workspaces and mise for version and task orchestration. It explains repo layout, workspace configuration, cross-package imports, and practical commands for dependency management. The guidance focuses on clear dependency direction, single lockfile practices, and shared developer tooling.

How this skill works

The skill inspects and documents how uv manages a unified workspace: a single pyproject.toml root workspace with members, a shared uv.lock, and a consolidated virtual environment. It shows how packages and apps reference each other by distribution name, how mise pins the Python version and defines task runners, and which uv commands install, link, and run tasks across the workspace. It also enforces rules to prevent packages from depending on apps and avoids circular dependencies.

When to use it

  • Setting up a new multi-app Python repository that shares libraries across services.
  • Migrating multiple small repos into a single monorepo to centralize CI and dependency management.
  • Configuring workspace-level tooling like linters, type checkers, and test runners with a single lock file.
  • Adding or linking workspace packages and ensuring cross-package imports resolve correctly.
  • Standardizing Python version and task definitions across all projects using mise.

Best practices

  • Keep one uv.lock at the repository root to ensure reproducible installs across all members.
  • Declare shared dev-dependencies (ruff, pytest, type checkers) in the root pyproject dev-dependencies.
  • Pin Python in .mise.toml to maintain consistent runtime and tooling versions across CI and developer machines.
  • Follow strict dependency direction: apps may depend on packages; packages must never depend on apps.
  • Use namespace packages or clear package naming to avoid import collisions and simplify cross-package imports.

Example use cases

  • Create an API app that imports domain models from packages/core and utilities from packages/utils.
  • Add a new shared library and link it into an existing app with uv add --package my-app.
  • Run workspace-wide checks with mise run check that chains lint, typecheck, and test tasks.
  • Upgrade dependency versions across the monorepo using uv lock --upgrade and then uv sync to apply.
  • Build lightweight multi-stage Docker images for apps by relying on the single lockfile and pinned Python version.

FAQ

How do apps import code from workspace packages?

Workspace packages expose their distribution names; apps import modules by the package namespace (for example, from my_core.entities import User) once uv sync has linked packages.

Where should dev tools be declared?

Declare shared dev tools like ruff and pytest in the root pyproject.toml dev-dependencies so all members use the same versions and a single lockfile captures them.