DOMShell
MCP serverFiles & storagedomshell lets your AI control Chrome using simple filesystem-style commands like ls, cd, grep, click, and type. Once added, your AI can browse web pages, find information on them, and interact with elements as if the browser were a folder of files. It works across multiple agents at once.
Unavailable. This server has no hosted endpoint yet, so Ahel can't serve it.
Add to setup to save this item as a reference. Ahel cannot run it, and signing in will not install it.
What your AI can do with it
- List and navigate page elements with ls and cd
- Search page content with grep
- Click buttons and links
- Type into forms and fields
- Run multiple agents in the same browser session
Getting started
- Save this item in Your setup as a reference.
- Read the source or reference documentation for its setup requirements. Saving it here does not connect it to your AI.
- Check this page for availability before trying to install it through Ahel.
From the project's README
As published by apireno/domshell in README.md.
| |
___|_|___
|___|_|___|
| | | |
|___|_|___|
/ | | \
/ | | \
|____|_|____|
| |
| 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 build
Load 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: 247
Browsing 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.com
You 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: 412
Tab 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 close
Subcommands: 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 main
Type 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 4
Searching
# 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 5 link
# Deep search with full paths (like Unix find)
dom@shell:~$find search
[x] /search_2/search_search (combobox)
[x] /search_2/search_btn (button)
# Find by role type
dom@shell:~$find --type combobox
[x] /search_2/search_search (combobox)
dom@shell:~$find --type textbox
[x] /main/form/email_input (textbox)
[x] /main/form/name_input (textbox)
# Limit results
dom@shell:~$find --type link -n 5
# Find all links with their URLs (great for content extraction)
dom@shell:~$find --type link --meta
[x] /nav/home_link (link) href=https://example.com/ <a>
[x] /main/Read_more (link) href=https://example.com/article <a>
Command Chaining (Bash-Style Composition)
DOMShell works like a filesystem — use the same mental model as searching files on disk. grep discovers where content lives (like grep -r in bash), cd scopes your context, and text/cat/find reads content (like cat/head/less). The pipe operator (|) filters output, just like bash.
The pattern is: grep (locate) → cd (scope) → extract (read).
# Workflow 1: Find and read an article section
dom@shell:~$ grep -r article
[d] article (article) → ./main/article/
dom@shell:~$ cd main/article
dom@shell:~/main/article$ text
[full article content in one call]
# Workflow 2: Find a section and extract its links
dom@shell:~$ grep -r references
[d] references (region) → ./main/article/references/
dom@shell:~$ cd main/article/references
dom@shell:~/main/article/references$ find --type link --meta
[x] /wiki_link (link) href=https://en.wikipedia.org/... <a>
[x] /paper_link (link) href=https://arxiv.org/... <a>
# Workflow 3: Find a table and extract structured data
dom@shell:~$ grep -r table
[d] table_4091 (table) → ./main/section/table_4091/
dom@shell:~$ extract_table table_4091
| Name | Value | Date |
|--------|--------|------------|
| Alpha | 42 | 2025-01-15 |
| Beta | 87 | 2025-02-20 |
# Workflow 4: Discover sections, then drill into one
dom@shell:~$ grep -r heading
[−] Introduction_heading (heading) → ./main/article/Introduction_heading
[−] Methods_heading (heading) → ./main/article/Methods_heading
[−] Results_heading (heading) → ./main/article/Results_heading
dom@shell:~$ cd main/article/Results_heading
dom@shell:~/main/article/Results_heading$ text
[text content of the Results section]
# Workflow 5: Find elements by visible text (not just name)
dom@shell:~$ grep -r --content "sign up"
[x] get_started_btn (button) → ./main/hero/get_started_btn
# The button's NAME is "get_started_btn" but its displayed text says "Sign Up Free"
dom@shell:~$ click get_started_btn
Pipe Operator
The pipe operator (|) lets you filter command output, just like bash:
# Filter find results to only GitHub links
dom@shell:~$ find --type link --meta | grep github
[x] /main/repo_link (link) href=https://github.com/example <a>
# Filter ls output to elements mentioning "login"
dom@shell:~$ ls --text | grep login
[x] login_btn "Log in to your account"
# Limit results with head
dom@shell:~$ find --type heading | head -n 3
[−] /main/intro_heading (heading)
[−] /main/features_heading (heading)
[−] /main/pricing_heading (heading)
# Chain multiple pipes
dom@shell:~$ find --type link --meta | grep docs | head -n 5
Path Resolution
All commands accept relative paths, eliminating the need to cd first:
# Read text from a nested element directly
dom@shell:~$ text main/article/paragraph_2971
# Click a button inside a form without cd'ing
dom@shell:~$ click main/form/submit_btn
# Inspect a link in the nav
dom@shell:~$ cat navigation/home_link
Sibling Navigation
Use --after and --before flags on ls to find content relative to a landmark:
# Show the 3 elements after a heading
dom@shell:~$ ls --after See_also_heading -n 3 --text
[d] related_topics_list "Machine Learning, Deep Learning, Neural..."
[−] paragraph_4512 "For more information on these topics..."
[x] Read_more_link "Read more on Wikipedia"
# Find links after a specific section heading
dom@shell:~$ ls --after References_heading --type link --meta
[x] source_1_link (link) href=https://arxiv.org/... <a>
[x] source_2_link (link) href=https://doi.org/... <a>
The key insight: grep output feeds cd, and cd scopes everything else. When you don't know where content lives on a page, always grep first, then scope, then extract.
Interacting with Elements
# Click a button or link
dom@shell:~$click submit_btn
✓ Clicked: submit_btn (button)
(tree will auto-refresh on next command)
# Focus an input field
dom@shell:~$focus email_input
✓ Focused: email_input
# Type into the focused field
dom@shell:~$type hello@example.com
✓ Typed 17 characters
# Navigate to a URL (current tab)
dom@shell:~$navigate https://example.com
✓ Navigated to https://example.com
# Open a URL in a new tab
dom@shell:~$open https://github.com
✓ Opened new tab → https://github.com
Auto-Refresh on DOM Changes
DOMShell automatically detects when the page changes — navigation, DOM mutations, or content updates from clicks. You no longer need to manually run refresh:
dom@shell:~$click search_btn
✓ Clicked: search_btn (button)
(tree will auto-refresh on next command)
dom@shell:~$ls
(page changed — tree refreshed, 312 nodes, path reset to tab root)
main/
navigation/
search_results/
...
If the page navigated, CWD is reset to the tab root. If the DOM just updated in place, your CWD is preserved. You can still force a manual refresh:
dom@shell:~$refresh
✓ Refreshed. 312 AX nodes loaded.
Tab Completion
Press Tab to auto-complete commands and element names — works like bash:
dom@shell:$ ta<Tab>
# completes to: tabs
dom@shell:$ cd nav<Tab>
# completes to: cd navigation/
dom@shell:$ click sub<Tab>
# if multiple matches, shows options:
# submit_btn
# subscribe_link
- Single match: auto-completes inline
- Multiple matches: shows options below, fills the longest common prefix
cdonly completes directories; other commands complete all elements
Paste Support
Cmd+V (Mac) / Ctrl+V (Windows/Linux) pastes text directly into the terminal. Multi-line pastes are flattened to a single line.
System Commands
# Check if you're authenticated (reads cookies)
dom@shell:~$whoami
URL: https://example.com
Status: Authenticated
Via: session_id
Expires: 2025-12-31T00:00:00.000Z
Total cookies: 12
# Environment variables
dom@shell:~$env
SHELL=/bin/domshell
TERM=xterm-256color
# Set a variable
dom@shell:~$export API_KEY=sk-abc123
# Debug the raw AX tree
dom@shell:~$debug stats
--- Debug Stats ---
Total AX nodes: 247
Ignored nodes: 83
Generic nodes: 41
With children: 62
Iframes: 2
Getting Help
Every command supports --help:
dom@shell:$ ls --help
ls — List children of the current node
Usage: ls [options]
Options:
-l, --long Long format: type prefix, role, and name
-r, --recursive Show nested children (one level deep)
-n N Limit output to first N entries
--offset N Skip first N entries (for pagination)
--type ROLE Filter by AX role (e.g. --type button)
--count Show count of children only
...
Command Reference
Browser Level
| Command | Description |
|---|---|
tabs | List all open tabs (shortcut for ls ~/tabs/) |
windows | List all windows with their tabs grouped underneath |
here | Jump to the active tab in the focused window |
cd ~ | Go to browser root |
cd ~/tabs/<id> | Switch to a tab by ID (enters automatically) |
cd ~/tabs/<pattern> | Switch to a tab by title/URL substring match |
cd ~/windows/<id> | Browse a window's tabs |
navigate <url> | Navigate the current tab to a URL |
open <url> | Open a URL in a new tab and enter it |
back | Go back in browser history (like the back button) |
forward | Go forward in browser history |
close [tab-id] | Close the current tab (or a specific tab by ID) |
DOM Tree
| Command | Description |
|---|---|
ls [options] | List children (-l, --meta, --text, -r, -n N, --offset N, --type ROLE, --count, --after NAME, --before NAME, --json) |
cd <path> | Navigate (.., ~ or / for browser root, %here% for focused tab, main/form for multi-level) |
pwd | Print current path (DOM path or browser path) |
tree [depth] | Tree view of current node (default depth: 2) |
cat <name> [--json] | Full element metadata: AX info + DOM properties (tag, href, src, id, class, outerHTML) |
text [name] [-n N] [--links] | Bulk extract all text from a section (--links inlines URLs as [text](url)) |
read [name] [opts] | Structured subtree extraction (--meta, --text, -d N depth) — tree + content in one call |
grep [opts] <pattern> | Search by name/role/value (-r recursive, --content match visible text, -n N limit) |
find [opts] <pattern> | Deep recursive search (--type ROLE with fuzzy aliases: input, dropdown, nav, toggle, modal, image, etc.; --meta, --text, --content, -n N, --json) |
extract_links [name] | Extract all links as [text](url) format (-n N limit) |
extract_table <name> | Extract table as markdown or CSV (--format csv, -n N row limit) |
click <name> | Click an element (falls back to coordinate-based click) |
focus <name> | Focus an input element |
type <text> | Type text into the focused element |
submit <input> <val> | Atomic form fill: focus + clear + type + submit (--submit btn or Enter) |
scroll [down|up] [N] | Scroll page by N viewport heights (default: 1). Returns scroll position %. |
scroll <name> | Scroll a specific element into the center of the viewport |
js <code> | Execute JavaScript in the tab context. Returns JSON-serialized result. Supports async/await. |
screenshot | Capture a PNG screenshot of the current tab (returns image via MCP, base64 in shell) |
select <name> <value> | Select a dropdown option by value or visible text (dispatches change/input events) |
wait <pattern> [--type ROLE] [--timeout N] | Wait for an element matching pattern to appear (polls AX tree, default 5s timeout, max 30s) |
eval <expr> | Evaluate a JS expression (read-only, no --allow-write needed). Same as js but Read tier. |
diff [--json] | Compare AX tree against pre-action snapshot. Shows added/removed/changed elements after click/submit/navigate. |
refresh | Force re-fetch the Accessibility Tree |
Automation
| Command | Description |
|---|---|
watch <cmd> [--interval N] [--times N] [--until-change] | Re-run a command periodically. --until-change stops when output differs. Capped at 28s. |
for <source-cmd> : <action-tpl> | Iterate over output lines. {} is replaced with each line. Capped at 50 items / 28s. |
script list|save|show|run|delete | Save and run multi-command scripts. script run name arg1 replaces $1 in saved commands. Persisted. |
each [--pattern FILTER] <cmd> | Run a command across all matching tabs. Restores original tab afterward. |
functions [pattern] [--json] | List callable global JS functions on the page with name, arity, params. |
call <funcName> [arg1] [arg2] ... | Call a global JS function by name. Args auto-parsed (JSON or string). Write-tier. |
System
Shortened here. Read the whole README on GitHub.
Signals
- GitHub stars
- 54
- Forks
- 8
- Last commit
- Aug 2026
- Weekly downloads
- 128
- Weekly_downloads
- 183 weekly_downloads
Advanced
- Delivery
- domshell MCP server → your Ahel connector (mcp.ahel.ai) → your AI.
- Item type
- mcp-server
- Key
io-github-apireno-domshell- Source
- github.com/apireno/domshell
More in Files & storage
MCP server · wonderwhy-er
More in Files & storagelocal-mcp
MCP server · colibird-ai
More in Files & storageruntime
MCP server · withruntime
More in Files & storageopen-agreements
MCP server · open-agreements
More in Files & storagegeml
MCP server · geml-spec
More in Files & storagecarbone-mcp
MCP server · carboneio
More in Files & storage