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 fastshipCreate 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.
Bump a version part (0=major, 1=minor, 2=patch):
ship_bump --part 2
ship_bump --part 1
ship_bump --part 0Decrement instead:
ship_bump --part 2 --unbumpBuild + upload to PyPI:
ship_pypiUpload to a named repository in ~/.pypirc (e.g. testpypi):
ship_pypi --repository testpypiQuiet mode:
ship_pypi --quietCreate 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 breakingThis 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.
Generate or update CHANGELOG.md from closed GitHub issues since your last release:
ship_changelogThis is useful when you want to edit the changelog separately (e.g., in an editor or Claude Code) before releasing.
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__
ship_release_ghIf you've already prepared the changelog (e.g., via ship_changelog), skip the changelog step:
ship_release_gh --no-changelogship_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).
Full release workflow assuming changelog is ready:
ship_changelog # generate changelog, edit as needed
ship_release # release to GitHub + PyPI, bump version, pushThis runs:
ship_release_gh --no_changelog(commit, push, create GitHub release)ship_pypi(upload to PyPI)ship_bump(bump patch version)- Commit and push the version bump
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).
To add fastship to an existing project:
In your package's main __init__.py:
__version__ = "0.0.1"[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