{"id":48789537,"url":"https://github.com/speakeasy-api/examples-downstream-spec-repo","last_synced_at":"2026-04-13T19:30:40.803Z","repository":{"id":334033632,"uuid":"1139767114","full_name":"speakeasy-api/examples-downstream-spec-repo","owner":"speakeasy-api","description":"Example spec repo that triggers downstream SDK generation","archived":false,"fork":false,"pushed_at":"2026-01-22T12:05:17.000Z","size":11,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-23T02:34:07.660Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/speakeasy-api.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-22T11:43:18.000Z","updated_at":"2026-01-22T12:05:22.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/speakeasy-api/examples-downstream-spec-repo","commit_stats":null,"previous_names":["speakeasy-api/examples-downstream-spec-repo"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/speakeasy-api/examples-downstream-spec-repo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/speakeasy-api%2Fexamples-downstream-spec-repo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/speakeasy-api%2Fexamples-downstream-spec-repo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/speakeasy-api%2Fexamples-downstream-spec-repo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/speakeasy-api%2Fexamples-downstream-spec-repo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/speakeasy-api","download_url":"https://codeload.github.com/speakeasy-api/examples-downstream-spec-repo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/speakeasy-api%2Fexamples-downstream-spec-repo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31768606,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T15:25:13.801Z","status":"ssl_error","status_checked_at":"2026-04-13T15:25:09.162Z","response_time":93,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-13T19:30:37.919Z","updated_at":"2026-04-13T19:30:40.792Z","avatar_url":"https://github.com/speakeasy-api.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spec Repo with Downstream SDK Generation\n\nThis example demonstrates a \"spec repo\" workflow where a central repository holds OpenAPI specs, and changes trigger SDK generation in separate downstream SDK repositories.\n\n## Use case\n\nThis pattern is useful when:\n\n- A central team manages the API specification\n- Multiple SDK repositories need to be generated from the same spec\n- SDK generation should be triggered automatically when the spec changes\n- SDK PRs should be created in downstream repos for review before merging\n\n## How it works\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                           Spec Repository                               │\n│  ┌─────────────┐    ┌─────────────────────────────────────────────┐    │\n│  │ OpenAPI     │    │ trigger-downstream-sdk-generation.yaml      │    │\n│  │ Spec        │───▶│ 1. Runs `speakeasy run` to tag spec         │    │\n│  │ (PR change) │    │ 2. Triggers downstream SDK workflows        │    │\n│  └─────────────┘    │ 3. Polls for completion                     │    │\n│                     │ 4. Updates PR comment with status           │    │\n│                     └─────────────────────────────────────────────┘    │\n└─────────────────────────────────────────────────────────────────────────┘\n                                    │\n                                    │ gh workflow run\n                                    ▼\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        Downstream SDK Repos                             │\n│  ┌──────────────────────────┐    ┌──────────────────────────┐          │\n│  │ TypeScript SDK           │    │ Python SDK               │          │\n│  │ - Pulls tagged spec      │    │ - Pulls tagged spec      │          │\n│  │ - Generates SDK          │    │ - Generates SDK          │          │\n│  │ - Creates PR             │    │ - Creates PR             │          │\n│  └──────────────────────────┘    └──────────────────────────┘          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n## Repository structure\n\n```\nspec-repo-downstream-sdks/\n├── .speakeasy/\n│   └── workflow.yaml               # Source-only workflow\n├── .github/workflows/\n│   ├── trigger-downstream-sdk-generation.yaml  # Triggers SDK generation on PR\n│   └── reconcile-sdk-prs.yaml                  # Merges/closes SDK PRs when spec PR closes\n├── specs/\n│   └── openapi.yaml                # OpenAPI spec\n└── README.md\n```\n\n## Required secrets\n\n### On the spec repository\n\n| Secret | Description | How to obtain |\n|--------|-------------|---------------|\n| `SPEAKEASY_API_KEY` | Authenticates the Speakeasy CLI | [Speakeasy Platform](https://app.speakeasy.com) → **API Keys** page |\n| `DOWNSTREAM_SDK_TOKEN` | Triggers workflows in downstream SDK repos | See [Creating the downstream SDK token](#creating-the-downstream-sdk-token) |\n\n### On each downstream SDK repository\n\n| Secret | Description | How to obtain |\n|--------|-------------|---------------|\n| `SPEAKEASY_API_KEY` | Authenticates the Speakeasy CLI | Same key as spec repo, or a separate key |\n\n## Creating the downstream SDK token\n\nThe `DOWNSTREAM_SDK_TOKEN` is a fine-grained Personal Access Token (PAT) that allows the spec repo to trigger workflows in the downstream SDK repositories.\n\n### Steps to create\n\n1. Go to [GitHub Settings → Developer Settings → Fine-grained personal access tokens](https://github.com/settings/tokens?type=beta)\n2. Click **Generate new token**\n3. Set the following:\n   - **Token name**: `spec-repo-downstream-trigger` (or similar)\n   - **Expiration**: Choose an appropriate expiration\n   - **Resource owner**: Select the organization that owns the SDK repos (e.g., `speakeasy-api`)\n   - **Repository access**: Select **Only select repositories** and choose all downstream SDK repos\n4. Under **Permissions → Repository permissions**, set:\n   - **Actions**: Read and write (to trigger `workflow_dispatch`)\n   - **Contents**: Read and write (to push branches)\n   - **Pull requests**: Read and write (to create PRs)\n5. Click **Generate token** and copy the value\n6. Add the token as a secret named `DOWNSTREAM_SDK_TOKEN` in the spec repository\n\n## Setting up downstream SDK repositories\n\nEach downstream SDK repository needs to be set up with Speakeasy:\n\n```bash\n# Clone the repo\ngh repo clone speakeasy-api/examples-downstream-spec-sdk-typescript\ncd examples-downstream-spec-sdk-typescript\n\n# Run Speakeasy quickstart to configure the SDK\nspeakeasy quickstart\n\n# Configure GitHub Actions\nspeakeasy configure github\n```\n\n### Modify the generated workflow\n\nAfter running `speakeasy configure github`, modify the generated workflow file (e.g., `.github/workflows/generate.yaml`) to accept `workflow_dispatch` inputs:\n\n```yaml\non:\n  workflow_dispatch:\n    inputs:\n      force:\n        description: \"Force SDK regeneration\"\n        required: false\n        default: \"false\"\n      feature_branch:\n        description: \"Branch for SDK changes\"\n        required: false\n      environment:\n        description: \"Environment variables (e.g., tag=branch-name)\"\n        required: false\n  # ... keep other triggers\n```\n\nAnd pass these inputs to the workflow executor:\n\n```yaml\njobs:\n  generate:\n    uses: speakeasy-api/sdk-generation-action/.github/workflows/workflow-executor.yaml@v15\n    with:\n      mode: pr\n      force: ${{ inputs.force }}\n      feature_branch: ${{ inputs.feature_branch }}\n      environment: ${{ inputs.environment }}\n    secrets:\n      github_access_token: ${{ secrets.GITHUB_TOKEN }}\n      speakeasy_api_key: ${{ secrets.SPEAKEASY_API_KEY }}\n```\n\n## Workflow\n\n1. **Create a PR** in the spec repository with changes to `specs/openapi.yaml`\n2. **SDK generation triggers**:\n   - `speakeasy run` executes and tags the spec in the registry with the branch name\n   - Downstream SDK workflows are triggered via `gh workflow run`\n   - The spec PR is updated with a comment showing generation status and links to SDK PRs\n3. **Review SDK PRs** in the downstream repositories\n4. **Merge or close the spec PR**:\n   - **If merged**: The `reconcile-sdk-prs.yaml` workflow automatically merges all downstream SDK PRs\n   - **If closed without merging**: The workflow closes all downstream SDK PRs with a comment explaining why\n\n## Downstream SDK repositories\n\nThis example uses the following downstream SDK repositories:\n\n- [speakeasy-api/examples-downstream-spec-sdk-typescript](https://github.com/speakeasy-api/examples-downstream-spec-sdk-typescript)\n- [speakeasy-api/examples-downstream-spec-sdk-python](https://github.com/speakeasy-api/examples-downstream-spec-sdk-python)\n\n## Related documentation\n\n- [Publish specs to API registry](/docs/guides/source-only-workflow/)\n- [SDK generation action](https://github.com/speakeasy-api/sdk-generation-action)\n- [Speakeasy CLI CI/CD usage](https://www.speakeasy.com/docs/speakeasy-reference/cli/getting-started#using-the-speakeasy-cli-in-cicd)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspeakeasy-api%2Fexamples-downstream-spec-repo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspeakeasy-api%2Fexamples-downstream-spec-repo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspeakeasy-api%2Fexamples-downstream-spec-repo/lists"}