muntjac
Translate
uv.lockinto Buck2 build rules.
What is muntjac?
Problem. uv is the modern Python dependency resolver — fast, correct, and what most Python teams are migrating to. But uv doesn't speak Buck. If your monorepo uses Buck2, you've had to either hand-write pypi_package rules per dependency or use Reindeer (which is Cargo-only).
Solution. muntjac reads uv.lock plus a small muntjac.toml config and emits BUCK, muntjac.bzl, wiring.bzl, and config/BUCK. PEP 503 normalization, marker evaluation per platform, PEP 517 sdist prebake, and native-extension fixups are all handled.
Moat. Community fixup registry at github.com/rsJames-ttrpg/muntjac-fixups. Native deps (libjpeg, openssl, libzmq, etc.) are notoriously fiddly — the registry means you don't write those incantations yourself.
Developer experience. muntjac flattens Buck2's learning curve for Python teams. Keep using uv add / uv lock / uv sync for day-to-day dependency work — muntjac re-derives Buck rules from uv.lock on demand. The mental model stays edit pyproject.toml → re-buckify; you never hand-edit pypi_package rules, never look up wheel filenames, never debug marker evaluation by hand. uv-native ergonomics in, Buck-native targets out.
Quickstart
Prereqs: a working Buck2 project (with prelude/, toolchains/, .buckconfig, PACKAGE). If you don't have one, see Setting up Buck2 below. Then:
That's it. Re-run muntjac buckify whenever uv.lock changes.
Setting up Buck2
If you're new to Buck2, the easiest starter is to copy the prelude/, toolchains/, .buckconfig, and PACKAGE files from muntjac's fixture 02 into your project root. They wire up the facebook/buck2-prelude and a Python toolchain rooted at python3.12.
If you have an existing Buck2 setup, muntjac just needs [repositories] prelude = ... in .buckconfig and a working system_python_toolchain named //toolchains:python.
Configuration
muntjac init writes a starter muntjac.toml. The interesting fields:
= "pyproject.toml"
= "third-party/python"
= ["3.11", "3.12"]
[]
= "x86_64-unknown-linux-gnu"
= "2_17"
[]
= "aarch64-apple-darwin"
= "11.0"
# Optional — include PEP 735 dependency groups:
# [lockfile]
# include_groups = ["test"]
[]
= "none" # or "github.com/rsJames-ttrpg/muntjac-fixups"
= true
[]
= "BUCK"
= false
Full schema reference: design spec §3 — configuration.
Community fixups
Most Python packages work out of the box. Some — packages with C extensions linking libjpeg, openssl, libzmq — need a fixup that wires the wheel up to the right //third-party/c:* targets.
Opt in via:
[]
= "github.com/rsJames-ttrpg/muntjac-fixups"
Then muntjac fixups update fetches the latest pinned SHA. Layered model: community fixups are applied first, then any in-tree third-party/python/fixups/<pkg>.toml overrides win on scalar fields and extend on lists. A local fixup can set replace_community = true to bypass the community entry entirely.
See muntjac-fixups README for the seed package list (pillow, cryptography, lxml, pyzmq, psycopg2-binary) and CONTRIBUTING for how to add one.
Status
v0.1.0. Linux x86_64 + macOS arm64 are the credible-launch platforms — numpy, pandas, fastapi, requests, and ruff are confirmed working end-to-end. Linux arm64 is supported and tested in CI. Windows + Intel macOS work via cargo install muntjac (compiles from source); prebuilt binaries are planned post-v0.1.0.
See roadmap for v0.2+ plans (vendor mode, audit, multi-tree).
Contributing
Issues + PRs welcome. See CONTRIBUTING.md once it lands; in the meantime, see docs/superpowers/specs/ for the design specs and docs/superpowers/TECH_DEBT.md for the open ledger.
License
MIT — see LICENSE.