The React UI lives at web/. The Python framework lives at src/runtime/.
A v2.0.0-rc1 release ships both as a single tag.
-
Verify
web/package.jsonversion matches the tag you intend to cut.jq -r .version web/package.json
For v2.0.0-rc1 the answer should be
2.0.0-rc1. -
Regenerate the framework bundles (HARD-08 requirement):
uv run python scripts/build_single_file.py git diff --exit-code dist/ # must be clean -
Build the React SPA:
cd web && npm ci && npm run build
-
Compose the air-gap deploy payload:
uv run python scripts/package_airgap.py --out dist/airgap
Output:
dist/airgap/{app.py, ui.py, web/, README.txt}— local-only, never committed. Drop it on the deploy host. -
Sanity-check the bundle gates locally:
uv run pytest -x uv run ruff check src/ tests/ uv run pyright src/runtime (cd web && npm run lint && npm run typecheck && npm run test:unit && npm run build && npm run check:size)
-
Tag the release. Tagging always happens on
mainafter the final PR merge, never on a feature branch:git switch main git pull --ff-only git tag v2.0.0-rc1 -m "v2.0.0-rc1: React UI" git push origin v2.0.0-rc1
When cutting v2.0.0-rc2 (or v2.0.0):
web/package.json— update theversionfield.- Repeat the build + tag steps above.
Avoid editing package.json mid-PR for an unrelated change; the version
field changes only in a release-prep PR.
dist/ui.py (legacy Streamlit) ships in the deploy folder until the
React UI hits 100% parity (see docs/REACT_UI_PARITY.md). Streamlit
displays a deprecation banner; the React UI is the supported path.