{"id":1368,"date":"2026-02-04T13:44:25","date_gmt":"2026-02-04T20:44:25","guid":{"rendered":"https:\/\/markalldritt.com\/?p=1368"},"modified":"2026-02-16T12:51:51","modified_gmt":"2026-02-16T19:51:51","slug":"aequery","status":"publish","type":"post","link":"https:\/\/markalldritt.com\/?p=1368","title":{"rendered":"AEQuery"},"content":{"rendered":"\n<h1>AEQuery<\/h1>\n\n\n\n<p>I\u2019ve released a new command-line tool called AEQuery. It queries scriptable macOS applications using XPath-like expressions, translating them directly into Apple Events.<\/p>\n\n\n\n<p>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.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>brew tap alldritt\/tools\nbrew install aequery<\/code><\/pre>\n\n\n\n<h2>Why<\/h2>\n\n\n\n<p>AppleScript is powerful but verbose. Getting the names of your Finder windows requires a <code>tell<\/code> block and a fair amount of ceremony. I wanted something I could fire off from the terminal, pipe into <code>jq<\/code>, and integrate into shell scripts without the overhead.<\/p>\n\n\n\n<h2>What it looks like<\/h2>\n\n\n\n<p>Get the names of all Finder windows:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aequery '\/Finder\/windows\/name'\n# &#91;\"AICanvas\", \"Documents\"]<\/code><\/pre>\n\n\n\n<p>Pull every unique email address out of Contacts:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aequery '\/Contacts\/people\/emails\/value' --flatten --unique<\/code><\/pre>\n\n\n\n<p>Find Mail messages from a specific sender:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aequery '\/Mail\/account\/mailboxes\/message&#91;sender = \"someone@example.com\"]\/subject' --flatten<\/code><\/pre>\n\n\n\n<p>The expression syntax supports index access (<code>[1]<\/code>, <code>[-1]<\/code>), named lookups (<code>[@name=\"Desktop\"]<\/code>), whose-clause filtering with <code>and<\/code>\/<code>or<\/code>, range slicing, and special selectors like <code>middle<\/code> and <code>some<\/code>.<\/p>\n\n\n\n<h2>Worth highlighting<\/h2>\n\n\n\n<p><code>--sdef<\/code> prints the SDEF definition for whatever class or property your path resolves to. It\u2019s a fast way to explore an app\u2019s scripting dictionary from the terminal.<\/p>\n\n\n\n<p><code>--find-paths<\/code> discovers all valid paths from the application root to a given class or property. If you know you want <code>name<\/code> but you\u2019re not sure where it lives in Finder\u2019s object model, this will map it out:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aequery --find-paths '\/Finder\/name'\n# \/Finder\/name\n# \/Finder\/files\/name\n# \/Finder\/windows\/name\n# ...<\/code><\/pre>\n\n\n\n<p><code>--applescript<\/code> and <code>--chevron<\/code> translate your expression back into AppleScript source \u2014 useful when you want to start from a working query and build a larger script around it.<\/p>\n\n\n\n<p>Default output is JSON, so AEQuery slots into pipelines with <code>jq<\/code> or anything else that speaks JSON.<\/p>\n\n\n\n<h2>Source<\/h2>\n\n\n\n<p>The code is on <a href=\"https:\/\/github.com\/alldritt\/aequery\">GitHub<\/a>. There\u2019s also a discussion thread on <a href=\"https:\/\/www.macscripter.net\/t\/aequery-a-command-line-tool-for-querying-scriptable-applications-using-an-xpath-like-expressions\/77708\">MacScripter<\/a> if you\u2019ve got questions or feedback.<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>AEQuery I\u2019ve 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&#8230;<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/markalldritt.com\/?p=1368\">Continue Reading<span class=\"screen-reader-text\">AEQuery<\/span><\/a><\/div><\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[5,6,15],"tags":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/s7AQk-aequery","_links":{"self":[{"href":"https:\/\/markalldritt.com\/index.php?rest_route=\/wp\/v2\/posts\/1368"}],"collection":[{"href":"https:\/\/markalldritt.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/markalldritt.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/markalldritt.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/markalldritt.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1368"}],"version-history":[{"count":2,"href":"https:\/\/markalldritt.com\/index.php?rest_route=\/wp\/v2\/posts\/1368\/revisions"}],"predecessor-version":[{"id":1370,"href":"https:\/\/markalldritt.com\/index.php?rest_route=\/wp\/v2\/posts\/1368\/revisions\/1370"}],"wp:attachment":[{"href":"https:\/\/markalldritt.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1368"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/markalldritt.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1368"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/markalldritt.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1368"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}