bough
is a tool to determine which uv workspace packages need rebuilding based on git changes.
When using uv workspaces, it's often unclear which packages are affected by a given change. This leads to either rebuilding everything (wasteful) or missing necessary rebuilds (broken deployments).
Analyze dependencies and git diffs to identify affected packages, then build only what's needed.
bough
# Custom base commit
bough --base main
# Display dependency graph
bough graph
# Output GitHub Actions matrix format
bough analyze --format github-matrix
my-app/
├── pyproject.toml
├── packages/
│ ├── auth/ # library (no deps)
│ ├── database/ # library (no deps)
│ └── shared/ # library (depends on: database)
└── apps/
├── api/ # buildable (depends on: auth, database, shared)
└── web/ # buildable (depends on: shared)
The bough graph
command shows the dependency relationships between packages:
🚀 Buildable Packages:
==================================================
📦 api (apps/api)
└─ depends on: auth, database, shared
📦 web (apps/web)
└─ depends on: shared
📚 Library Packages:
==================================================
📖 auth (packages/auth)
├─ depends on: (none)
└─ depended on by: api
📖 database (packages/database)
├─ depends on: (none)
└─ depended on by: api, shared, web
📖 shared (packages/shared)
├─ depends on: database
└─ depended on by: api, web
The bough analyze
command shows what packages should be built based on what files have changed.
GitHub Matrix (for parallel CI jobs):
{
"include": [
{"package": "api", "directory": "apps/api"},
{"package": "web", "directory": "apps/web"}
]
}
Text (default):
Packages to rebuild:
api (apps/api)
web (apps/web)
Changed files:
packages/database/models.py
.bough.yml
:
# Packages that produce build artifacts (default: ["apps/*"])
buildable:
- "apps/*"
# Files that never trigger rebuilds
ignore:
- "*.md"
- "docs/**"
See GitHub Actions Integration Guide for examples of using Bough in CI/CD pipelines.
- Find all workspace members from
pyproject.toml
- Build dependency graph from
tool.uv.sources
- Detect changed files with git diff
- Apply change detection rules:
- File changed inside package → package directly affected
- File changed at workspace root → all packages affected
- Calculate transitive impacts (if A depends on B and B changes, A is affected)
- Filter to only buildable packages
- Output build list
If packages/database/models.py
changes:
database
is directly affectedshared
is affected (depends on database)api
is affected (depends on database and shared)web
is affected (depends on shared)- Output shows only
api
andweb
(they're buildable)
This tool is intentionally simple:
- Not a build system (like Bazel or Buck)
- Not a task runner
- Not multi-language aware
- Not trying to optimize build order or parallelization
- Not caching build artifacts
- una - Unify Python packaging commands
- postmodern-mono - Python monorepo example
- Nx affected - Similar concept for JS/TS monorepos
- Turborepo --affected - Git-based filtering for builds
- provide an option that outputs all affected packages, not just buildable ones (useful for selectively running tests)
- check in a sample configuration file and document the defaults better
- improve or remove the github actions examples
- setup a release workflow to pypi
- add a contributing guide