ワンクリックで
safari
Navigate, search, click links, read content, and manage tabs in Safari
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Navigate, search, click links, read content, and manage tabs in Safari
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
AX-first automation for Logic Pro — transport, tracks, tempo, mixer, and view controls
Browse conversations, read messages, and send texts in Apple Messages
Minimal Calendar automation using EventKit with optional Shortcuts integration
Search and create contacts via CNContact, with AppleScript/Shortcuts helpers
Automate Apple Mail using AX for UI interactions and AppleScript for draft/message data flows
AX-first automation for Apple Maps search and result interactions
| name | safari |
| description | Navigate, search, click links, read content, and manage tabs in Safari |
Always connect with: connect_app({ name: "Safari" })
Safari's AX tree has two main areas:
web_area element containing the page's DOM-like accessibility tree (headings, links, groups, text, lists, tables, etc.)Navigate to a URL — fill on the address bar sets the AX value but does NOT trigger navigation. Use open via shell instead:
open -a Safari "https://example.com"
Or with the macbeth SDK:
import { execSync } from "node:child_process";
execSync('open -a Safari "https://example.com"');
Read current URL:
{ "query": [
{ "role": "window" },
{ "role": "toolbar" },
{ "role": "text_field", "identifier": "WEB_BROWSER_ADDRESS_AND_SEARCH_FIELD" }
]}
The value field contains the current URL.
Back / Forward: Click the toolbar buttons:
{ "query": [{ "role": "window" }, { "role": "toolbar" }, { "role": "button", "identifier": "BackButton" }] }
{ "query": [{ "role": "window" }, { "role": "toolbar" }, { "role": "button", "identifier": "ForwardButton" }] }
Reload: select_menu_item({ app: "Safari", menuPath: ["View", "Reload Page"] }) or click ReloadButton
| Element | Query |
|---|---|
| Address bar | [{ "role": "window" }, { "role": "toolbar" }, { "role": "text_field", "identifier": "WEB_BROWSER_ADDRESS_AND_SEARCH_FIELD" }] |
| Back | [{ "role": "window" }, { "role": "toolbar" }, { "role": "button", "identifier": "BackButton" }] |
| Forward | [{ "role": "window" }, { "role": "toolbar" }, { "role": "button", "identifier": "ForwardButton" }] |
| Reload | [{ "role": "window" }, { "role": "toolbar" }, { "role": "button", "identifier": "ReloadButton" }] |
| New Tab | [{ "role": "window" }, { "role": "toolbar" }, { "role": "button", "identifier": "NewTabButton" }] |
| Share | [{ "role": "window" }, { "role": "toolbar" }, { "role": "button", "identifier": "ShareButton" }] |
| Sidebar | [{ "role": "window" }, { "role": "toolbar" }, { "role": "button", "identifier": "SidebarButton" }] |
| Tab Overview | [{ "role": "window" }, { "role": "toolbar" }, { "role": "button", "identifier": "TabOverviewButton" }] |
Queries use recursive descent — you don't need to specify every intermediate container. Just scope to web_area and target the element directly:
[{ "role": "window" }, { "role": "web_area" }, { "role": "link", "title": "Sign in" }][{ "role": "window" }, { "role": "web_area" }, { "role": "link", "titlePattern": "Learn.*more" }][{ "role": "window" }, { "role": "web_area" }, { "role": "heading", "title": "Example Domain" }][{ "role": "window" }, { "role": "web_area" }, { "role": "text_field" }][{ "role": "window" }, { "role": "web_area" }, { "role": "button", "title": "Submit" }]Use index to disambiguate when multiple elements match:
[{ "role": "window" }, { "role": "web_area" }, { "role": "link", "titlePattern": "comments", "index": 2 }]
Tabs are radio elements inside an opaqueprovidergroup (TabBar):
[{ "role": "window" }, { "role": "opaqueprovidergroup" }, { "role": "radio", "title": "Example Domain" }]
value: "1", inactive tabs have value: "0"Use select_menu_item instead of press_key — it doesn't steal focus.
| Action | Menu path |
|---|---|
| New tab | ["File", "New Tab"] |
| Close tab | ["File", "Close Tab"] |
| New window | ["File", "New Window"] |
| New private window | ["File", "New Private Window"] |
| Find on page | ["Edit", "Find", "Find…"] |
| Back | ["History", "Back"] |
| Forward | ["History", "Forward"] |
| Reopen closed tab | ["History", "Reopen Last Closed Tab"] |
| Show all history | ["History", "Show All History"] |
| Reload | ["View", "Reload Page"] |
| Zoom in | ["View", "Zoom In"] |
| Zoom out | ["View", "Zoom Out"] |
| Actual size | ["View", "Actual Size"] |
| Next tab | ["Window", "Show Next Tab"] |
| Previous tab | ["Window", "Show Previous Tab"] |
AXPress. Use fill to set its value, or open -a Safari <url> to navigate.open -a Safari <url> instead.maxDepth: 4-5 to keep output manageable. For the web content area specifically, the DOM adds several levels of nesting.wait_for on a known page element to confirm the page has loaded before interacting.open -a Safari "https://example.com" (shell)wait_for a known element on the target pagequery_tree with maxDepth: 6-8 to see the page structureget_element to read specific text valuesquery_tree to find form fieldsfill each text field (web form fields DO support fill, unlike the address bar)click the submit button[{ "role": "window" }, { "role": "opaqueprovidergroup" }, { "role": "radio", "title": "Tab Title" }]select_menu_item({ app: "Safari", menuPath: ["Window", "Show Next Tab"] })