This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
A Cloud Foundry buildpack for deploying Python applications managed with the uv package manager. Buildpacks must implement three scripts: bin/detect, bin/compile, and bin/release.
# Run unit tests
make unit-test
# Run smoke tests (requires Python 3.13 on PATH)
make smoke-test
# Run smoke tests for a specific app
make test-buildpack APP_DIR=test/smoke/my-app-1
# Package the buildpack into a zip
make build
# Clean up temp staging directories
make clean-test-buildpack
# Stage and run an app locally on 127.0.0.1:8000
make start-local APP_DIR=test/smoke/my-app-1Unit tests are shell scripts in test/unit/ — run a single file directly with bash test/unit/detect_test.sh.
bin/detect: Exits 0 ("python-uv") if both pyproject.toml and uv.lock exist; exits 1 otherwise.
bin/compile: The main build script. Receives BUILD_DIR, CACHE_DIR, ENV_DIR.
- Installs
uv(prefers systemuv, falls back to standalone installer) - Reads
.python-versionto pick Python version - Installs managed Python into
$BUILD_DIR/.uv/python/viauv python install - Creates Python shims at
.python/bin/python3and.python/bin/pythonusing relative paths — critical because CF relocates the droplet after staging - Exports deps to requirements.txt via
uv export, installs to.python_packages/ - Writes
.profile.d/python.shto setPATHandPYTHONPATHat runtime
bin/release: Determines the web startup command (output as YAML default_process_types).
Priority order:
- If
Procfileexists → exits 0 (CF uses it directly) - Console script in
[project.scripts]matching[project].name - A
startscript in[project.scripts] python3 main.pyfallbackpython3 app.pyfallback
Console scripts like server.main:start are converted to python3 -c "from server.main import start; start()".
test/unit/— shell script unit tests for each bin script (detect, compile, release). Use fakeuv/Python binaries to avoid real installs.test/smoke/— four fixture apps covering different scenarios:my-app-1: flat layout,main.pyentry pointmy-app-2:src/layout,startconsole scriptmy-app-3:src/layout, script name matches project namemy-app-4: usesProcfile(tests that release script is bypassed)
- Relative path shims: Python wrapper scripts must use paths relative to the app root, not absolute paths, because CF relocates the droplet between staging and runtime.
- Dual layout support:
.profile.d/python.shmust handle bothsrc/layout and flat layout forPYTHONPATH. - No external runtime deps: The buildpack must work without
pythonoruvpre-installed on the staging machine. bin/releaserequiresBUILD_DIRas$1: All three bin scripts nowcdinto their first argument. The Makefile and unit tests pass the directory explicitly — do not callbin/releasewithout arguments.- MTA deployments must exclude
.venvviabuild-parameters.ignore:mbt builddoes not respect.cfignoreor.gitignore. A local.venvbuilt on macOS will be packaged into the.mtarand cause an exec format error on the Linux CF stack. Always add.venv/tobuild-parameters.ignoreinmta.yaml.
Releases are automated via semantic-release (.releaserc.json). On push to main, if commits follow conventional commit format, it bumps VERSION, runs buildpack-packager build -cached -any-stack, and creates a GitHub release with the packaged zip.