Skip to main content

A desktop keeper for uv virtual environments: track, sync and open the environments you already have.

Project description

Bombadil — a desktop keeper for uv virtual environments

CI Rust 1.88+ uv 0.12.1 Apache 2.0


A desktop application for the Python virtual environments you already have. Bombadil keeps an account of them — which exist, which have drifted from what their manifest declares, what is installed in each — and gives you one place to sync, inspect and open them.

It never owns an environment. uv creates them, uv resolves them, and Bombadil is the thing that tells you the truth about them and gets out of the way. Delete Bombadil and every environment it showed you is still there, untouched.

"Bright blue his jacket was, and his boots were yellow." Tom Bombadil is the keeper of a bounded domain who owns nothing he tends. That is the whole design brief, and it is where the palette comes from.

What it does

Projects and environments. Register a project by its pyproject.toml. A project can carry several environments — a 3.11 and a 3.12, say — shown as a tree beneath it, with one marked default: the one Sync, the terminal and the dependency view act on. An environment can live beside the project or anywhere else on disk, including one another project already uses.

One glyph vocabulary, everywhere. Every row in every pane — projects, dependencies, workspace members, indexes — reports state the same way, and no two states ever look alike:

present it exists and matches
absent declared, not installed
drifted installed, but not what was asked for

Sync, with the output. uv sync streams into a drawer that follows the output and stays where you put it. A failure shows the transcript rather than a shrug.

Dependencies and workspace members. What the manifest declares against what is actually installed, joined on PEP 503-canonical names so calc_service and calc-service are one row. Monorepo members are listed with what a sync would add or remove before you run it.

Environment variables and secrets. Global variables and per-project ones, with the project's overriding. Mark a variable secret and its value moves to the OS keychain — it is never written to config.toml, never carried in a message, and never read back to be redisplayed.

Private indexes. Name, URL, and credentials in the keychain, injected as UV_INDEX_* at sync time. Global by default, selectable per project.

Pre-activate scripts. Shell scripts run before an environment is used, in an order you control, with their exported variables composed into everything Bombadil launches.

Terminals and PyCharm. Open a terminal in the project directory with the environment activated — every emulator's argv is built for the platform, and the app knows which ones cannot carry an environment rather than pretending. The PyCharm button opens the project folder with the same composed environment. (PyCharm's interpreter cannot be set from outside the IDE; bombadil_core::ide documents exactly why.)

Pinned interpreters, safely. uv sync -p X against an environment built on another version deletes it. Bombadil compares pins segment-wise against what pyvenv.cfg actually records, so 3.12.13 and 3.12 are not treated as a conflict, and a genuinely destructive pin change asks first.

Install

Bombadil bundles uv 0.12.1, so there is nothing else to install. By default it uses uv from PATH when that is at least 0.12.1 and falls back to the bundled copy; you can force either.

pip install bombadil     # or: uv tool install bombadil
cargo install bombadil

Either gets you the same application. The wheel carries the compiled binary and a console entry point and contains no Python at all — the route uv itself takes to PyPI — so bombadil lands on your PATH the same way.

Wheels are built for Linux (x86-64 and ARM), macOS on Apple Silicon, and Windows. An Intel Mac has no prebuilt wheel; cargo install bombadil builds there from source. bombadil is a meta crate: it owns the name worth typing and pulls in bombadil-gui, bombadil-core and bombadil-uv-bin behind it. It has to be a real binary rather than an alias, because cargo install installs binaries defined in the package being installed and never in its dependencies.

From a checkout instead:

git clone https://github.com/marcelotrevisani/bombadil
cd bombadil
just run-release          # or: cargo run --release -p bombadil

Rust 1.88 or newer, edition 2024. The build downloads the pinned uv release for your platform.

Configuration lives at ~/.config/bombadil/config.toml on Linux, ~/Library/Application Support/bombadil/ on macOS, and %APPDATA%\bombadil\config\ on Windows. Secrets live in the OS keychain, never in that file.

Development

just            # list every recipe
just run        # debug build
just test       # workspace tests
just ci         # fmt-check, clippy, test, cargo-deny, msrv -- what CI runs
just icon       # regenerate assets/ from the SVGs there (needs cairosvg)

On Linux, just install-desktop puts a desktop entry and the themed icons in ~/.local/share (per-user, no root; just uninstall-desktop removes exactly those). This is not decoration: GNOME on Wayland ignores the icon a window carries. It resolves a window's icon by matching its app_id to the basename of an installed .desktop file and reading that file's Icon= key out of the icon theme, so without the entry the panel shows a generic placeholder no matter what the binary holds. X11, Windows and macOS use the compiled-in icon, which is why it is set both ways.

808 tests across three crates, green on Linux, macOS and Windows.

Conventions worth knowing before you patch it

  • view is dumb and untested. Logic worth a test lives in a free function that view calls. A change that only exists inside view ships without a test, and its commit says so.
  • A fix needs a mutation proof. Break the fix on purpose and watch a test fail. Seventeen tests in this repo's history passed for the wrong reason; one was in a test double that could not tell spawn from run, so every test on that seam inherited the blind spot.
  • Never compare a display()ed path to a string literal. PathBuf::join uses \ on Windows. Three CI failures here came from a platform assumption hiding in an assertion rather than in the code.
  • Secrets never enter a Message — it derives Debug — and never reach a ConfigPersist.
  • Runners, secret stores, persisters and filesystem probes are parameters, never constructed inline, so tests stay hermetic and no test can reach the real keychain.
  • BOOT is rationed. The attention colour appears only where the user must look. If it starts appearing elsewhere it stops meaning anything, and the test that guards this is the most important one in theme.
  • Never edit deny.toml to dodge a licence or advisory failure. Escalate.

Specs and implementation plans live in docs/superpowers/.

Releasing

Publishing is irreversible — crates.io versions can be yanked but never replaced, and a yanked version still resolves for anything that already has it in a lock file. So the pipeline gates everything before it uploads anything, and can be rehearsed:

  1. Run Release from the Actions tab with dry_run left on. It packages and verifies all three crates and uploads nothing.
  2. Bump version in the workspace Cargo.toml, commit, and tag it vX.Y.Z. The tag and the manifest must agree — the pipeline refuses otherwise, because a mismatch is silent and neither half can be taken back.
  3. Push the tag. It re-runs the full CI set against that exact commit, builds each crate from its own packaged tarball, then publishes bombadil-corebombadil-uv-binbombadil-guibombadil in dependency order, uploads one wheel per platform to PyPI, and opens a GitHub release.

crates.io and PyPI are published by separate jobs with separate tokens (RELEASE_TOKEN, PYPI_BOMBADIL), so failing to reach one never leaves the other half-done.

The crates.io token is RELEASE_TOKEN on the crates_deploy environment, so nothing outside the publish job can read it.

Crates

Crate What it is
bombadil The binary. Install this one; it brings the rest.
bombadil-gui The iced front end, as a library with one public function.
bombadil-core Model, config store, uv invocation, environment composition, keychain, terminals, IDE launch. No GUI.
bombadil-uv-bin Fetches and embeds the pinned uv binary at build time.

Licence

Apache-2.0. See LICENSE.

Bombadil ships uv (Apache-2.0 / MIT), Atkinson Hyperlegible Next and IBM Plex Mono (both SIL OFL 1.1). Every licence text is in the application itself, under Help → Bundled licences, as those licences require.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

bombadil-0.2.2-py3-none-win_amd64.whl (45.8 MB view details)

Uploaded Python 3Windows x86-64

bombadil-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (52.6 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

bombadil-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (50.3 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

bombadil-0.2.2-py3-none-macosx_11_0_arm64.whl (41.6 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

File details

Details for the file bombadil-0.2.2-py3-none-win_amd64.whl.

File metadata

  • Download URL: bombadil-0.2.2-py3-none-win_amd64.whl
  • Upload date:
  • Size: 45.8 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.14.1

File hashes

Hashes for bombadil-0.2.2-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 be535112a5c4a36d48ab40ed68063cde8366e16d915972fd03f583fc59156c9c
MD5 7fc5a44b97e9e0e0f8331f873b79fb68
BLAKE2b-256 a28bf48f596bce3ad5d0c69abd1366d7c6488fb41d3f1c232cbe8876530e24e5

See more details on using hashes here.

File details

Details for the file bombadil-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for bombadil-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e972cf17b135304f0c1de3e987bfdc9872ae5b3963e3e0587c2e8aacaf459c6e
MD5 479346f3dd10b8bd1094c39cf379ff17
BLAKE2b-256 21c418f64bb86f0760df0e8bea0db5368b6e6a3267e87ef07bdf47ad00451a74

See more details on using hashes here.

File details

Details for the file bombadil-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for bombadil-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 1354378f297bc44c1ad431563aa1b0102568b3673de4aec2bace8536e4969e90
MD5 cc6ecde8146633366cc9993dd0354e1a
BLAKE2b-256 333f425a6191323f8790a3818e4ec9c87d16d6d61773d1d94b7601f5874ba78d

See more details on using hashes here.

File details

Details for the file bombadil-0.2.2-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for bombadil-0.2.2-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 557d5acc3cf447b847e9682cab3dc7a561a703680e40212799feebd8f2f91f9d
MD5 09fb4120a7c72d82ef0f1f30c823166a
BLAKE2b-256 ba8a7b62751060ee909b461853affaccca5c3cd285581b69e1ed7f90570ff423

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page