Publish Python packages
Build the distribution first, then upload its files to the repository’s PyPI upload host.
Build the package
Section titled “Build the package”From the Python project root:
rvs art select platform/releasesrvs uv buildReview the generated files in dist/ before uploading them.
Publish through rvs
Section titled “Publish through rvs”After signing in with rvs, either wrap Twine:
rvs art select platform/releasesrvs twine upload dist/*rvs supplies temporary access without writing a token to .pypirc.
Before uploading, rvs shows the destination and files and asks for
confirmation. Use rvs twine --rvs-yes upload dist/* only in a guarded
automation job.
Publish with uv through rvs
Section titled “Publish with uv through rvs”rvs art select platform/releasesrvs uv publishUse rvs uv --rvs-yes publish only in a guarded automation job.
Both wrappers select the upload URL and provide temporary authentication without writing credentials into project files, shell history, or package-tool settings.
Verify the upload
Section titled “Verify the upload”- Open the repository in Ravenstash.
- Confirm the package name and version.
- Inspect the uploaded wheel or source-distribution files.
- Install the exact version from the private index.
Use uv or Twine directly
Section titled “Use uv or Twine directly”To run uv publish or twine upload without a wrapper, mint a short-lived
publish token:
RVS_NATIVE_TOKEN=$(rvs art token mint \ --target platform/releases \ --format pypi \ --access publish)export RVS_NATIVE_TOKENCopy the current upload address from Ravenstash. The examples below use:
https://push.pypi.rvsta.sh/platform/releases/Print only the upload address or generate a complete target-specific recipe:
rvs art endpoint --target platform/releases --format pypi --access publishrvs art native config uv --target platform/releases --access publishrvs art native config twine --target platform/releasesendpoint only prints the address. native config prints configuration and
commands without writing files, minting a token, or running the package tool.
Configure the named index and its upload address in pyproject.toml:
[[tool.uv.index]]name = "ravenstash"url = "https://pypi.rvsta.sh/platform/releases/simple/"publish-url = "https://push.pypi.rvsta.sh/platform/releases/"default = trueauthenticate = "always"export UV_INDEX_RAVENSTASH_USERNAME=rvsexport UV_INDEX_RAVENSTASH_PASSWORD="$RVS_NATIVE_TOKEN"
uv builduv publish --index ravenstashUse Twine’s environment variables so the token is not saved in .pypirc or
placed on the command line:
export TWINE_USERNAME=rvsexport TWINE_PASSWORD="$RVS_NATIVE_TOKEN"export TWINE_REPOSITORY_URL="https://push.pypi.rvsta.sh/platform/releases/"export TWINE_NON_INTERACTIVE=1
twine upload dist/*Unset the credential variables after publication. See Use tokens with package tools for expiry, access, and rotation details.

