CLI
ThinkRun exposes both the legacy browse.sh surface and the modern typed thinkrun CLI. The typed CLI is the product default and is kept in strict parity with the MCP browser surface for local browser work.
Setup
Mode is auto-detected: if the native host is running (Chrome must be open with the extension), it uses local mode. Otherwise it falls back to cloud mode with an API key.
# Cloud mode export THINKRUN_API_KEY=your-api-key # Local mode (auto-detected if native host is running) # Just open Chrome with the ThinkRun extension — no server to start export THINKRUN_LOCAL=true # optional: force local mode
Dependencies: curl, jq
If using the typed CLI against a local mech-browser-service endpoint, use that server's TEST_API_KEY and run thinkrun doctor for diagnostics.
Environment Variables
THINKRUN_API_KEYAPI key for cloud mode authentication(required for cloud)THINKRUN_LOCALForce local mode (skip cloud fallback)falseTHINKRUN_BRIDGE_PORTOverride native host port (auto-discovered from ~/.thinkbrowse/port)autoTHINKRUN_URLCloud API base URL overridehttps://mech-browser-service.fly.devTHINKRUN_TAB_IDTarget a specific Chrome tab ID for all action commands (overridden by --tab flag; overrides the current attached agent-scoped working-location file)(unset)Config file: ~/.config/thinkrun/config.json (alternative to env vars for API key)
Session Management
session-createCreate a new browser session. Prints session ID to stdout. Cloud mode polls up to 120s for machine provisioning.
browse session-createsession-statusGet session details (local: bridge health, cloud: session metadata).
browse session-status <sid>session-artifactsList artifacts (screenshots, recordings, actions) for a session.
browse session-artifacts <sid>doctorDiagnose endpoint, auth, and session setup (Typed CLI only).
thinkrun doctorsession debugInspect local continuity, ownership, working-location, and live bridge recovery state before re-attaching or retrying.
thinkrun session debug [--json]reset-connectionRe-arm the extension circuit breaker after a false trip (idempotent). See doctor output for when to use this.
thinkrun reset-connection [--json]session-deleteClose the session and free resources.
browse session-delete <sid>Navigation
gotoNavigate to a URL. Waits for page load.
browse goto <sid> <url>scrollScroll the page. Default: down 500px.
browse scroll <sid> [up|down] [pixels]scroll (typed CLI)Local/cloud typed CLI: pixel scroll requires positive integers for --down/--up; retries transient bridge failures then may fall back to a safe evaluate scroll.
thinkrun scroll --down <px>|--up <px>|--direction up|down [--amount <px>]|--to <selector>Observation
snapshotGet accessibility tree / DOM snapshot of the current page.
browse snapshot <sid>screenshotCapture a screenshot (base64 JSON in cloud, raw data in local).
browse screenshot <sid>extractExtract page content as plain text or HTML.
browse extract <sid> [text|html]Interaction
clickClick an element matching the CSS selector.
browse click <sid> <selector>fillFill a form field (clears existing value first).
browse fill <sid> <selector> <value>typeType text into an element (appends to existing value).
browse type <sid> <selector> <text>pressPress a keyboard key (Enter, Tab, Escape, ArrowDown, etc).
browse press <sid> <key>hoverHover over an element to trigger hover states.
browse hover <sid> <selector>selectSelect a dropdown option by value.
browse select <sid> <selector> <value>waitWait for an element to appear. Default timeout: 10000ms.
browse wait <sid> <selector> [timeout_ms]evaluateExecute JavaScript on the page and return the result.
browse evaluate <sid> <javascript>Tab Management (Local Mode)
tabsList all open Chrome tabs (id, url, title, active).
thinkrun tabsnew-tabOpen a new local browser tab without rebinding the attached session.
thinkrun new-tab [url]close-tabClose a local browser tab. Defaults to the attached tab when tabId is omitted.
thinkrun close-tab [tabId]attachRegister agent session and set tab as active for subsequent commands. Re-attaching to the same live tab is idempotent for the same controller lineage (the same agent and control-session ownership chain for that tab); see the recovery docs for ownership conflicts and bridge failures such as BRIDGE_UNREACHABLE. Uses fire-and-forget cloud session registration (local-init) if API key is set.
thinkrun attach <tabId>switch-tabSwitch the extension's active Chrome tab (does not change CLI session config). Same bridge errors as attach.
thinkrun switch-tab <tabId>focusBring the Chrome window for the currently attached tab to the foreground (same bridge call as switch-tab for the session tab).
thinkrun focusnew-windowOpen an isolated Chrome window and auto-attach to it. Uses fire-and-forget cloud session registration if API key is set.
thinkrun new-window [url] [--no-focus]releaseRelease local tab ownership for this process (or named group), clear local context, best-effort unregister the native-host session, and call local-close with status=completed so the session appears as finished in the Activity Feed.
thinkrun release [--group <name>]Screenshot captions: when a local tab is synced to ThinkRun, thinkrun screenshot requires --caption <text> so the dashboard shows the intended meaning of the capture.
Tab targeting without attach: All action commands accept -t/--tab <tabId> to target a specific Chrome tab directly without running attach first. Priority: --tab flag > THINKRUN_TAB_ID env var > agent-scoped working-location file (from attach, under ~/.thinkrun/working-locations/<agentId>.json). Lock safety: commands are blocked if another live agent owns the tab.
Recovery contract: If the remembered tab was closed, commands fail with TAB_NOT_FOUND and clear stale continuity so the next step is thinkrun tabs followed by thinkrun attach <tabId>. If ownership looks inconsistent, run thinkrun session debug --json before re-attaching so you can distinguish a same-controller repair from a true foreign-owner block.
Agent Identity
Run once per agent before the first attach or new-window call. The generated agentId (prefixed agt_) is persisted to ~/.thinkrun/agent.json and used for tab lock ownership and the Activity Feed.
agent-initGenerate and persist a stable agent identity. Registers with ThinkRun cloud if an API key is set.
thinkrun agent-init [--name <name>] [--reset] [--show]Alternative: set THINKRUN_AGENT_ID=agt_... to override the file-based identity.
Retry Behavior
Both modes automatically retry transient errors with exponential backoff (1s, 2s, 4s).
retryable: true responses. Max 4 attempts.snapshot, extract, title, html, and screenshot can survive a short reconnect window on the same bridge. Arbitrary evaluate and mutating commands are not blindly replayed after transport loss; if the request may already have left the process, the CLI tells you to verify page state before retrying. The native host port in ~/.thinkbrowse/port may change after reconnect, so the CLI re-probes health and may refresh the port once on transport errors. It still fails fast on TAB_NOT_FOUND and true ownership conflicts.Local Workflow Recovery
Bridge reconnecting: EXTENSION_NOT_CONNECTED or EXTENSION_DISCONNECTED means the extension/native-host transport is unhealthy. Safe reads may retry automatically after a live health probe; if the bridge stays unstable, run thinkrun doctor first for bridge state, then thinkrun session debug --json if you still need continuity or ownership details.
Transport unavailable: NATIVE_HOST_UNREACHABLE means the CLI could not complete the route after revalidation. Safe reads are retried automatically before this error is surfaced. For evaluate or other mutating actions, treat the outcome as potentially ambiguous and verify page state before retrying.
Ownership conflict: TAB_OWNED_BY_OTHER_SESSION is not the same as a bridge disconnect. Run thinkrun session debug --json first. If the same controller lineage still owns the tab, re-attach only to rebuild local authority. If a different live owner holds the tab, use thinkrun new-window or wait for that owner to release it.
Closed remembered tab: TAB_NOT_FOUND means the stored tab binding is stale, not that you should keep retrying. Choose a live tab with thinkrun tabs, then attach again.
Example Workflow
# Create session and navigate SID=$(browse session-create) browse goto "$SID" "https://example.com" # Observe browse snapshot "$SID" browse extract "$SID" text # Interact browse click "$SID" "a[href]" browse fill "$SID" "input[name=q]" "search term" browse press "$SID" "Enter" # Clean up browse session-delete "$SID"
Typed CLI (thinkrun)
The modern, typed CLI. Install: npm install -g @thinkrun/cli
Agent / CI Mode (--json)
Pass --json or pipe stdout to get machine-readable NDJSON output. JSON mode auto-enables when stdout is not a TTY (piped or redirected).
# Success → stdout:
{"success":true,"command":"navigate","durationMs":842,"data":{"url":"https://example.com","title":"Example"}}
# Error → stderr (exit 1):
{"success":false,"command":"click","error":"Element not found","code":"ELEMENT_NOT_FOUND","hint":"Run: thinkrun snapshot","retryable":true}AI Tasks (Local Mode)
Delegate multi-step tasks to the native host AI loop. Requires an active local tab session.
taskRun AI task. Blocks until done by default. --async returns taskId immediately. --stream emits SSE events as NDJSON.
thinkrun task <instruction> [--async] [--stream] [--timeout <ms>] [--max-iterations <n>]task-statusPoll status of a running or completed AI task.
thinkrun task-status <taskId>task-cancelCancel a running AI task.
thinkrun task-cancel <taskId>Run thinkrun attach <tabId> before using task commands.
Quick Setup
# Installation npm install -g @thinkrun/cli # Cloud setup thinkrun config set apiKey YOUR_KEY thinkrun doctor # Cloud session thinkrun cloud start thinkrun navigate https://example.com thinkrun snapshot thinkrun cloud stop # Local session (optional: persist agent identity first) thinkrun agent-init --name "my-agent" # generates agt_ id, registers with cloud thinkrun tabs thinkrun attach <tabId> thinkrun navigate https://example.com thinkrun screenshot --caption "Sign-in page before entering credentials" thinkrun task "click the Sign In button" thinkrun release # releases lock + closes cloud session # Target a specific tab without attach (--tab flag) thinkrun navigate --tab 656849988 https://example.com thinkrun screenshot --tab 656849988 --caption "Top story on Hacker News" --output /tmp/shot.png # Or set once for the shell session: export THINKRUN_TAB_ID=656849988
Page Cache (Stateless)
Fetch HTML, extract text, or capture a screenshot for any URL without creating a browser session. Cloud mode consumes credits (HTML/text: 1, screenshot: 3). Local mode is free. Force local-only with --sensitive to prevent third-party fetches.
# Installed package thinkrun cache html https://example.com thinkrun cache html https://example.com --provider local # Extract plain text thinkrun cache text https://example.com # Capture screenshot thinkrun cache screenshot https://example.com --full-page --max-dimension 1920 thinkrun cache screenshot https://example.com --provider cloud # From repo (development) bun run packages/cli/bin/thinkrun.ts cache html https://example.com bun run packages/cli/bin/thinkrun.ts cache screenshot https://example.com --full-page # Common options (all subcommands) # --provider cloud|local provider selection (default: cloud when billing is configured) # --sensitive force local-only (URL not sent to third parties) # --timeout <ms> navigation timeout (default: 30000, max: 60000) # --wait-for <value> load | domcontentloaded | networkidle | positive ms # --full-page full scrollable page capture (screenshot only) # --max-dimension <px> resize longest edge to N pixels (screenshot only)
CLI action sync: When an API key is configured, all browser actions (navigate, click, type, screenshot, etc.) are synced fire-and-forget to the cloud session action log via POST /api/sessions/:id/local-sync/action. This means the dashboard Activity Feed shows a live action log for CLI sessions — not just screenshots.