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:
- Inputs: service/package names, paths, build command, package lists, Homebrew tap info, Jamf config.
- 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_NAMEis deprecated and ignored — packages are always unsigned.
- Always required for AI features:
- Permissions:
- Release/version bump jobs need
contents: write - Label checks need
pull-requests: read - PR commenting needs
pull-requests: write
- Release/version bump jobs need
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-releasesupports prerelease path directly.typescript-service-release,rust-service-release, andgo-service-releasegate release jobs onrelease(or forced input), and treat prerelease as flavor once release is active.swift-release,pkg-release,dylib-release, andmakefile-dylib-releasecheck onlyrelease.release.yaml(generic) checksreleaselabel and supports areleaseboolean input to force.
Implementation Procedure
When asked to set up BuildSpace in a repo:
- Detect repo type (Rust, TS single, TS monorepo, Go, Swift, macOS pkg, dylib).
- Confirm publish targets (GitHub only, npm, crates, Jamf, Homebrew tap).
- Create a caller workflow in the user repo (
.github/workflows/release.yamlorci.yaml) withuses: photon-hq/buildspace/...@v1. - Wire
with:inputs andsecrets:exactly for that workflow. - Add recommended permissions block.
- Add
dry-run: truefor first validation run unless the user requests immediate publish. - Explain how to trigger (
releaselabel + merge path, or forcedrelease: true). - For monorepos, validate
packagesJSON and dependency order behavior. - For Homebrew tap updates, wire
tap-repoandtap-formulainputs plusAPP_ID/APP_PRIVATE_KEYsecrets. - For Jamf uploads, wire
jamf-urland 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:
packagesinput 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: truepulls downstream packages into release. root-build-commandtakes precedence over per-packagebuild-command.- Pre-release npm tag is automatically
betawhen prerelease is active. - Uses
release/YYYY-MM-DD.Ndate-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, requiresAPP_ID+APP_PRIVATE_KEY)
- Go workflow:
- cross-builds for macOS ARM64 and Linux AMD64
- can also update Homebrew tap (
tap-repo+tap-formula, requiresAPP_ID+APP_PRIVATE_KEY)
Swift / macOS .pkg Notes
swift-releasebuilds the Swift binary, creates an unsigned.pkg, creates GitHub Release, and optionally uploads to Jamf.pkg-releaseis for.pkgpackages that contain no compiled binary — only payload files and/or scripts.swift-pkg-prandpkg-release-prare the PR preview counterparts (build on every commit, comment on PR).- Packages are always unsigned (
DEVELOPER_ID_INSTALLER_NAMEis deprecated and ignored). - Compile-time env vars are passed via
SECRET_ENV_VARSsecret (written to.env). - Jamf upload is optional — set
jamf-urlinput and provideJAMF_CLIENT_ID+JAMF_CLIENT_SECRETsecrets.
Dylib Notes
dylib-release.ymlis for projects using an Xcode workspace with CocoaPods. Builds arm64e dylib.makefile-dylib-release.ymlis for projects using a Makefile. Runsmake releaseand embeds version.- Both create a GitHub Release with the
.dylibas 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_KEYand 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_KEYand 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
packagesJSON is valid and paths exist. - For publish failures, test with
dry-run: trueand verify auth token scopes. - For Homebrew tap updates, confirm
APP_ID+APP_PRIVATE_KEYsecrets are set and the GitHub App has push access to the tap repo. - For Jamf uploads, confirm
JAMF_CLIENT_ID+JAMF_CLIENT_SECRETare set andjamf-urlis 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:
- Chosen workflow and why.
- Copy-ready YAML for caller workflow.
- Secrets to add (list exactly which ones and where to get them).
- How to trigger and verify.
- First-run safe mode (
dry-run) recommendation.
Keep recommendations concrete and default to the smallest working setup.