Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
R

rodney

> 编程语言
Open source

CLI tool for interacting with the web

744 stars0 likes1 views
WebsiteGitHub

About

CLI tool for interacting with the web

Rodney: Chrome automation from the command line

A Go CLI tool that drives a persistent headless Chrome instance using the rod browser automation library. Each command connects to the same long-running Chrome process, making it easy to script multi-step browser interactions from shell scripts or interactive use.

Architecture

rodney start          →  launches Chrome (headless, persists after CLI exits)
                          saves WebSocket debug URL to ~/.rodney/state.json

rodney connect H:P    →  connects to an existing Chrome on a remote debug port
                          saves WebSocket debug URL to ~/.rodney/state.json

rodney open URL       →  connects to running Chrome via WebSocket
                          navigates the active tab, disconnects

rodney js EXPR        →  connects, evaluates JS, prints result, disconnects

rodney stop           →  connects and shuts down Chrome, cleans up state

Each CLI invocation is a short-lived process. Chrome runs independently and tabs persist between commands.

Building

bash
go build -o rodney .

Requires:

  • Go 1.21+
  • Google Chrome or Chromium installed (or set ROD_CHROME_BIN=/path/to/chrome)

Usage

Start/stop the browser

bash
rodney start              # Launch headless Chrome
rodney start --show       # Launch with visible browser window
rodney start --insecure   # Launch with TLS errors ignored (-k shorthand)
rodney connect host:9222  # Connect to existing Chrome on remote debug port
rodney status             # Show browser info and active page
rodney stop               # Shut down Chrome

Navigate

bash
rodney open https://example.com    # Navigate to URL
rodney open example.com            # http:// prefix added automatically
rodney back                        # Go back
rodney forward                     # Go forward
rodney reload                      # Reload page
rodney reload --hard               # Reload bypassing cache
rodney clear-cache                 # Clear the browser cache

Extract information

bash
rodney url                    # Print current URL
rodney title                  # Print page title
rodney text "h1"              # Print text content of element
rodney html "div.content"     # Print outer HTML of element
rodney html                   # Print full page HTML
rodney attr "a#link" href     # Print attribute value
rodney pdf output.pdf         # Save page as PDF

Run JavaScript

bash
rodney js document.title                        # Evaluate expression
rodney js "1 + 2"                               # Math
rodney js 'document.querySelector("h1").textContent'  # DOM queries
rodney js '[1,2,3].map(x => x * 2)'            # Returns pretty-printed JSON
rodney js 'document.querySelectorAll("a").length'     # Count elements

The expression is automatically wrapped in () => { return (expr); }.

Interact with elements

…

Wait for conditions

bash
rodney wait ".loaded"       # Wait for element to appear and be visible
rodney waitload             # Wait for page load event
rodney waitstable           # Wait for DOM to stop changing
rodney waitidle             # Wait for network to be idle
rodney sleep 2.5            # Sleep for N seconds

Screenshots

bash
rodney screenshot                         # Save as screenshot.png
rodney screenshot page.png                # Save to specific file
rodney screenshot -w 1280 -h 720 out.png  # Set viewport width/height
rodney screenshot-el ".chart" chart.png   # Screenshot specific element

Manage tabs

bash
rodney pages                    # List all tabs (* marks active)
rodney newpage https://...      # Open URL in new tab
rodney page 1                   # Switch to tab by index
rodney closepage 1              # Close tab by index
rodney closepage                # Close active tab

Query elements

bash
rodney exists ".loading"    # Exit 0 if exists, exit 1 if not
rodney count "li.item"      # Print number of matching elements
rodney visible "#modal"     # Exit 0 if visible, exit 1 if not
rodney assert 'document.title' 'Home'  # Exit 0 if equal, exit 1 if not
rodney assert 'document.querySelector("h1") !== null'  # Exit 0 if truthy

Accessibility testing

bash
rodney ax-tree                           # Dump full accessibility tree
rodney ax-tree --depth 3                 # Limit tree depth
rodney ax-tree --json                    # Output as JSON

rodney ax-find --role button             # Find all buttons
rodney ax-find --name "Submit"           # Find by accessible name
rodney ax-find --role link --name "Home" # Combine filters
rodney ax-find --role button --json      # Output as JSON

rodney ax-node "#submit-btn"             # Inspect element's a11y properties
rodney ax-node "h1" --json               # Output as JSON

These commands use Chrome's Accessibility CDP domain to expose what assistive technologies see. ax-tree uses getFullAXTree, ax-find uses queryAXTree, and ax-node uses getPartialAXTree.

bash
# CI check: verify all buttons have accessible names
rodney ax-find --role button --json | python3 -c "
import json, sys
buttons = json.load(sys.stdin)
unnamed = [b for b in buttons if not b.get('name', {}).get('value')]
if unnamed:
    print(f'FAIL: {len(unnamed)} button(s) missing accessible name')
    sys.exit(1)
print(f'PASS: all {len(buttons)} buttons have accessible names')
"

Directory-scoped sessions

By default, Rodney stores state globally in ~/.rodney/. You can instead create a session scoped to the current directory with --local:

bash
rodney start --local          # State stored in ./.rodney/state.json
                              # Chrome data in ./.rodney/chrome-data/
rodney open https://example.com   # Auto-detects local session
rodney stop                       # Cleans up local session

This is useful when you want isolated browser sessions per project — each directory gets its own Chrome instance, cookies, and state.

Auto-detection: When neither --local nor --global is specified, Rodney checks for ./.rodney/state.json in the current directory. If found, it uses the local session; otherwise it falls back to the global ~/.rodney/ session.

bash
# Force global even when a local session exists
rodney --global open https://example.com

# Force local (errors if no local session)
rodney --local status

The --local and --global flags can appear anywhere in the command:

bash
rodney --local start
rodney start --local          # Same effect
rodney open --global https://example.com

Add .rodney/ to your .gitignore to keep session state out of version control.

Shell scripting examples

bash
# Wait for page to load and extract data
rodney start
rodney open https://example.com
rodney waitstable
title=$(rodney title)
echo "Page: $title"

# Conditional logic based on element presence
if rodney exists ".error-message"; then
    rodney text ".error-message"
fi

# Loop through pages
for url in page1 page2 page3; do
    rodney open "https://example.com/$url"
    rodney waitstable
    rodney screenshot "${url}.png"
done

rodney stop

Exit codes

Rodney uses distinct exit codes to separate check failures from errors:

Exit code Meaning
0 Success
1 Check failed — the command ran successfully but the condition/assertion was not met
2 Error — something went wrong (bad arguments, no browser session, timeout, etc.)

This makes it easy to distinguish between "the assertion is false" and "the command couldn't run" in scripts and CI pipelines.

Using Rodney for checks

Several commands return exit code 1 when a condition is not met, making them useful as assertions in shell scripts and CI pipelines. All of these print their result to stdout and exit cleanly — no error message is written to stderr.

exists — check if an element exists in the DOM

bash
rodney exists "h1"
# Prints "true", exits 0

rodney exists ".nonexistent"
# Prints "false", exits 1

visible — check if an element is visible

bash
rodney visible "#modal"
# Prints "true" and exits 0 if the element exists and is visible

rodney visible "#hidden-div"
# Prints "false" and exits 1 if the element is hidden or doesn't exist

ax-find — check for accessibility nodes

bash
rodney ax-find --role button --name "Submit"
# Prints the matching node(s), exits 0

rodney ax-find --role banner --name "Nonexistent"
# Prints "No matching nodes" to stderr, exits 1

assert — assert a JavaScript expression

With one argument, checks that the expression is truthy. With two arguments, checks that the expression's value equals the expected string. Use --message / -m to set a custom failure message.

…

The expression is evaluated the same way as rodney js — the result is converted to its string representation before comparison. This means rodney assert 'document.title' 'Dashboard' compares the unquoted string, and rodney assert '1 + 2' '3' compares the number as a string.

Use --message (or -m) to add a human-readable description to the failure output:

bash
rodney assert 'document.querySelector(".logged-in")' -m "User should be logged in"
# On failure: "fail: User should be logged in (got null)"

rodney assert 'document.title' 'Dashboard' --message "Wrong page loaded"
# On failure: 'fail: Wrong page loaded (got "Home", expected "Dashboard")'

Combining checks in a shell script

You can chain these together in a single script to run multiple assertions. Because check failures use exit code 1 while real errors use exit code 2, you can use set -e to abort on errors while handling check failures explicitly:

…

This pattern is useful in CI — run Rodney as a post-deploy check, an accessibility audit, or a smoke test against a staging environment. Because exit code 2 signals an actual error (e.g. Chrome didn't start), set -e will abort the script immediately if something is broken rather than reporting a misleading test failure.

Configuration

Environment Variable Default Description
RODNEY_HOME ~/.rodney Data directory for state and Chrome profile
ROD_CHROME_BIN /usr/bin/google-chrome Path to Chrome/Chromium binary
ROD_TIMEOUT 30 Default timeout in seconds for element queries
HTTPS_PROXY / HTTP_PROXY (none) Authenticated proxy auto-detected on start

Global state is stored in ~/.rodney/state.json with Chrome user data in ~/.rodney/chrome-data/. When using --local, state is stored in ./.rodney/state.json and ./.rodney/chrome-data/ in the current directory instead. Set RODNEY_HOME to override the default global directory.

Proxy support

In environments with authenticated HTTP proxies (e.g., HTTPS_PROXY=http://user:pass@host:port), rodney start automatically:

  1. Detects the proxy credentials from environment variables
  2. Launches a local forwarding proxy that injects Proxy-Authorization headers into CONNECT requests
  3. Configures Chrome to use the local proxy

This is necessary because Chrome cannot natively authenticate to proxies during HTTPS tunnel (CONNECT) establishment. The local proxy runs as a background process and is automatically cleaned up by rodney stop.

See claude-code-chrome-proxy.md for detailed technical notes.

How it works

The tool uses the rod Go library which communicates with Chrome via the DevTools Protocol (CDP) over WebSocket. Key implementation details:

  • start uses rod's launcher package to start Chrome with Leakless(false) so Chrome survives after the CLI exits
  • Proxy auth handled via a local forwarding proxy that bridges Chrome to authenticated upstream proxies
  • **State

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

Go

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言