Collection of CLI tools mostly found on GitHub.
Tracked in tasks/metadata.yaml, installed from upstream release binaries,
and optionally packaged into a container image.
This project uses uv for dependency management and task execution.
Install uv (if not already installed):
curl -Ls https://astral.sh/uv/install.sh | shCreate the virtual environment and install dependencies:
uv syncList all available tasks:
uv run inv --listInstall all tools to dist/ (default):
uv run inv tools.installInstall a single tool to dist/:
uv run inv tools.install --name <tool>Install all tools to ~/.local/bin (or ~/bin):
uv run inv tools.install --localInstall a single tool to ~/.local/bin:
uv run inv tools.install --name <tool> --localForce reinstall all tools:
uv run inv tools.install --forceForce reinstall a single tool:
uv run inv tools.install --name <tool> --forceThe install task:
- Resolves the correct version from
metadata.yaml - Renders the
download_urltemplate for your platform - Downloads and places the binary in the configured install location
Add a new entry to tasks/metadata.yaml using the tools.add task:
uv run inv tools.add \
--repo-url https://github.com/owner/repo \
--download-url "{{repo_url}}/releases/download/v{{version}}/{{name}}-{{os}}-{{arch}}" \
--license MIT \
--description "Short tool description"Options:
--name— Override the inferred tool name--dry-run— Preview the generated entry without writing changes
The command will fail if the tool name already exists.
This task:
- Fetches the latest GitHub release from the provided
repo_url - Infers the tool name from the repository if
--nameis not provided - Extracts and normalizes the semantic version (strips leading
v) - Inserts the tool into
metadata.yaml - Keeps entries in strict alphanumeric order
- Validates against
metadata.schema.json
Update all tools to their latest GitHub release:
uv run inv tools.updateUpdate a single tool:
uv run inv tools.update --name <tool>Preview updates without writing changes:
uv run inv tools.update --dry-run
uv run inv tools.update --name <tool> --dry-runAdjust the release age filter (default is 7 days):
uv run inv tools.update --cooldown 14
uv run inv tools.update --name <tool> --cooldown 14These commands:
- Query the latest GitHub release
- Compare against the current version
- Update
metadata.yamlif a newer semantic version is found - Skip releases younger than the cooldown period
- Preserve strict alphanumeric ordering
Run updates with automatic PR creation and auto-merge:
uv run inv tools.update --prOptions:
--pr— Create a pull request and auto-merge after approval--dry-run— Preview actions without making changes--cooldown— Release age filter in days (default: 7)
This task:
- Detects all available updates across tracked tools
- Creates a feature branch (
automation/update-<timestamp>) - Commits version changes to
metadata.yaml - Opens a pull request against
mainwith a summary of changes - Labels the PR with
dependencies - Enables auto-merge (respects branch protection rules)
- Reports skipped releases that are too young
A scheduled GitHub Actions workflow runs this weekly (Sundays at 03:00 UTC).
When a sha256 field is present in a tool's metadata, the install task
verifies the downloaded file against the expected hash before extraction.
If the hash doesn't match, the download is deleted and an IntegrityError
is raised. Tools without a sha256 field install as before with no
verification.
Fetch SHA256 digests for all tools:
uv run inv tools.digestsFetch a digest for a single tool:
uv run inv tools.digests --name <tool>The tools.digests task populates sha256 values by:
- Querying the GitHub Release Asset API
digestfield first - Falling back to checksum files (checksums.txt, SHA256SUMS, etc.) in release assets
- Using special handling for HashiCorp tools (releases.hashicorp.com)
- Skipping asdf (only MD5 available)
Build a container image with all tools pre-installed:
uv run inv build.containerPush the image to a registry:
uv run inv build.container --pushOptions:
--registry— Target registry (default:ghcr.io/$GITHUB_REPOSITORY)--tag— Image tag (default: current git SHA)--push— Push the image after building
The build.container task auto-detects podman or docker and builds
using the Containerfile, which uses a multi-stage build producing a minimal
scratch image with all binaries under /dist.
When run on the main branch (detected via GITHUB_REF), the build
automatically tags and pushes a :latest image alongside the SHA-tagged one.
The download_url field is rendered using Jinja. Common variables:
| Variable | Description |
|---|---|
{{name}} |
The tool name |
{{version}} |
Resolved semantic version |
{{repo_url}} |
Repository URL from metadata |
{{os}} |
Target operating system |
{{arch}} |
Target architecture (Go-style) |
{{rust_arch}} |
Rust-style architecture (when required by upstream) |
Refer to existing entries in tasks/metadata.yaml for patterns.
| Variable | Description |
|---|---|
GITHUB_TOKEN |
GitHub API token (increases rate limits) |
CONTAINER_REGISTRY |
Override the container image registry |
GITHUB_REPOSITORY |
Auto-detected in CI for registry and labels |
Copy .env.example to .env for local configuration.
GitHub Actions workflows:
| Workflow | Trigger | Description |
|---|---|---|
lint-and-test.yaml |
Push to main, pull requests |
Runs pre-commit hooks (lint, tests) |
build-and-publish-image.yaml |
Push to main, pull requests, manual |
Builds and pushes container to GHCR |
bump-tool-versions.yaml |
Weekly schedule (Sundays 03:00), manual | Runs tools.update --pr for tool bumps |
prune-ghcr-images.yaml |
Daily schedule (01:30 UTC), manual | Removes stale GHCR images |
Install pre-commit hooks:
pre-commit installRun linting:
uv run ruff check
uv run ruff format --checkRun tests:
uv run pytest
uv run pytest tests/test_update.py
uv run pytest -k test_nameGenerate coverage report:
uv run pytest --cov=tasks
uv run pytest --cov=tasks --cov-report=html