Repository navigation
Releasing
TopKit is published to PyPI as topkit:
https://pypi.org/project/topkit/. The name was claimed with 0.2.0a3 on
2026-09-21. Only the Director publishes it.
Releases go out through Trusted Publishing: PyPI trusts one workflow
in this repository, .github/workflows/release.yml, and GitHub proves to
PyPI, for each run, that an upload comes from it. PyPI then grants that
run a token that expires within minutes, so there is no token to keep,
lose or leak. The workflow runs when the Director publishes a
GitHub Release, and it uploads only after the Director approves it.
-
The PyPI account. It exists, with two-factor authentication on; PyPI refuses uploads without it.
-
The trusted publisher, on PyPI. Your projects →
topkit→ Manage → Publishing → Add a new publisher → GitHub, with exactly:- Owner:
JulTob - Repository name:
Tag_Oriented_Programming - Workflow name:
release.yml - Environment name:
pypi
Then Add.
- Owner:
-
The environment, on GitHub. The repository's Settings → Environments → New environment named
pypi→ Configure environment (or openpypiif it already exists):- Required reviewers: tick it and add
JulTob. Leave "Prevent self-review" off: the Director approves his own releases. Untick "Allow administrators to bypass configured protection rules", so that every upload waits for the approval. Save protection rules. - Deployment branches: choose "Selected branches and tags" → Add
deployment branch or tag rule → set Ref type to Tag (as a branch
rule it would refuse the release) → pattern
v*→ Add rule.
These rules hold while the repository is public; on GitHub's free plan a private repository ignores them.
- Required reviewers: tick it and add
-
Old tokens. Once a release has gone through this way, delete the API tokens under PyPI's Account settings → API tokens. Nothing needs them any more.
-
Prepare it in a pull request, reviewed and merged like any other:
-
pyproject.toml'sversionis higher than the last one on PyPI. -
CHANGELOG.mdhas a heading for that version, dated:## 0.2.0a5 — 2026-10-20, no longer "unreleased". - The README's links are absolute GitHub links: PyPI shows the README, and a relative link is broken there.
-
-
Publish a GitHub Release. Releases → Draft a new release:
- Choose a tag: type
vand the version, for examplev0.2.0a5, then Create new tag. Target:main. - Title
TopKit 0.2.0a5; for the notes, paste the changelog entry. - Tick the pre-release box for an alpha.
- Publish release.
- Choose a tag: type
-
The workflow checks everything. Under Actions, "Release to PyPI"
runs:
- the suite on Python 3.12, 3.13 and 3.14, and the oracle at its audited size;
- a check that the tag is
vpluspyproject.toml's version and that the changelog has a dated heading for it; - the build, and
twine check --stricton both files. If any step fails, nothing is uploaded.
-
Approve the upload. The run stops at "Publish to PyPI" and waits:
Review deployments → tick
pypi→ Approve and deploy. Only then does it upload. - Check that https://pypi.org/project/topkit/ shows the new version.
If a check fails before the upload, the version number is still free: fix it in a pull request, delete the GitHub Release and its tag, and publish the release again. If the failure had nothing to do with the code (a runner hiccup, a typo in PyPI's publisher form), fix that and use Re-run failed jobs instead.
A version uploaded by hand never gets a GitHub Release afterwards: the workflow would run and stop at the upload, because PyPI refuses a second upload of the same number.
Make an API token on PyPI for this one upload (Account settings → API
tokens, scoped to topkit only). Keep it where no chat, file or
repository will ever see it; a token that has been pasted anywhere is
spent, so revoke it and make a new one.
Work in a fresh clone of main and a virtual environment. Homebrew and
distribution Pythons refuse system-wide installs, and a fresh clone
keeps stray files, and an older dist/, out of the upload.
git clone https://github.com/JulTob/Tag_Oriented_Programming.git topkit-release-<version>
cd topkit-release-<version>
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install --upgrade pip build twine
PYTHONPATH=. python3 -m unittest discover -s tests -t .
PYTHONPATH=. python3 tests/oracle_topkit.py --seeds 50 --steps 1200 --population 18
python3 -m build # writes dist/
python3 -m twine check --strict dist/* # both files must say PASSED
python3 -m twine upload -u __token__ dist/*
__token__ is typed as it stands: it is PyPI's user name for token
logins. Twine first warns that this machine is not set up for trusted
publishing, which is expected, and then asks "Enter your API token:".
Paste the token there, where it is not shown and not kept. Never put the token on the command line,
where the shell history would keep it. Twine prints the release page
when it succeeds. Then deactivate, delete the clone, and delete the
token on PyPI.
A version number, once uploaded, can be yanked but never reused. Bump
version in pyproject.toml before any further upload; a second upload
of the same number is refused.
0.2.0aN while the Specification is still moving. The version rises
when a STEP is Deployed, not when the code changes: the kit tracks the
paradigm, not the other way round.
While no final release exists, a plain pip install topkit installs the
newest alpha: pip follows PEP 440 and takes a pre-release when no final
release matches. Once a final release is on PyPI, a plain pip installs
that, and users who want an alpha say pip install --pre topkit.
pip index versions topkit hides alphas unless given --pre.