This page takes you from a fresh machine to a checkout that builds and passes
the checks. To install sbrs without a checkout, or for every system package a
feature needs, see Building and installing.
What you will learn
- What to install first on macOS, Linux and Windows.
- How the workspace is laid out.
- How to build the library, the command line and their features.
- How to keep builds small on a machine with little memory.
- How to run the checks, including the tests that need a real Chrome.
- How to write the generated files again, and how to build the Docker image.
At a glance
- Rust 1.99, from
rust-toolchain.toml - Library at the root, no default features
sbrsandsbrs-mcpincrates/cli- Checks: fmt, clippy, test, deny, mdbook
- Real-Chrome tests:
*_chrome.rs, one at a time
What you need#
- Rust 1.99. The workspace sets
rust-version = "1.99"inCargo.toml, andrust-toolchain.tomlpins the1.99channel withclippyandrustfmt, so rustup uses that toolchain inside the checkout. - A C compiler and linker. Some dependencies, such as
ring, compile C code. - Git, to clone the repository.
- Google Chrome or Chromium, only to run
sbrsand the tests that drive a real browser. Building needs no browser.
Nothing here needs Python. Only the parity scripts in tools/ do (Python 3.10
or newer).
Debian and Ubuntu:
Fedora:
Google Chrome’s own package works too; see Building and installing.
Open a new terminal afterwards, so the new programs are on the PATH. Clone
into a short folder such as C:\src\seleniumbase-rs: a deep target\ path can
hit the 260-character limit.
Extra packages for some features#
Most features need nothing more. These do:
| Feature | Debian and Ubuntu | macOS and Windows |
|---|---|---|
s3 | libssl-dev pkg-config | nothing |
gui | libgtk-3-dev libx11-dev libxdo-dev libxkbcommon-dev libxtst-dev libssl-dev pkg-config | nothing to build; on macOS allow the program under Accessibility at run time |
| The Tauri example | libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libgtk-3-dev libssl-dev libx11-dev libxdo-dev, and Node LTS | Node LTS (Windows also uses WebView2, which comes with Windows 10 and 11) |
Tools for the checks#
| Tool | Used for | Install |
|---|---|---|
mdbook | mdbook build | cargo install mdbook |
cargo-deny, cargo-audit | the dependency checks | cargo install cargo-deny cargo-audit |
cargo-nextest | faster test runs and the one-thread chrome test group | cargo install cargo-nextest |
just | the recipes in the justfile | cargo install just |
With mise, mise install sets up Rust 1.99, Python,
Node, mdBook, just and cargo-deny from mise.toml, and mise run gate runs the
checks a change must pass.
Get the code#
Port of seleniumbase from python to rust
Clone
Check the toolchain
Inside the checkout it should print version 1.99, which rust-toolchain.toml
selects. If rustup says that toolchain is not installed, run
rustup toolchain install 1.99.
Build and check the setup
doctor prints the SB_* settings, the browser it found, and the chromedriver
it found with its major version next to Chrome’s.
Workspace layout#
The repository is a Cargo workspace of two packages. default-members names
both, so a plain cargo build or cargo test at the root covers both.
seleniumbase-rsthe workspace root
srcthe library seleniumbase-rs: both engines, the MCP tools and the library half of the command line; no binary
crates
clithe package seleniumbase-rs-cli
src
testsintegration tests of the library
benchessee Benchmarking
examplesrunnable examples
The module map of src/ is in CLAUDE.md and in the
Developer guide.
Build#
Features#
| Package | On by default | Notes |
|---|---|---|
seleniumbase-rs (the library) | nothing | Every feature is opt-in: gui, tui, turso, playwright, plugins, ocr, visual, pdf, mcp-server, s3, azure, gcp, test-util, full-tracing, tokio-console and more. |
seleniumbase-rs-cli (sbrs, sbrs-mcp) | pdf, mcp-server, plugins-builtin | Forwards tui, gui and turso to the library, and also plugins, the plugin-* features, test-util, full-tracing and tokio-console. |
A build of both packages unifies their features, so the command line’s pdf
and mcp-server reach the library too. Use -p seleniumbase-rs to build and
test the library with its own defaults, as a project that depends on it would.
The library job in .github/workflows/ci.yml does exactly that.
sbrs-mcp needs the mcp-server feature, so a build without default features
has sbrs only. Every feature and what it costs is in
Building and installing.
Install the binaries#
Keep builds small#
A cold build compiles a large dependency tree. Three environment variables keep it within a small machine’s memory:
How many compiler processes run at once. 2 keeps memory low.
Default: "every core"
0 turns off the incremental cache in target/. sccache needs it off to
cache anything.
0 leaves debug information out of development builds: smaller files and
faster links.
Use the same values for every cargo command, so builds share their compiled artifacts instead of compiling them again.
Run one heavy cargo command at a time: cargo serialises builds in one target
directory anyway. Do not share one CARGO_TARGET_DIR between several checkouts
or worktrees of this repository: they overwrite each other’s compiled library,
and doctests then fail with “extern location does not exist”. A development
target/ with the test, bench and check artifacts grows past 10 GB.
Run the checks#
Every change must pass these, the same ones CI runs.
Format
Lint
src/mcp and src/sb_cdp are held to the stricter pedantic lint set. An
#[allow(...)] needs a reason = "...".
Test
Count failures from the exit code and the test result: lines, never from a
filtered search of the output.
Check the dependencies
Run them when Cargo.lock changed. cargo deny check reads deny.toml, where
every ignored advisory has a written reason.
Build the book
Run it when the docs changed. It writes the book to book/.
With cargo-nextest, cargo nextest run --features "mcp-server test-util"
replaces the test step, but it does not run doctests: add
cargo test --doc --features "mcp-server test-util". Code that only builds with
the results database is checked by cargo check --features turso --all-targets.
Tests that need a real Chrome#
Needs ChromeTests that start a real browser live in files named *_chrome.rs, plus
browser_smoke.rs; edge_msedgedriver.rs and firefox_geckodriver.rs drive
Edge and Firefox. They are #[ignore]d, so the default run skips them. Run them
one test binary at a time: a Chrome that is starved of CPU and memory misses its
20 second DevTools deadline.
.config/nextest.tomlputs these binaries in achrometest group with one thread, and reports a test as slow after 60 seconds (it is ended after three such periods).--run-ignored onlyruns the Edge and Firefox tests too.mise run chromerunstests/*_chrome.rs,tests/browser_smoke.rsandcrates/cli/tests/*_chrome.rsone binary at a time, and skipsplaywright_chrome.- The WebDriver tests need a chromedriver that matches Chrome:
sbrs installdownloads it intodownloaded_drivers/. The pure CDP tests need none. - As root or in a container, Chrome needs
--no-sandbox: the tests pass it whenCIis set. To run them in Docker with Chromium and Xvfb, see Run the tests in a container.
Write the generated files again#
Some files are generated. Edit their source, then write them again:
| File | Made from | Command |
|---|---|---|
completions/sbrs.usage.kdl and docs/help/cli_reference.md | the declarations in crates/cli/src/sbrs.rs | SB_UPDATE_COMPLETIONS=1 cargo test -p seleniumbase-rs-cli --bin sbrs usage_spec |
docs/parity.md | parity/api.toml | just parity-docs |
the navigation in docs/docs.json | docs/SUMMARY.md | python3 -I tools/docs7_nav.py |
docs/completions/fig-sbrs.ts | sbrs completions fig, through prettier | see docs/completions/README.md |
The usage_spec test fails when the first two are stale, and just parity-docs
fails when docs/parity.md was out of date. No test checks the Fig spec.
Make, just and mise#
The repository has the same everyday tasks in three runners. Use whichever you have.
| Task | just | make | mise |
|---|---|---|---|
| Format check | just fmt | make fmt | mise run fmt |
| Tests | just test | make test | mise run test |
| The library alone | just test-library | make test-library | - |
| Lint | just lint | make lint | mise run lint |
| Every check in a row | - | make all | mise run gate |
| Real-Chrome tests | - | - | mise run chrome |
| The book | just docs | make docs | mise run docs |
sbrs --help, --version and doctor | just smoke | make smoke | mise run smoke |
Shell completions into target/completions | just completions | make completions | - |
just lint, just test-all, just build and their make twins turn on
s3,azure,gcp,playwright,mcp-server,full-tracing,gui,tui (the justfile adds
pdf), so they need the gui and s3 system packages. They are not the CI
checks above; mise run gate is closer to those.
The Docker image#
The Dockerfile builds sbrs with Rust 1.99, without the command line’s
default features, and copies it into a debian:bookworm-slim image with
Chromium and its driver. It runs as the non-root user sbrs. More is under
Container and Deployment.
The Dockerfile caches dependencies with a skeleton step that creates an empty
file for every target the manifests declare. A new [[bin]], [[bench]],
[[example]] or [[test]], in either manifest, must be added to that step, or
the image build fails. tests/dockerfile_skeleton.rs checks it.
Working with an AI assistant#
The repository is set up for coding assistants: CLAUDE.md is the module map,
the commands and the things that have bitten before, AGENTS.md is a short rule
sheet, llms.txt indexes the docs, and rust-analyzer.toml makes analysis cover
the mcp-server and test-util features. Two optional tools make an assistant
read far less:
A code graph of the repository. Run tokensave init in the checkout; the
assistant then asks it for symbols, callers, the impact of a change, and reads
files by symbol instead of searching and reading whole files.
A command proxy that condenses the output of cargo, git and test runners
before it reaches the assistant: rtk cargo test, rtk git log. Exit codes
are unchanged.
Neither is needed to build, test or contribute. tokensave init writes its
index to .tokensave/, which the repository’s .gitignore does not list: if
git status shows it, add it to .git/info/exclude. Whoever opens the pull
request owns the result; see
Working with AI assistants.
Check this seleniumbase-rs checkout. Read CLAUDE.md first. Export CARGO_BUILD_JOBS=2 CARGO_INCREMENTAL=0 CARGO_PROFILE_DEV_DEBUG=0 and run one cargo command at a time: cargo fmt —all — —check, then cargo clippy —all-targets —features “mcp-server test-util” — -D warnings, then cargo test —features “mcp-server test-util”. Do not edit any code. Report the exit code of each command, and the passed and failed counts from the “test result” lines, not from a filtered search of the output.
Build problems#
The linker or C compiler is missing
The build stops with linker 'cc' not found or a missing link.exe. Install
the build tools for your system: xcode-select --install on macOS,
build-essential (or gcc gcc-c++ make) on Linux, and the Visual Studio 2022
Build Tools with the C++ workload on Windows. Open a new terminal afterwards.
Rust is too old, or 1.99 is missing
Cargo refuses a package that needs a newer rustc, or rustup says the 1.99
toolchain is not installed. Run rustup toolchain install 1.99 and check
rustc --version inside the checkout. Every package of the workspace needs
1.99.
The build runs out of memory
The linker is killed, or the machine stops responding. Set the three variables
from Keep builds small, lower CARGO_BUILD_JOBS further,
and stop other builds. In a 4 GB container the doctests also need
-- --test-threads=2.
Blocking waiting for file lock
Another cargo command is building in the same target directory. Wait for it, or
stop it. rust-analyzer checks into a target directory of its own
(targetDir = true in rust-analyzer.toml), so it does not hold this lock.
extern location does not exist
Two checkouts share one CARGO_TARGET_DIR and overwrote each other’s compiled
library. Give each checkout its own target directory, and do not cargo clean a
target directory that another build is using.
The gui or s3 feature fails on Linux
A missing system library: gui links GTK and X11, and s3 needs OpenSSL. Install
the packages from Extra packages for some features.
The first build fails without a network
A first build downloads crates from crates.io, and the plugin crates from
GitHub. Run cargo fetch while you are online; later builds can then use
--offline.
A test says a generated file is stale
Write the file again with the command from Write the generated files again and commit the result with your change.
A manifest test or the Docker build fails
tests/dockerfile_skeleton.rs fails, or the image build stops, after you added
a [[bin]], [[bench]], [[example]] or [[test]]: list it in the skeleton
step of the Dockerfile. tests/library_manifest.rs fails when a command-line
crate is in the library’s [dependencies]: it belongs in
crates/cli/Cargo.toml.
More system-specific notes are in Operating systems.