# 🐍 orchestkit-hook-contract → PyPI publish workflow

Tag-driven release pipeline for the Python sibling package. Pattern adapted from Yonatan-HQ/core's publish-python.yml; simplified for public PyPI + OIDC trusted publishing.

## Pipeline shape

         git tag hook-contract-py/v0.1.0
                  │
                  ▼
         ┌──────────────────────┐
         │ preflight            │  • tag regex match
         │                      │  • tag version == pyproject version
         │                      │  • codegen --check passes
         └──────────┬───────────┘
                    ▼
         ┌──────────────────────┐
         │ build                │  • python -m build (hatchling)
         │                      │  • emits wheel + sdist
         │                      │  • sha256 + size to step summary
         └──────────┬───────────┘
                    ▼
         ┌──────────────────────┐
         │ test                 │  • pytest -v on built source tree
         │                      │    (82 cases must all pass)
         └──────────┬───────────┘
                    ▼
         ┌──────────────────────┐
         │ publish-testpypi     │  • OIDC trusted publishing
         │                      │  • environment: testpypi
         └──────────┬───────────┘
                    ▼
         ┌──────────────────────┐
         │ smoke-testpypi       │  • wait for CDN propagation (poll)
         │                      │  • fresh ubuntu, fresh python
         │                      │  • pip install from test.pypi.org
         │                      │  • import + assert 19 events
         │                      │  • Pydantic typed instantiation works
         └──────────┬───────────┘
                    ▼
         ┌──────────────────────┐
         │ publish-pypi         │  • OIDC trusted publishing
         │                      │  • environment: pypi (production)
         └──────────┬───────────┘
                    ▼
         ┌──────────────────────┐
         │ github-release       │  • gh release create
         │                      │  • wheel + sdist + SHA256SUMS as assets
         └──────────────────────┘

## What it borrows from Yonatan-HQ/core

- `pkg/<name>/v<version>` tag-format pattern (adapted to `hook-contract-py/v*` since this is a single-package workflow)
- `workflow_dispatch` with tag input as recovery lever
- Preflight asserting tag/version match before any build work
- Two-stage publish (test → prod) with smoke gate between
- GitHub Release with wheel + sdist as assets
- Per-job permissions narrowing
- Concurrency group to serialize publishes

## What it does DIFFERENTLY

- Public PyPI (pypi.org) + OIDC trusted publishing, NOT private pypi.yonyon.ai + basic auth
- No secret to manage — OIDC short-lived tokens via `pypa/gh-action-pypi-publish`
- ubuntu-latest runners, NOT self-hosted
- hatchling + `python -m build`, NOT `uv build --package` (we're not in a uv workspace)
- Single-package focus — no per-pkg parameter parsing; the tag prefix encodes which package
- No SBOM yet — deferred to a follow-up
- No "notify consumers" downstream — deferred until there are actual subscribers

## Manual prerequisite (one-time setup)

Register `orchestkit-hook-contract` as a Trusted Publisher on PyPI and TestPyPI. See `packages/hook-contract-py/RELEASING.md` for the exact form fields.

Field | Value
--- | ---
PyPI project name | `orchestkit-hook-contract`
Owner | `yonatangross`
Repository | `orchestkit`
Workflow filename | `publish-hook-contract-py.yml`
Environment (testpypi) | `testpypi`
Environment (pypi) | `pypi`

## How to cut v0.1.0 after merge

    $ # bump version (already 0.1.0 in pyproject, ready to ship)
    $ git tag hook-contract-py/v0.1.0
    $ git push origin hook-contract-py/v0.1.0
    $ # watch CI at /actions/workflows/publish-hook-contract-py.yml
    $ # when green: pip install orchestkit-hook-contract works for everyone

## Unblocks

- #1809 (M141-8) yonatan-hq/platform consumer migration — once the package is on PyPI, the cross-repo PR can `pip install` it normally
- External OSS consumers — anyone can `pip install orchestkit-hook-contract`
- OSS-coherence with the npm sibling `@orchestkit/hook-contract`