Distributable, signed and notarized builds of OpenPromptr are produced by
trsdn/macos-notarization-broker
(profile openpromptr), not by this repository.
Apple credentials never reach this repository. The broker treats application repositories as untrusted: it builds the app from a pinned commit in a job with no secrets, validates and repackages the result on a second secretless runner, and only then signs and notarizes with broker-owned code in a protected environment.
The practical consequence is that this repository does not define the
release bundle. build-app.sh exists for local development and testing
only; the broker assembles the bundle itself with its own
assemble_openpromptr build step. If the two ever disagree, the broker's
preflight rejects the release rather than signing something unexpected.
That also means a change to the bundle — identifier, executable name,
layout, architecture, entitlements, or minimum macOS version — is not a
local decision. It requires a reviewed pull request against the broker's
profiles/apps.json, and the release fails until that lands.
SwiftPM's Package.swift has no fields for a description, a licence or a
repository URL, so those live in the file the app itself carries,
Config/Info.plist, and the GitHub repository settings mirror them:
| Property | Home | Mirrored in |
|---|---|---|
| Name | CFBundleName, CFBundleDisplayName |
repository name |
| Version | the git tag, stamped into CFBundleShortVersionString and CFBundleVersion by the build |
release title |
| Description | OPRProductDescription |
GitHub repository description |
| Licence | OPRLicenseIdentifier (and NSHumanReadableCopyright for the holder) |
LICENSE, GitHub licence |
| Repository, issue tracker | OPRRepositoryURL, OPRIssueTrackerURL |
GitHub |
When one changes, change the others in the same pull request.
-
Update
CHANGELOG.md: move entries out of Unreleased into a new version heading, with the date. -
Do not hand-bump the version. Unlike some sibling apps,
Config/Info.plist'sCFBundleShortVersionString/CFBundleVersionare only the fallback for a non-git checkout — bothbuild-app.sh(local builds) and the broker'sassemble_openpromptr(release builds) derive the real version from the git tag and stamp it into the built bundle. The tag is the source of truth; editing the plist by hand does nothing for a release. -
swift build && swift test— must be clean.swift format lint --strict --recursive Sources Tests Package.swift— must be clean; CI enforces both, but check locally first. -
./build-app.shand run the result. At minimum, the optional runtime self-test if the app already holds Screen Recording permission; otherwise a manual check — pick each source type in turn, start output, and confirm the physical target display shows the mirrored/rotated image correctly. -
Merge to
main, then tagv<version>and push the tag. -
Request the notarized build from a checkout of the broker:
scripts/request.sh openpromptr v<version> --publish
The broker verifies the pinned commit and the reviewed dependency lock, builds with
assemble_openpromptr, and produces the artifacts declared in theopenpromptrprofile:OpenPromptr-v<version>-macOS-arm64.zip,OpenPromptr-v<version>-macOS-arm64.dmg, andOpenPromptr-<version>.dmg— the last one is a copy of the DMG under the exact filename AppUpdater requires to find it.--publishuploads all three to the GitHub release for the tag, with release notes extracted automatically from this repository'sCHANGELOG.mdentry for<version>— which is exactly why step 1 has to happen first.--publishrefuses to create the release at all if that entry is missing, empty, or still sitting under[Unreleased].
./build-app.shSigned with whatever identity is on this machine (falling back to ad-hoc, with a warning, if none is found), and not notarized. Good enough for testing on this machine; publishing an ad-hoc or non-notarized build would give users a Gatekeeper block on first launch.
Notarization is easy to believe has happened, so check the broker's artifact explicitly rather than trusting that a script printed something:
xcrun stapler validate OpenPromptr-v<version>-macOS-arm64.dmg
spctl --assess --type open --context context:primary-signature --verbose=2 \
OpenPromptr-v<version>-macOS-arm64.dmg
shasum -a 256 -c OpenPromptr-v<version>-macOS-arm64.dmg.sha256Then mount it, drag the app to /Applications, and confirm on a machine
that has never run it that it starts without a Gatekeeper warning.
Scripts/smoke-published.sh is the smoke kit. It needs nobody at the machine:
Scripts/smoke-published.sh v<version>It downloads the published DMGs, zip and checksums, and checks the checksums, that the AppUpdater copy is the same file, that the notarization ticket is stapled, that Gatekeeper accepts the DMG and the app, that the signature verifies, and that the app launches and reports the version the tag names. Exit status 0 is a pass. It does not capture a source or draw on a display; that needs a display and a Screen Recording grant, so it stays the manual check in step 4 above.
Run it after every release and add a row. A record stands for later releases until one changes how the app is built, signed or packaged.
| Version | Date | Result | Run by |
|---|---|---|---|
| v1.3.0 | 2026-09-20 | pass — 9 of 9 checks; app reports OpenPromptr 1.3.0 (64) |
AI agent |
| v1.3.1 | 2026-09-20 | pass — 9 of 9 checks; app reports OpenPromptr 1.3.1 (68) |
AI agent |
| v1.3.2 | 2026-09-21 | pass — 9 of 9 checks; app reports OpenPromptr 1.3.2 (74) |
AI agent |
Existing installs of the pre-rename Teleprompter Mirror have no updater at all and will never auto-update to OpenPromptr — see Upgrading from Teleprompter Mirror in the README. Every OpenPromptr release from the first one onward carries the updater, but there is nothing for it to find until a second release exists. After cutting the second release:
- Install the first release.
- Launch it and use Check for Updates… (status menu or the app's
Update menu). It should find the second release, download it, and offer
Install Update
<version>and Restart…. - Confirm installing actually replaces the app and relaunches it at the
new version (
OpenPromptr --versionor the About panel). - Confirm the install is refused with an explanatory alert if attempted
while output is running or recovering (
AppModel.canStop) — start output first, then try installing, to check this deliberately rather than by accident.
The bundle identifier is part of every TCC grant. If it ever changes again, old grants for the previous identifier stay behind in System Settings under Privacy & Security, pointing at an app that no longer exists. Remove them so users are not asked to trust two entries for one app. The broker's profile pins the identifier, so a rename also needs a reviewed profile change.