Prepare and publish a production Yohaku Companion macOS release. Use when asked to determine a release version, write verified release notes, update Xcode marketing/build versions, create an annotated Git tag, push a release, monitor the GitHub Release workflow, or diagnose a failed Yohaku Companion release or Sparkle appcast.
Prepare and publish a production Yohaku Companion macOS release. Use when asked to determine a release version, write verified release notes, update Xcode marketing/build versions, create an annotated Git tag, push a release, monitor the GitHub Release workflow, or diagnose a failed Yohaku Companion release or Sparkle appcast.
Release Yohaku Companion
Produce one auditable release commit and annotated tag. Let GitHub Actions own the deterministic Apple Silicon arm64 build, Developer ID signing, Apple notarization, DMG creation, Sparkle EdDSA appcast, and GitHub Release publication. Every release is Developer ID signed and notarized; there is no unsigned or ad-hoc distribution path.
Safety contract
Read AGENTS.md, .github/workflows/release.yml, ExportOptions.plist, and the current Xcode build settings before acting.
Require a clean working tree and main checked out at origin/main before changing versions.
Treat an explicit request to release a named version as authorization to commit, tag, and atomically push. Otherwise, obtain confirmation before the external push.
Never move, replace, force-push, or delete an existing tag. Never replace an existing public GitHub Release.
Stop when the version is not strictly greater than the version inside the newest real distributed application. Do not trust GitHub's latest label alone; inspect semantic tags and release assets when history is inconsistent. The sole exception is the repository bootstrap release described below, where no Yohaku Companion tag, Release, or distributed application exists yet.
Stop when notes contain claims that cannot be traced to source changes or verification evidence.
Preserve unrelated user changes; do not use destructive restore/reset commands.
One-time repository setup
The release job always requires this stable Sparkle key pair, either as repository secrets or in the protected GitHub environment:
release
Secret
Content
SPARKLE_PRIVATE_KEY
Fixed private key exported by Sparkle generate_keys -x
SPARKLE_PUBLIC_ED_KEY
Matching base64 public EdDSA key
Generate a Yohaku Companion-specific Sparkle pair once, back it up securely, and reuse it for every release. Never copy ProcessReporter’s pair and never generate a new key in CI. This key pair does not require an Apple developer account.
Developer ID distribution additionally requires all five of the following. The release job fails immediately when any one is missing; distribution never degrades to an unsigned artifact.
Secret
Content
BUILD_CERTIFICATE_BASE64
Base64-encoded Developer ID Application .p12 for team KAMM5N88X3
P12_PASSWORD
Password for the .p12
NOTARY_PRIVATE_KEY_BASE64
Base64-encoded App Store Connect API .p8
NOTARY_KEY_ID
App Store Connect API key ID
NOTARY_ISSUER_ID
App Store Connect issuer ID
The notarization key must be a Team Key issued at App Store Connect → Users and Access → Integrations → App Store Connect API → Team Keys. The Developer role is sufficient. Individual keys are not accepted by notarytool.
DEVELOPMENT_TEAM in project.pbxproj and teamID in ExportOptions.plist must both match the team that issued the certificate. A mismatch fails at xcodebuild -exportArchive with no signing certificate found.
See references/developer-id-provisioning.md for certificate selection and export, API key issuance, the local distribution rehearsal, and the commands that store these secrets. Rehearse locally before the first release on a new certificate or key.
Protect v* tags from deletion or force updates.
Release workflow
1. Establish the release boundary
Fetch tags and inspect git status, the current branch, origin/main, semantic tags, and GitHub Releases.
Inspect the actual version in the newest distributed app when tag history or latest is inconsistent.
Select a semantic version X.Y.Z strictly greater than the distributed version. If the repository has no Yohaku Companion tags or Releases, use the existing 1.7.3 project version and .github/release-notes/v1.7.3.md as the one-time bootstrap release.
Confirm that no local/remote tag or public Release already uses vX.Y.Z.
The script updates every Xcode configuration to MARKETING_VERSION=X.Y.Z and increments the unique positive CURRENT_PROJECT_VERSION.
Skip this script only for the one-time bootstrap v1.7.3 release when the repository still has no tags or Releases; that version and its notes are already committed as the initial Core-compatible baseline.
3. Write evidence-based release notes
Create .github/release-notes/vX.Y.Z.md with this structure:
# Yohaku Companion vX.Y.Z## Highlights- User-visible outcome.
## Fixes and reliability- Corrected behavior and affected boundary.
## Update notes- Compatibility or configuration note, if required.
Derive statements from the committed diff since the relevant previous release. Prefer observable behavior over implementation details. Omit empty sections and speculative claims. Mention migrations, permission changes, removed compatibility, or required secret/configuration changes explicitly.
Also run strict-concurrency and static-analysis checks when the release changes Swift runtime or data-flow code. The workflow runs scripts/prepare_arm64_app.sh after export because Sparkle's macOS binary framework contains multiple architecture slices even when the app target builds for arm64. Verify that Sparkle resolves to the reviewed version, every shipped executable is arm64-only after that preparation step, no legacy Discord SDK dynamic library is present, release notes are non-empty, and tag/project versions match.
5. Commit, tag, and atomically push
Review the complete diff. Then create one release commit and annotated tag:
rtk git add YohakuCompanion.xcodeproj/project.pbxproj .github/release-notes/vX.Y.Z.md
rtk git commit -m "release: vX.Y.Z"
rtk git tag -a vX.Y.Z -m "Yohaku Companion vX.Y.Z"
rtk git push --atomic origin main vX.Y.Z
Do not create the GitHub Release manually. The tag-triggered workflow verifies that all distribution credentials are present, creates a hidden draft, validates the arm64-only hardened-runtime application, notarizes and staples both the application and the DMG, generates an appcast whose DMG enclosure has a Sparkle EdDSA signature, publishes the release, and explicitly repairs GitHub's latest pointer.
6. Monitor the real endpoint
Watch the Release Actions run through completion. Confirm all of the following before reporting success:
The workflow concluded successfully.
The Release is public, non-prerelease, and marked latest.
The DMG, appcast.xml, checksum-covered Markdown notes, and SHA256SUMS.txt exist.
The latest appcast references the new tag, marketing version, build number, and an EdDSA signature.
The asset URLs return successfully.
If Actions fails, preserve the immutable tag, report the failing stage and evidence, and fix forward with explicit user direction. Do not silently republish different bytes under an already public version.