Skip to content

Repository files navigation

attui

attui is a keyboard-first terminal browser for navigating the accessible web. It does not rasterize HTML or implement another browser engine. It drives Chromium with Playwright, reads Chromium's accessibility tree, and maps that semantic tree into Ink primitives.

Rendering model:

Chromium accessibility tree -> roles, labels, values, state, actions
DOM flow hints               -> compact row/column presentation only
semantic renderer            -> terminal primitives
terminal geometry            -> Norigin spatial navigation
Ink                          -> terminal view and keyboard interaction

The accessibility tree is the only source of content, order, roles, names, and state. DOM/CSS access can only affect layout through flow hints; it cannot add, remove, rename, or reorder semantic nodes. A small capability channel preserves native input type where Chromium's accessibility tree does not expose it. Spatial navigation uses the rendered terminal rectangles, never browser pixels. Pages are rendered as soon as Chromium reaches domcontentloaded. A debounced live watcher then refreshes the semantic view when an SPA changes history, accessible DOM content, focus, online state, or service-worker control, without waiting for network-idle.

Install from the public repository:

git clone https://github.com/srsatt/attui.git
cd attui
npm ci
npm run build
npm link
attui browser install

On Linux, attui browser install --with-deps can also install Chromium's operating-system dependencies. npm link is optional; without it, use npm start -- https://example.com after building.

Run:

npm run dev
npm run dev -- https://example.com
npm run dev -- --profile ~/.local/share/attui/profiles/main https://app.example.com
npm start -- https://example.com

Sessions are ephemeral by default. Pass --profile <path> to preserve cookies, local storage, and other Chromium profile data for authenticated PWAs. Use --headful to show Chromium while debugging, and --width / --height to change the browser viewport. Run npm run dev -- --help for the complete CLI help. Web notifications are denied by default; --allow-notifications requests Chromium permission and surfaces page/service-worker notification events in the terminal status line.

Keys:

Enter       load the address while the address bar is focused
Enter       activate the selected primitive while the page is focused
Enter       enter edit mode for a selected text/search input
Enter       open a selected native select as a full-screen picker
l           focus the address bar
i           enter focused-control mode for the selected primitive
r           reload
u           refresh the semantic document
[ / ]       back / forward through Chromium history
Arrow keys  spatial navigation between links, buttons, and controls
Arrow keys  adjust the selected slider or numeric spinbutton
j/k         scan selection by rendered primitive row
Tab         jump to the next link, button, or control
Shift+Tab   jump to the previous link, button, or control
Space/b     move selection one page down/up
g/G         top/bottom
q           quit
Ctrl+C      quit
t           open a new tab
x / X       close the current tab / reopen the last closed tab
{ / }       previous / next tab
T           open the tab switcher
D           inspect site data and optionally clear it
/           find text in the semantic document
n / N       next / previous find match
f           open link hints
y / Y       copy selected text / current URL via OSC 52
m           add or remove a bookmark for the current page
B / H       open bookmarks / browsing history
? / :       open command help / searchable command palette
I           inspect the raw accessibility tree (semantic data only)
E           review and export a diagnostic bug bundle

Focused text/search inputs:

Typing      update the local input buffer
Enter       apply a single-line value / add a multiline newline
Ctrl+S      apply a multiline value without submitting
Ctrl+Enter  apply the value and submit its form
Esc         cancel editing without applying the buffer
Backspace   delete the last character
Ctrl+U      clear the input buffer

Focused-control mode sends a bounded set of trusted Playwright key presses to the focused web control. This supports custom ARIA comboboxes, listboxes, menus, trees, and grids while keeping ordinary terminal navigation separate.

Arrows/Home/End/PageUp/PageDown  send navigation keys to the web control
Enter/Space/Tab/Shift+Tab        send activation or focus keys
Esc                              send Escape and leave focused-control mode
Ctrl+]                           leave focused-control mode without sending a key

File inputs and downloads open a terminal path prompt. Nothing is uploaded or saved until Enter confirms the displayed path; Esc cancels, and Ctrl+U clears the path. Paths are resolved directly by Node without shell evaluation.

Chromium pages are real tabs with independent history and terminal cursor/scroll positions. The header shows the active tab index. --popup switch follows new windows, --popup background keeps them as background tabs, and --popup block closes them immediately.

Sessions without --profile are ephemeral. --private makes that intent explicit and cannot be combined with a persistent profile. The site-data view shows counts without exposing cookie values; clearing requires pressing C twice and is scoped to the active HTTP(S) origin. If Chromium has locked a persistent profile, attui reports how to close the competing session or choose a different profile path.

Camera, microphone, geolocation, clipboard, and notification API requests pause at a terminal allow/deny prompt and are granted only for the requesting origin. HTTP Basic credentials can be supplied with --http-user and --http-password-env so the password stays out of the command line. Invalid certificates remain errors unless --ignore-https-errors is explicit. Non-web schemes such as mailto: and custom application protocols are blocked and shown as errors; attui never launches an external handler automatically.

Bookmarks and deduplicated browsing history are stored atomically in $XDG_DATA_HOME/attui (or ~/.local/share/attui) and can be relocated with --data-dir. Explicit private sessions never write browsing history. Copy commands use OSC 52 and only emit a clipboard sequence when stdout is a TTY.

Terminal presentation can be tuned with --theme default|high-contrast|mono, --density comfortable|compact, and --verbosity quiet|normal|verbose. --zoom 50..300 changes the effective Chromium CSS viewport so responsive page layout follows browser-style zoom. --reduced-motion disables any optional motion (the core document renderer is already static). Accessibility text, titles, options, and saved library labels are sanitized before display; control, C1, and bidi-override characters cannot be emitted as terminal instructions. CJK and emoji geometry uses terminal cell width for navigation and mouse targeting.

Configuration is read from $XDG_CONFIG_HOME/attui/config.json (or ~/.config/attui/config.json). The JSON object accepts the long-option names in camel case plus keybindings, whose keys are terminal key names and values are stable command IDs shown by ?. Explicit CLI flags take precedence. Use --config <path> for another file or --no-config to ignore configuration.

Diagnostics are opt-in. attui doctor checks Node, Chromium, writable data and profile paths, profile locks, and terminal capabilities. --log-file <path> writes JSONL lifecycle events with credentials, secret-shaped fields, URL queries, and fragments redacted. --trace-dir <path> captures a Playwright trace; traces can contain page content and should be shared only after manual review. E shows the exact privacy boundary before writing a mode-0600 JSON bug bundle: it excludes cookies, storage, credentials, profile paths, URL paths, queries, and fragments, but includes visible accessibility text, page titles, origins, and runtime metadata. Shell definitions are emitted by attui completions bash|fish|zsh.

Select picker mode:

Enter       choose the selected option
Esc/q       close the picker
Arrow/j/k   move between options
Space/b     move ten options down/up
g/G         first/last option

Current primitive coverage includes pages, header/nav/sidebar/footer/main landmarks, headings, wrapped text, horizontal link/control rows, buttons, text/search inputs, checkboxes, radios, switches, select-like comboboxes, options, menus, tabs, sliders, progress/status nodes, images, lists, and tables. Links and clickable controls are activated through the backing DOM node exposed by Chromium's accessibility tree.

Editable native inputs retain their browser type. Date, time, month, week, datetime, color, number, email, URL, telephone, password, and search values are applied through Chromium and emit the page's normal input and change events. Required, read-only, disabled, and invalid states are shown alongside controls; validation descriptions, alerts, status messages, and ARIA live-region updates remain visible in the semantic document.

Development checks:

npm test              # unit tests plus deterministic Chromium fixtures
npm run typecheck
npm run build

Supported targets are Linux and macOS on Node.js 22 or 24. Dependency versions and the Playwright-compatible Chromium revision are pinned; see docs/RELEASING.md for upgrade and version policy and docs/SECURITY.md for the threat/privacy review. The current version is pre-release software; compatibility evidence and known limitations are tracked in docs/COMPATIBILITY.md.

About

A11y-tree based TUI browser

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages