DOMShell
Navega por la web con comandos del sistema de archivos. 38 herramientas MCP permiten a los agentes de IA ejecutar ls, cd, grep, clic y escritura a través de Chrome mediante una extensión de Chrome.
Documentación
DOMShell
| |
___|_|___
|___|_|___|
| | | |
|___|_|___|
/ | | \
/ | | \
|____|_|____|
| |
| DOMSHELL |
| |
|___________|
|###########|
|###########|
\#########/
\_______/
██ ██ ██ ███████
██ ██ ██ ███
███████ ██ ██
██░░░██ ██ ██
██ ██ ██ ██
░░ ░░ ░░ ░░
███████ ██ ██ ███████
███ ███████ ██░░░░░
███ ██░░░██ █████
███ ██ ██ ██░░░
███ ██ ██ ███████
░░░ ░░ ░░ ░░░░░░░
██████ ██████ ███ ███ ██
██ ██ ██ ██ ████ ████ ██
██ ██ ██ ██ ██ ████ ██ ██
██ ██ ██ ██ ██ ██ ██ ░░
██████ ██████ ██ ██ ██
░░░░░░ ░░░░░░ ░░ ░░ ░░
El navegador es tu sistema de archivos. Una extensión de Chrome que permite a los agentes de IA (y a los humanos) navegar por la web usando comandos estándar de Linux — ls, cd, cat, grep, click — a través de una terminal en el Panel Lateral de Chrome.
Instalar desde Chrome Web Store | paquete npm | Leer el artículo del blog | Página del proyecto
DOMShell mapea el navegador en un sistema de archivos virtual. Las ventanas y pestañas se convierten en directorios de nivel superior (~). El Árbol de Accesibilidad de cada pestaña se convierte en un sistema de archivos anidado donde los elementos contenedores son directorios y los botones, enlaces e inputs son archivos. Navega por Chrome de la misma manera en que navegarías por /usr/local/bin.
Por qué
Los agentes de IA que interactúan con sitios web suelen depender de capturas de pantalla, coordenadas de píxeles o selectores CSS frágiles. DOMShell adopta un enfoque diferente: expone el propio Árbol de Accesibilidad del navegador como una metáfora familiar de sistema de archivos.
Esto significa que un agente puede:
- Navegar por pestañas con
ls ~/tabs/y cambiar concd ~/tabs/123en lugar de adivinar qué pestaña está activa - Explorar una página con
lsytreeen lugar de analizar capturas de pantalla - Navegar hacia secciones con
cd navigation/en lugar de adivinar coordenadas - Actuar sobre elementos con
click submit_btnen lugar de consultas DOM frágiles - Leer contenido con
cato extraer en masa contexten lugar de raspar innerHTML - Buscar elementos con
find --type comboboxen lugar de escribir selectores
La abstracción del sistema de archivos es determinista, semántica y funciona en cualquier sitio web — no se necesitan adaptadores específicos por sitio.
Instalación
Chrome Web Store (Recomendado)
Instala DOMShell directamente desde la Chrome Web Store. No se requiere paso de compilación.
Desde el código fuente
git clone https://github.com/apireno/DOMShell.git
cd DOMShell
npm install
npm run build
Cargar en Chrome
- Abre
chrome://extensions/ - Activa Modo desarrollador (interruptor en la esquina superior derecha)
- Haz clic en Cargar descomprimida
- Selecciona la carpeta
dist/ - Haz clic en el icono de DOMShell en tu barra de herramientas — se abre el panel lateral
Uso
Primeros pasos
Abre cualquier página web y luego abre el panel lateral de DOMShell. Verás una 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:~$
Comienzas en ~ (la raíz del navegador). Salta directamente a la pestaña activa con here, o explora:
dom@shell:~$ ls
windows/ (2 windows)
tabs/ (5 tabs)
dom@shell:~$ here
✓ Entered tab 123
Title: Google
URL: https://google.com
AX Nodes: 247
Navegación por pestañas y ventanas
# 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
También puedes navegar o abrir nuevas pestañas:
# 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
Grupos de pestañas (aislamiento)
Por defecto, DOMShell opera en tu navegador general — modo compartido, exactamente como antes. El comando group coloca una sesión en su propio grupo de pestañas aislado de Chrome, de modo que el agente trabaje en un carril claramente marcado mientras tú sigues navegando libremente en otras pestañas:
# 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
Subcomandos: group (estado), group new [name], group attach <id>, group detach, group close, group list. El modo aislado mantiene al agente fuera de tus otras pestañas; el modo compartido es el predeterminado y no ha cambiado.
Cuando un cliente MCP se conecta, DOMShell automáticamente le da a esa sesión su propio grupo 🐚 agent nuevo. El grupo se deja abierto cuando la sesión se desconecta (no destructivo) — se instruye al agente para que pregunte si deseas que se cierre antes de finalizar, y siempre puedes limpiar los restos tú mismo con group close.
Multi-sesión. Cada cliente de DOMShell obtiene su propio carril de sesión — cada ventana del panel lateral, cada conexión MCP, aisladas por separado. Dos paneles laterales en dos ventanas de Chrome mantienen posiciones independientes; múltiples agentes MCP concurrentes trabajan cada uno en su propio grupo 🐚 agent con su propio cursor. Ejecuta group list en cualquier momento para ver todos los carriles activos; group close <id> para cerrar uno.
Múltiples agentes en una conexión MCP. Algunos clientes MCP (por ejemplo, Claude Desktop) comparten una conexión entre todos los chats — por lo que por defecto dos chats en el mismo cliente caerían en un mismo carril. Cada chat puede crear su propio carril pasando el parámetro group_id a domshell_execute: pasa "new" para crear uno nuevo (su id se devuelve al final de la respuesta como [lane: <id>]), y luego pasa ese id en cada llamada posterior. Dos chats → dos carriles → sin colisiones. Los agentes también pueden usar esto para transferencia — un agente informa su id de carril, el siguiente agente lo pasa como group_id y continúa en el mismo estado. Se instruye a los agentes para que cierren cualquier carril que hayan creado cuando la tarea esté completa.
Navegación por el DOM
Una vez que estás dentro de una pestaña, el Árbol de Accesibilidad aparece como un sistema de archivos:
# 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
Prefijos de tipo
Cada nodo tiene un prefijo de tipo que comunica metadatos sin depender solo del color:
| Prefijo | Significado | Ejemplos |
|---|---|---|
[d] | Directorio (contenedor, se puede hacer cd) | navigation/, form/, main/ |
[x] | Interactivo (clicable/enfocable) | botones, enlaces, inputs, casillas de verificación |
[-] | Estático (solo lectura) | encabezados, imágenes, texto |
Lectura de contenido
# 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
Búsqueda
# 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>
Encadenamiento de comandos (composición estilo Bash)
DOMShell funciona como un sistema de archivos — usa el mismo modelo mental que para buscar archivos en disco. grep descubre dónde vive el contenido (como grep -r en bash), cd delimita tu contexto, y text/cat/find lee el contenido (como cat/head/less). El operador de tubería (|) filtra la salida, igual que en bash.
El patrón es: grep (localizar) → cd (delimitar) → extract (leer).
# 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
Operador de tubería
El operador de tubería (|) te permite filtrar la salida de comandos, igual que en 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
Resolución de rutas
Todos los comandos aceptan rutas relativas, eliminando la necesidad de hacer cd primero:
# 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
Navegación entre hermanos
Usa las banderas --after y --before en ls para encontrar contenido relativo a un punto de referencia:
# 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>
La idea clave: la salida de grep alimenta a cd, y cd delimita todo lo demás. Cuando no sabes dónde vive el contenido en una página, primero haz grep, luego delimita, y luego extrae.
Interacción con elementos
# 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
Actualización automática ante cambios en el DOM
DOMShell detecta automáticamente cuando la página cambia — navegación, mutaciones del DOM o actualizaciones de contenido por clics. Ya no necesitas ejecutar refresh manualmente:
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/
...
Si la página navegó, el CWD se restablece a la raíz de la pestaña. Si el DOM solo se actualizó en su lugar, tu CWD se conserva. Aún puedes forzar una actualización manual:
dom@shell:~$refresh
✓ Refreshed. 312 AX nodes loaded.
Autocompletado con tabulador
Presiona Tab para autocompletar comandos y nombres de elementos — funciona como 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
- Coincidencia única: autocompleta en línea
- Múltiples coincidencias: muestra opciones debajo, completa el prefijo común más largo
cdsolo completa directorios; otros comandos completan todos los elementos
Soporte de pegado
Cmd+V (Mac) / Ctrl+V (Windows/Linux) pega texto directamente en la terminal. Los pegados de varias líneas se aplastan a una sola línea.
Comandos del sistema
# 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
Obtener ayuda
Cada comando admite --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
...
Referencia de comandos
Nivel de navegador
| Comando | Descripción |
|---|---|
tabs | Lista todas las pestañas abiertas (atajo para ls ~/tabs/) |
windows | Lista todas las ventanas con sus pestañas agrupadas debajo |
here | Salta a la pestaña activa en la ventana enfocada |
cd ~ | Ir a la raíz del navegador |
cd ~/tabs/<id> | Cambiar a una pestaña por ID (entra automáticamente) |
cd ~/tabs/<pattern> | Cambiar a una pestaña por coincidencia de subcadena en título/URL |
cd ~/windows/<id> | Explorar las pestañas de una ventana |
navigate <url> | Navegar la pestaña actual a una URL |
open <url> | Abrir una URL en una pestaña nueva y entrar en ella |
back | Retroceder en el historial del navegador (como el botón atrás) |
forward | Avanzar en el historial del navegador |
close [tab-id] | Cerrar la pestaña actual (o una pestaña específica por ID) |
Árbol DOM
| Comando | Descripción |
|---|---|
ls [options] | Listar hijos (-l, --meta, --text, -r, -n N, --offset N, --type ROLE, --count, --after NAME, --before NAME, --json) |
cd <path> | Navegar (.., ~ o / para la raíz del navegador, %here% para la pestaña enfocada, main/form para múltiples niveles) |
pwd | Imprimir la ruta actual (ruta DOM o ruta del navegador) |
tree [depth] | Vista de árbol del nodo actual (profundidad predeterminada: 2) |
cat <name> [--json] | Metadatos completos del elemento: información AX + propiedades DOM (tag, href, src, id, class, outerHTML) |
text [name] [-n N] [--links] | Extraer en masa todo el texto de una sección (--links inserta URLs como [text](url)) |
read [name] [opts] | Extracción estructurada de subárbol (--meta, --text, -d N profundidad) — árbol y contenido en una sola llamada |
grep [opts] <pattern> | Buscar por nombre/rol/valor (-r recursivo, --content coincidir texto visible, -n N límite) |
find [opts] <pattern> | Búsqueda recursiva profunda (--type ROLE con alias difusos: input, dropdown, nav, toggle, modal, image, etc.; --meta, --text, --content, -n N, --json) |
extract_links [name] | Extraer todos los enlaces en formato [text](url) (límite -n N) |
extract_table <name> | Extraer tabla como markdown o CSV (--format csv, límite de filas -n N) |
click <name> | Hacer clic en un elemento (con respaldo a clic por coordenadas) |
focus <name> | Enfocar un elemento de entrada |
type <text> | Escribir texto en el elemento enfocado |
submit <input> <val> | Relleno atómico de formularios: enfocar + limpiar + escribir + enviar (--submit btn o Enter) |
scroll [down|up] [N] | Desplazar la página por N alturas de viewport (predeterminado: 1). Devuelve el porcentaje de posición de desplazamiento. |
scroll <name> | Desplazar un elemento específico al centro del viewport |
js <code> | Ejecutar JavaScript en el contexto de la pestaña. Devuelve resultado serializado en JSON. Admite async/await. |
screenshot | Capturar una captura de pantalla PNG de la pestaña actual (devuelve imagen vía MCP, base64 en shell) |
select <name> <value> | Seleccionar una opción de lista desplegable por valor o texto visible (despacha eventos change/input) |
wait <pattern> [--type ROLE] [--timeout N] | Esperar a que aparezca un elemento que coincida con el patrón (sondea el árbol AX, tiempo de espera predeterminado 5s, máximo 30s) |
eval <expr> | Evaluar una expresión JS (solo lectura, no se necesita --allow-write). Igual que js pero en nivel de Lectura. |
diff [--json] | Comparar el árbol AX contra una instantánea previa a la acción. Muestra elementos añadidos/eliminados/cambiados después de clic/enviar/navegar. |
refresh | Forzar la recuperación del Árbol de Accesibilidad |
Automatización
| Comando | Descripción |
|---|---|
watch <cmd> [--interval N] [--times N] [--until-change] | Re-ejecutar un comando periódicamente. --until-change se detiene cuando la salida difiere. Limitado a 28s. |
for <source-cmd> : <action-tpl> | Iterar sobre líneas de salida. {} se reemplaza con cada línea. Limitado a 50 elementos / 28s. |
script list|save|show|run|delete | Guardar y ejecutar scripts de múltiples comandos. script run name arg1 reemplaza a $1 en comandos guardados. Persistente. |
each [--pattern FILTER] <cmd> | Ejecutar un comando en todas las pestañas que coincidan. Restaura la pestaña original después. |
functions [pattern] [--json] | Listar funciones JS globales invocables en la página con nombre, aridad, parámetros. |
call <funcName> [arg1] [arg2] ... | Invocar una función JS global por nombre. Los argumentos se auto-analizan (JSON o cadena). Nivel de escritura. |
Sistema
| Comando | Descripción |
|---|---|
whoami | Verificar cookies de sesión/autenticación de la página actual |
env | Mostrar variables de entorno |
export K=V | Establecer una variable de entorno |
history [-n N] | Mostrar historial de comandos. history clear para restablecer. !N para recuperar el comando N. |
bookmark [name] [path] | Guardar/listar rutas nombradas. bookmark inbox guarda la ruta actual. cd @inbox regresa. bookmark --delete name elimina. |
debug [sub] | Inspeccionar árbol AX sin procesar (stats, raw, node <id>) |
connect <token> | Conectar a un servidor MCP mediante puente WebSocket |
disconnect | Desconectar del servidor MCP, limpiar token |
help | Mostrar todos los comandos disponibles |
clear | Limpiar la terminal |
Cómo Funciona el Mapeo del Sistema de Archivos
DOMShell mapea el navegador en un sistema de archivos virtual de dos niveles:
Nivel del Navegador (~)
El navegador en sí se convierte en la parte superior de la jerarquía del sistema de archivos:
~ (browser root)
├── windows/ (all Chrome windows)
│ ├── <window-id>/ (tabs in that window)
│ │ ├── <tab-id> (cd into = enter AX tree)
│ │ └── ...
│ └── ...
└── tabs/ (flat listing of ALL tabs)
├── <tab-id> (cd into = enter AX tree)
└── ...
Hacer cd en una pestaña adjunta transparentemente CDP y te lleva a su árbol DOM.
Nivel DOM (dentro de una pestaña)
El Árbol de Accesibilidad (AXTree) de cada pestaña se lee mediante el Protocolo de Chrome DevTools. Cada nodo AX se mapea a un archivo o directorio virtual:
Directorios (roles contenedores): navigation/, main/, form/, search/, list/, region/, dialog/, menu/, table/, Iframe/, etc.
Archivos (roles interactivos/hoja): submit_btn, home_link, email_input, agree_chk, theme_switch, etc.
cd .. desde la raíz del DOM sale de vuelta a la lista de pestañas. cd ~ regresa a la raíz del navegador desde cualquier lugar.
Heurística de Nombres
Los nombres se generan a partir del nombre accesible y el rol del nodo:
| Nodo AX | Nombre Generado |
|---|---|
role=button, name="Submit" | submit_btn |
role=link, name="Contact Us" | contact_us_link |
role=textbox, name="Email" | email_input |
role=checkbox, name="I agree" | i_agree_chk |
role=navigation | navigation/ |
role=generic, no name, 1 child | (aplanado — el hijo se promueve hacia arriba) |
Los nombres duplicados se desambiguizan automáticamente con _2, _3, etc.
Aplanamiento de Nodos
El árbol AX contiene muchos nodos "envoltorio" — nodos ignorados, genéricos sin nombre y elementos con role=none que añaden ruido estructural sin significado semántico. DOMShell aplana recursivamente a través de ellos, promoviendo sus hijos hacia arriba para que veas los elementos significativos sin navegar por capas de divs invisibles.
Soporte de Iframes
DOMShell descubre iframes mediante Page.getFrameTree y obtiene el árbol AX de cada iframe por separado. Los nodos de iframes se fusionan en el árbol principal con IDs prefijados para evitar colisiones, de modo que los elementos dentro de los iframes aparecen naturalmente en el sistema de archivos.
Codificación de Colores
| Color | Significado |
|---|---|
| Azul (negrita) | Directorios (contenedores) |
| Verde (negrita) | Botones |
| Magenta (negrita) | Enlaces |
| Amarillo (negrita) | Campos de texto / cuadros de búsqueda |
| Cian (negrita) | Casillas de verificación / radios / interruptores |
| Blanco | Otros elementos |
| Gris | Imágenes, metadatos |
Arquitectura
┌────────────────────┐
│ Claude Desktop │──┐
└────────────────────┘ │
┌────────────────────┐ │ HTTP POST/GET/DELETE ┌─────────────────────┐
│ Claude CLI │──┼─ localhost:3001/mcp ──┐ │ Side Panel (UI) │
└────────────────────┘ │ (Bearer token auth) │ │ │
┌────────────────────┐ │ │ │ React + Xterm.js │
│ Cursor / Other │──┘ │ │ - Paste support │
└────────────────────┘ ▼ │ - Tab completion │
┌─────────────────────┐ │ - Command history │
│ MCP Server │ └─────────┬───────────┘
│ (mcp-server/) │ │
│ │ chrome.runtime
│ Express HTTP server │ .connect()
│ Per-session MCP │ │
│ Security layer: │ ┌─────────▼───────────┐
│ - Auth token │ │ Background Worker │
│ - Command tiers │ │ (Shell Kernel) │
│ - Domain allowlist │ │ │
│ - Audit log │ │ Browser hierarchy │
└──────────┬───────────┘ │ (~, tabs, windows) │
│ │ Command parser │
WebSocket (localhost:9876) │ Shell state (CWD) │
+ auth token │ VFS mapper │
+ alarm keepalive │ CDP client │
│ │ DOM change detect │
└─────────────────►│ WebSocket bridge │
└─────────┬───────────┘
│
chrome.debugger
(CDP 1.3)
│
┌─────────▼───────────┐
│ Active Tab │
│ Accessibility │
│ Tree + iframes │
│ │
│ DOM events ──────►│
│ (auto-refresh) │
└─────────────────────┘
El servidor MCP se ejecuta como un servicio HTTP independiente al que cualquier número de clientes MCP puede conectarse simultáneamente. Expone dos puertos: un endpoint HTTP para clientes MCP (por defecto 3001) y un puente WebSocket para la extensión de Chrome (por defecto 9876).
La extensión sigue un modelo de Cliente Ligero / Host Pesado. El panel lateral es una terminal tonta — captura pulsaciones de teclas, maneja el pegado y renderiza texto con colores ANSI. Toda la lógica vive en el service worker en segundo plano: análisis de comandos, recorrido del árbol AX, mapeo del sistema de archivos, interacción CDP, navegación de la jerarquía del navegador y detección de cambios en el DOM.
Estructura del Código Fuente
src/
background/
index.ts # Shell kernel — commands, state, message router, auto-refresh, WS bridge
cdp_client.ts # Promise-wrapped chrome.debugger API + iframe discovery
vfs_mapper.ts # Accessibility Tree → virtual filesystem mapping
sidepanel/
index.html # Side panel entry HTML
index.tsx # React entry point
Terminal.tsx # Xterm.js terminal (paste, tab completion, history)
shared/
types.ts # Message types, AXNode interfaces, role constants
public/
manifest.json # Chrome Manifest V3
options.html # Extension settings page (MCP bridge config)
mcp-server/
index.ts # MCP server — standalone Express HTTP + StreamableHTTP, WebSocket bridge, security
proxy.ts # Stdio↔HTTP bridge for clients that require command/args (e.g. Claude Desktop)
package.json # MCP server dependencies
tsconfig.json # MCP server TypeScript config
Stack Tecnológico
- React + TypeScript — UI del panel lateral
- Xterm.js (
@xterm/xterm) — Emulador de terminal con esquema de colores Tokyo Night - Vite — Herramienta de compilación con soporte multi-entrada para extensiones de Chrome
- Protocolo de Chrome DevTools (CDP 1.3) mediante
chrome.debugger— Acceso al árbol AX, interacción con elementos, descubrimiento de iframes, eventos de mutación del DOM - Chrome Manifest V3 — Permisos
sidePanel,debugger,activeTab,cookies,storage,alarms
Desarrollo
# Watch mode (rebuilds on file changes)
npm run dev
# One-time production build
npm run build
# Type checking
npm run typecheck
Después de compilar, recarga la extensión en chrome://extensions/ y vuelve a abrir el panel lateral para aplicar los cambios.
Conexión de Clientes MCP (Claude Desktop, CLI, Cursor, etc.)
DOMShell incluye un servidor MCP reforzado que permite que cualquier cliente compatible con MCP controle el navegador mediante comandos de DOMShell. El servidor se ejecuta como un servicio HTTP independiente — varios clientes pueden conectarse simultáneamente.
Tres rutas de instalación
El servidor MCP de DOMShell admite tres rutas de instalación — elige la que se ajuste a tu configuración. La ruta 1 es el valor predeterminado documentado y lo que la mayoría de los usuarios quiere. Las rutas 2 y 3 son opcionales y existen para usuarios que quieren aislamiento de contenedores o gestión del ciclo de vida.
| Ruta | Qué ejecutas | Comportamiento al reiniciar | Cuándo elegirla |
|---|---|---|---|
| 1. Nativa (npx) | npx @apireno/domshell --allow-write --token <token> | Sobrevive naturalmente — el cliente MCP (Claude Desktop, Cursor, …) lo inicia bajo demanda | Quieres la instalación más simple — sin Docker, sin herramientas adicionales |
| 2. Dockerizada (compose) | docker compose up -d desde mcp-server/ con un archivo .env | Sobrevive con el interruptor "Iniciar al iniciar sesión" de Docker Desktop (restart: unless-stopped) | Quieres aislamiento de contenedores pero no necesitas un supervisor multi-MCP |
| 3. Gestionada por ToolHive (thv) | thv run + un agente launchd de inicio automático único | Sobrevive mediante launchd → thv restart --all | Estás ejecutando varios servidores MCP y quieres un solo lugar para thv list / thv logs todos ellos |
Instrucciones completas de la Ruta 2 / Ruta 3 (compilación, patrón de instalación .env, plantilla de inicio automático launchd, recuperación tras reinicio): docs/deploy/container-and-toolhive.md. El resto de este README cubre la Ruta 1 — la más simple y recomendada por defecto.
Instalación mediante npm (Ruta 1 — predeterminada)
npm install -g @apireno/domshell
O ejecuta directamente sin instalar:
npx @apireno/domshell --allow-write --token my-secret-token
Arquitectura
User starts independently:
npx @apireno/domshell --allow-write --token xyz
→ HTTP on :3001/mcp (MCP clients)
→ WebSocket on :9876 (Chrome extension)
Claude Desktop spawns (stdio proxy): ┐
npx domshell-proxy --port 3001 --token xyz ├─► HTTP :3001/mcp
Claude CLI connects directly: │
url: http://localhost:3001/mcp?token=xyz │
Gemini CLI connects directly: │
url: http://localhost:3001/mcp?token=xyz ┘
El servidor MCP es un servicio HTTP independiente — lo inicias por separado, y cualquier número de clientes MCP se conecta a él. Ningún cliente "posee" el proceso del servidor. Para clientes que requieren stdio (como Claude Desktop), un pequeño proxy conecta stdio al servidor HTTP en ejecución.
Configuración
Configuración rápida (recomendada):
npx @apireno/domshell init
El asistente detecta los clientes MCP instalados (Claude Desktop, Cursor, Windsurf), genera un token compartido y escribe la configuración de cada cliente. Luego inicias el servidor una vez en una terminal — todos los clientes se conectan a él.
Usa --yes para el modo no interactivo con valores predeterminados sensatos:
npx @apireno/domshell init --yes
Configuración manual:
1. Inicia el servidor MCP:
npx @apireno/domshell --allow-write --token my-secret-token
El servidor inicia dos listeners:
- HTTP en
http://127.0.0.1:3001/mcp— endpoint del cliente MCP - WebSocket en
ws://127.0.0.1:9876— puente de la extensión de Chrome
Consejo: Usa
--tokenpara establecer un token conocido y poder preconfigurar los clientes. Si se omite, se genera un token aleatorio y se imprime al inicio.
2. Conecta los clientes MCP:
Claude CLI / Gemini CLI / Cursor (HTTP directo — recomendado):
http://localhost:3001/mcp?token=my-secret-token
Claude Desktop (requiere stdio — usa el proxy):
Añade a ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"domshell": {
"command": "npx",
"args": ["-y", "@apireno/domshell", "--allow-write", "--token", "my-secret-token"]
}
}
}
Reinicia Claude Desktop. Las herramientas de DOMShell aparecerán.
3. Conecta la extensión (Página de Opciones):
- Ve a
chrome://extensions/ - Encuentra DOMShell y haz clic en Opciones (o haz clic derecho en el icono de la extensión → Opciones)
- Activa el interruptor Puente MCP
- Pega el mismo token que usaste en la configuración de Claude Desktop (
my-secret-token) - Haz clic en Guardar — el indicador de estado se vuelve verde cuando está conectado
La página de opciones muestra el estado de conexión en vivo: Deshabilitado, Conectando, Conectado o Desconectado.
Alternativa: Conectar mediante terminal
También puedes conectarte desde la terminal de DOMShell en lugar de la página de opciones:
dom@shell:$ connect my-secret-token
4. Pruébalo:
Pregunta a Claude: "Lista mis pestañas abiertas y dime qué hay en la primera."
Seguridad
El servidor MCP está reforzado con múltiples capas de seguridad. Por defecto, es de solo lectura — Claude puede navegar pero no hacer clic ni escribir.
Niveles de Comandos
| Nivel | Comandos | Predeterminado | Habilitar con |
|---|---|---|---|
| Lectura | ls, cd, pwd, cat, text, grep, find, tree, refresh, tabs, windows, here, screenshot, wait, eval, diff, history, bookmark, functions, watch, for, script, each | Habilitado | (siempre activo) |
| Navegación | navigate, goto, open, back, forward | Deshabilitado | --allow-write |
| Escritura | click, focus, type, scroll, js, select, close, call | Deshabilitado | --allow-write |
| Sensible | whoami (expone cookies) | Deshabilitado | --allow-sensitive |
El nivel Navegación está separado de Escritura porque navegar equivale a escribir una URL — requiere --allow-write pero omite el mensaje de confirmación interactivo. Esto es importante para Claude Desktop donde /dev/tty no está disponible.
Banderas de Seguridad
| Bandera | Descripción |
|---|---|
--allow-write | Habilitar comandos de clic/enfoque/escritura/desplazamiento/js/selección/cierre/navegación/atrás/adelante |
--allow-sensitive | Habilitar whoami (acceso a cookies) |
--allow-all | Abreviatura para ambos |
--confirm | Optar por mensajes de sí/no por acción en la terminal del servidor antes de cada escritura. Desactivado por defecto. |
--no-confirm | Sin operación (se mantiene por compatibilidad hacia atrás — los mensajes por acción están desactivados por defecto). |
--domains example.com,app.example.com | Restringir comandos a dominios específicos |
--expose-cookies | Mostrar valores completos de cookies (predeterminado: redactados) |
--mcp-port N | Puerto del endpoint HTTP de MCP (predeterminado: 3001) |
--port N | Puerto del puente WebSocket (predeterminado: 9876) |
--log-file PATH | Archivo de registro de auditoría (predeterminado: audit.log) |
Confirmación por Acción (opt-in)
Los mensajes de terminal por acción están desactivados por defecto — la terminal del servidor MCP está separada de donde realmente se ejecutan el agente y el panel lateral, por lo que el mensaje es incómodo de responder en cualquier configuración iniciada por GUI (Claude Desktop, Cursor, el entorno de CLI-Anything). El registro de auditoría captura cada comando, y las banderas de nivel (--allow-write, --allow-sensitive) más --domains siguen siendo los límites de seguridad reales.
Si inicias el servidor en tu propia terminal y quieres un mensaje de sí/no antes de cada escritura, añade --confirm:
[DOMShell] Claude wants to: click submit_btn
Allow? (y/n):
--no-confirm se conserva como una operación sin efecto (coincide con el valor predeterminado), por lo que cualquier configuración existente que lo pase seguirá funcionando sin cambios.
Token de Autenticación
- Usa
--tokenpara establecer un token conocido en la configuración del servidor MCP, o deja que el servidor genere uno aleatorio al inicio - La extensión debe presentar este token (mediante la página de opciones o
connect <token>) antes de que el puente funcione - Las conexiones WebSocket sin un token válido se rechazan
- El token se almacena en
chrome.storage.local— sobrevive a los reinicios del service worker
Lista de Dominios Permitidos
Con --domains, los comandos solo se ejecutan cuando la URL de la pestaña activa coincide:
npx tsx index.ts --allow-write --domains "github.com,docs.google.com"
Registro de Auditoría
Cada comando se registra con marcas de tiempo en audit.log (o --log-file):
[2026-02-07T12:00:00.000Z] EXECUTE: ls -l
[2026-02-07T12:00:01.000Z] RESULT: 12 items
[2026-02-07T12:00:05.000Z] [WRITE] EXECUTE: click submit_btn
[2026-02-07T12:00:05.500Z] [WRITE] RESULT: ✓ Clicked: submit_btn (button)
Desconexión
Desactiva el interruptor del Puente MCP en la página de opciones de la extensión, o ejecuta disconnect en la terminal de DOMShell:
dom@shell:$ disconnect
✓ Disconnected from MCP server.
La interfaz domshell_execute
El servidor MCP de DOMShell expone una única herramienta por defecto — domshell_execute — la forma recomendada de manejar DOMShell. Pasas una cadena de comando, exactamente como la escribirías en la terminal de DOMShell:
domshell_execute("ls")
domshell_execute("cd tabs/4815")
domshell_execute("find --type link --meta")
Llamadas con múltiples comandos. Pasa varios comandos separados por saltos de línea y se ejecutan en secuencia, con la salida combinada devuelta — un flujo de trabajo completo en una sola llamada de herramienta:
domshell_execute("open https://example.com
cd main
text")
Un solo viaje de ida y vuelta en lugar de tres, y menos ciclos de llamadas de herramienta.
Semántica multilínea. Cada línea se ejecuta en orden en la misma sesión y carril de MCP, por lo que cwd, el entorno y el historial persisten entre líneas (el cd main de la segunda línea es relativo a la pestaña recién abierta de la primera línea). Un error en cualquier línea individual no detiene el resto — su mensaje de error se incluye en la salida combinada y las líneas posteriores aún se ejecutan. Esa es la forma correcta para modismos de líneas de limpieza como "cd path\ngrep pattern\ncd back" donde la restauración final debe ejecutarse incluso si el paso intermedio falla. Implementación: mcp-server/index.ts:1115-1136.
Dos modos:
| Modo | Herramientas expuestas | Úsalo cuando |
|---|---|---|
| Herramienta única (por defecto) | Solo domshell_execute | Uso normal. Una aprobación cubre toda la sesión — sin avisos por comando. |
Granular (--granular) | 38 herramientas por comando (domshell_ls, domshell_click, …) | Quieres que tu cliente MCP solicite aprobación por tipo de operación — supervisión humana más fina en la capa del cliente. |
Inicia el servidor con --granular para las herramientas por comando:
npx @apireno/domshell --granular
La seguridad es idéntica en ambos modos. Los niveles del lado del servidor de DOMShell (write / sensitive — establecidos por --allow-write, --allow-sensitive, con --confirm opcional para avisos de terminal del servidor por acción) controlan las operaciones riesgosas independientemente de qué herramienta emitió el comando. El modo granular no añade seguridad — añade un aviso de aprobación adicional en tu cliente MCP por tipo de operación. Eso es más supervisión humana, no más protección.
Referencia de Herramientas MCP (modo --granular)
La tabla siguiente enumera las herramientas por comando expuestas cuando el servidor se ejecuta con --granular. En el modo de herramienta única por defecto, ejecuta los mismos comandos a través de domshell_execute — la columna Maps To muestra la cadena de comando.
| Herramienta MCP | Se asigna a | Nivel |
|---|---|---|
domshell_tabs | tabs (listar todas las pestañas) | Lectura |
domshell_here | here (saltar a la pestaña activa) | Lectura |
domshell_ls | ls [options] (nivel DOM o navegador) | Lectura |
domshell_cd | cd <path> (~, ~/tabs/, /, ..) | Lectura |
domshell_pwd | pwd | Lectura |
domshell_cat | cat <name> | Lectura |
domshell_text | text [name] [-n N] [--links] (texto masivo; links=true inserta URLs) | Lectura |
domshell_read | read [name] [--meta] [--text] [-d N] (subárbol estructurado) | Lectura |
domshell_find | find [pattern] [--type ROLE/alias] [--meta] [--text] [-n N] (el tipo acepta alias difusos: input, dropdown, nav, etc.) | Lectura |
domshell_grep | grep [-r] [-n N] [--content] <pattern> (descubrimiento de secciones) | Lectura |
domshell_tree | tree [depth] | Lectura |
domshell_extract_links | extract_links [name] [-n N] (todos los enlaces como [text](url)) | Lectura |
domshell_extract_table | extract_table <name> [--format csv] (tabla → markdown/CSV) | Lectura |
domshell_refresh | refresh | Lectura |
domshell_navigate | navigate <url> (pestaña actual) | Navegación |
domshell_open | open <url> (nueva pestaña) | Navegación |
domshell_click | click <name> | Escritura |
domshell_focus | focus <name> | Escritura |
domshell_scroll | scroll [down|up] [N] o scroll <target> | Escritura |
domshell_js | js <code> (ejecución arbitraria de JavaScript) | Escritura |
domshell_type | type <text> | Escritura |
domshell_submit | submit <input> <value> [--submit btn] (relleno atómico de formularios) | Escritura |
domshell_back | back (retroceder en el historial del navegador) | Navegación |
domshell_forward | forward (avanzar en el historial del navegador) | Navegación |
domshell_close | close [tab-id] (cerrar una pestaña) | Escritura |
domshell_screenshot | screenshot (capturar pestaña como imagen PNG) | Lectura |
domshell_select | select <name> <value> (selección en lista desplegable) | Escritura |
domshell_wait | wait <pattern> [--type ROLE] [--timeout N] (esperar un elemento) | Lectura |
domshell_eval | eval <expression> (evaluación JS de solo lectura, sin --allow-write necesario) | Lectura |
domshell_diff | diff [--json] (comparar árbol contra instantánea previa a la acción) | Lectura |
domshell_whoami | whoami | Sensible |
domshell_functions | functions [pattern] [--json] (listar funciones de página invocables) | Lectura |
domshell_call | call <funcName> [args] (llamar una función JS global) | Escritura |
domshell_watch | watch <cmd> [--interval N] [--times N] [--until-change] (re-ejecución periódica) | Lectura |
domshell_for | for <source> : <template> (iterar sobre líneas de salida, {} reemplazado) | Lectura |
domshell_script | script list|save|show|run|delete (scripts con sustitución de $1) | Lectura |
domshell_each | each [--pattern FILTER] <cmd> (operaciones entre pestañas) | Lectura |
domshell_execute | (cualquier comando) | Varía |
Hoja de ruta
Distribución e instalación
- Listado en Chrome Web Store — en vivo en Chrome Web Store
- Lanzamiento en GitHub con .crx — lanzamiento v1.1.1 con zip de extensión
- Asistente de configuración MCP —
npx @apireno/domshell initdetecta clientes MCP instalados, genera un token y escribe la configuración automáticamente - Soporte para otros clientes MCP — Gemini Desktop, OpenAI ChatGPT desktop, Cursor, Windsurf y otros hosts compatibles con MCP
Nuevos comandos
-
watch— re-ejecución periódica de un comando (p. ej.watch ls --times 3 --interval 1para sondear cambios en el DOM) -
history— historial de comandos con recuperación (history,!npara re-ejecutar) -
back/forward— navegación de historial estilo navegador dentro de la pestaña actual -
close— cerrar la pestaña actual (closeoclose <tab-id>) -
screenshot— capturar una captura de pantalla de la pestaña actual (útil para verificación visual junto con la inspección del árbol AX) -
pipe/|— canalizar salida entre comandos (p. ej.find --type link | grep login) -
select <name>— seleccionar una opción de una lista desplegable<select>por valor o texto visible -
scroll— desplazarse por la página o un elemento específico (scroll down,scroll up,scroll <name>) -
wait— esperar a que aparezca un elemento específico (p. ej.wait submit_btnse bloquea hasta que exista en el árbol) - Bucle
for— iterar sobre líneas de salida de comandos (p. ej.for "find --type heading -n 3" : text {}) — reemplaza la iteración manual - Comando
script— guardar y ejecutar scripts de múltiples comandos (p. ej.script save scrape open url ; cd main ; text) para flujos de trabajo repetibles
Capa de JavaScript
- Comando
js— ejecutar JavaScript arbitrario en el contexto de la pestaña y devolver el resultado -
functions+call—functions [pattern]lista funciones JS globales invocables con nombre/aridad/parámetros;call funcName arg1 arg2las invoca.calles de nivel de escritura. -
eval <expr>— evaluación rápida de expresiones (p. ej.eval document.title,eval window.location.href)
Ergonomía para agentes
- Indicador
--text— mostrar vistas previas de texto visible en línea conlsyfindusando.innerText(solo texto renderizado, respeta la visibilidad CSS); longitud configurable mediante--textlen N;cattambién muestra VisibleText por separado de textContent - Indicador
--meta— mostrar propiedades DOM (href, src, id, tag) en línea con la salida dels,findyread— esencial para extraer URLs sin llamadascatseparadas - Coincidencia
--content— buscar por contenido de texto visible congrep --contentyfind --content(ofind --text "pattern") — encuentra elementos por lo que muestran, no solo por su nombre AX - Resolución de rutas — todos los comandos aceptan rutas relativas (p. ej.
text main/article/paragraph,click form/submit_btn) — elimina viajes de ida y vueltacdinnecesarios - Navegación entre hermanos — indicadores
--after/--beforeenlspara dividir hijos en relación con un elemento de referencia (p. ej.ls --after heading --type link --meta) - Indicador
--linksentext— incluir URLs de hipervínculos en línea como[text](url)markdown en la salida de texto; extrae tanto el contenido como los destinos de los enlaces en una sola llamada (p. ej.text --links main/paragraph) - Alias de tipo difusos para
find—find --typeacepta alias en lenguaje natural (input, dropdown, nav, toggle, modal, image, btn, sidebar, etc.) que se expanden a roles AX coincidentes — elimina llamadas de herramienta desperdiciadas al adivinar nombres de roles exactos - Caché de texto visible — caché perezosa para resultados de
innerText, claveada porbackendDOMNodeId, limpiada al reconstruir el árbol — elimina llamadas CDP redundantes durante la coincidencia--contentengrep/find -
bookmark/alias— guardar rutas con nombre para navegación rápida (p. ej.bookmark inbox ~/tabs/gmail/main/inbox_list,cd @inbox) -
each(multi-pestaña) — ejecutar un comando en múltiples pestañas (p. ej.each --pattern wiki textpara extraer texto de cada pestaña de Wikipedia) - Modo de salida estructurada — indicador
--jsonen comandos para salida analizable por máquina (p. ej.ls --json,cat --json,find --json,diff --json) - Persistencia de sesión — guardar y restaurar el estado del shell (ruta, variables de entorno, marcadores, historial) entre reinicios del service worker mediante
chrome.storage.local -
diff— comparar instantáneas del árbol AX para ver qué cambió después de una acción (instantáneas automáticas antes de click/submit/navigate) - Aislamiento de grupos de pestañas por sesión — las pestañas de cada sesión se colocan en un grupo de pestañas de Chrome etiquetado y cada comando se limita a ese grupo, de modo que el agente trabaje en su propio carril mientras sigues navegando libremente en otras pestañas de la misma ventana (#32)
- DOMShell multi-sesión — cada consola del panel lateral y cada conexión MCP obtiene su propia sesión de shell independiente (su propio directorio actual, pestaña y cursor DOM), de modo que múltiples consolas humanas y agentes concurrentes trabajen cada uno en un carril aislado en lugar de compartir un cursor global (#33)
- Sesiones declaradas por el agente — un
group_idopcional endomshell_executepermite a un agente dirigirse a un carril específico: omítelo para el carril actual,"new"para uno nuevo, o pasa un id para unirse a un carril existente — de modo que dos chats de agentes que comparten una conexión MCP permanezcan aislados, y un agente pueda entregar una sesión a otro (#34)
Plataforma
- Navegador headless independiente — distribuir DOMShell como un proceso Chromium headless autocontenido (mediante Chrome for Testing o Chromium embebido) que los agentes lancen directamente — sin instalación de extensión, sin perfil de Chrome del usuario; solo
npx @apireno/domshell --headlessy conectar vía MCP. Ideal para pipelines de CI, automatización del lado del servidor y flujos de trabajo de agente-en-bucle donde no se necesita un navegador visible - Extensión para Firefox — portar a Firefox usando la API WebExtensions + protocolo de depuración remota
- Backend Playwright/Puppeteer — alternativa a la extensión de Chrome para flujos de trabajo headless de agentes
- Modo API REST — exponer comandos de DOMShell sobre HTTP para integraciones no MCP
- Compilación WASM — compilar DOMShell a WebAssembly para que pueda integrarse directamente en un sitio web para demostraciones interactivas sin requerir la instalación de una extensión de Chrome
Experimentos
- Nexa: DOMShell vs HTML crudo — mismo modelo (Qwen3-4B), mismas tareas: comparar la interfaz de texto/árbol AX de DOMShell contra el raspado de HTML crudo. Pruebas en los backends de nexa serve y Ollama. Se encontró una interacción cruzada: Ollama+DOMShell y Nexa+HTML son igualmente los mejores (promedio 1.20). Ver
experiments/nexa_ollama/. - Nexa vs Claude (tamaño del modelo) — se compararon Qwen3-1.7B/4B en tareas progresivas. Límite de capacidad en T3 (extracción de párrafos). El 4B muestra mejor recuperación de errores. Ver
experiments/nexa_claude/. - Competencia de modelos — se compararon Qwen3-4B, Hermes3-3B, Granite4-Tiny, Llama3.2-3B en Ollama+DOMShell. Qwen3-4B sigue siendo el mejor (8/15), único modelo que supera el límite de T3. Llama3.2-3B es un cercano segundo (7/15, cero alucinaciones). Ver
experiments/model_shootout/. - Benchmark de costo de tokens — medir el total de tokens de entrada/salida por tarea entre DOMShell y la navegación basada en capturas de pantalla (CiC). Extender el
experiments/claude_domshell_vs_cic/existente con el conteo de tokens. Hipótesis: el texto estructurado (2-3KB por respuesta) frente a capturas de pantalla en base64 (500KB+) debería mostrar un ahorro de tokens de >2x además de la reducción de 2x en el número de llamadas ya medida
Integraciones
Nexa AI (LLM local)
Ejecuta DOMShell con modelos locales a través de nexa-sdk — automatización del navegador completamente en el dispositivo sin necesidad de API en la nube. Usa el mismo protocolo MCP que Claude Desktop, pero impulsado por inferencia local (Granite-4-Micro, Qwen3, etc.).
python integrations/nexa/agent.py --task "Open wikipedia.org/wiki/AI and extract the first paragraph" --verbose
Consulta integrations/nexa/ para la configuración y el uso.
Cómo se construyó este proyecto
La especificación técnica de DOMShell fue escrita por Google Gemini, diseñada como un prompt integral que podría entregarse directamente a un agente de codificación para construir todo el proyecto desde cero. La especificación original completa se conserva en intitial_project_prompt.md.
La implementación fue luego construida por Claude (Anthropic) a través de Claude Code, trabajando a partir de esa especificación.
Un proyecto diseñado por IA, construido por otra IA, destinado a que los agentes de IA lo usen. Son agentes hasta el final.
Enlaces
- Chrome Web Store
- npm: @apireno/domshell
- Registro de servidores MCP
- mcpservers.org
- Glama
- Blog: Por qué construí un sistema de archivos para el navegador
- Página del proyecto y política de privacidad
- Construido por Pireno
Licencia
MIT