This guide walks through setting up code signing and notarization for distributing Claude Usage as a signed .dmg.
- An Apple Developer account ($99/year)
- A Developer ID Application certificate (not "Apple Development" — that's for testing only)
- Xcode command line tools installed
If you don't have one yet:
- Go to developer.apple.com/account/resources/certificates
- Click + to create a new certificate
- Select Developer ID Application
- Follow the instructions to create a Certificate Signing Request (CSR) from Keychain Access
- Download and double-click the certificate to install it
Verify it's installed:
security find-identity -v -p codesigningYou should see something like:
1) ABC123... "Developer ID Application: Your Name (TEAM_ID)"
Important: You need "Developer ID Application", not "Apple Development". Only Developer ID certificates work for distribution outside the App Store.
- Open Keychain Access (
/Applications/Utilities/Keychain Access.app) - Go to login keychain → My Certificates
- Find "Developer ID Application: Your Name (TEAM_ID)"
- Right-click → Export...
- Save as
.p12format - Set a strong password — you'll need this for
MACOS_CERTIFICATE_PWD
base64 < ~/Desktop/Certificates.p12 | pbcopyThe base64 string is now on your clipboard. This is the value for MACOS_CERTIFICATE.
Notarization requires an app-specific password (not your regular Apple ID password):
- Go to appleid.apple.com
- Sign in → Sign-in and Security → App-Specific Passwords
- Click + → name it "GitHub Actions" → Create
- Copy the generated password (format:
xxxx-xxxx-xxxx-xxxx)
This is the value for AC_PASSWORD.
Your Team ID is in parentheses in the certificate name:
"Developer ID Application: Your Name (WQ8V5KRNUG)"
^^^^^^^^^^
This is your Team ID
Or find it at developer.apple.com/account → Membership Details.
Go to your repo → Settings → Secrets and variables → Actions → New repository secret.
Add these 6 secrets:
| Secret | Value | Example |
|---|---|---|
MACOS_CERTIFICATE |
Base64-encoded .p12 file | MIIFbTCCBFWg... (long string) |
MACOS_CERTIFICATE_PWD |
Password from step 2 | your-p12-password |
MACOS_CERTIFICATE_NAME |
Full certificate name | Developer ID Application: Your Name (TEAM_ID) |
AC_USERNAME |
Apple ID email | you@example.com |
AC_PASSWORD |
App-specific password from step 4 | xxxx-xxxx-xxxx-xxxx |
AC_TEAM_ID |
Team ID from step 5 | WQ8V5KRNUG |
Once secrets are configured, create a release by pushing a tag:
git tag v1.0.0
git push origin v1.0.0The release.yml workflow will:
- Run all tests
- Build the app with xcodegen + xcodebuild
- Sign with your Developer ID certificate
- Create a
.dmgwith Applications symlink - Submit to Apple for notarization
- Staple the notarization ticket to the DMG
- Create a GitHub Release with the DMG attached
To build a signed app locally without CI:
# Generate Xcode project
xcodegen generate
# Build and sign
xcodebuild -project ClaudeUsage.xcodeproj \
-scheme ClaudeUsage \
-configuration Release \
-derivedDataPath build/DerivedData \
CODE_SIGN_STYLE="Automatic" \
DEVELOPMENT_TEAM="YOUR_TEAM_ID" \
build
# Verify signature
codesign -dvv "build/DerivedData/Build/Products/Release/Claude Usage.app""No identity found" — Your certificate isn't installed or has expired. Check with security find-identity -v -p codesigning.
"bundle format unrecognized" — The framework target needs GENERATE_INFOPLIST_FILE: YES in project.yml. This is already configured.
Notarization fails — Ensure you're using a "Developer ID Application" certificate, not "Apple Development". Check that your app-specific password is valid.
Stapling fails — Apple's servers can be slow to propagate. The workflow retries 5 times with 30-second delays.