---
name: contract-sync
description: Regenerate `.ai-sync/contracts/openapi.yaml` from the backend app and `types.ts` from OpenAPI. Auto-invoke after any Edit on backend router / schema / Pydantic models, or when the user says "sync contract", "regen types", "update openapi".
allowed-tools: Bash(hexa *), Bash(python *), Bash(npx openapi-typescript *), Bash(node *)
---

# contract-sync

Enforces single-source-of-truth for the FE/BE contract.

## Flow

```
backend/main.py (FastAPI)
  → `python scripts/gen_openapi.py` dumps openapi.json
  → .ai-sync/contracts/openapi.yaml  (committed, single source of truth)
  → `npx openapi-typescript openapi.yaml -o types.ts`
  → .ai-sync/contracts/types.ts      (generated, committed for diff visibility)
  → FE imports `@/contracts/types`
```

## Commands

```bash
# Regenerate the OpenAPI spec from the backend app
python scripts/gen_openapi.py

# Derive TypeScript types
npx -y openapi-typescript .ai-sync/contracts/openapi.yaml \
  -o .ai-sync/contracts/types.ts

# Verify no drift vs HEAD
git diff --exit-code -- .ai-sync/contracts/
```

## Safety

- Only the **Orchestrator** persona (or CI) may commit contract changes.
  Other agents append a `.ai-sync/events/CONTRACT_PROPOSAL_*.md` ticket instead.
- CI workflow `contracts-drift.yml` (W5) runs this skill in `--dry-run` and
  blocks the PR if the committed files diverge from the regenerated output.
