How to Create and Distribute a Python CLI Tool
pyproject.toml lets you attach any Python function to an executable command name via [project.scripts]. When someone installs the package, their package manager creates a wrapper script that calls that function. With uvx, users can run the tool without even installing it first.
Tip
New to Python packaging? Start with the Create your first Python project with uv tutorial before following this guide.
Define the entry point
Add a [project.scripts] table to your pyproject.toml. If you don’t have a package project yet, uv init --package my-tool scaffolds one with a build backend pre-configured:
[project.scripts]
my-tool = "my_tool:main"The value my_tool:main means “call the main function from the my_tool package.” The key on the left (my-tool) becomes the executable command name on the user’s PATH. This is the PEP 621 equivalent of the console_scripts entry point in older setuptools-based projects.
The function can use argparse, click, or plain sys.argv. The packaging mechanism is the same regardless of what the function does internally.
Test locally
uv run my-tool --helpuv run installs the project into the local virtual environment and invokes the entry point. No manual pip install -e . step is needed.
Build the package
$ uv build
Successfully built dist/my_tool-0.1.0.tar.gz
Successfully built dist/my_tool-0.1.0-py3-none-any.whl
Both a source distribution and a wheel land in the dist/ directory.
Publish to PyPI
The recommended publishing workflow is trusted publishing from GitHub Actions, which requires no stored secrets. For quick one-off uploads, generate an API token at pypi.org/manage/account/ and pass it with --token.
Before publishing to the live index, verify the package looks correct on TestPyPI:
uv publish --publish-url https://test.pypi.org/legacy/ --token YOUR_TEST_TOKENThen publish to PyPI:
uv publishRun the published tool with uvx
After publishing, anyone with uv installed can run the tool without a prior install step:
$ uvx my-tool Alice
Hello, Alice!
uvx resolves and caches the tool environment on first run and reuses the cache on subsequent calls. The tool never touches the user’s project dependencies.
For a permanent installation that puts the command on PATH:
uv tool install my-tool
my-tool AliceThe executable lands in ~/.local/bin/.
Run uv tool upgrade my-tool to pull a newer version later.
Learn More
- uvx reference
- pyproject.toml reference
- What is a build backend?
- How to publish to PyPI with trusted publishing
- uv tools documentation
- pipx reference (alternative tool installer if uv isn’t available)