mac-browser
Control the user's running browser on macOS via AppleScript. Supports Microsoft Edge, Google Chrome, and Safari. Reuses existing sessions, cookies, and login state — no restart or special flags needed. Use this skill whenever the user asks you to read, check, or extract content from their browser — especially for authenticated pages (private GitHub repos, Google Docs, internal tools, Notion, etc.), checking what tabs are currently open, navigating to a URL in their browser, or running JavaScript on a page. Triggers include "read this page in my browser", "what tabs do I have open", "get content from the page I have open", "use my browser session", "access this private URL", "open this in my browser", "check my browser".
mac-browser
Control the user's running browser on macOS via AppleScript. Supports Microsoft Edge, Google Chrome, and Safari. Reuses existing login sessions and cookies — no remote debugging port required.
Prerequisites
- macOS only
- A supported browser must be running (Edge, Chrome, or Safari)
- Enable Allow JavaScript from Apple Events in the browser:
- Edge: View → Developer → Allow JavaScript from Apple Events
- Chrome: View → Developer → Allow JavaScript from Apple Events
- Safari: Develop → Allow JavaScript from Apple Events (enable Develop menu first: Settings → Advanced → Show Develop menu)
Browser Selection
Scripts auto-detect the running browser (priority: Edge → Chrome → Safari).
find-tab.sh, eval-js.sh, and get-text.sh search across all running browsers to find the right tab automatically.
Override with the MAC_BROWSER env var:
MAC_BROWSER=chrome ./scripts/find-tab.sh "github.com"
MAC_BROWSER=safari ./scripts/get-text.sh "example.com"
Common Workflows
Read content from a tab that's already open:
SKILL_DIR="/path/to/mac-browser"
bash "$SKILL_DIR/scripts/get-text.sh" "docs.google.com"
Open a new URL and read it:
# navigate.sh waits ~1.5s internally for redirects to settle, then returns the actual landed URL
# Output format: <browser> <window> <tab> <url>
RESULT=$(bash "$SKILL_DIR/scripts/navigate.sh" "https://example.com")
OPENED_URL=$(echo "$RESULT" | cut -d' ' -f4-)
sleep 1 # allow additional time for page content to fully load
bash "$SKILL_DIR/scripts/get-text.sh" "$OPENED_URL"
If the tab is not found, navigate first:
# Capture find-tab.sh output; if not found, navigate and use its output instead
FOUND=$(bash "$SKILL_DIR/scripts/find-tab.sh" "example.com") || {
RESULT=$(bash "$SKILL_DIR/scripts/navigate.sh" "https://example.com")
sleep 1
FOUND="$RESULT"
}
bash "$SKILL_DIR/scripts/get-text.sh" "$(echo "$FOUND" | cut -d' ' -f4-)"
Script paths: All
./scripts/references below are relative to this skill's directory. Always use the absolute path when calling scripts from the terminal (e.g.bash /path/to/mac-browser/scripts/list-tabs.sh).
List All Tabs
./scripts/list-tabs.sh
Lists all open tabs across all running browsers: <browser> <window_num> <tab_num> <url>
Find a Tab
./scripts/find-tab.sh "lists.apache.org"
Returns browser window_num tab_num url for the first tab whose URL matches the pattern. Exits with code 1 if not found.
Evaluate JavaScript
./scripts/eval-js.sh "lists.apache.org" 'document.title'
./scripts/eval-js.sh "github.com" '(() => { return document.querySelectorAll("a").length })()'
Execute JavaScript in the tab matching the URL pattern. Uses a temp file to safely pass arbitrary JS without quoting issues.
IMPORTANT: Code must be a single expression or IIFE for multiple statements.
Get Page Text
./scripts/get-text.sh "lists.apache.org"
./scripts/get-text.sh "lists.apache.org" 5000 # limit to 5000 chars
Convenience wrapper: finds the tab and returns document.body.innerText.
Navigate (Open New Tab)
./scripts/navigate.sh "https://example.com"
Opens a new tab and navigates to the URL. Focus is automatically restored to your current app afterwards.
Output format: <browser> <window> <tab> <url> — same as find-tab.sh. Capture this to get the exact tab coordinates for subsequent calls.
Screenshot
./scripts/screenshot.sh
./scripts/screenshot.sh "/tmp/my-screenshot.png"
Takes a screenshot of the browser window. Returns the file path.
⚠️ IMPORTANT — Before calling screenshot.sh, always use ask_user to confirm with the user:
The browser window needs to be briefly activated (brought to front) to take a screenshot. Focus will be restored to your current app automatically afterwards. Please avoid switching apps during this time — continue?
Only proceed if the user confirms. If they decline, skip the screenshot.
Known Limitations & Workarounds
Google Docs (and other canvas-rendered pages)
get-text.sh uses document.body.innerText, which returns only UI chrome for Google Docs — the document content is rendered as canvas/SVG, not DOM text nodes.
Workaround: Access the mobilebasic version, which serves a simple HTML rendering:
# Replace {DOC_ID} with the document ID from the URL
RESULT=$(bash "$SKILL_DIR/scripts/navigate.sh" "https://docs.google.com/document/d/{DOC_ID}/mobilebasic")
OPENED_URL=$(echo "$RESULT" | cut -d' ' -f4-)
sleep 1
bash "$SKILL_DIR/scripts/get-text.sh" "$OPENED_URL"
The mobilebasic URL works with the user's existing login session — no sharing settings need to change. Google Sheets has a similar limitation; use export?format=csv or gviz/tq endpoints instead.
Note: Google services redirect URLs by inserting an account prefix (e.g.
/document/d/→/document/u/2/d/).navigate.shhandles this automatically and returns the actual landed URL. If you need a fallback pattern, the document ID (the long hash in the URL) is stable across redirects and safe to use as aget-text.shpattern.
URL Pattern Specificity
find-tab.sh and get-text.sh return the first tab matching the pattern. When multiple similar tabs are open, use a specific URL segment to avoid false matches:
# Too broad — may hit the wrong tab if multiple Docs are open
bash "$SKILL_DIR/scripts/get-text.sh" "docs.google.com"
# Specific — targets only this document
bash "$SKILL_DIR/scripts/get-text.sh" "docs.google.com/document/d/1abc123"
After navigate.sh, always use the URL from its output as the pattern rather than guessing a broad domain.
Usage Notes
- Works with the user's existing browser session — all cookies and logins are available
- No need to restart the browser or set any flags
- Edge/Chrome stay in the background during JS execution — only the active tab within the target window is briefly switched, then automatically restored
- Safari executes JS directly in any tab by index without switching active tabs at all
- If
eval-js.shreturns an error about JavaScript from Apple Events being disabled, remind the user to enable it (see Prerequisites) - For complex JS, prefer IIFE syntax:
'(() => { ... return result; })()'