agentleFS
dundasdundas/thinkrun/.cursor/skills/thinkbrowse-cli/SKILL.md

thinkbrowse-cli

Skill2 starsChanged 54 days agoMITView on GitHub

Control browsers via the ThinkBrowse CLI (the thinkbrowse / thinkrun command) — navigate pages, interact with elements, extract content, take screenshots. Use ONLY when the user explicitly names the thinkbrowse or thinkrun CLI, or asks to drive the browser from shell scripts / terminal commands. For general browse, scrape, or automation asks that don't name the CLI, prefer the web-browse skill. Do NOT use for simple URL fetching (use WebFetch tool instead).

  • Reads credentials
  • Installs packages

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 1 is distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    All commands return JSON:

    line 154
  2. Very specific:

    Use --tab <tabId> on every command to prevent tab contention:

    line 182

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

ThinkBrowse CLI

Control real browsers from Claude Code using the thinkbrowse CLI. Two modes:

  • Local mode — drives your actual Chrome via the ThinkBrowse extension (free, auth cookies available)
  • Cloud mode — provisions isolated Playwright browsers on Fly.io (credits, headless, stealth)

Quick Start

# Local mode — list tabs, attach, navigate, observe
thinkbrowse tabs
thinkbrowse attach <tabId>
thinkbrowse navigate "https://example.com"
thinkbrowse snapshot              # accessibility tree (best for AI)
thinkbrowse screenshot --output /tmp/page.png

# Cloud mode — create session, navigate, observe, clean up
thinkbrowse cloud start "https://example.com"
thinkbrowse snapshot
thinkbrowse screenshot --output /tmp/page.png
thinkbrowse cloud stop --all

Mode Detection

SignalMode
Bridge running + extension connectedLocal
THINKBROWSE_API_KEY setCloud
NeitherError

Priority: --tab flag > THINKBROWSE_TAB_ID env > working-location.json > API key (cloud).

Top 5 Patterns

1. Navigate and Observe

thinkbrowse navigate "https://example.com"
sleep 2                                    # Wait for page load + CSRF tokens
thinkbrowse snapshot                       # Read structure before interacting
thinkbrowse screenshot --output /tmp/page.png
# Then use Read tool on /tmp/page.png to view it

2. Click by Text Content (RECOMMENDED)

Direct CSS selectors often fail when elements lack unique selectors. Use evaluate:

thinkbrowse evaluate "[...document.querySelectorAll('button,a,[role=button]')].find(el=>el.textContent.trim()==='Sign In')?.click()"
sleep 1

3. Fill React Forms

# React inputs need keyboard events — use `type`, NOT `fill`
thinkbrowse click "input[type=email]"
thinkbrowse type "input[type=email]" "user@example.com"
thinkbrowse click "input[type=password]"
thinkbrowse type "input[type=password]" "password123"
thinkbrowse click "button[type=submit]"
sleep 3

4. List All Interactive Elements

thinkbrowse evaluate "[...document.querySelectorAll('button,[role=tab],[role=button]')].map(b=>({label:b.getAttribute('aria-label'),text:b.textContent.trim(),class:b.className.slice(0,50)})).filter(b=>b.text||b.label)"

5. Wait Then Act

thinkbrowse navigate "https://app.example.com"
thinkbrowse wait "button[type=submit]" --timeout 10000
thinkbrowse click "button[type=submit]"

For all 10+ patterns, see references/patterns.md.

Top 5 Anti-Patterns

1. Using text as a CSS selector

# BAD — "Timeline & Logs" is not a CSS selector
thinkbrowse click "Timeline & Logs"     # ELEMENT_NOT_FOUND

# GOOD — find by text via evaluate
thinkbrowse evaluate "[...document.querySelectorAll('button')].find(b=>b.textContent.includes('Timeline'))?.click()"

2. Using fill on React inputs

# BAD — fill uses native DOM, React won't detect the change
thinkbrowse fill "#search" "query text"

# GOOD — type uses keyboard events, triggers React onChange
thinkbrowse type "#search" "query text"

3. Screenshotting immediately after attach

# BAD — screenshot fails with "fetch failed"
thinkbrowse attach <tabId>
thinkbrowse screenshot --output /tmp/page.png   # ERROR

# GOOD — wait for connection
thinkbrowse attach <tabId>
sleep 2
thinkbrowse screenshot --output /tmp/page.png

4. Clicking a link without waiting for navigation

# BAD — extract runs before new page loads
thinkbrowse click "a[href='/next-page']"
thinkbrowse extract ".content"           # OLD page content!

# GOOD — wait for new page element
thinkbrowse click "a[href='/next-page']"
thinkbrowse wait "h1" --timeout 5000
thinkbrowse extract ".content"

5. Not cleaning up sessions

# ALWAYS release/stop when done
thinkbrowse release                # local mode
thinkbrowse cloud stop --all       # cloud mode

Output Format

All commands return JSON:

{"success": true, "command": "navigate", "durationMs": 1234, "data": {...}}
{"success": false, "error": "...", "code": "ELEMENT_NOT_FOUND", "hint": "...", "retryable": true}

Key gotchas:

  • thinkbrowse url returns {"data": "https://..."} — plain string, NOT nested object
  • thinkbrowse screenshot --output /tmp/x.png returns {"data": {"path": "/tmp/x.png"}} — use Read tool on that path to view it
  • evaluate auto-wraps single expressions; multi-statement needs IIFE: (()=>{const x=5; return x*2})()
  • evaluate does NOT await Promises — async operations return {}
  • Scroll has no effect on fixed-layout pages — screenshot after to verify
  • Protected iframes (Stripe, OAuth) return {"blocked": true, "handoffRequired": true} — stop automation

Timing Guidelines

ActionWait After
navigatesleep 2 (page load + CSRF)
clicksleep 1 (state change)
type / fillNo wait needed
attach (new tab)sleep 2 (connection)
evaluate (click)sleep 1
scrollsleep 1 (rendering)

Multi-Agent Coordination

Use --tab <tabId> on every command to prevent tab contention:

thinkbrowse navigate "https://site-a.com" --tab 12345
thinkbrowse navigate "https://site-b.com" --tab 67890

Or: export THINKBROWSE_TAB_ID=12345

Setup & Diagnostics

thinkbrowse doctor                        # Check bridge, extension, config
thinkbrowse config show                   # Show current config
thinkbrowse config set apiKey <key>       # Set API key for cloud mode
thinkbrowse agent-init [--name <name>]    # Set agent identity

References

  • For complete command reference, see references/command-reference.md
  • For all 10+ patterns and additional gotchas, see references/patterns.md
  • For error codes and recovery playbooks, see references/error-recovery.md

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.