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.
Install
Quick start
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.
Commands
ship-bump
Bump 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-pypi
Build + upload to PyPI:
Upload to a named repository in ~/.pypirc (e.g. testpypi):
ship-pypi --repository testpypi
Quiet mode:
ship-pr
Create 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:
- Creates a new branch from your current work
- Commits any uncommitted changes (using the title as commit message)
- Pushes to origin and creates a PR
- Adds the specified label (default:
enhancement) - Squash-merges the PR
- Deletes the remote branch and resets local to updated main
You must be on the default branch (usually main) with no unpulled changes.
ship-changelog
Generate or update CHANGELOG.md from closed GitHub issues since your last release:
This is useful when you want to edit the changelog separately (e.g., in an editor or Claude Code) before releasing.
If you already have a CHANGELOG.md, it must include <!-- do not remove --> near the top so fastship knows where to insert the next release notes.
ship-release-gh
This is an interactive helper:
- Creates/updates
CHANGELOG.mdfrom closed GitHub issues since your last GitHub release - Opens your
$EDITOR(defaults tonano) so you can edit the changelog - Prompts you to confirm
- Runs
git commit -am release,git push - Creates a GitHub release tagged with your current
__version__
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.
GitHub token setup
ship-release-gh looks for a token in this order:
FASTSHIP_TOKEN- a
./tokenfile in your repo root GITHUB_TOKEN
The token must have permission to create releases (typically repo scope for classic PATs, or appropriate fine-grained permissions).
ship-release
Full 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(openCHANGELOG.mdfor final review, commit if needed, push, create GitHub release)ship-pypi(upload to PyPI)ship-bump(bump patch version)- Commit and push the version bump
Notes
ship-pypidoes not bump your version for you — keep it explicit and boring.ship-release-ghrequires that your project has a gitoriginremote pointing at GitHub (or use--repo OWNER/REPO).
Existing projects
To add fastship to an existing project:
1) Put your version in __init__.py
In your package's main __init__.py:
2) Configure 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.
3) Optional: specify branch
Fastship infers your package name from [project].name (changing - to _). To override the release branch:
[tool.fastship] branch = "main" # defaults to current git branch