This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
mdbrowser is a CLI tool that converts webpages to clean markdown. It supports Chrome cookie authentication, headless browser rendering for SPAs, and interactive browser sessions.
No build step. No test suite. No linter. Run directly with Node:
node src/cli.js <url> # basic fetch
node src/cli.js <url> --chrome --render # authenticated SPA
node src/cli.js open <url> # interactive sessionInstall after dependency changes: npm install
cli.js (entry, arg parsing, routing)
├─ fetch.js HTTP fetch with cookie injection
├─ render.js Puppeteer headless rendering
├─ convert.js Defuddle HTML→Markdown + metadata extraction
├─ cookies.js Chrome cookie DB decryption (macOS only)
├─ cache.js SHA-256 keyed file cache in /tmp/mdbrowser-cache/
├─ session.js Detached browser process, WebSocket reconnection
├─ act.js Interactive commands (open/click/type/read/close)
└─ interact.js ARIA snapshot traversal + DOM fallback for elements
Two main flows:
- Single fetch —
cli.js→processUrl()→fetch.js/render.js→convert.js→ output - Interactive session —
cli.js→act.js→session.js(persistent detached Chrome) →interact.jsfor element discovery
- ES Modules throughout (
"type": "module"in package.json). Useimport/export. - Lazy dynamic imports for optional deps (
puppeteer,better-sqlite3,./act.js). These are loaded only when the relevant flag is used, keeping startup fast. - stdout for content, stderr for diagnostics — token counts, cache hits, warnings go to stderr. Markdown/JSON output goes to stdout.
--no-*flags are pre-filtered fromprocess.argvbeforeparseArgsbecause Node's negation support varies by version.- Console suppression —
console.warnandconsole.logare temporarily replaced during Defuddle calls to suppress its noisy output. - Session persistence — interactive mode stores WebSocket endpoint + target ID in
/tmp/mdbrowser-session.json. The browser runs as a detached process that survives the CLI exiting. - File permissions — cache files and session files use
0o600(owner-only). htmlToMarkdownis async and returns{ markdown, meta }, not a plain string.
error()helper writes to stderr withmdbrowser:prefix- Cookie strings use format
"name1=value1; name2=value2" - Element refs are 1-indexed integers; text targets use
::-p-text()Puppeteer selectors - Cache keys include URL + flags (raw/render/selector) to avoid collisions