A macOS menu bar shortcut manager. Launch apps, run shell commands, open URLs, and manage developer workflows — all from a single popover.
- Menu bar popover with search, grouped shortcuts, and recent history
- Command types: app, shell, terminal, URL, file/folder, editor
- Placeholder parameters with last-used memory
- Screenshot watcher — copies new screenshot paths to clipboard
- Time converter — floating panel with day offset indicator
- Toast notifications — non-intrusive HUD alerts
- Settings — default apps, time zones, export/import, launch at login
- Sparkle auto-updates — in-app update notifications
On first launch, CmdEx will:
- Appear in your menu bar (no Dock icon by default)
- Prompt for Accessibility permission (required for the global hotkey ⌘⇧K)
- Additional permissions (Automation, Full Disk Access) are requested as needed
Press ⌘⇧K from any app to open the popover, or click the menu bar icon.
Built with The Composable Architecture (TCA) and Swift 6 strict concurrency.
AppFeature→ShortcutsFeatureviaScope@Dependencyclients:ExecutorClient,PersistenceClient,PermissionClient,ScreenshotClient,ToastClient,ClipboardClient@Shared(.appSettings)file storage — no UserDefaultsIdentifiedArrayOffor shortcuts and groups- Semantic typography and accessibility labels throughout
- macOS 15.0+
- Xcode 16+
- Swift 6.0
- XcodeGen (
brew install xcodegen)
Open in Xcode (recommended):
xcodegen generate
open CmdEx.xcodeprojOr build from the command line:
xcodegen generate
xcodebuild -project CmdEx.xcodeproj -scheme CmdEx -configuration Debug build -skipMacroValidation-skipMacroValidation is required because several SPM dependencies (TCA, swift-dependencies, swift-case-paths, swift-perception) use Swift macros. Xcode trusts them automatically via its UI; the CLI requires the flag.
cd CmdExCore && swift testTests live in CmdExCore/Tests/CmdExCoreTests/ and cover models, reducers, dependency clients, and feature logic. All tests use Swift Testing (@Test, #expect) — no XCTest.
The project uses CODE_SIGN_STYLE = Automatic. Debug builds sign with "Apple Development" — make sure you have a valid Apple Development certificate in your keychain and your team is selected in Xcode's Signing & Capabilities tab.
- The
project.ymlhasDEVELOPMENT_TEAMandCODE_SIGN_STYLE = Automaticpre-configured. Do not passDEVELOPMENT_TEAMorCODE_SIGN_IDENTITYon the xcodebuild command line — this overrides the project settings and breaks SPM macro plugin signing. - CLI builds use
-skipMacroValidationto bypass the macro trust prompt (which only works in Xcode GUI). - GitHub Actions CI also uses
-skipMacroValidationand handles signing via an imported certificate.
CmdEx/ # App target (SwiftUI views, AppKit integration)
App/ # AppDelegate, MenuBarManager, PopoverManager, ToastWindow, etc.
Features/ # Views: Dashboard, Preferences, DeveloperWindow, etc.
Assets.xcassets/ # App icon and menu bar icon
CmdExCore/ # Swift package (testable core logic)
Sources/CmdExCore/
AppFeature.swift # Root TCA reducer
ShortcutsFeature.swift # Shortcuts CRUD, execution, import/export
Models/ # Shortcut, ShortcutGroup, AppSettings, etc.
Logic/ # Dependency clients (Executor, Persistence, Permission, etc.)
Tests/CmdExCoreTests/ # All tests
project.yml # XcodeGen spec (source of truth for project config)
| Permission | Why | How to grant |
|---|---|---|
| Accessibility | Global hotkey (⌘⇧K) | System Settings → Privacy & Security → Accessibility → toggle CmdEx on |
| Automation | Send commands to Terminal/iTerm2 via AppleScript | Run a terminal shortcut once — macOS prompts automatically |
| Full Disk Access | Shell commands accessing protected paths | System Settings → Privacy & Security → Full Disk Access → add CmdEx |
The app checks permission status every 3 seconds and shows a warning banner when any are missing, with a "Fix" button that navigates to the Permissions section.
Reset individual services — never use tccutil reset All as it can freeze macOS:
tccutil reset Accessibility com.cmdex.app && \
tccutil reset AppleEvents com.cmdex.app && \
tccutil reset ListenEvent com.cmdex.app && \
tccutil reset SystemPolicyAllFiles com.cmdex.appThere's also a hidden Developer window (tap the version number 7 times in Settings → About) with a "Copy Command" button that generates the correct reset + relaunch command for the current build.
Releases are automated via GitHub Actions. Bump the version, push to main, and the workflow handles the rest.
- Bump
MARKETING_VERSIONinproject.yml:MARKETING_VERSION: "1.5.0"
- Bump
CURRENT_PROJECT_VERSIONif needed:CURRENT_PROJECT_VERSION: "6"
- Commit and push:
git add -A && git commit -m "chore: bump version to 1.5.0" git push origin main
- GitHub Actions automatically:
- Detects the version bump (compares against existing tags)
- Builds a Release archive on macOS
- Zips and signs the
.appwith Sparkle EdDSA - Generates
appcast.xml - Creates a GitHub Release (
v1.5.0) with the zip and appcast
Users running CmdEx are notified of the update via Sparkle and can install it with one click.
Set the SPARKLE_PRIVATE_KEY GitHub secret for Sparkle update signing:
generate_keys -x /tmp/sparkle_key.txt
gh secret set SPARKLE_PRIVATE_KEY < /tmp/sparkle_key.txt
rm /tmp/sparkle_key.txt# Build
xcodegen generate
xcodebuild -project CmdEx.xcodeproj -scheme CmdEx -configuration Release archive \
-archivePath ./build/CmdEx.xcarchive -skipMacroValidation
# Package
cp -R ./build/CmdEx.xcarchive/Products/Applications/CmdEx.app ./build/CmdEx.app
ditto -c -k --keepParent ./build/CmdEx.app ./build/CmdEx-1.5.0.zip
# Sign (prints edSignature and length for appcast.xml)
sign_update ./build/CmdEx-1.5.0.zip
# Create release
gh release create v1.5.0 ./build/CmdEx-1.5.0.zip ./build/appcast.xml \
--title "v1.5.0" --generate-notesList recent workflow runs:
gh run list --repo rlchandani/CmdEx --limit 10View a specific failed run (use the run ID from the list):
gh run view <RUN_ID> --repo rlchandani/CmdExFind the failed job ID:
gh run view <RUN_ID> --repo rlchandani/CmdEx --json jobs --jq '.jobs[] | "\(.databaseId) \(.name) \(.conclusion)"'Get the failed job's logs:
gh run view --log-failed --job=<JOB_ID> --repo rlchandani/CmdExCommon failures:
- "No signing certificate found" —
MACOS_CERTIFICATEsecret is missing or the.p12is invalid. - "failed downloading Sparkle" — stale SPM cache on CI runner. The workflow clears it automatically.
- "Library Validation failed" — app and frameworks signed with different identities. Ensure
DEVELOPMENT_TEAMis set inproject.yml.
MIT — see LICENSE for details.