PyPI publishing — one-time setup
Status: the Actions workflow (
/.github/workflows/release.yml) is ready. This document is the checklist for one-time PyPI configuration that unblockspip install llm-notebook(#101).
How the pipeline works
Every time a version tag (v*.*.*) is pushed:
build— builds sdist + wheel withpython -m buildon Python 3.12.publish— uploads to PyPI via OIDC trusted publisher. Gated onvars.PYPI_PUBLISHING == 'true': until that variable is set, the job is skipped silently so unconfigured repos don't fail on every tag.sign— signs artifacts with Sigstore (gh-action-sigstore-python).github-release— creates (or updates) the matching GitHub Release with--generate-notes, attaches all artifacts + signatures. Runs even if publish/sign fail so Releases always keep tracking tags.
The package is uploaded as llm-notebook — llmwiki was already
taken on PyPI. The CLI command, the Python import (import llmwiki),
and the GitHub repo (Pratiyush/llm-wiki) all stay unchanged. Same
pattern as pillow → import PIL.
A future cleanup may unify all three — see the open issue for the full
repo / CLI rename to llm-notebook.
One-time setup (do this once, on pypi.org)
1. Reserve the project name on PyPI
- Log in to pypi.org (create an account if you haven't yet — GitHub sign-in works).
- "Your projects" → "Manage" — the
llmwikiname was already registered to another user. We usellm-notebookinstead. - Reserve the
llm-notebookname (PyPI lets you create a project directly via the trusted-publisher flow below — no upload needed).
2. Add the GitHub repo as a trusted publisher
Inside the PyPI "Your account → Publishing" page (or the project's own Publishing tab once it exists):
Add a new pending publisher → GitHub
| Field | Value |
|---|---|
| PyPI Project Name | llm-notebook |
| Owner | Pratiyush |
| Repository name | llm-wiki |
| Workflow name | release.yml |
| Environment name | release |
Save. This binds the GitHub OIDC identity to PyPI so the workflow can upload without a long-lived API token.
3. Create the release GitHub environment
- Repository settings → Environments → New environment
- Name:
release - Optional protection rules:
- Required reviewers — add your own handle so every PyPI upload
requires an explicit click.
- Wait timer — 5 minutes gives you time to abort a mis-tagged release.
- Deployment branches — limit to
masterso only master-tagged releases can trigger the upload.
4. Flip the publishing gate on
gh variable set PYPI_PUBLISHING --body "true" --repo Pratiyush/llm-wiki
# Verify
gh variable list --repo Pratiyush/llm-wiki | grep PYPI_PUBLISHING
5. Cut a real release tag
# Make sure you are on master with everything merged
git checkout master && git pull
# Bump version if needed, update CHANGELOG, commit...
# Create a signed tag
git tag -s v1.1.0 -m "v1.1.0 release"
git push origin v1.1.0
Watch the workflow at: <https://github.com/Pratiyush/llm-wiki/actions/workflows/release.yml>
The publish job should now run and show uploading + success.
6. Verify from a clean machine
python3 -m venv /tmp/pypi-smoke && source /tmp/pypi-smoke/bin/activate
pip install llm-notebook
llmwiki --version # should match the tag
llmwiki adapters # should list Claude Code, Codex, Cursor, Gemini, …
deactivate
Troubleshooting
publish skipped — PYPI_PUBLISHING variable not set, or set to
something other than "true". Fix:
gh variable set PYPI_PUBLISHING --body "true".
publish fails with "invalid-publisher" — the OIDC binding on
pypi.org doesn't match what GitHub sent. Double-check: owner =
Pratiyush, repo = llm-wiki, workflow = release.yml, environment
= release. Casing matters.
publish fails with "403 Forbidden: User ... isn't allowed to upload
to project ..." — the PyPI project exists but the trusted publisher
hasn't been added yet (or was added under a different project name).
Re-check step 2.
Artifacts rejected for metadata — check that pyproject.toml's
name, version, and description are all present; python -m build
locally + twine check dist/* surface issues before a tag push.
Second upload of the same version — PyPI refuses to overwrite a
version. Bump to the next patch (v1.1.1), update the changelog, re-tag.
Related
#101— this issue.github/workflows/release.yml— the pipelinedocs/deploy/homebrew-setup.md— sibling doc for the Homebrew tap (#102)