# 🐍 M141-3 — PyPI scaffold (`orchestkit-hook-contract`)

Python sibling of `@orchestkit/hook-contract`. Both packages regenerate from `spec/hook-events.spec.yml`. Closes the npm↔Python schema drift class.

## 📦 Package surface

    from orchestkit_hook_contract import (
        HOOK_EVENT_NAMES,         # tuple of 19 event names
        HookEvent,                 # Pydantic v2 envelope (event, timestamp, ...)
        HookEventName,             # Literal[...] type
        PAYLOAD_MAP,               # event name -> payload class
        HOOK_EVENT_SCHEMAS,        # per-event JSON Schema (draft-07)
        validate_hook_event,       # structural validator
        is_hook_event_name,        # type guard

        # Per-event payload classes (13 of 19 events covered)
        PreToolUsePayload, PostToolUsePayload, PostToolUseFailurePayload,
        UserPromptSubmitPayload, NotificationPayload, PermissionRequestPayload,
        SubagentStartPayload, SubagentStopPayload, StopPayload,
        SessionStartPayload, PreCompactPayload, TeammateIdlePayload,
        TaskCompletedPayload,
    )

## 🔁 Cross-language parity

Surface | npm | PyPI
--- | --- | ---
event names | HOOK_EVENT_NAMES (19) | HOOK_EVENT_NAMES (19)
typed payloads | PayloadFor<'PreToolUse'> | PreToolUsePayload
JSON schemas | HOOK_EVENT_SCHEMAS | HOOK_EVENT_SCHEMAS
structural validator | validateHookEvent | validate_hook_event
codegen source | spec/hook-events.spec.yml | spec/hook-events.spec.yml
drift gate | codegen.mjs --check | codegen-py.py --check

## 🛠 What ships in this PR (M141-3)

- `packages/hook-contract-py/pyproject.toml` — Pydantic v2 dep, hatchling build, mypy/ruff/pytest deps
- `scripts/codegen-py.py` + `scripts/_codegen_emit.py` — hand-rolled emitter
- `src/orchestkit_hook_contract/events.py` — generated Pydantic models + envelope
- `src/orchestkit_hook_contract/schemas.py` — generated JSON Schema dicts
- `src/orchestkit_hook_contract/validate.py` — hand-written structural validator
- `tests/test_payloads.py` + `tests/test_validate.py` — 82 pytest cases, all pass
- `.github/workflows/hook-contract-py.yml` — codegen-check · mypy · ruff · pytest · build · wheel-import smoke

## 🔮 What's deferred (still under M141)

- #1807 (M141-6): Cross-language parity gate CI — diff npm + PyPI emits field-by-field
- #1809 (M141-8): Migrate yonatan-hq/platform consumer to use this package (separate-repo PR)
- PyPI publish workflow (test-pypi on tag → prod) — deferred to follow-up commit on this branch or a sibling PR
- The 6 envelope-only events (SessionEnd, Setup, Worktree*, ConfigChange, InstructionsLoaded) — same as the npm side, CC docs need to catch up

## ✅ Verified locally

    $ python scripts/codegen-py.py
    [codegen-py] wrote src/orchestkit_hook_contract/events.py
    [codegen-py] wrote src/orchestkit_hook_contract/schemas.py

    $ python scripts/codegen-py.py --check
    [codegen-py --check] OK: events.py + schemas.py match spec.

    $ pytest -v
    ============================== 82 passed in 0.93s ==============================

    $ python -c 'from orchestkit_hook_contract import PreToolUsePayload; PreToolUsePayload(tool_name="Bash", tool_input={"cmd": "ls"})'
    # typed Pydantic v2 model ✓