DOMShell
| |
___|_|___
|___|_|___|
| | | |
|___|_|___|
/ | | \
/ | | \
|____|_|____|
| |
| DOMSHELL |
| |
|___________|
|###########|
|###########|
\#########/
\_______/
██ ██ ██ ███████
██ ██ ██ ███
███████ ██ ██
██░░░██ ██ ██
██ ██ ██ ██
░░ ░░ ░░ ░░
███████ ██ ██ ███████
███ ███████ ██░░░░░
███ ██░░░██ █████
███ ██ ██ ██░░░
███ ██ ██ ███████
░░░ ░░ ░░ ░░░░░░░
██████ ██████ ███ ███ ██
██ ██ ██ ██ ████ ████ ██
██ ██ ██ ██ ██ ████ ██ ██
██ ██ ██ ██ ██ ██ ██ ░░
██████ ██████ ██ ██ ██
░░░░░░ ░░░░░░ ░░ ░░ ░░The browser is your filesystem. A Chrome Extension that lets AI agents (and humans) browse the web using standard Linux commands — ls, cd, cat, grep, click — via a terminal in the Chrome Side Panel.
Install from Chrome Web Store | npm package | Read the blog post | Project home
DOMShell maps the browser into a virtual filesystem. Windows and tabs become top-level directories (~). Each tab's Accessibility Tree becomes a nested filesystem where container elements are directories and buttons, links, and inputs are files. Navigate Chrome the same way you'd navigate /usr/local/bin.
Why
AI agents that interact with websites typically rely on screenshots, pixel coordinates, or brittle CSS selectors. DOMShell takes a different approach: it exposes the browser's own Accessibility Tree as a familiar filesystem metaphor.
This means an agent can:
- Browse tabs with
ls ~/tabs/and switch withcd ~/tabs/123instead of guessing which tab is active - Explore a page with
lsandtreeinstead of parsing screenshots - Navigate into sections with
cd navigation/instead of guessing coordinates - Act on elements with
click submit_btninstead of fragile DOM queries - Read content with
cator bulk-extract withtextinstead of scraping innerHTML - Search for elements with
find --type comboboxinstead of writing selectors
The filesystem abstraction is deterministic, semantic, and works on any website — no site-specific adapters needed.
Installation
Chrome Web Store (Recommended)
Install DOMShell directly from the Chrome Web Store. No build step required.
From Source
git clone https://github.com/apireno/DOMShell.git
cd DOMShell
npm install
npm run buildLoad into Chrome
- Open
chrome://extensions/ - Enable Developer mode (toggle in top right)
- Click Load unpacked
- Select the
dist/folder - Click the DOMShell icon in your toolbar — the side panel opens
Usage
Getting Started
Open any webpage, then open the DOMShell side panel. You'll see a terminal:
╔══════════════════════════════════════╗
║ DOMShell v1.1.0 ║
║ The browser is your filesystem. ║
╚══════════════════════════════════════╝
Type 'help' to see available commands.
Type 'tabs' to see open browser tabs, then 'cd tabs/<id>' to enter one.
dom@shell:~$You start at ~ (the browser root). Jump straight to the active tab with here, or explore:
dom@shell:~$ ls
windows/ (2 windows)
tabs/ (5 tabs)
dom@shell:~$ here
✓ Entered tab 123
Title: Google
URL: https://google.com
AX Nodes: 247Browsing Tabs and Windows
# List all open tabs
dom@shell:~$ tabs
ID TITLE URL WIN
123 Google google.com 1
124 GitHub - apireno github.com/apireno 1
125 Wikipedia en.wikipedia.org 2
# Switch to a tab by ID
dom@shell:~$ cd tabs/125
✓ Entered tab 125
Title: Wikipedia
URL: https://en.wikipedia.org
AX Nodes: 312
# You're now inside the tab's DOM tree
dom@shell:~$ pwd
~/tabs/125
# Go back to browser level
dom@shell:~$ cd ~
dom@shell:~$
# Or use substring matching
dom@shell:~$ cd tabs/github
✓ Entered tab 124 (GitHub - apireno)
# List windows (shows tabs grouped under each window)
dom@shell:~$ windows
Window 1 (focused)
├── *123 Google google.com
├── 124 GitHub - apireno github.com/apireno
└── 125 Wikipedia en.wikipedia.org
Window 2
├── *126 Stack Overflow stackoverflow.com
└── 127 MDN Web Docs developer.mozilla.org
# Browse a specific window's tabs
dom@shell:~$ cd windows/2
dom@shell:~/windows/2$ ls
ID TITLE URL
125 Wikipedia en.wikipedia.org
126 LinkedIn linkedin.comYou can also navigate or open new tabs:
# Navigate the current tab to a URL (requires being inside a tab)
dom@shell:~$ navigate https://example.com
# Open a URL in a new tab (works from anywhere)
dom@shell:~$ open https://github.com
✓ Opened new tab
URL: https://github.com
Title: GitHub
AX Nodes: 412Tab Groups (isolation)
By default DOMShell operates on your general browser — shared mode, exactly as before. The group command puts a session in its own isolated Chrome tab group, so the agent works in a clearly-marked lane while you keep browsing freely in other tabs:
# Create an isolated tab group and work inside it
dom@shell:~$ group new research
✓ Created isolated group '🐚 research' [id 4]
Working tab: 312
# While isolated, every command is confined to the group's tabs —
# entering a tab outside the group is rejected:
dom@shell:~$ cd tabs/126
cd: tab 126 is outside the session group (id 4). ...
# Show the current mode and group
dom@shell:~$ group
Group mode: isolated
Group: 🐚 research [id 4]
Tabs: 1
# Leave the group (it stays open) — back to shared mode
dom@shell:~$ group detach
# Close the group's DOMShell tabs (your own tabs are kept)
dom@shell:~$ group closeSubcommands: group (status), group new [name], group attach <id>, group detach, group close, group list. Isolated mode keeps the agent out of your other tabs; shared mode is the default and unchanged.
When an MCP client connects, DOMShell automatically gives that session its own fresh 🐚 agent group. The group is left open when the session disconnects (non-destructive) — the agent is instructed to ask whether you'd like it closed before it wraps up, and you can always clear leftovers yourself with group close.
Multi-session. Every DOMShell client gets its own session lane — each side-panel window, each MCP connection, separately isolated. Two side panels in two Chrome windows hold independent positions; multiple concurrent MCP agents each work in their own 🐚 agent group with their own cursor. Run group list anytime to see every active lane; group close <id> to close one.
Multiple agents on one MCP connection. Some MCP clients (e.g. Claude Desktop) share one connection across every chat — so by default two chats in the same client would land in one lane. Each chat can carve out its own lane by passing the group_id parameter to domshell_execute: pass "new" to create a fresh one (its id is returned at the end of the reply as [lane: <id>]), then pass that id on every later call. Two chats → two lanes → no collision. Agents can also use this for handoff — one agent reports its lane id, the next agent passes it as group_id and continues in the same state. Agents are instructed to close any lane they created when the task is done.
Navigating the DOM
Once you're inside a tab, the Accessibility Tree appears as a filesystem:
# List children of the current node
dom@shell:~$ ls
navigation/
main/
complementary/
contentinfo/
skip_to_content_link
logo_link
# Long format shows type prefixes and roles
dom@shell:~$ ls -l
[d] navigation navigation/
[d] main main/
[x] link skip_to_content_link
[x] link logo_link
# Filter by type
dom@shell:~$ ls --type link
skip_to_content_link
logo_link
# Show DOM metadata (href, src, id) inline — great for finding URLs
dom@shell:~$ ls --meta --type link
[x] link skip_to_content_link href=https://example.com/#content <a>
[x] link logo_link href=https://example.com/ <a>
# Paginate large directories
dom@shell:~$ ls -n 10 # First 10 items
dom@shell:~$ ls -n 10 --offset 10 # Items 11-20
# Count children by type
dom@shell:~$ ls --count
45 total (12 [d], 28 [x], 5 [-])
# Enter a directory (container element)
dom@shell:~$ cd navigation
# See where you are
dom@shell:~$ pwd
~/tabs/125/navigation
# Go back up
dom@shell:~$ cd ..
# Jump to browser root
dom@shell:~$ cd ~
# Multi-level paths work too
dom@shell:~$ cd main/article/form
# Path variable: %here% expands to the focused tab (via its window)
dom@shell:~$ cd %here% # Enter the active tab
dom@shell:~$ cd %here%/.. # Go to the window containing the active tab
dom@shell:~$ cd %here%/main # Enter the active tab and cd into mainType Prefixes
Every node has a type prefix that communicates metadata without relying on color alone:
| Prefix | Meaning | Examples |
|---|---|---|
[d] | Directory (container, cd-able) | navigation/, form/, main/ |
[x] | Interactive (clickable/focusable) | buttons, links, inputs, checkboxes |
[-] | Static (read-only) | headings, images, text |
Reading Content
# Inspect an element — cat shows full AX + DOM metadata
dom@shell:~$ cat submit_btn
--- submit_btn ---
Role: button
Type: [x] interactive
AXID: 42
DOM: backend#187
Tag: <button>
ID: submit-form
Class: btn btn-primary
Text: Submit Form
HTML: <button id="submit-form" class="btn btn-primary">Submit Form</button>
# cat on a link reveals the href URL
dom@shell:~$ cat Read_more
--- Read_more ---
Role: link
Type: [x] interactive
AXID: 98
DOM: backend#312
Tag: <a>
URL: https://en.wikipedia.org/wiki/Article_Title
Text: Read more
HTML: <a href="https://en.wikipedia.org/wiki/Article_Title">Read more</a>
# Navigate to parent to find its properties (e.g. span inside a link)
dom@shell:~$ cd ..
dom@shell:~$ cat parent_link
# Bulk extract ALL text from a section (one call instead of 50+ cat calls)
dom@shell:/main$ text
[textContent of /main — 4,821 chars]
Heading: Welcome to Our Site
Today we announce the launch of our new product...
(full article text continues)
# Extract text from a specific child
dom@shell:~$text main
[textContent of main — 4,821 chars]
# Limit output length
dom@shell:~$text main -n 500
# Include link URLs inline as markdown [text](url)
dom@shell:~$text --links main/article/paragraph_2978
--- Text (with links): paragraph_2978 ---
Artificial intelligence (AI) is the capability of [computational systems](https://en.wikipedia.org/wiki/Computer)
to perform tasks typically associated with [human intelligence](https://en.wikipedia.org/wiki/Human_intelligence),
such as [learning](https://en.wikipedia.org/wiki/Learning), [reasoning](https://en.wikipedia.org/wiki/Reason)...
(text + link URLs in a single call)
# Get a tree view (default depth: 2)
dom@shell:~$tree
navigation/
├── [x] home_link
├── [x] about_link
├── [x] products_link
└── [x] contact_link
# Deeper tree
dom@shell:~$tree 4Searching
# Search current directory
dom@shell:~$grep login
[x] login_btn (button)
[d] login_form (form)
[x] login_link (link)
# Recursive search across all descendants
dom@shell:~$grep -r search
[x] search_search (combobox)
[x] search_btn (button)
# Limit results
dom@shell:~$grep -r -n
…