Read the *visible* text from kapture-dom snapshots without drowning in `<div>` soup.
SaferSkills independently audited kapture-dom-erode (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A companion skill for the [Kapture MCP](https://github.com/anthropics/kapture) browser plugin.
Modern web pages produce enormous DOM snapshots -- often 1-5 MB of deeply nested HTML. When an AI agent saves a page with kapture_dom, the result is millions of characters of markup where the actual on-screen text is buried inside layers of <div>, <span>, and framework-generated wrappers. This skill cuts through that noise.
kapture-dom-erode takes a saved Kapture DOM snapshot and helps you:
Think of it like grep for what's actually visible on a web page, not what's buried in the source code.
The Kapture MCP plugin captures the full DOM of a browser tab. That's great for fidelity, but the raw HTML is unreadable -- a single sidebar might be wrapped in 20 levels of nested divs. Screenshots show you what's on screen but aren't machine-parseable. This skill bridges the gap: it lets an agent find and read specific on-screen content from the raw DOM, without screenshots and without drowning in markup.
Typical use cases:
This is the critical first step. The kapture_dom MCP tool returns a JSON response object with many keys, including "html".
Where to save: Write the DOM to a local scratch space in your current working directory (e.g., .tmp/, scratch/, or similar). If your sandbox does not permit local writes, use /tmp as a fallback.
File format: Save one of these two formats:
kapture_dom to a file as-is. This includes metadata fields like success, url, title, and html.<body>...</body>) -- no JSON wrapper.The parser defaults to reading "html" from JSON. Use -k / --content-key if your JSON uses a different field name.
# Save to local scratch space (preferred)
./skills/kapture-dom-erode/tools.sh top-content -f .tmp/page.json
./skills/kapture-dom-erode/tools.sh top-content -f .tmp/page.json -k html
# Or fallback to /tmp if local writes are blocked
./skills/kapture-dom-erode/tools.sh top-content -f /tmp/page.jsonGlobal behavior across commands:
-k, --content-key -- optional JSON key for DOM extraction. Default is html.gron-grep -- find text in the DOMSearch for any text and get back its structural path (like a GPS coordinate for where it sits in the page).
./skills/kapture-dom-erode/tools.sh gron-grep -f page.json -q "search text" [-i]Options:
-f, --file -- saved DOM file (JSON with "html" key, or raw HTML -- see "Saving the DOM" above)-k, --content-key -- JSON key for DOM content when using JSON input (default: html)-q, --query -- the text to search for-i, --ignore-case -- case-insensitive searchExample: find the word "Online" in a messaging app DOM:
./skills/kapture-dom-erode/tools.sh gron-grep -f .tmp/page.html -q "online" -iOutput:
html[0].body[0].div[6].div[0]...div[0].span[0] = "Online"
html[0].body[0].div[6].div[0]...div[1].span[0] = "Offline"These paths are like addresses -- they tell you exactly where in the page tree each match lives.
extract-text -- erode tags, reveal contentGiven a structural path, strip away all HTML tags below that point and return just the visible text, in reading order.
./skills/kapture-dom-erode/tools.sh extract-text -f page.html -p "structural.path.here"Options:
-f, --file -- saved DOM file (JSON with "html" key, or raw HTML -- see "Saving the DOM" above)-k, --content-key -- JSON key for DOM content when using JSON input (default: html)-p, --path -- a gron-style path from gron-grep output (or a common ancestor of multiple results)Example: extract the member list from a chat sidebar:
./skills/kapture-dom-erode/tools.sh extract-text -f .tmp/page.html \
-p "html[0].body[0].div[6].div[0].div[0].div[0].div[1]"All the wrapper divs, spans, avatar markup, and CSS classes are gone. What's left is what the user sees.
The typical two-step process:
./skills/kapture-dom-erode/tools.sh gron-grep -f page.html -q "Online" -i ./skills/kapture-dom-erode/tools.sh extract-text -f page.html -p "shared.path"This works on any web app -- dashboards, messaging platforms, admin panels, documentation sites -- anything Kapture can capture.
tools.sh -- POSIX shell wrapper (handles dependencies automatically)kapture_dom_erode.py -- Python implementation (BeautifulSoup + lxml)tools.sh uses uv run to auto-install dependencies at runtime without polluting the global Python environment. Install with: curl -LsSf https://astral.sh/uv/install.sh | shThe wrapper script will exit with a clear error if uv is not found.
uv)uv run at runtime)No manual installation required.
The tool filters hidden elements detected from inline attributes only: display:none, visibility:hidden, hidden, aria-hidden="true", and common screenreader-only CSS classes. It also strips HTML comments.
Some SPAs (e.g., Canvas LMS) keep both "fulfilled" and "unfulfilled" states in the DOM and toggle visibility via external CSS class rules. Since we parse the DOM without the full stylesheet, these toggle-state templates may appear as duplicate noise in the output. If you encounter repeated template fragments, narrow your extraction path to skip the noisy container.
kapture, kapture-mcp, kapture-dom, dom-erode, dom-parse, dom-extract, tag-soup, structural-erosion, browser-automation, web-scraping, opencode-skill
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.