Skip to content

Browser and terminal tabs

People switch between tabs, not windows. aos window sees one Chrome window; the thing you want is the pull request in its ninth tab, or the terminal tab sitting in ~/src/aos. aos tab reaches inside the window.

  • A browser or a terminal is just a window kind: aos window list now prints browser, terminal, editor, files or other, and --kind= filters on it.
  • Each app is asked in the language it speaks: AppleScript (JXA) on macOS, UI Automation on Windows, the accessibility tree as the catch-all.
  • Apps that are not running are skipped, never launched.
Terminal window
$ aos window list --kind=terminal
* Ghostty terminal mon 2 1920x963+0+30 host.local: deemwar-one-os
Ghostty terminal mon 1 864x1084-864+33 me@host:/private/tmp
$ aos tab list --app=chrome
chrome:1658109204:1658109205 browser Example Domain https://example.com/
* chrome:1658109204:1658109210 browser Example Domains https://www.iana.org/help/example-domains
chrome:1658109204:1658109212 browser aos-bg-test data:text/html,<title>aos-bg-test</title>bg

* marks the selected tab of each window. Terminals print the folder instead of a URL, and split panes indented under their tab:

Terminal window
$ aos tab list --app=ghostty --window=tab-group-8039faee0
ghostty:tab-group-8039faee0:tab-802a71200 terminal me@host:/private/tmp /private/tmp
* ghostty:tab-group-8039faee0:tab-802a71c00 terminal me@host:/usr /usr
* ghostty:tab-group-8039faee0:tab-802a71c00:41E9EDB7-DBC0-43E6-9A86-EE7ED8CCF27F me@host:/usr /usr
ghostty:tab-group-8039faee0:tab-802a71c00:C8A30C61-013D-4EB2-A97E-2D301201105D me@host:/var /var

--json gives every field an agent needs:

Terminal window
$ aos tab list --app=ghostty --json
[
{
"id": "ghostty:tab-group-8039faee0:tab-802a71200",
"app": "Ghostty",
"kind": "terminal",
"window": "22626",
"native_window": "tab-group-8039faee0",
"index": 1,
"title": "me@host:/private/tmp",
"cwd": "/private/tmp",
"active": true,
"source": "applescript"
}
]

window is the aos window id from window list, matched by app, bounds and title. native_window is the app’s own id. Listing 63 Chrome tabs takes about 100 ms: aos reads every title and URL in one request instead of one per tab.

Name it by title, URL, folder or id. aos raises the window and selects the tab.

Terminal window
$ aos tab focus --title=aos-bg-test --app=chrome
chrome:1658109204:1658109212 aos-bg-test
$ aos tab focus --url=iana.org --app=safari
safari:22718:2 Example Domains
$ aos tab focus --cwd=/usr --app=ghostty
ghostty:tab-group-8039faee0:tab-802a73a00 me@host:/usr
$ aos tab focus --title=nomatchxyz
aos: no tab matched title="nomatchxyz"
$ echo $?
3

Matching is a case-insensitive substring; --exact wants the whole title, URL or folder. When several tabs match, the selected one wins, else the first. A pane id focuses that split.

The new tab’s id is printed, ready for focus, send or close.

Terminal window
$ aos tab open https://www.iana.org/help/example-domains --app=chrome --window=1658109204
chrome:1658109204:1658109210
$ aos tab open "data:text/html,<title>aos-bg-test</title>bg" --app=Chrome --window=1658109204 --background
chrome:1658109204:1658109212
$ aos tab open --app=ghostty --window=tab-group-8039faee0 --cwd=/usr --command="echo opened-by-aos-tab" --background
ghostty:tab-group-8039faee0:tab-802a73a00
  • --window takes an aos window id, the app’s own id, or any tab id in that window. Without it the tab goes into the front window.
  • --new-window opens a window instead.
  • --background leaves the current tab selected and the app where it was.
  • In a terminal, --command runs once and the tab stays open with your normal shell after it.

No focus needed: the terminal receives the text directly, so the person can keep working in another window.

Terminal window
$ aos tab send --id=ghostty:tab-group-8039faee0:tab-802a73a00 --text="echo sent-by-aos"
$ aos tab send --id=ghostty:tab-group-8039faee0:tab-802a73a00 --key=enter
$ aos tab send --id=iterm:22758:2 --key=ctrl+c
$ aos tab send --id=chrome:1658109204:1658109205 --text=hi
aos: Google Chrome tabs cannot receive input from aos: a browser tab has no input channel; focus it and use `aos key` / `aos type`

One tab at a time, never the whole window, and never a close that would stop on a confirmation prompt.

Terminal window
$ aos tab close --id=chrome:1658109204:1658109210
closed chrome:1658109204:1658109210 Example Domains
$ aos tab close --title=aos-bg-test --app=chrome
closed chrome:1658109204:1658109212 aos-bg-test

If the flags match more than one tab, close (and send) refuse with exit 4 and list the candidates; name one with --id or --exact. Index ids (Safari, iTerm2, Terminal) shift when an earlier tab closes, so pass --expect-title to make sure the id still points at the tab you listed:

Terminal window
$ aos tab close --id=safari:22718:2 --expect-title=Example
closed safari:22718:2 Example Domains
app list focus open send close
Chrome, Edge, Brave, Vivaldi, Chromium title, URL yes URL, new window, background no yes
Safari title, URL yes URL, new window, background no yes
Ghostty 1.3+ title, folder, panes tab and pane folder, command text, keys yes
iTerm2 title, folder, panes tab and pane folder, command text, enter, ctrl+letter yes
Terminal.app title yes new window only text (run as a command) a window’s only tab, when idle
any other app (macOS) title, from the accessibility tree yes no no cmd+w, best-effort
any app (Windows) title, from UI Automation yes Edge, Chrome, Brave, Windows Terminal no ctrl+w (browsers, Notepad), ctrl+shift+w (Windows Terminal), best-effort

Accessibility close is best-effort: aos re-checks that the tab’s window is in front immediately before pressing the shortcut, and reports success only when the tab count dropped. Apps whose shortcut it does not know are refused. On Windows no URL or folder goes through cmd.exe; --command for Windows Terminal is a shell command by design.

Linux is not supported yet; aos tab exits 2 there.

Symptom Fix
macOS blocked aos from controlling Google Chrome (Automation permission) macOS asks once per app. If it was denied, turn it on in System Settings > Privacy & Security > Automation, or run tccutil reset AppleEvents and try again to get the prompt back.
aos tab: Google Chrome: timed out on stderr The app took longer than 1.5 s to answer, usually a beachballing browser. The other apps’ tabs still print.
… is gone (list again with aos tab list) The tab or window closed since you listed it. Index ids (Safari, iTerm2, Terminal) also shift when an earlier tab closes.
A Ghostty or Terminal window’s aos id changed macOS makes each native tab its own window. Use native_window or a tab id with --window.