Local-first release CLI tools: ship_bump, ship_pypi, ship_release_gh
Tiny, local-first release tools for modern Python projects.
fastship gives you the same workflow feel as the nbdev nbdev-bump-version, release-pypi, and release-gh commands — but for plain (non-notebook) Python projects.
pip install fastship
Create a new project:
ship-new my-project
cd my-project
pip install -e .[dev]
This creates a complete project with pyproject.toml, __version__, LICENSE, README, and everything wired for fastship.
ship-bumpBump a version part (0=major, 1=minor, 2=patch):
ship-bump --part 2
ship-bump --part 1
ship-bump --part 0
Decrement instead:
ship-bump --part 2 --unbump
ship-pypiBuild + upload to PyPI:
ship-pypi
Upload to a named repository in ~/.pypirc (e.g. testpypi):
ship-pypi --repository testpypi
Quiet mode:
ship-pypi --quiet
ship-prCreate a PR from uncommitted or unpushed work, merge it immediately, and clean up:
ship-pr "Add new feature"
ship-pr "Fix bug" --label bug
ship-pr "Breaking change" --label breaking
This command:
enhancement)You must be on the default branch (usually main) with no unpulled changes.
ship-changelogGenerate or update CHANGELOG.md from closed GitHub issues since your last release:
ship-changelog
This is useful when you want to edit the changelog separately (e.g., in an editor or Claude Code) before releasing.
ship-release-ghThis is an interactive helper:
CHANGELOG.md from closed GitHub issues since your last GitHub release$EDITOR (defaults to nano) so you can edit the changeloggit commit -am release, git push__version__ship-release-gh
If you’ve already prepared the changelog (e.g., via ship-changelog), skip the changelog step:
ship-release-gh --no-changelog
This still opens CHANGELOG.md in your editor for final review before the release is created.
ship-release-gh looks for a token in this order:
FASTSHIP_TOKEN./token file in your repo rootGITHUB_TOKENThe token must have permission to create releases (typically repo scope for classic PATs, or appropriate fine-grained permissions).
ship-releaseFull release workflow assuming changelog is ready:
ship-changelog # generate changelog, edit as needed
ship-release # release to GitHub + PyPI, bump version, push
This runs:
ship-release-gh --no_changelog (open CHANGELOG.md for final review, commit if needed, push, create GitHub release)ship-pypi (upload to PyPI)ship-bump (bump patch version)ship-pypi does not bump your version for you — keep it explicit and boring.ship-release-gh requires that your project has a git origin remote pointing at GitHub (or use --repo OWNER/REPO).To add fastship to an existing project:
__init__.pyIn your package’s main __init__.py:
__version__ = "0.0.1"
pyproject.toml[project]
name = "my-project"
dynamic = ["version"]
[tool.setuptools.dynamic]
version = { attr = "my_project.__version__" }
Keep __version__ = "x.y.z" as a simple literal (don’t compute it). ship-bump will rewrite this line near the top of the file to keep builds happy.
Fastship infers your package name from [project].name (changing - to _). To override the release branch:
[tool.fastship]
branch = "main" # defaults to current git branch