|
| 1 | +--- |
| 2 | +description: Speakeasy SDK generation configuration and workflow conventions |
| 3 | +globs: .speakeasy/**/*.yaml |
| 4 | +alwaysApply: false |
| 5 | +--- |
| 6 | + |
| 7 | +# Speakeasy SDK Configuration |
| 8 | + |
| 9 | +## Customization layers (per [Speakeasy docs](https://www.speakeasy.com/docs/sdks/customize/basics)) |
| 10 | + |
| 11 | +1. **OpenAPI overlays** (`.speakeasy/speakeasy-modifications-overlay.yaml`) — schema-level changes |
| 12 | +2. **`gen.yaml`** — generation config (naming, params, env vars, etc.) |
| 13 | +3. **SDK hooks** (`src/cloudinary_account_provisioning/_hooks/`) — custom auth, request/response transforms |
| 14 | +4. **Custom code** — Speakeasy's 3-way merge preserves edits across regenerations (`persistentEdits`) |
| 15 | +5. **Post-generation scripts** (`scripts/`) — recommended for fixes Speakeasy can't handle natively |
| 16 | + |
| 17 | +## gen.yaml |
| 18 | + |
| 19 | +Key Python settings: |
| 20 | +- `maxMethodParams: 4` with `methodArguments: infer-optional-args` — Python keyword args are idiomatic |
| 21 | +- `usageSDKInit: CldProvisioning()` — clean snippet init (relies on envVarPrefix for credentials) |
| 22 | +- `usageSDKInitImports: []` — avoid duplicate imports in snippets |
| 23 | +- `envVarPrefix: CLOUDINARY` — env var auto-loading for security and globals |
| 24 | +- `asyncMode: split` — separate `CldProvisioning` (sync) and `AsyncCldProvisioning` (async) classes |
| 25 | +- `packageManager: uv` — faster than poetry, Speakeasy default |
| 26 | +- `enableCustomCodeRegions: true` — preserve custom code blocks across regenerations |
| 27 | +- `forwardCompatibleEnumsByDefault: true` — resilient to new API enum values |
| 28 | +- `forwardCompatibleUnionsByDefault: tagged-only` — resilient to new API union variants |
| 29 | +- `flattenGlobalSecurity: true`, `responseFormat: flat`, `enumFormat: enum` |
| 30 | + |
| 31 | +All generation fix flags enabled (`securityFeb2025`, `sharedErrorComponentsApr2025`, `sharedNestedComponentsJan2026`, `nameOverrideFeb2026`). |
| 32 | + |
| 33 | +## workflow.yaml |
| 34 | + |
| 35 | +- PyPI publishing uses Speakeasy variable syntax in workflow.yaml |
| 36 | +- The GitHub secret name is `PYPI_TOKEN` |
| 37 | + |
| 38 | +## Publishing (pr mode) |
| 39 | + |
| 40 | +- `sdk_generation.yaml` generates SDK and opens a PR (`mode: pr`) |
| 41 | +- `sdk_publish.yaml` publishes to PyPI when the PR merges (push to main + gen.lock change) |
| 42 | + |
| 43 | +## Post-generation fixes (`scripts/fix-readme.sh`) |
| 44 | + |
| 45 | +- Reorders "Available Resources and Operations" in README.md to match OpenAPI schema tag order |
| 46 | +- Reads the schema URL from `.speakeasy/workflow.yaml` automatically — portable across SDK repos |
| 47 | +- Runs as part of `scripts/publish.sh` before PyPI publishing |
| 48 | +- **SIGPIPE pitfall**: never use `grep | head -1` with `set -eo pipefail` — use `grep -m 1` instead |
| 49 | +- Script is idempotent — safe to run multiple times |
| 50 | + |
| 51 | +## README sections |
| 52 | + |
| 53 | +To take over a Speakeasy-managed README section: |
| 54 | +1. Change `<!-- Start SectionName [tag] -->` to `<!-- Custom SectionName [tag] -->` |
| 55 | +2. **Remove** the `<!-- End SectionName [tag] -->` comment entirely |
| 56 | +3. If both markers remain, Speakeasy regenerates a duplicate section |
| 57 | + |
| 58 | +## Committing changes |
| 59 | + |
| 60 | +- **Separate generated from non-generated files**: commit config/scripts/custom code independently from Speakeasy-generated code |
| 61 | +- Use `chore:` prefix for non-release commits (won't trigger publish) |
| 62 | +- Generated code changes should come through the Speakeasy PR workflow, not manual commits |
0 commit comments