11# Releasing CodexMonitor (macOS)
22
3- This guide is written for fresh agents and humans. It assumes the machine has
4- no access to private keys by default. Signing and notarization require the
5- Developer ID certificate and notarization credentials, which must be provided
6- by a human.
7-
8- ## Prereqs (Human-Provided)
9-
10- - Apple Developer account with Team ID.
11- - Developer ID Application certificate installed in Keychain.
12- - Notarization credentials for ` notarytool ` :
13- - Apple ID + app-specific password, or
14- - App Store Connect API key.
15-
16- ## Versioning
17-
18- Read the current version and decide the next release tag:
3+ This is a copy/paste friendly script-style guide. It assumes you have a
4+ Developer ID Application certificate installed and a ` notarytool ` keychain
5+ profile named ` codexmonitor-notary ` .
196
207``` bash
21- cat src-tauri/tauri.conf.json
22- cat package.json
23- ```
8+ set -euo pipefail
249
25- Bump both to the release version before building. After the release is published, bump both to the next minor.
26-
27- ## Build (Signed for Updater)
28-
29- The updater requires signing artifacts during the build. Export the private key
30- before ` tauri build ` :
31-
32- ``` bash
33- export TAURI_SIGNING_PRIVATE_KEY=~ /.tauri/codexmonitor.key
34- # optional if you set a password
35- export TAURI_SIGNING_PRIVATE_KEY_PASSWORD=" "
36- ```
10+ # --- Set versions ---
11+ # Update these two values each release.
12+ RELEASE_VERSION=" 0.4.3"
13+ PREV_VERSION=" 0.4.2"
3714
38- ``` bash
15+ # --- Update version fields (manual check afterwards) ---
16+ perl -pi -e " s/\" version\" : \" [^\" ]+\" /\" version\" : \" ${RELEASE_VERSION} \" /" package.json
17+ perl -pi -e " s/\" version\" : \" [^\" ]+\" /\" version\" : \" ${RELEASE_VERSION} \" /" src-tauri/tauri.conf.json
3918npm install
40- npm run tauri build
41- ```
42-
43- The app bundle is produced at:
44-
45- ```
46- src-tauri/target/release/bundle/macos/CodexMonitor.app
47- ```
4819
49- ## Bundle OpenSSL (Required for distribution)
20+ # --- Commit + push version bump ---
21+ git add package.json package-lock.json src-tauri/tauri.conf.json
22+ git commit -m " chore: bump version to ${RELEASE_VERSION} "
23+ git push origin main
5024
51- The app links to OpenSSL. Bundle and re-sign the OpenSSL dylibs:
25+ # --- Build (signed for updater) ---
26+ export TAURI_SIGNING_PRIVATE_KEY=~ /.tauri/codexmonitor.key
27+ export TAURI_SIGNING_PRIVATE_KEY_PASSWORD=" release"
28+ npm run tauri -- build --bundles app
5229
53- ``` bash
54- CODESIGN_IDENTITY=" Developer ID Application: Your Name (TEAMID )" \
30+ # --- Bundle OpenSSL + re-sign app ---
31+ CODESIGN_IDENTITY=" Developer ID Application: Thomas Ricouard (Z6P74P6T99 )" \
5532 scripts/macos-fix-openssl.sh
56- ```
5733
58- ## Sign + Notarize + Staple (Human Step)
59-
60- 1 ) Confirm signing identity (from Keychain):
61-
62- ``` bash
63- security find-identity -v -p codesigning
64- ```
65-
66- 2 ) Zip the app:
67-
68- ``` bash
34+ # --- Zip, notarize, staple ---
6935ditto -c -k --keepParent \
7036 src-tauri/target/release/bundle/macos/CodexMonitor.app \
7137 CodexMonitor.zip
72- ```
7338
74- 3 ) Store notary credentials (one-time per machine):
75-
76- ``` bash
77- xcrun notarytool store-credentials codexmonitor-notary \
78- --apple-id " you@apple.com" \
79- --team-id " TEAMID" \
80- --password " app-specific-password"
81- ```
82-
83- If the profile already exists in Keychain, reuse it:
84-
85- ``` bash
86- --keychain-profile " codexmonitor-notary"
87- ```
88-
89- Validate the profile (works even if listing is unsupported):
90-
91- ``` bash
92- xcrun notarytool history --keychain-profile " codexmonitor-notary"
93- ```
94-
95- 4 ) Submit for notarization and wait:
96-
97- ``` bash
9839xcrun notarytool submit CodexMonitor.zip \
99- --keychain-profile " codexmonitor-notary" \
40+ --keychain-profile codexmonitor-notary \
10041 --wait
101- ```
102-
103- 5 ) Staple the app:
10442
105- ``` bash
10643xcrun stapler staple \
10744 src-tauri/target/release/bundle/macos/CodexMonitor.app
108- ```
109-
110- ## Package Release Artifacts
11145
112- Note: Tauri's DMG bundling can fail if the generated ` bundle_dmg.sh ` script
113- is invoked without arguments. The manual packaging flow below is the fallback
114- and is the expected path if that happens.
115-
116- ``` bash
46+ # --- Package ZIP + DMG from stapled app ---
11747mkdir -p release-artifacts release-artifacts/dmg-root
11848rm -rf release-artifacts/dmg-root/CodexMonitor.app
11949ditto src-tauri/target/release/bundle/macos/CodexMonitor.app \
@@ -126,90 +56,61 @@ ditto -c -k --keepParent \
12656hdiutil create -volname " CodexMonitor" \
12757 -srcfolder release-artifacts/dmg-root \
12858 -ov -format UDZO \
129- release-artifacts/CodexMonitor_< RELEASE_VERSION> _aarch64.dmg
130- ```
131-
132- ## Rebuild Updater Bundle (After Stapling)
133-
134- After stapling, rebuild the updater tarball and re-sign it so the signature
135- matches the stapled app:
59+ release-artifacts/CodexMonitor_${RELEASE_VERSION} _aarch64.dmg
13660
137- ``` bash
138- tar -czf src-tauri/target/release/bundle/macos/CodexMonitor.app.tar.gz \
61+ # --- Rebuild updater tarball without AppleDouble files ---
62+ COPYFILE_DISABLE=1 tar -czf \
63+ src-tauri/target/release/bundle/macos/CodexMonitor.app.tar.gz \
13964 -C src-tauri/target/release/bundle/macos CodexMonitor.app
14065
14166npm run tauri signer sign -- \
14267 -f ~ /.tauri/codexmonitor.key \
143- -p " <PASSWORD_IF_SET> " \
68+ -p " release " \
14469 src-tauri/target/release/bundle/macos/CodexMonitor.app.tar.gz
145- ```
146-
147- ## Generate Changelog (from git log)
148-
149- Create release notes from the tag range using plain git log:
150-
151- ``` bash
152- git log --name-only --pretty=format:" %h %s" v< PREV_VERSION> ..v< RELEASE_VERSION>
153- ```
154-
155- Summarize user-facing changes into short bullet points and use them in the GitHub release notes.
156-
157- ## Tag, Release, and Updater Manifest (with gh)
158-
159- Tag first so the changelog is tied to the release tag:
16070
161- ``` bash
162- git tag v< RELEASE_VERSION>
163- git push origin v< RELEASE_VERSION>
164- ```
71+ # --- Changelog (for release notes) ---
72+ git log --name-only --pretty=format:" %h %s" v${PREV_VERSION} ..v${RELEASE_VERSION}
16573
166- Create the GitHub release with artifacts:
74+ # --- Tag ---
75+ git tag v${RELEASE_VERSION}
76+ git push origin v${RELEASE_VERSION}
16777
168- ``` bash
169- gh release create v< RELEASE_VERSION> \
170- --title " v<RELEASE_VERSION>" \
171- --notes " Signed + notarized macOS release." \
172- release-artifacts/CodexMonitor.zip \
173- release-artifacts/CodexMonitor_< RELEASE_VERSION> _aarch64.dmg
174- ```
78+ # --- Build latest.json for updater ---
79+ PUB_DATE=$( date -u +%Y-%m-%dT%H:%M:%SZ)
80+ SIGNATURE=$( cat src-tauri/target/release/bundle/macos/CodexMonitor.app.tar.gz.sig)
17581
176- Generate ` latest.json ` for the Tauri updater and upload it alongside the
177- signed artifacts. The updater manifest should include short notes and point at
178- the released artifacts + signatures.
179-
180- ``` json
82+ cat << EOF > release-artifacts/latest.json
18183{
182- "version" : " < RELEASE_VERSION> " ,
183- "notes" : " - Short update notes\n - Keep it brief " ,
184- "pub_date" : " 2025-01-01T12:00:00Z " ,
84+ "version": "${ RELEASE_VERSION} ",
85+ "notes": "- Short update notes",
86+ "pub_date": "${PUB_DATE} ",
18587 "platforms": {
18688 "darwin-aarch64": {
187- "url" : " https://github.com/Dimillian/CodexMonitor/releases/download/v< RELEASE_VERSION> /CodexMonitor.app.tar.gz" ,
188- "signature" : " <BASE64_SIGNATURE> "
89+ "url": "https://github.com/Dimillian/CodexMonitor/releases/download/v${ RELEASE_VERSION} /CodexMonitor.app.tar.gz",
90+ "signature": "${SIGNATURE} "
18991 }
19092 }
19193}
192- ```
193-
194- Signatures are generated during the build and emitted as ` .sig ` files next to
195- the bundles. Upload both the ` .sig ` files and ` latest.json ` to the same release:
94+ EOF
19695
197- ``` bash
198- gh release upload v< RELEASE_VERSION> \
96+ # --- Create GitHub release with artifacts ---
97+ gh release create v${RELEASE_VERSION} \
98+ --title " v${RELEASE_VERSION} " \
99+ --notes " - Short update notes" \
199100 release-artifacts/CodexMonitor.zip \
200- release-artifacts/CodexMonitor_< RELEASE_VERSION> _aarch64.dmg \
101+ release-artifacts/CodexMonitor_${ RELEASE_VERSION} _aarch64.dmg \
201102 src-tauri/target/release/bundle/macos/CodexMonitor.app.tar.gz \
202103 src-tauri/target/release/bundle/macos/CodexMonitor.app.tar.gz.sig \
203- latest.json \
104+ release-artifacts/latest.json
105+
106+ # --- If you need to update assets later ---
107+ gh release upload v${RELEASE_VERSION} \
108+ src-tauri/target/release/bundle/macos/CodexMonitor.app.tar.gz \
109+ src-tauri/target/release/bundle/macos/CodexMonitor.app.tar.gz.sig \
110+ release-artifacts/latest.json \
204111 --clobber
205112```
206113
207- After uploading, edit the GitHub release notes to use the changelog summary.
208-
209- ## Notes
210-
211- - Signing/notarization cannot be performed without the Developer ID certificate
212- and notarization credentials.
213- - If the app fails to launch on another machine, verify OpenSSL is bundled:
214- ` otool -L .../CodexMonitor.app/Contents/MacOS/codex-monitor ` should show
215- ` @rpath/libssl.3.dylib ` and ` @rpath/libcrypto.3.dylib ` .
114+ Notes:
115+ - Never commit ` ~/.tauri/codexmonitor.key ` .
116+ - If notarization fails, run ` xcrun notarytool log <ID> --keychain-profile codexmonitor-notary ` .
0 commit comments