Repository navigation
OMC 5.4.0
OMC 5 requires macOS 14.6 or later. For older macOS versions, use OMC 4.x.
OMC 5.4 is built against ActionUI 0.8.4. It closes a hole in applet URL schemes, gives every applet an identity of its own for macOS privacy prompts, fixes several List and Table selection bugs, and moves the embedded Python to 3.14.8, a security release.
If your applet is opened by links, read the first section before you rebuild. A command now has to opt in before a URL can run it, so an applet that relies on <scheme>://exe?commandID=... links stops answering them until you add one key.
Rebuild your applets with AppletBuilder 5.4. The URL rule, the window and selection fixes and the per-applet identity all arrive only when an applet is rebuilt. An applet with an embedded Python should be rebuilt with "Update Embedded Python" on (appletbuilder build --update-python).
A URL can run a command only when the command allows it
An applet that declares a URL scheme used to run any command named in a link of the form <scheme>://exe?commandID=<id>, with the text or file context chosen by whoever wrote the link. The applet's author could not turn this off. A link on a web page or in an email could run app.will.terminate, or a dialog handler with no window to act on. AppletBuilder adds a URL scheme to every new applet, so this applied to most applets, including ones that never meant to use links.
In 5.4 the exe URL runs a command only when the command sets URL_INVOCABLE to true:
{
"NAME": "MyApp",
"COMMAND_ID": "myapp.open.item",
"URL_INVOCABLE": true
}- Application lifecycle commands, dialog event handlers and the predefined
omc.dialog.*ids are never run by a URL, whatever the key says. - Each
file=value must be the absolute path of an existing file or folder. One bad value refuses the whole URL. - A refused URL runs nothing and writes one line to the system log, starting with
OMC: URL refused, with the command id and the reason. omc.app.handle-urlneeds no key and works as before: receiving URLs is its only purpose.- Every run started by a URL exports the URL as
$OMC_TRIGGER_URL. The variable is absent in every other run, so a command that is also reachable from a menu or a button can tell the two apart and be stricter with a link, for example by asking first.
Set the key only on commands meant to be entry points, and treat $OMC_OBJ_TEXT and $OMC_OBJ_PATH as untrusted in them: the sender of the link chose both. The full rules are in the command reference under "Running a Command from a URL".
The command verifier checks the key. It reports an error when URL_INVOCABLE is set on a command a URL can never run, and warns when a command sets it but Info.plist declares no URL scheme.
Each applet is its own program to macOS
Every applet's executable is a copy of AppletBuilder's, and until now all of them carried the same Mach-O UUID. macOS identifies a program by that UUID for Local Network privacy, so the "find devices on local networks" prompt, and the row in System Settings > Privacy & Security > Local Network, named whichever applet the Mac had seen first, and one answer covered all of them.
AppletBuilder now writes a UUID derived from the bundle identifier into the executable every time it signs an applet. It is the same after every build and every engine update, so the user is not asked again. Changing the bundle identifier makes the applet a new program to macOS.
- An applet built with an earlier AppletBuilder keeps the shared UUID until it is built again.
- An applet that reaches the local network, or starts a tool that does, should also carry
NSLocalNetworkUsageDescriptionin itsInfo.plist: it is the sentence macOS shows in the prompt. create --no-codesignis now ignored. An unsigned applet does not launch on Apple silicon.
New applets no longer keep the template's URL scheme
New Applet, and a rename on the General tab, added the applet's own URL scheme next to the template's instead of replacing it, so every new applet answered two schemes, one of them shared with every other applet made from the same template. The scheme list is now replaced as a whole.
The scheme is also derived more carefully from the name: it must start with a letter, so a name starting with a digit gets an applet- prefix. A failed write to Info.plist is now reported instead of passing silently, and New Applet removes its half-made copy.
Applets created with an earlier version still list the template's scheme. Check CFBundleURLSchemes in their Info.plist and remove the extra entry.
Lists and tables keep the right row selected
- Deselecting a row in a List runs its action. A List with rows cleared its value when the user deselected the selected row but did not run its
actionID, unlike a Table. A handler that tracks the selection never heard about it, and a detail pane went on showing the deselected row. - A click selects the row it lands on. In a List with hidden rows (rows with an empty first column), a click below a hidden row selected a different row.
- Refreshing the rows keeps the selection. When a handler rewrote the rows and another column of the selected row had changed, the highlight vanished with no event. The selection now stays on its row, matched by first column, and among rows sharing a first column it stays at the same place. No action runs for this.
- A click racing a refresh no longer brings back old data. A rows update arriving between a click and its effect could write the row's previous columns back as the value. This applies to List and Table.
ActionUI windows can be minimized
Regular ActionUI windows were created without the minimize ability, so the yellow button, Window > Minimize and Cmd-M did nothing in every ActionUI applet. They work now. Blocking dialogs and floating panels still do not minimize: a hidden modal window would leave the applet stuck.
Remote images in Chat and RichText
Chat and RichText have a new "remoteImages" property that decides when http and https images in their Markdown are fetched: "automatic" (the default, as before), "on-click" (a placeholder naming the image's host until the reader clicks it) or "never". Set one of the last two for Markdown that a model or an agent wrote, because fetching an image delivers whatever its URL carries to the image's host. A misspelled value is treated as "on-click", so a typo cannot turn the protection off.
Chat also gains sessionConfig for the acp transport (options set right after the session starts), and RichText no longer leaves a placeholder when several documents show the same image at once.
Embedded Python 3.14.8
The embedded Python shipped in AppletBuilder, and copied into every new Python applet, moves from 3.14.7 to 3.14.8, with OpenSSL 3.6.5 and expat 2.8.5. Python 3.14.8 is an expedited security release. The fixes that matter to applets:
tarfile: thetaranddataextraction filters could create directories outside the destination.zipfile: a small bzip2, LZMA or Zstandard member could expand into an unbounded allocation even when read in small pieces (CVE-2026-15310).urllib: a password stored for an https URL was offered to the matching http URL (CVE-2026-15806).ssl:SSLContext.wrap_bio()completed a handshake without checking the peer's host name when none was given, and a server's SNI callback could crash the process (CVE-2026-19445).- Formatting a float with a very large precision could crash.
A few behavior changes a handler could notice:
SSLContext.wrap_bio()on a context that checks host names now raisesValueErrorwhen noserver_hostnameis passed.plistlib.dumps()withskipkeys=Trueandsort_keys=Truedrops non-string keys instead of raisingTypeError.xml.etree.ElementTreeno longer treats characters such as U+00A0 as white space.tokenizeno longer produces<>as a single token.
The lzma module is included. import lzma works, .xz data can be read and written, and zipfile and tarfile handle LZMA-compressed members. liblzma is linked statically into the module, so nothing has to be installed on the user's Mac. Earlier releases were meant to include it but did not.
The distribution no longer names the machine it was built on. Python's generated configuration files and pip's package records carried the absolute path of the build directory. They are rewritten at build time; install paths are unaffected, because Python derives them from where the interpreter is running.
An applet does not pick up a new embedded Python on an ordinary build. Turn on "Update Embedded Python" in Build & Run, or pass --update-python to appletbuilder build. Modules installed into Contents/Library/Packages survive the update; anything installed into the runtime's own site-packages does not.
AppletBuilder
- ActionUI validation no longer needs Python. AppletBuilder ships
actionui-verify, a native verifier, and uses it for the build, the UI Files Validate button andappletbuilder validate. It prints the same lines with the same exit codes as the Python verifier, which stays as the fallback. Checking a document for one platform now follows the same rules as the runtime, and an element id repeated across platform variants of the same children is no longer reported as a duplicate. - Icon-only buttons have help strings. Hover over one to see what it does.
codesign_applet.shkeeps what a nested helper needs. Signing ad hoc used to re-sign every nested binary without its entitlements, so a helper that needs one launched but failed later. Entitlements of an ad hoc signed helper are now carried over; those from a real certificate are still dropped in an ad hoc run. A loose executable also keeps the identifier it was signed with instead of getting a generated one, which keeps the privacy and keychain grants tied to that identifier. If you keep your own copy of the script beside an applet, replace it with the one inScripts/.
Compatibility notes
- Links: an applet that relied on
exe?commandID=links must addURL_INVOCABLEto each command meant to be reached that way. Nothing else about the URL format changed. - Local Network permission: after an applet is rebuilt, macOS sees a program it has not met before and may ask once more. The answer then holds across later builds.
- List
actionID: a handler now also runs when the user deselects a row, with an empty value. A handler that assumed a selection is always present should check for it. OMCTEST_API_VERSIONis unchanged at 7. Suites written for 5.3 run as they are.
In this distribution
- AppletBuilder.app - OMC applet development studio.
- OnMyCommandCM.plugin - contextual menu plugin for use with Shortcuts.app; commands load from
~/Library/Preferences/com.abracode.OnMyCommandCMPrefs.plist. - OMCService.service - macOS service template for standalone OMC-based system services.
- Skill/ - the OMC AI agent skill (three flavors) plus its installer.
- Scripts/ -
codesign_applet.sh,install_contextual_menu_plugin.sh,thin_distribution.sh,OMCApplet.entitlements, and the examplecom.abracode.OnMyCommandCMPrefs.plist.
See the main OMC README at https://github.com/abra-code/OMC/ for full documentation on commands, runtime context, dialogs, and services.