Skip to content
Tech News
← Back to articles

Ohbin – uv wrapper for installing tools from GitHub

read original more articles

ohbin Declare binaries, not wrapper packages.

Your project needs ripgrep , or oasdiff , or some Rust linter that ships only as a GitHub release. Python can't install it. So you either tell every developer "go install it yourself" — and watch versions drift and CI break — or you hand-write a download-and-verify wrapper package, and copy it into every repo, for every tool.

ohbin deletes that. Declare the tool in pyproject.toml ; it's fetched on first use, SHA256-checked against a pinned hash, cached per host, and exec'd. One dev-dependency. Any number of tools.

uv add --dev git+https://github.com/prostomarkeloff/ohbin.git

Before & After

❌ The hand-rolled wrapper — a whole package, per tool, copied into every repo

# a download-and-verify wrapper · ~180 lines · written again for the next tool _PLATFORM_ASSETS = { ( "linux" , "x86_64" ): _Asset ( "ripgrep-14.1.1-x86_64-unknown-linux-musl.tar.gz" , "4cf9f2741e6c…" ), ( "darwin" , "arm64" ): _Asset ( "ripgrep-14.1.1-aarch64-apple-darwin.tar.gz" , "24ad767777…" ), # ...two more, each SHA hand-copied from the release page } def ensure_binary () -> Path : asset = _resolve_asset () # platform.machine() guesswork with _flock ( cache / ".lock" ): # concurrency, if you bother _download ( url , archive ) # urllib + redirects (+ retries, if you bother) _verify_checksum ( archive , asset . sha256 ) # hashlib _extract ( archive , binary ) # tarfile, atomic rename return binary # + a wheel shim, [project.scripts], and a [tool.uv.sources] entry — in every repo

✅ ohbin — one dev-dependency, one table per tool

uv run ohbin add BurntSushi/ripgrep --version 14.1.1 --name rg --binary rg

[ tool . ohbin . tools . rg ] repo = " BurntSushi/ripgrep " version = " 14.1.1 " binary = " rg " # + one [..assets.<os>-<arch>] table per platform — written by `add`, checksums and all

... continue reading