# Buildspace Ci Cd

> Configure and troubleshoot BuildSpace reusable GitHub Actions workflows and blocks for automated…

Configure and troubleshoot BuildSpace reusable GitHub Actions workflows and blocks for automated releases. Covers Rust, TypeScript (single package and monorepo), Go, Swift package, macOS .pkg (binary and payload-only), dylib (Xcode and Makefile), generic release, AI-based versioning/release notes, README freshness checks, skills documentation checks, labels, permissions, secrets, Homebrew tap updates, Jamf uploads, dry-run testing, and custom block composition. Use when users mention BuildSpace, release automation, reusable workflows, GitHub Actions CI/CD, or publishing to npm/crates/Homebrew/Jamf. Keywords: buildspace, ci/cd, github actions, release automation, reusable workflows, npm, crates, homebrew, rust, typescript, go, swift, monorepo, dylib, macOS, pkg, jamf, skills.

- Page: https://ss33.ai/skills/photon-hq/buildspace-ci-cd-64801374323
- Publisher: photon-hq
- Category: [Software Development](https://ss33.ai/skills/category/software-development-t44z8z) › [DevOps & cloud](https://ss33.ai/skills/category/software-development-t44z8z/devops-and-cloud-unkt50)
- License: MIT
- Source: https://github.com/photon-hq/skills/blob/abf227fdec233d654b4198293e5901207c6d8332/skills/buildspace-ci-cd/SKILL.md

## Skill

SKILL.md: https://ss33.ai/api/v1/ss33/download/photon-hq/buildspace-ci-cd-64801374323

# BuildSpace Release Workflows Skill

Use this skill to set up or debug BuildSpace-powered release automation in repositories that use reusable GitHub Actions workflows.

## What BuildSpace Provides

BuildSpace has two layers:

- **Workflows**: full release pipelines under `.github/workflows/*`.
- **Blocks**: reusable composite actions under `.github/blocks/*` for custom pipelines.

Default recommendation: use a prebuilt workflow unless the user explicitly needs custom behavior.

## Workflow Selection

Pick exactly one primary workflow based on project type:

| Project type | Workflow file | Trigger |
|---|---|---|
| Rust binary/library | `rust-service-release.yaml` | PR label `release` |
| TypeScript/JavaScript single package | `typescript-service-release.yaml` | PR label `release` |
| TypeScript monorepo (multiple packages) | `typescript-monorepo-release.yaml` | PR label `release` |
| Go binary | `go-service-release.yaml` | PR label `release` |
| Swift macOS `.pkg` (with compiled binary) | `swift-release.yml` | PR label `release` |
| macOS `.pkg` without binary (payload/scripts only) | `pkg-release.yml` | PR label `release` |
| macOS `.pkg` PR build (payload/scripts only) | `pkg-release-pr.yml` | Every PR commit |
| Swift macOS `.pkg` PR build previews | `swift-pkg-pr.yml` | Every PR commit |
| macOS dylib release (Xcode workspace) | `dylib-release.yml` | PR label `release` |
| macOS dylib release (Makefile) | `makefile-dylib-release.yml` | PR label `release` |
| Generic release (version + GitHub Release only) | `release.yaml` | PR label `release` |
| README freshness check on PRs | `check-readme.yaml` | Every PR |
| Skills documentation freshness check on PRs | `check-skills.yaml` | Every PR |

## Required Inputs, Secrets, and Permissions

Always verify these before writing YAML:

1. **Inputs**: service/package names, paths, build command, package lists, Homebrew tap info, Jamf config.
2. **Secrets**:
   - Always required for AI features: `OPENAI_API_KEY`
   - npm publishing: `NPM_TOKEN`
   - crates publishing: `CARGO_REGISTRY_TOKEN`
   - Swift compile-time env vars: `SECRET_ENV_VARS`
   - Jamf upload: `JAMF_CLIENT_ID` + `JAMF_CLIENT_SECRET`
   - Protected-branch pushes or Homebrew tap updates: `APP_ID` + `APP_PRIVATE_KEY`
   - Skills documentation check (private repos): `SKILLS_REPO_TOKEN`
   - Note: `DEVELOPER_ID_INSTALLER_NAME` is **deprecated and ignored** — packages are always unsigned.
3. **Permissions**:
   - Release/version bump jobs need `contents: write`
   - Label checks need `pull-requests: read`
   - PR commenting needs `pull-requests: write`

## Release Trigger Rules (Important)

BuildSpace is label-gated by default.

- Standard release label: `release`
- Optional prerelease label: `prerelease`
- No label usually means no release job.

Behavior nuance to keep accurate:

- `typescript-monorepo-release` supports prerelease path directly.
- `typescript-service-release`, `rust-service-release`, and `go-service-release` gate release jobs on `release` (or forced input), and treat prerelease as flavor once release is active.
- `swift-release`, `pkg-release`, `dylib-release`, and `makefile-dylib-release` check only `release`.
- `release.yaml` (generic) checks `release` label and supports a `release` boolean input to force.

## Implementation Procedure

When asked to set up BuildSpace in a repo:

1. Detect repo type (Rust, TS single, TS monorepo, Go, Swift, macOS pkg, dylib).
2. Confirm publish targets (GitHub only, npm, crates, Jamf, Homebrew tap).
3. Create a caller workflow in the user repo (`.github/workflows/release.yaml` or `ci.yaml`) with `uses: photon-hq/buildspace/...@v1`.
4. Wire `with:` inputs and `secrets:` exactly for that workflow.
5. Add recommended permissions block.
6. Add `dry-run: true` for first validation run unless the user requests immediate publish.
7. Explain how to trigger (`release` label + merge path, or forced `release: true`).
8. For monorepos, validate `packages` JSON and dependency order behavior.
9. For Homebrew tap updates, wire `tap-repo` and `tap-formula` inputs plus `APP_ID`/`APP_PRIVATE_KEY` secrets.
10. For Jamf uploads, wire `jamf-url` and Jamf secrets.

## Workflow Reference

### rust-service-release.yaml

Complete release pipeline for Rust services: label check, AI version + release notes, cross-build (Linux x64, macOS ARM64, Windows x64), sync workspace crate versions, publish crates to crates.io, create GitHub Release with binaries, optionally update Homebrew tap.

**Inputs:**

| Input | Type | Required | Default | Description |
|---|---|---|---|---|
| `service-name` | string | Yes | — | Display name for the service |
| `binary-name` | string | Yes | — | Name of the binary from `Cargo.toml` |
| `binary-path` | string | No | `""` | Path to crate directory (e.g., `crates/client`) |
| `crates` | string | No | `[]` | JSON array of crate paths to publish in dependency order |
| `build-env` | string | No | `""` | Compile-time env vars (e.g., `BASE_URL=https://...`) |
| `labels-to-check` | string | No | `["release", "prerelease"]` | PR labels that trigger releases |
| `prerelease` | boolean | No | `false` | Force prerelease (adds `-rc.N` suffix) |
| `release` | boolean | No | `false` | Force release (bypasses label check) |
| `dry-run` | boolean | No | `false` | Test without actually publishing |
| `tap-repo` | string | No | `""` | Homebrew tap repository (e.g., `photon-hq/homebrew-photon`). Empty to skip. |
| `tap-formula` | string | No | `""` | Formula name in tap (e.g., `jamf-package-updater`). Required if `tap-repo` is set. |

**Secrets:**

| Secret | Required | Description |
|---|---|---|
| `OPENAI_API_KEY` | Yes | For AI-powered versioning and release notes |
| `CARGO_REGISTRY_TOKEN` | No | crates.io API token (required for publishing) |
| `APP_ID` | No | GitHub App ID (for protected branches and Homebrew tap updates) |
| `APP_PRIVATE_KEY` | No | GitHub App private key |

### typescript-service-release.yaml

Complete release pipeline for a single TypeScript/JavaScript package: label check, AI version + release notes, bump `package.json`, create GitHub Release, publish to npm.

**Inputs:**

| Input | Type | Required | Default | Description |
|---|---|---|---|---|
| `service-name` | string | Yes | — | Display name for the service |
| `bun-version` | string | No | `latest` | Bun version to use |
| `npm-tag` | string | No | `latest` | npm dist-tag (e.g., `latest`, `beta`, `next`) |
| `no-npm-publish` | boolean | No | `false` | Skip npm publishing (GitHub Release only) |
| `working-directory` | string | No | `.` | Directory containing `package.json` |
| `build-command` | string | No | `bun run build` | Build command to run |
| `labels-to-check` | string | No | `["release", "prerelease"]` | PR labels that trigger releases |
| `prerelease` | boolean | No | `false` | Force prerelease |
| `release` | boolean | No | `false` | Force release (bypasses label check) |
| `dry-run` | boolean | No | `false` | Test without actually publishing |

**Secrets:**

| Secret | Required | Description |
|---|---|---|
| `OPENAI_API_KEY` | Yes | For AI-powered versioning and release notes |
| `NPM_TOKEN` | No | npm auth token (required for publishing) |

### typescript-monorepo-release.yaml

Complete release pipeline for TypeScript monorepos with independently-versioned packages. Detects changed packages, topologically sorts by dependency order, single AI call for all versions/notes, bumps each `package.json`, creates GitHub Release with `release/YYYY-MM-DD.N` tag, publishes to npm in order.

**Inputs:**

| Input | Type | Required | Default | Description |
|---|---|---|---|---|
| `service-name` | string | Yes | — | Display name for the monorepo |
| `packages` | string | Yes | — | JSON array: `[{"name":"pkg","path":"packages/pkg"}]` |
| `bun-version` | string | No | `latest` | Bun version to use |
| `npm-tag` | string | No | `latest` | npm dist-tag |
| `build-command` | string | No | `bun run build` | Per-package build command (ignored if `root-build-command` is set) |
| `root-build-command` | string | No | `""` | Build once at repo root (e.g., `turbo build`) |
| `include-dependents` | boolean | No | `false` | Also release downstream dependents |
| `labels-to-check` | string | No | `["release", "prerelease"]` | PR labels that trigger releases |
| `prerelease` | boolean | No | `false` | Force prerelease |
| `release` | boolean | No | `false` | Force release |
| `dry-run` | boolean | No | `false` | Test without actually publishing |

**Secrets:**

| Secret | Required | Description |
|---|---|---|
| `OPENAI_API_KEY` | Yes | For AI-powered versioning and release notes |
| `NPM_TOKEN` | Yes | npm authentication token |
| `APP_ID` | No | GitHub App ID (for pushing to protected branches) |
| `APP_PRIVATE_KEY` | No | GitHub App private key |

### go-service-release.yaml

Complete release pipeline for Go binaries: label check, AI version + release notes, cross-compile for macOS (ARM64) and Linux (AMD64), create GitHub Release with binaries, optionally update Homebrew tap.

**Inputs:**

| Input | Type | Required | Default | Description |
|---|---|---|---|---|
| `service-name` | string | Yes | — | Display name for the service |
| `binary-name` | string | Yes | — | Output binary name |
| `go-version` | string | No | `stable` | Go version to use |
| `build-flags` | string | No | `""` | Additional `go build` flags |
| `ldflags` | string | No | `-s -w` | Linker flags |
| `labels-to-check` | string | No | `["release", "prerelease"]` | PR labels that trigger releases |
| `prerelease` | boolean | No | `false` | Force prerelease |
| `release` | boolean | No | `false` | Force release |
| `tap-repo` | string | No | `""` | Homebrew tap repository. Empty to skip. |
| `tap-formula` | string | No | `""` | Formula name in tap. Required if `tap-repo` is set. |

**Secrets:**

| Secret | Required | Description |
|---|---|---|
| `OPENAI_API_KEY` | Yes | For AI-powered versioning and release notes |
| `APP_ID` | No | GitHub App ID (for Homebrew tap updates) |
| `APP_PRIVATE_KEY` | No | GitHub App private key |

### swift-release.yml

Complete release pipeline for macOS `.pkg` distribution with a compiled Swift binary: label check, AI version + release notes, Swift build, `.pkg` creation (unsigned), GitHub Release, optional Jamf upload.

**Inputs:**

| Input | Type | Required | Default | Description |
|---|---|---|---|---|
| `package-name` | string | Yes | — | Name of the Swift binary / package |
| `identifier` | string | Yes | — | Package identifier (e.g., `com.example.mytool`) |
| `scripts-path` | string | No | `""` | Path to scripts directory with preinstall/postinstall scripts |
| `payload-path` | string | No | `""` | Path to additional payload directory (mirrors install root) |
| `jamf-url` | string | No | `""` | Jamf Pro instance URL (leave empty to skip) |
| `jamf-package-priority` | string | No | `""` | Package priority in Jamf Pro |
| `jamf-package-name` | string | No | `""` | Package name to match in Jamf Pro |

**Secrets:**

| Secret | Required | Description |
|---|---|---|
| `OPENAI_API_KEY` | Yes | For AI-powered versioning and release notes |
| `SECRET_ENV_VARS` | No | Compile-time env vars written to `.env` |
| `JAMF_CLIENT_ID` | No | Jamf Pro API client ID |
| `JAMF_CLIENT_SECRET` | No | Jamf Pro API client secret |

### pkg-release.yml

Release pipeline for macOS `.pkg` that does **not** contain a compiled binary. Packages payload files and scripts into a `.pkg`, creates GitHub Release, optionally uploads to Jamf. Use instead of `swift-release` when packages only deliver configuration files, LaunchDaemons, scripts, or other non-binary payload.

**Inputs:**

| Input | Type | Required | Default | Description |
|---|---|---|---|---|
| `package-name` | string | Yes | — | Name of the package |
| `identifier` | string | Yes | — | Package identifier (e.g., `com.example.my-config`) |
| `scripts-path` | string | No | `""` | Path to scripts directory with preinstall/postinstall scripts |
| `payload-path` | string | No | `""` | Path to payload directory (mirrors install root) |
| `jamf-url` | string | No | `""` | Jamf Pro instance URL (leave empty to skip) |
| `jamf-package-priority` | string | No | `""` | Package priority in Jamf Pro |
| `jamf-package-name` | string | No | `""` | Package name to match in Jamf Pro |

**Secrets:**

| Secret | Required | Description |
|---|---|---|
| `OPENAI_API_KEY` | Yes | For AI-powered versioning and release notes |
| `JAMF_CLIENT_ID` | No | Jamf Pro API client ID |
| `JAMF_CLIENT_SECRET` | No | Jamf Pro API client secret |

### pkg-release-pr.yml

Builds a macOS `.pkg` (without a compiled binary) on every PR commit and reports status in the PR as a living comment. Same experience as `swift-pkg-pr` but for payload/scripts-only packages. Stale in-progress builds are automatically cancelled on new commits.

**Inputs:**

| Input | Type | Required | Default | Description |
|---|---|---|---|---|
| `package-name` | string | Yes | — | Name of the package |
| `identifier` | string | Yes | — | Package identifier (e.g., `com.example.my-config`) |
| `scripts-path` | string | No | `""` | Path to scripts directory with preinstall/postinstall scripts |
| `payload-path` | string | No | `""` | Path to payload directory (mirrors install root) |

### swift-pkg-pr.yml

Builds a macOS `.pkg` (with Swift binary) on every PR commit, posts/updates a single PR comment with build status, uploads artifact (7-day retention). Stale in-progress builds are automatically cancelled on new commits.

**Inputs:**

| Input | Type | Required | Default | Description |
|---|---|---|---|---|
| `package-name` | string | Yes | — | Name of the Swift binary / package |
| `identifier` | string | Yes | — | Package identifier (e.g., `com.example.mytool`) |
| `scripts-path` | string | No | `""` | Path to scripts directory with preinstall/postinstall scripts |

**Secrets:**

| Secret | Required | Description |
|---|---|---|
| `SECRET_ENV_VARS` | No | Compile-time env vars written to `.env` |

### dylib-release.yml

Release pipeline for macOS dynamic libraries built from an Xcode workspace with CocoaPods. Label check, AI version + release notes, install CocoaPods, build dylib (arm64e), create GitHub Release with `.dylib` artifact.

**Inputs:**

| Input | Type | Required | Default | Description |
|---|---|---|---|---|
| `workspace` | string | Yes | — | Path to `.xcworkspace` |
| `scheme` | string | Yes | — | Xcode scheme to build |
| `dylib-name` | string | Yes | — | Name of the output dylib (e.g., `BlueBubblesHelper`) |
| `project-directory` | string | Yes | — | Directory containing the Podfile |

**Secrets:**

| Secret | Required | Description |
|---|---|---|
| `OPENAI_API_KEY` | Yes | For AI-powered versioning and release notes |

### makefile-dylib-release.yml

Release pipeline for macOS dynamic libraries built from a Makefile. Label check, AI version + release notes, `make release`, create GitHub Release with `.dylib` artifact.

**Inputs:**

| Input | Type | Required | Default | Description |
|---|---|---|---|---|
| `dylib-name` | string | Yes | — | Name of the output dylib (e.g., `imessage-helper`) |

**Secrets:**

| Secret | Required | Description |
|---|---|---|
| `OPENAI_API_KEY` | Yes | For AI-powered versioning and release notes |

### release.yaml

Generic release pipeline for projects that only need AI-powered versioning and a GitHub Release (no build step, no package publishing). Useful for configuration repos, documentation repos, or any project that just needs tagged releases.

**Inputs:**

| Input | Type | Required | Default | Description |
|---|---|---|---|---|
| `service-name` | string | Yes | — | Display name for the service |
| `labels-to-check` | string | No | `["release"]` | JSON array of PR labels to check |
| `release` | boolean | No | `false` | Force release (overrides label) |

**Secrets:**

| Secret | Required | Description |
|---|---|---|
| `OPENAI_API_KEY` | Yes | For AI-powered versioning and release notes |

### check-readme.yaml

Runs on every PR to check if `README.md` is up to date with the changes. Uses AI to analyze changed files against the README. Posts/removes PR comments automatically.

**Inputs:**

| Input | Type | Required | Default | Description |
|---|---|---|---|---|
| `blocking` | boolean | No | `false` | If `true`, fail the workflow when README is outdated. If `false`, only post a warning comment. |

**Secrets:**

| Secret | Required | Description |
|---|---|---|
| `OPENAI_API_KEY` | Yes | For AI-powered README analysis |

### check-skills.yaml

Runs on every PR to check if skills documentation (in a separate skills repo) is up to date with the changes. Uses AI to analyze changed files against skill SKILL.md files. Posts/removes PR comments automatically.

**Inputs:**

| Input | Type | Required | Default | Description |
|---|---|---|---|---|
| `fail_on_missing_skills` | boolean | No | `false` | If `true`, fail workflow when skills are outdated. If `false`, only post a warning comment. |
| `skills-repo` | string | No | `photon-hq/skills` | Skills repository to check against (`owner/repo` format) |

**Secrets:**

| Secret | Required | Description |
|---|---|---|
| `OPENAI_API_KEY` | Yes | For AI-powered skills analysis |
| `SKILLS_REPO_TOKEN` | No | GitHub token for skills repo (defaults to `GITHUB_TOKEN`; use PAT for private repos) |

## Monorepo-Specific Guidance

For `typescript-monorepo-release`:

- `packages` input must be a JSON array:
  `[{"name":"pkg","path":"packages/pkg"}]`
- Changed package detection is diffed from last release tag.
- Packages are topologically sorted using local dependency edges.
- Optional `include-dependents: true` pulls downstream packages into release.
- `root-build-command` takes precedence over per-package `build-command`.
- Pre-release npm tag is automatically `beta` when prerelease is active.
- Uses `release/YYYY-MM-DD.N` date-based tags since there's no single version.

## Rust/Go Notes

- Rust workflow can:
  - cross-build artifacts for Linux x64, macOS ARM64, Windows x64
  - sync workspace versions across all crates
  - publish crates in provided order
  - optionally update Homebrew tap (`tap-repo` + `tap-formula`, requires `APP_ID` + `APP_PRIVATE_KEY`)
- Go workflow:
  - cross-builds for macOS ARM64 and Linux AMD64
  - can also update Homebrew tap (`tap-repo` + `tap-formula`, requires `APP_ID` + `APP_PRIVATE_KEY`)

## Swift / macOS .pkg Notes

- `swift-release` builds the Swift binary, creates an unsigned `.pkg`, creates GitHub Release, and optionally uploads to Jamf.
- `pkg-release` is for `.pkg` packages that contain **no compiled binary** — only payload files and/or scripts.
- `swift-pkg-pr` and `pkg-release-pr` are the PR preview counterparts (build on every commit, comment on PR).
- Packages are **always unsigned** (`DEVELOPER_ID_INSTALLER_NAME` is deprecated and ignored).
- Compile-time env vars are passed via `SECRET_ENV_VARS` secret (written to `.env`).
- Jamf upload is optional — set `jamf-url` input and provide `JAMF_CLIENT_ID` + `JAMF_CLIENT_SECRET` secrets.

## Dylib Notes

- `dylib-release.yml` is for projects using an Xcode workspace with CocoaPods. Builds arm64e dylib.
- `makefile-dylib-release.yml` is for projects using a Makefile. Runs `make release` and embeds version.
- Both create a GitHub Release with the `.dylib` as an artifact.

## README Check Guidance

Use `check-readme.yaml` for PR docs drift detection:

- `blocking: false` (default): warning comment only.
- `blocking: true`: fails job when README appears stale.
- Requires `OPENAI_API_KEY` and PR write permission for comments.

## Skills Check Guidance

Use `check-skills.yaml` for skills documentation drift detection:

- `fail_on_missing_skills: false` (default): warning comment only.
- `fail_on_missing_skills: true`: fails job when skills appear outdated.
- Requires `OPENAI_API_KEY` and PR write permission for comments.
- For private skills repos, provide `SKILLS_REPO_TOKEN` (PAT with repo access).

## Blocks Reference

All blocks live under `.github/blocks/`. Workflows compose these internally — use them directly only for custom pipelines.

### Version & Release Info

| Block | Path | Purpose |
|---|---|---|
| `determine-publish-version` | `.github/blocks/determine-publish-version/action.yaml` | AI-powered next semantic version (standalone, no release notes) |
| `generate-release-info` | `.github/blocks/generate-release-info/action.yaml` | AI-powered version + release notes in one step |
| `create-github-release` | `.github/blocks/create-github-release/action.yaml` | Create GitHub Release with optional artifact attachments |

### Label & PR Interaction

| Block | Path | Purpose |
|---|---|---|
| `check-pr-label` | `.github/blocks/check-pr-label/action.yaml` | Check PR labels to decide if release should trigger |
| `comment-on-pr` | `.github/blocks/comment-on-pr/action.yaml` | Post or update a single PR comment (idempotent via `comment-key`) |
| `check-readme` | `.github/blocks/check-readme/action.yaml` | AI-powered README freshness check |
| `check-skills` | `.github/blocks/check-skills/action.yaml` | AI-powered skills documentation freshness check |

### Build Blocks

| Block | Path | Purpose |
|---|---|---|
| `rust-build` | `.github/blocks/rust-build/action.yaml` | Build Rust binary for a target triple |
| `go-build` | `.github/blocks/go-build/action.yaml` | Build Go binary for a target OS/arch |
| `typescript-build` | `.github/blocks/typescript-build/action.yaml` | Build TypeScript project using Bun |
| `swift-build` | `.github/blocks/swift-build/action.yml` | Build Swift binary (SPM, supports `.env` injection) |
| `swift-pkg` | `.github/blocks/swift-pkg/action.yml` | Create macOS `.pkg` from binary and/or payload/scripts |
| `build-dylib` | `.github/blocks/build-dylib/action.yml` | Build macOS dylib from Xcode workspace (arm64e) |
| `build-makefile-dylib` | `.github/blocks/build-makefile-dylib/action.yml` | Build macOS dylib from Makefile |
| `install-cocoapods` | `.github/blocks/install-cocoapods/action.yml` | Cache and install CocoaPods dependencies |

### Publish Blocks

| Block | Path | Purpose |
|---|---|---|
| `publish-npm` | `.github/blocks/publish-npm/action.yaml` | Publish single package to npm |
| `publish-npm-packages` | `.github/blocks/publish-npm-packages/action.yaml` | Publish multiple monorepo packages to npm in dependency order |
| `publish-crates` | `.github/blocks/publish-crates/action.yaml` | Publish workspace crates to crates.io in order |
| `bump-npm-version` | `.github/blocks/bump-npm-version/action.yaml` | Bump version in `package.json` and push |
| `bump-monorepo-versions` | `.github/blocks/bump-monorepo-versions/action.yaml` | AI version bump for all changed monorepo packages |
| `sync-crates-version` | `.github/blocks/sync-crates-version/action.yaml` | Set a single version across all Rust workspace crates |
| `update-tap` | `.github/blocks/update-tap/action.yaml` | Update Homebrew tap formula (auto-calculates SHA256 for npm/Go/prebuilt) |
| `detect-changed-packages` | `.github/blocks/detect-changed-packages/action.yaml` | Detect changed monorepo packages and return in topological order |

## Troubleshooting Checklist

If release did not run:

- Confirm PR had expected label before merge.
- Confirm workflow permissions include required scopes.
- Confirm secrets exist at repository level.
- Confirm caller workflow points to correct reusable workflow path.
- For monorepos, confirm `packages` JSON is valid and paths exist.
- For publish failures, test with `dry-run: true` and verify auth token scopes.
- For Homebrew tap updates, confirm `APP_ID` + `APP_PRIVATE_KEY` secrets are set and the GitHub App has push access to the tap repo.
- For Jamf uploads, confirm `JAMF_CLIENT_ID` + `JAMF_CLIENT_SECRET` are set and `jamf-url` is a valid Jamf Pro URL.
- For dylib builds, confirm Xcode workspace/scheme or Makefile exists and produces expected output.

## Output Format for Agent Responses

When generating BuildSpace setup instructions, respond with:

1. **Chosen workflow** and why.
2. **Copy-ready YAML** for caller workflow.
3. **Secrets to add** (list exactly which ones and where to get them).
4. **How to trigger and verify**.
5. **First-run safe mode** (`dry-run`) recommendation.

Keep recommendations concrete and default to the smallest working setup.
