Define the reusable workflow in .github/workflows/build.yml with on: workflow_call: with inputs (type, required) and outputs: (image-tag: value: ${{ jobs.build.outputs.image-tag }}) and secrets: inherit or explicit secrets: declarations
In the reusable workflow's job, export the output: outputs: image-tag: ${{ steps.build.outputs.image-tag }} where the step sets echo "image-tag=$TAG" >> $GITHUB_OUTPUT
In the caller workflow, reference the reusable workflow: jobs: build: uses: ./.github/workflows/build.yml with: ... secrets: inherit
Gate the deploy job on the build output: jobs: deploy: needs: build; if: needs.build.result == 'success'; with: image-tag: ${{ needs.build.outputs.image-tag }}
Pass secrets to the deploy job's environment using environment: production to enforce any required reviewers gate before the job runs
Test with act -j deploy locally or via a pull request to a non-production branch before promoting to main
Known gotchas
Outputs from a reusable workflow must be declared at the workflow level (on: workflow_call: outputs:) as well as at the job level; declaring only the job output without the workflow-level mapping means the caller cannot access it
secrets: inherit passes all caller secrets including GITHUB_TOKEN to the reusable workflow, but the GITHUB_TOKEN in the called workflow has the permissions of the caller repository, not the reusable workflow's repository
Reusable workflows from a private repository can only be called by workflows in the same organization or with explicit sharing configured; calling a private reusable workflow across organizations requires making the workflow public or using a PAT
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp