AEQuery
I’ve released a new command-line tool called AEQuery. It queries scriptable macOS applications using XPath-like expressions, translating them directly into Apple Events.
The short version: you describe what you want using a slash-delimited path, and AEQuery resolves the SDEF terminology, constructs the Apple Events, and returns the results as JSON.
brew tap alldritt/tools
brew install aequery
Why
AppleScript is powerful but verbose. Getting the names of your Finder windows requires a tell block and a fair amount of ceremony. I wanted something I could fire off from the terminal, pipe into jq, and integrate into shell scripts without the overhead.
What it looks like
Get the names of all Finder windows:
aequery '/Finder/windows/name'
# ["AICanvas", "Documents"]
Pull every unique email address out of Contacts:
aequery '/Contacts/people/emails/value' --flatten --unique
Find Mail messages from a specific sender:
aequery '/Mail/account/mailboxes/message[sender = "someone@example.com"]/subject' --flatten
The expression syntax supports index access ([1], [-1]), named lookups ([@name="Desktop"]), whose-clause filtering with and/or, range slicing, and special selectors like middle and some.
Worth highlighting
--sdef prints the SDEF definition for whatever class or property your path resolves to. It’s a fast way to explore an app’s scripting dictionary from the terminal.
--find-paths discovers all valid paths from the application root to a given class or property. If you know you want name but you’re not sure where it lives in Finder’s object model, this will map it out:
aequery --find-paths '/Finder/name'
# /Finder/name
# /Finder/files/name
# /Finder/windows/name
# ...
--applescript and --chevron translate your expression back into AppleScript source — useful when you want to start from a working query and build a larger script around it.
Default output is JSON, so AEQuery slots into pipelines with jq or anything else that speaks JSON.
Source
The code is on GitHub. There’s also a discussion thread on MacScripter if you’ve got questions or feedback.