Skip to main content

ohbin

Python 3.11+ License: MIT

ohbin runs the binaries your project needs but can't pip install. You know the ones: ripgrep (or… can you?), find-dup-defs, oasdiff, some linter written in Rust that only ships as a GitHub release. uv installs Python packages, and those aren't Python packages, so normally you're stuck either telling everyone to install them by hand and watching the versions drift, or writing a little download-and-verify wrapper package and copying it into every repo.

With ohbin you just write the tool down in your pyproject.toml. The first time you run it, ohbin downloads it, checks it against a SHA256 you pinned, caches it, and runs it. One dev-dependency, as many tools as you want.

It's a small thing on purpose, built for people who already live in uv. Your binaries get pinned right next to your Python deps, in the same file, and run through the same flow.

What it gives you:

  • binaries pinned to a version, pulled from GitHub releases
  • a SHA256 per platform, checked before anything gets unpacked
  • one dev-dependency, however many tools you declare
  • a per-host cache that's safe to hit from parallel CI
  • mostly stdlib (it shells out to gh and openssl only for the private-gist part)

Installation

It's a dev dependency, so with uv:

uv add --dev ohbin

How to?

Say you want ripgrep. Point ohbin at the repo:

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

This goes and looks at the release, finds the right asset for each platform, pins the SHA256s, and writes a little table into your pyproject.toml. Your comments and formatting stay where they are:

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

--name is what you'll type when it's different from the repo name (ripgrep becomes rg), and --binary is the actual executable inside the archive. If add guesses an asset wrong, don't fight it, the table is the source of truth, just fix the line.

Then run it:

uv run ohbin run rg -- --files     # first time: downloads, checks, caches, runs
uv run ohbin run rg -- TODO src/   # after that it just runs

ohbin hands the process straight over with execv, so the tool itself gets stdin, stdout, signals and the exit code, exactly like you'd run it yourself. In a Makefile I usually hide the prefix behind a variable:

RG := uv run ohbin run rg --
search:; $(RG) TODO src/

ohbin which fd prints the cached path (and downloads it first if it has to), and ohbin list shows what you've declared.

Private binaries

Sometimes the binary isn't on a public release page. Maybe you built it yourself and you don't want it in a repo at all. ohbin can ship it through a secret gist instead, encrypted with a password:

uv run ohbin publish-gist ./dist/mytool --password "$PW"

That gzips it, encrypts it, and drops one gist file per platform plus a small index. Run it from each platform's own machine, passing --gist <id> to add to the same gist. After that it's just another tool:

uv run ohbin add-gist https://gist.github.com/you/ab12… --name mytool
uv run ohbin run --password "$PW" mytool -- --help

Why a gist and not a private repo? Because a gist isn't tied to a repo, and that's the whole point. You don't commit the binary anywhere, you don't hand out repo access and tokens to everyone who needs it, you just give them a link and a password. The link is unlisted and the bytes are AES-256-CBC, so a leaked link on its own is nothing without the password. The password goes to openssl over a file descriptor, never on the command line. To take access away, delete the gist or change the password.

From Python

If you want the path instead of running the thing:

from ohbin import ensure

path = ensure("rg")   # a Path, downloaded and checked the first time

It finds your pyproject.toml by walking up from wherever you are. Set OHBIN_PYPROJECT if you need to point it at a specific file, like in CI.

How it works

Nothing clever. On ohbin run rg, it reads the rg table, works out your os and arch, and looks for ~/.cache/ohbin/rg/14.1.1/rg. If it's there, it runs it. If not, it downloads under a lock (so two parallel runs don't race), checks the SHA256 before unpacking anything, extracts, and runs. The version is in the cache path, so bumping it is just a fresh download that doesn't step on the old one. Downloads retry with backoff, and a real 404 doesn't get mistaken for a flaky network.

Limitations

POSIX only for now, the locking uses fcntl so it won't even import on Windows. add auto-resolves four platforms (linux and macOS, x86_64 and arm64); anything else (windows, musl, riscv) you add to the table by hand and the engine runs it fine. Asset matching is just looking at the os/arch words in the filename and preferring .tar.gz, so a weird naming scheme might cost you a one-line fix.

Development

git clone https://github.com/prostomarkeloff/ohbin
cd ohbin && uv sync

make lint-heavy   # ruff format + check + pyright
make test-full    # the network-free test suite

License

MIT, see LICENSE.

Made with 📦 by prostomarkeloff and contributors.

Metadata

Release files for ohbin 0.2.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ohbin 0.2.3
File Size Uploaded Provenance Actions
ohbin-0.2.3.tar.gz 22.3 kB Without provenance Details for ohbin-0.2.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ohbin 0.2.3
File Interpreter ABI Platform Actions
ohbin-0.2.3-py3-none-any.whl Python 3 none any Details for ohbin-0.2.3-py3-none-any.whl

Total release size: 50.9 kB

Release files / ohbin-0.2.3.tar.gz

Download URL ohbin-0.2.3.tar.gz
Size 22.3 kB
Tags Source
SHA-256 checksum
How to use checksums
0de749a40bc9b896f5b987dc979e48ceb9388ab9c02bb833aaa4a924af27b5c8
BLAKE2b-256 checksum
How to use checksums
36ba4ed3617e17792194b76ed7e826f6eccc0ddc83f724fdf9cce7ca2f95c437
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.1

Release files / ohbin-0.2.3-py3-none-any.whl

Download URL ohbin-0.2.3-py3-none-any.whl
Size 28.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bbacb1e1cd332da8be2f948a4d90fe8a9bfd8cf72c2aabdf99bbb907581f3e96
BLAKE2b-256 checksum
How to use checksums
5bb0cfa9fe5d2f75d82e529fbf3bafe25818a2b4d753fa3012f35e95c479ba04
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.1

Security for ohbin 0.2.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.3 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page