Local build utilities
Project description
lfp-build
A comprehensive workspace management tool designed to handle complicated and common code generation tasks across multi-project Python environments. Built to be adopted by any project requiring automated code generation, workspace synchronization, and build orchestration.
Features
- Workspace Synchronization: Keep build configs, dependencies, and tool settings consistent across workspace projects.
- Project Scaffolding: Bootstrap new projects with standard layouts and automatic workspace integration.
- Version Coordination: Manage version strings across multiple projects with git integration.
- Wheel Metadata Normalization: During
dist, rewrite workspace-localfile://dependency references in wheel metadata. - Multi-platform Support: Supports macOS (arm64/x64), Linux (arm64/x64), and Windows (x64).
- Git Hook Bootstrapping:
create memberinitializes git and configures.githooks/pre-commitwhen needed.
Installation
This package requires Python >= 3.11.
You can install lfp-build directly from GitHub using pip:
pip install git+https://github.com/regbo/lfp-build-py.git
Or add it to your pyproject.toml dependencies:
dependencies = [
"lfp-build @ git+https://github.com/regbo/lfp-build-py.git"
]
For Use in Your Project (Recommended)
lfp-build is designed to be used as a development dependency. Add it to your pyproject.toml:
[dependency-groups]
dev = [
"lfp-build @ git+https://github.com/regbo/lfp-build-py.git"
]
Then use it via uv run without polluting your production dependencies:
# Sync configurations
uv run lfp-build sync
# Create new projects
uv run lfp-build create new-service
Using uv run ensures lfp-build and its dependencies are isolated from your project's runtime dependencies while
remaining available for all developers and CI/CD environments.
Install Scripts (Nothing Preinstalled)
If you want to run lfp-build from a fresh machine with nothing installed, use the install scripts in this repo.
They will:
- Ensure a usable
HOMEexists (fallback to/home/app, then/home, then/tmp/home) - Install
pixiinto$HOME/.local/bin(usingPIXI_HOMEandPIXI_BIN_DIR) - Install
uvif missing - Install
gitif missing (viapixi global install --channel conda-forge git) - Install
lfp-buildas a uv tool - Run the pixi shell activation hook (best effort)
Linux/macOS:
curl -fsSL https://raw.githubusercontent.com/regbo/lfp-build-py/main/install.sh | bash
If you want a single command that both installs and updates your current shell's environment:
eval "$(curl -fsSL https://raw.githubusercontent.com/regbo/lfp-build-py/main/install.sh | bash -s -- --emit-env)"
Windows PowerShell:
irm -useb https://raw.githubusercontent.com/regbo/lfp-build-py/main/install.ps1 | iex
For lfp-build Development
# Clone and install in editable mode
git clone https://github.com/regbo/lfp-build-py.git
cd lfp-build-py
pip install -e .
Commands
Create
Usage: lfp-build create COMMAND [OPTIONS] NAME
Create a new member project in the workspace.
Sets up a pyproject.toml and a standard src//init.py layout. Internal workspace
dependencies are automatically synchronized after creation.
╭─ Commands ───────────────────────────────────────────────────────────────────╮
│ member Create a new member project in the workspace. │
│ project Create a new workspace root project. │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Parameters ─────────────────────────────────────────────────────────────────╮
│ --working-directory Set the current working directory. │
│ * NAME --name The name of the new project (used for directory │
│ and package name). [required] │
│ --path -p Optional parent directory within the workspace │
│ root. Defaults to packages/. [default: │
│ packages] │
│ --project-dependency -pd List of existing workspace projects to depend │
│ on. │
│ --dependency -d Additional dependency strings to add to the new │
│ project's dependencies. │
╰──────────────────────────────────────────────────────────────────────────────╯
# Create a new project
uv run lfp-build create my-project
# Create a member with dependencies on other workspace projects
uv run lfp-build create my-api \
--project-dependency my-core \
--project-dependency my-models
# Create in a specific path within the workspace
uv run lfp-build create my-project --path /path/to/parent
# Create a new workspace root project (writes root pyproject.toml and creates packages/common)
uv run lfp-build create project agent-demo
Created projects include:
- Standard Python src layout (
src/<package_name>/) - Configured
pyproject.tomlwith optional dependencies __init__.pyfor package initialization- Workspace integration support
Create member vs create project
lfp-build create(orlfp-build create member) creates a new member package under the workspace.lfp-build create projectbootstraps a new workspace root project with:- a minimal root
pyproject.tomlconfigured for uv and pixi packages/commoncreated as an initial member- a copied local
.gitignoretemplate (cwd, parent, then repo fallback) if the target project does not already have one
- a minimal root
Sync
Usage: lfp-build sync [OPTIONS]
Synchronize project configurations across the workspace.
This command performs several synchronization tasks to keep member projects
aligned with the root project settings and ensure consistent dependencies.
╭─ Parameters ─────────────────────────────────────────────────────────────────╮
│ --working-directory Set the current working directory. │
│ --name Specific member project names to sync. │
│ --version Sync version from git history to all member │
│ projects. [default: True] │
│ --build-system Sync [build-system] from root project to all │
│ member projects. [default: True] │
│ --member-project-tool Sync [tool.member-project] from root project │
│ to all member projects. [default: True] │
│ --member-project-dependencie Sync internal member dependencies and uv │
│ s workspace sources. Dependency format is │
│ controlled by │
│ _config.MEMBER_PROJECT_DIRECT_REFERENCE.get() │
│ (plain names when False, ${PROJECT_ROOT} file │
│ references when True). [default: True] │
│ --member-paths Sync member path patterns. [default: True] │
│ --reorder-pyproject Order pyproject entries where applicable. │
│ [default: True] │
│ --format-pyproject Format pyproject.toml files using taplo. │
│ [default: True] │
│ --format-python Run ruff format and check on all projects. │
│ [default: True] │
╰──────────────────────────────────────────────────────────────────────────────╯
# Sync all configuration
uv run lfp-build sync
# Sync specific projects only
uv run lfp-build sync --name project1 --name project2
# Disable specific sync tasks
uv run lfp-build sync --no-version --no-format-python
Dist
Usage: lfp-build dist [OPTIONS]
Build wheel artifacts for workspace projects.
When _config.MEMBER_PROJECT_DIRECT_REFERENCE.get() is True, built wheels are
inspected in the temporary output directory and workspace-local Requires-Dist:
... @ file://... entries are normalized to plain package requirements before
copying artifacts to out_dir.
╭─ Parameters ─────────────────────────────────────────────────────────────────╮
│ --working-directory Set the current working directory. │
│ --name Optional member project names to build. If omitted, all │
│ workspace projects from metadata are built in metadata │
│ order. │
│ --out-dir Destination directory for built artifacts. Builds are │
│ performed in a temporary directory first, then copied │
│ into this directory with overwrite semantics. [default: │
│ dist] │
╰──────────────────────────────────────────────────────────────────────────────╯
# Build wheel artifacts for every workspace project
uv run lfp-build dist
# Build wheel artifacts for selected projects
uv run lfp-build dist --name common --name api
Rename
Usage: lfp-build rename [ARGS]
╭─ Parameters ─────────────────────────────────────────────────────────────────╮
│ --working-directory Set the current working directory. │
│ TRANSFORM --transform [default: []] │
│ DRY-RUN --dry-run [default: False] │
│ DASH-TO-UNDERSCORE [default: False] │
│ --dash-to-underscore │
╰──────────────────────────────────────────────────────────────────────────────╯
# Rename strings in files and folder names recursively
uv run lfp-build rename old-name:new-name
# Preview rename changes without writing
uv run lfp-build rename old-name:new-name --dry-run
# Also rewrite underscore variants (old_name -> new_name)
uv run lfp-build rename old-name:new-name --dash-to-underscore
README
Usage: lfp-build readme COMMAND
╭─ Commands ───────────────────────────────────────────────────────────────────╮
│ update-cmd Update README command sentinel blocks. │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Parameters ─────────────────────────────────────────────────────────────────╮
│ --working-directory Set the current working directory. │
╰──────────────────────────────────────────────────────────────────────────────╯
Automatically update README.md files by executing help commands embedded in sentinel blocks.
# Update all command blocks in README
uv run lfp-build readme update-cmd
# Specify a different README file
uv run lfp-build readme update-cmd --readme docs/CLI.md
# Only update specific commands (filter by regex)
uv run lfp-build readme update-cmd --filter "sync"
# Preview changes without writing
uv run lfp-build readme update-cmd --write false
# Control parallelism
uv run lfp-build readme update-cmd --jobs 4
Note: This README's command documentation was automatically generated using
lfp-build readme, which executes commands and embeds their help output into sentinel blocks.
How It Works
The readme update-cmd command looks for sentinel blocks in your README:
<!-- BEGIN:cmd lfp-build sync --help -->
<!-- END:cmd -->
It executes the command between BEGIN:cmd and --help, captures the output, and replaces the content between the
BEGIN and END markers with a formatted code block containing the command's output.
Features:
- Parallel Execution: Runs multiple commands in parallel for faster updates
- Smart Help Filtering: Automatically removes
--helpoption rows from help output to reduce noise - Empty Section Removal: Removes empty Options sections when
--helpis the only option - Selective Updates: Use
--filterto update only specific commands - Safe by Default: Preview mode available with
--write false
This approach ensures your documentation stays in sync with actual command behavior, preventing documentation drift.
Adopting lfp-build in Your Project
Initial Setup
- Install lfp-build in your project's dependencies
- Create a root pyproject.toml if you don't have one
- Configure workspace members to tell lfp-build which projects to manage
- Run your first sync to align configurations
Project Structure
The tool works with any workspace layout that has a root pyproject.toml and member projects:
your-workspace/
├── pyproject.toml # Root configuration
├── core/ # Your projects
│ ├── pyproject.toml
│ └── src/
│ └── core/
├── api/
│ ├── pyproject.toml
│ └── src/
│ └── api/
├── services/
│ ├── pyproject.toml
│ └── src/
│ └── services/
└── packages/ # Optional subdirectory for projects
Workspace Configuration
Add workspace configuration to your root pyproject.toml:
[tool.uv.workspace]
members = ["core", "api", "services"]
# Or use globs for flexibility
members = ["*/"]
exclude = ["legacy", "archived"]
[build-system]
requires = ["uv_build>=0.9.6,<0.10.0"]
build-backend = "uv_build"
# This section will be synced to all member projects
[tool.member-project]
# Shared configuration for all projects
Common Workflows
Keeping Projects in Sync:
# Sync everything (run after changing root config)
uv run lfp-build sync
# Or sync specific aspects
uv run lfp-build sync --format-python
Before Committing:
# Sync and format
uv run lfp-build sync
Module Reference
util.py
Common utilities including logging initialization and subprocess management.
pyproject.py
Utility for managing and manipulating pyproject.toml files using tomlkit and taplo.
workspace.py
Interface for uv workspace metadata retrieval.
workspace_create.py
Utilities for creating new workspace member projects.
workspace_sync.py
Core synchronization logic for versions, build systems, and dependencies.
workspace_dist.py
Build distribution artifacts for workspace projects.
readme.py
Automated README documentation updater using command output sentinels.
Development
Dependencies
Core dependencies:
uv: Workspace and dependency managementcyclopts: CLI frameworklfp-logging: Logging facadepython-dotenv: Environment file loadingsitecustomize-entrypoints: Automatic config initialization vialfp_build._config:loadtomlkit: TOML parsing and round-trip writesmergedeep: Member project config mergingruff: Python formatting and linting
Formatting notes:
- TOML formatting prefers
taplowhen available and falls back totombiviauv tool run. taplo/tombiare invoked as tools and are not required as direct project dependencies.
Environment Variables
LOG_LEVEL: Control logging verbosity (DEBUG, INFO, WARNING, ERROR, CRITICAL)LFP_BUILD_PYTHON_DOTENV_FILE: Override dotenv file name loaded at startup (default.dev.env).LFP_BUILD_MEMBER_PROJECT_DIRECT_REFERENCE: Controls how internal workspace dependencies are written during sync and metadata repair.true(default): write internal dependencies asname @ file://${PROJECT_ROOT}/.... Duringdist, built wheel metadata is inspected and workspace-localRequires-Dist: ... @ file://...entries are rewritten to plain dependency names before copy.false: keep internal dependencies as plain names (for example,common) and maintaintool.uv.sources.<dep>.workspace = true.
Extending lfp-build
The tool is designed to be extended for your specific needs:
Adding New Commands
The modular architecture makes it easy to add new commands for your specific needs:
- Create a new module in
src/lfp_build/ - Define a Cyclopts app with your commands
- Add it to
cli.pyto integrate with the CLI
Real-World Examples
Microservice Architecture
Use lfp-build to manage a microservice ecosystem where each service has its own project but shares common infrastructure code, build configs, and deployment settings.
Monorepo Management
Coordinate builds, tests, and deployments across dozens of related Python packages with consistent tooling and dependencies.
License
See LICENSE file for details.
Contributing
Contributions that enhance workspace management capabilities are welcome. Maintain these principles:
- Preserve existing variable names and logic unless explicitly refactoring
- Add comprehensive documentation to all new or significantly modified code
- Follow Python standard ordering for globals, functions, and classes
- Use
_prefix for private functions with limited scope
Support
For issues, questions, or feature requests related to using lfp-build in your project, please open an issue on GitHub.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lfp_build-0.0.9.tar.gz.
File metadata
- Download URL: lfp_build-0.0.9.tar.gz
- Upload date:
- Size: 28.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3facbc5a9809cafcdece4f76aaa0a71410b964393c3fe2c447d7a51b0b78f080
|
|
| MD5 |
a6a48fcb5c4746946779d6e70fb66e24
|
|
| BLAKE2b-256 |
9d34c55664cf8194a92466b3fa4dfa17be56542861e19b147fa9a7962ec7a5c2
|
Provenance
The following attestation bundles were made for lfp_build-0.0.9.tar.gz:
Publisher:
publish.yml on regbo/lfp-build-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lfp_build-0.0.9.tar.gz -
Subject digest:
3facbc5a9809cafcdece4f76aaa0a71410b964393c3fe2c447d7a51b0b78f080 - Sigstore transparency entry: 1046806731
- Sigstore integration time:
-
Permalink:
regbo/lfp-build-py@8a48c82caccfcc8f8b200703561e0a7506b735ed -
Branch / Tag:
refs/tags/v0.0.9 - Owner: https://github.com/regbo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8a48c82caccfcc8f8b200703561e0a7506b735ed -
Trigger Event:
push
-
Statement type:
File details
Details for the file lfp_build-0.0.9-py3-none-any.whl.
File metadata
- Download URL: lfp_build-0.0.9-py3-none-any.whl
- Upload date:
- Size: 33.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
153e26191adb15d38b0417faa8ed431dcb8cb653ee9dffe0af24d23aacc8af59
|
|
| MD5 |
e8a8a0c9cb1afb5b95776fb855d45c72
|
|
| BLAKE2b-256 |
456d50cc0b577cf7ed8c4748214855b7f43d9bf7e04760a422a9cafe9478f1de
|
Provenance
The following attestation bundles were made for lfp_build-0.0.9-py3-none-any.whl:
Publisher:
publish.yml on regbo/lfp-build-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lfp_build-0.0.9-py3-none-any.whl -
Subject digest:
153e26191adb15d38b0417faa8ed431dcb8cb653ee9dffe0af24d23aacc8af59 - Sigstore transparency entry: 1046806753
- Sigstore integration time:
-
Permalink:
regbo/lfp-build-py@8a48c82caccfcc8f8b200703561e0a7506b735ed -
Branch / Tag:
refs/tags/v0.0.9 - Owner: https://github.com/regbo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8a48c82caccfcc8f8b200703561e0a7506b735ed -
Trigger Event:
push
-
Statement type: