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

monorepo skill

/plugins/atelier-python/skills/monorepo

This skill helps you design and manage Python monorepos with uv workspaces, enabling cross-package dependencies and streamlined development.

This is most likely a fork of the atelier-python-monorepo skill from martinffx
npx playbooks add skill martinffx/claude-code-atelier --skill 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 practical Python monorepo architecture using uv workspaces and mise for Python version and task orchestration. It documents a clear apps/packages pattern, a single root lockfile, and workspace-level tooling to manage dependencies and cross-package imports. Use it to standardize multi-package repos for reproducible builds and streamlined developer workflows.

How this skill works

The architecture places deployable applications under apps/ and reusable libraries under packages/, with uv managing a single workspace and unified uv.lock. mise pins the Python runtime and exposes composer-like tasks (lint, test, typecheck) so developers run consistent commands across the repo. Workspace packages are referenced by distribution name in pyproject.toml, allowing direct imports between packages while keeping apps dependent on packages only.

When to use it

  • Creating a repo that hosts multiple related apps and shared libraries
  • Needing a single lock file and consistent virtual environment across packages
  • Coordinating dev tools (linters, tests, type checkers) for all teams
  • Managing cross-package dependencies without publishing packages externally
  • Enforcing dependency direction and avoiding circular dependencies

Best practices

  • Keep one uv.lock at the repository root and list workspace members in root pyproject.toml
  • Declare dev-tools and test runners as root dev-dependencies to ensure parity
  • Pin Python version in .mise.toml and use mise tasks to run common pipelines
  • Enforce apps → packages dependency direction; never let packages depend on apps
  • Use uv add --package to add dependencies to a specific package and uv sync to install
  • Avoid circular imports; prefer small, focused packages and explicit package boundaries

Example use cases

  • A backend monorepo with api and worker apps sharing core domain logic and utilities
  • A microservice suite where multiple services depend on common authentication and model packages
  • A library ecosystem under active development where packages reference each other locally before publishing
  • Standardizing CI pipelines to run lint, typecheck, and tests via mise run check
  • Building reproducible Docker images using the single lock file and workspace-aware installs

FAQ

How do packages reference each other inside the workspace?

List the other package by its distribution name in the package's pyproject.toml dependencies and uv will resolve it via the workspace, enabling normal imports like from my_core.entities import User.

Where should dev tools like ruff and pytest be declared?

Declare dev tools in the root pyproject.toml under tool.uv dev-dependencies so all members share the same versions and a single virtual environment.