Browser4
platonai/Browser4/AGENTS.md
Repo: https://github.com/platonai/Browser4 handleCommandBatch() → handleBatchTool() in MCPToolController. CLI's compilebatchrequest() builds step arrays with op: "tool". preFocusSelector only added for keydown/keyup (not fill/type/press). Any method that implements behavior by calling CDP directly (or by evaluating JavaScript that synthesizes browser events) — drag, press, click, dialog handling, screenshots, scroll, storage restore, etc. — must satisfy ALL of the following before it is considered done. "It works on my machine" is not sufficient; each gate below has burned this project before. 1. Anti-bot…
- Reads credentials
- Installs packages
What's in it
- Repository Guidelines
- Architecture
- Dispatch chain (CLI → browser)
- Batch commands
- Known CDP pitfalls
- Direct CDP methods: mandatory review gates
- Project Structure
- Development Environment (Running from Source)
- Invocation wrappers
- First-run latency from a source tree
- Prerequisites for development
- Running the CLI from source
- Output Redirection in Dev Mode
- Build & Test
- Quick commands
- E2E test filtering
- Test locations
- Code Style
- Kotlin
- Logging
- Naming
- Testing Guidelines
- Configuration
- Development Patterns
- CLI command naming: spaced form preferred
- Adding a browser4-cli command
- REST-based commands (swarm, crawl)
- Snapshot-related commands
- Modifying install/uninstall/upgrade code
- PowerShell Cross-Platform Compatibility
# Repository Guidelines
Repo: https://github.com/platonai/Browser4
## Architecture
```
browser4-cli (Rust) ──MCP over HTTP──▶ browser4-rest (Kotlin/Spring) ──▶ PulsarWebDriver (Kotlin/CDP)
▲ │
│ ▼
└──── e2e tests ────▶ Fixture HTTP server (Rust test harness)
```
- **CLI:** `cli/browser4-cli/` — Rust binary, MCP tool calls over HTTP
- **Backend:** `browser4-rest/` — Spring Boot, `MCPToolController` dispatches tools
- **Browser driver:** `browser4-core/browser4-browser/` — `PulsarWebDriver` wraps CDP
- **Agent tools:** `browser4-agentic/` — `AgentToolManager` maps MCP tool names → driver methods
### Dispatch chain (CLI → browser)
1. CLI builds MCP tool call: `{tool: "browser_type", arguments: {ref: "#el", text: "hi"}}`
2. `MCPToolController.callTool()` → `dispatchToToolExecutor()`
3. `normalizeFrontendToolCall()` applies `FRONTEND_TOOL_NAME_ALIASES` (e.g., `browser_type` → `fill`)
4. `DefaultArgumentNormalizer` maps `ref` → `selector`, strips `sessionId`, converts snake_case
5. `resolveMcpToolCall()` → `ToolCall("tab", "fill", args)`
6. `AgentToolManager.execute()` → `executor.callFunctionOn(toolCall, driver)` → `PulsarWebDriver.fill()`
### Batch commands
`handleCommandBatch()` → `handleBatchTool()` in `MCPToolController`. CLI's `compile_batch_request()` builds step arrays with `op: "tool"`. `preFocusSelector` only added for `keydown`/`keyup` (not fill/type/press).
### Known CDP pitfalls
- **crbug.com/444929150:** `Input.dispatchMouseEvent` type `mouseWheel` race condition in headless Chrome. Fix: dispatch to `{passive: false}` wheel listener.
- **Cursor positioning:** `DOM.focus()` + `Input.dispatchMouseEvent` (click) may leave cursor at 0. Fix: `setSelectionRange(99999, 99999)` after focus+click.
- **`Input.insertText` racing:** 0ms delay between chars drops `input` events. Fix: use same inter-char delay as `type()` via `randomDelayMillis("type")` (90-240ms).
### Direct CDP methods: mandatory review gates
Any method that implements behavior by calling CDP directly (or by evaluating
JavaScript that synthesizes browser events) — `drag`, `press`, `click`, dialog
handling, screenshots, scroll, storage restore, etc. — must satisfy ALL of the
following before it is considered done. "It works on my machine" is not
sufficient; each gate below has burned this project before.
1. **Anti-bot detection** — the page can observe the automation, and many sites
actively fingerprint it. Consider:
- `event.isTrusted` is `false` for JS-synthesized events; if a trusted path
exists (CDP `Input.*`, `userGesture=true`), prefer it or document why not.
- Fixed inter-event delays and exact element-center coordinates are
fingerprints; randomize delays (via `randomDelayMillis` or an equivalent
bucket) and jitter coordinates like real input would.
- The full input story: real drags/clicks have trusted `mousedown` →
`mousemove` → `mouseup` context; a synthetic event sequence with no
trusted accompaniment is itself detectable.
2. **Negative impact** — check the failure modes, not just the happy path:
- No silent failures: a method must fail loudly rather than dispatch onto
an unrelated element (occlusion, `pointer-events:none`, layout shift,
frames). Validate before dispatching so retries stay idempotent.
- Error messages must surface the real cause to the CLI/user instead of
being swallowed or wrapped by retry machinery.
- Retry safety: blocks inside `invokeOnPage`/`invokeOnElement` must be
idempotent or the deterministic failures must bypass the retry.
- Don't regress error semantics of the upstream method you override.
3. **Cross-platform compatibility** — headless vs GUI Chrome, Docker/CI,
Windows/Linux/macOS all behave differently:
- Scroll commits and layout updates are asynchronous (`scrollIntoViewIfNeeded`
may prefer smooth animation); poll for the observable state instead of
assuming a single read is current.
- Event dispatch timing, renderer scheduling, and viewport geometry differ
under load and in containers; never rely on a single hardcoded delay.
- CDP API availability varies by Chrome version; provide fallbacks or
explicit errors, never a silent no-op.
4. **Real-webpage testing** — unit tests alone are insufficient:
- Add a fixture page (under
`browser4-tests/pulsar-tests-common/src/main/resources/static/b4/`) that
exercises the real behavior: event order, payloads, occluded/disabled/
off-viewport/frame targets, async layout changes.
- Prove it against a real browser through the e2e harness
(`cargo test --test e2e -- --scenario=...`, `requires_browser4: true`),
not only against mocks.
## Project Structure
| Module | Description |
|---|---|
| `browser4-core` | Core engine: sessions, scheduling, DOM, browser control |
| `browser4-dependencies` | BOM and dependency alignment |
| `browser4-tools` | Operational tools and launch helpers |
| `browser4-agentic` | AI agents, MCP, skill registration |
| `browser4-agent-tools` | High-level agent tools: scraping, crawling, stateful page interaction |
| `browser4-rest` | Spring Boot REST layer & command endpoints |
| `cli/browser4-cli` | Rust CLI binary |
| `skills/browser4-cli` | AI agent skill definitions |
| `browser4-apps/browser4-standalone` | Product packaging, unified launcher (`target/Browser4.jar`) |
| `examples/browser4-examples` | Runnable examples |
| `browser4-tests` | E2E, integration, scenario tests |
| `browser4-tests/pulsar-tests-common` | Shared test base classes and utilities |
| `cdp-protocol` | Chrome DevTools Protocol JSON definitions |
| `coworker/` | File-queue automation for task-driven AI workflows |
## Development Environment (Running from Source)
When developing or running the CLI from the source tree (not an installed
binary), the following applies.
### Invocation wrappers
| Shell | Command | Notes |
|-------|---------|-------|
| PowerShell (Windows) | `./b4w.ps1 <command>` | Primary dev wrapper; builds from source if needed |
| Git Bash (Windows) | `./b4w.sh <command>` | Quotes args automatically for pwsh safety |
| Git Bash (alt) | `pwsh ./b4w.ps1 <command>` | Direct PowerShell invocation |
| Linux / macOS | `./b4w.sh <command>` | Same script works cross-platform |
| Any (installed) | `browser4-cli <command>` | After `browser4-cli install` |
> **Important:** The `$(./b4w.ps1) <command>` syntax shown in some task
> instructions does **not** work in bash — `$(…)` is command substitution, not
> invocation. Use `pwsh ./b4w.ps1 <command>` or `./b4w.sh <command>` instead.
### First-run latency from a source tree
The first launch builds the runtime bundle via Maven (~1–3 min, before the
spinner appears) and then starts the Browser4 backend (Spring Boot + JVM,
~10s). Subsequent commands are instant — the server stays alive between
invocations. The spinner shows stage-level progress (JVM → Spring Boot → MCP
tools).
### Prerequisites for development
- **[Rust](https://rustup.rs/)** — via `rustup`; needed to compile the CLI binary.
- **Java 25+** — required by the Browser4 backend server.
- **[Git](https://git-scm.com/)** — for cloning the repository.
Verify your setup with:
```bash
cargo --version && java -version
```
### Running the CLI from source
When running from source (not a globally installed binary), use `cargo run`
from the CLI directory:
```bash
cd cli/browser4-cli
cargo build # build the binary
cargo run -- <command> # run a command (the -- separates cargo args from CLI args)
cargo run -- goto "https://example.com"
cargo run -- snapshot -v 0
```
**Note:** All docs use `browser4-cli` as the generic command name. If running
from source, substitute `cargo run --` (with the leading
`cd cli/browser4-cli &&` if not already in that directory).
**From repo root (no `cd` required):**
```bash
cargo run --manifest-path cli/browser4-cli/Cargo.toml -- <command>
```
This pattern works from any directory — no need to `cd` first.
### Output Redirection in Dev Mode
The working directory during `cargo run` is `cli/browser4-cli/`, so relative
file paths must account for this. Use `--quiet` to suppress cargo build output:
```bash
# From repo root: redirect query results to a file
cd cli/browser4-cli && cargo run --quiet -- htmlsnapshot query --sql @../../query.sql --result-only > ../../results.json
# From cli/browser4-cli/: same pattern with shorter relative paths
cargo run --quiet -- htmlsnapshot query --sql @query.sql --result-only > results.json
```
> **Tip:** `--quiet` passes through to cargo and suppresses the "Finished" /
> "Running" build-status lines that would otherwise pollute the output file.
> Without `--quiet`, those lines appear on stderr but `2>&1` captures them
> along with the data — use `--quiet` instead of `2>&1` for clean output.
## Build & Test
### Quick commands
```bash
# Build (skip tests)
./mvnw -DskipTests # Linux/macOS
.\mvnw.cmd -q -D"skipTests" # Windows PowerShell
# Rust unit tests (fast, no backend needed)
cd cli/browser4-cli && cargo test --bin browser4-cli
# Kotlin tests
mvn test -pl browser4-rest -am
mvn test -pl browser4-rest -am -Dtest=MCPToolControllerTest
# E2E tests (needs running backend or mock server)
cargo test --test e2e -- --nocapture
cargo test --test e2e -- --nocapture --scenario=test_e2e_batch_*
# Scoped test runs (Windows)
bin/test.ps1 fast|it|e2e|rest|skills|mcp|cli|browser4|mock-site
```
Maven profile switches in root `pom.xml`: `-DrunITs=true`, `-DrunE2ETests=true`, `-DrunCoreTests=true`, `-DrunRestTests=true`.
### E2E test filtering
```
cargo test --test e2e -- --help # All options
--scenario <pattern> # Glob filter
--group <name> # Group filter (repeatable)
--level SMOKE|BASIC|EXTENDED|ALL # Test depth
--fail-fast / --failed # Stop early / rerun failures
--max-failures <count> # Tolerated failing scenarios (default 5, 0 = none)
--list / --list-groups # Discover without running
--enable-all # Opt into excluded-by-default tests
--force-rebuild-bundle # Force local Maven + runtime rebuild
--force-remote-bundle # Download pre-built bundle instead
```
### Test locations
| Scope | Path |
|---|---|
| Unit tests | `src/test/kotlin/...` |
| REST integration/E2E | `browser4-tests/browser4-rest-tests/` |
| Shared utilities | `browser4-tests/pulsar-tests-common/` |
| Rust E2E | `cli/browser4-cli/tests/e2e/` |
> **Note:** The former integration/E2E suites in `pulsar-it-tests` and `pulsar-e2e-tests`
> have been migrated into the base library (browser4-core modules and
> `pulsar-tests-common`); the placeholder modules have been removed from this repo.
## Code Style
### Kotlin
- Immutable `data class`; explicit return types; null-safety (`require`/`check`/`?:`)
- Public APIs require KDoc
- Store AI-generated task docs in `docs-dev/copilot/`
### Logging
```kotlin
logger.info("Task {} finished in {} ms", taskId, cost) // placeholders, never concatenation
```
### Naming
- Test methods: camelCase + `@DisplayName("...")` — **NOT** backtick naming
- Test classes: `<Name>Test.kt` (unit), `<Name>IT.kt` (integration), `<Name>E2ETest.kt` (e2e)
## Testing Guidelines
**Default policy:** Don't run full suites. Compile with tests skipped, run smallest relevant scope. Upgrade scope when risk increases (cross-module, public API/DTO/serialization, Spring wiring, dependency bumps, concurrency/I/O, browser lifecycle).
**Tag-driven scheduling** — use tags from `docs/TESTING.md`:
- Scope: `Unit`, `Integration`, `E2E`, `SDK`
- Speed: `Fast` (<5s), `Slow` (5–30s), `Heavy` (>30s)
- Gates: `Requires*`, `ManualOnly`
**Coverage targets:** Global ≥70%, Core ≥80%, Utilities ≥90%, Controllers ≥85%
**CI has two gates with different Maven test scopes** — pick the tags for the gate you are writing tests for:
| Gate | Workflow | Maven `excluded_groups` | Scope |
|---|---|---|---|
| PR Quality Gate | `.github/workflows/pr.yml` | `ManualOnly,RequiresAI,E2E,E2ETest,Slow,Heavy,HeavyTest,Integration,IntegrationTest,RequiresServer,RequiresBrowser,RequiresDocker,TestInfraCheck` | fast/unit only (`run_pulsar_tests: 'false'`) |
| CI/CD Pipeline (main + release tags) | `.github/workflows/ci.yml` | `ManualOnly,RequiresAI,E2E,E2ETest,Slow,HeavyTest,TestInfraCheck` | adds integration/infra tests that need Chrome, Docker and the started app |
Both gates pass `-Dsurefire.excludes=**integration**` (class-file pattern, not tags) and both derive success from **the Maven exit code plus the surefire XML totals** — the exit code is authoritative (`reconcile-status` in `.github/actions/run-tests/action.yml` refuses to turn a non-zero exit into a pass, and refuses a pass when no XML was produced at all), so a breached JaCoCo floor, a compile error or a dead test fork fails the gate even with zero parsed test failures. A test class is skipped by **tag**, never by name. `SDK` is excluded by neither gate (no test carries that tag today); `Heavy` is excluded only by the PR gate, `HeavyTest` by both. `.github/workflows/ci.yml` also builds all-main-modules, starts a Dockerized app on port 18182 and runs `cargo test` in `cli/browser4-cli`.
Neither `ci.yml` nor `nightly.yml` fails early any more: `Check Test Status` only records `MAVEN_TESTS_FAILED` in `$GITHUB_ENV`, the Docker build / app startup / CLI e2e stages still run, and a final `Enforce CI Gate` / `Enforce Nightly Gate` step (after `Pipeline Summary`) decides the job outcome from the JVM stage flag plus the CLI e2e outcome. So one round reports both sides instead of hiding the CLI suite behind a single broken JVM test.
The nightly gate (`.github/workflows/nightly.yml`, 00:00 UTC) is a superset: it adds `Slow`/`HeavyTest`/`TestInfraCheck`, measures JaCoCo in observe-only mode
(`-P...,quality-gate -Djacoco.check.skip=true`, no floor), runs `cargo test --bin browser4-cli --lib` (the only place the Rust unit tests run), runs the CLI e2e suite with `--level=EXTENDED --enable-all --max-failures=0`, and defers the job outcome to a final `Enforce Nightly Gate` step so a failing JVM test never skips the CLI e2e stage. See [TESTING.md § CI 门禁实际覆盖](docs/TESTING.md) for the current coverage inventory.
See [CI stabilization notes](docs-dev/copilot/ci-stabilization-4.13.x.md) before changing either list.
## Configuration
- Default port: **18182**
- Config files: `application.properties` → `application-*.properties` → `application-private.properties` (git-ignored, secrets here or env vars)
- Key properties: `openrouter.api.key`, `browser.profile.mode` (DEFAULT|SYSTEM_DEFAULT|SEQUENTIAL|TEMPORARY), `browser.display.mode` (GUI|HEADLESS|SUPERVISED)
- Display mode precedence: session capabilities (`headed` / `displayMode`, e.g. from `open --headed`/`--headless`) override the server-wide `browser.display.mode` default at browser launch (`AbstractPulsarSession.createBoundDriver`); server default applies only when the session has no display preference
- LLM providers configured via env vars: `DEEPSEEK_API_KEY`, `OPENROUTER_API_KEY`, `VOLCENGINE_API_KEY`, `OPENAI_API_KEY`
## Development Patterns
### CLI command naming: spaced form preferred
New CLI commands must use the **spaced name** style (`verb noun`) — e.g.
`swarm submit`, `htmlsnapshot get`, `profiles list`, `plugin <domain>` — to
stay consistent with every other prefixed command. Internally the CLI is
kebab-case (`swarm-submit`); users type the spaced form, which
`rewrite_prefixed_command()` (main.rs) rewrites to the internal kebab name.
When adding a prefixed command:
1. `CommandDef.name` stays kebab-case (the internal dispatch name).
2. Register the prefix in `rewrite_prefixed_command()` so `prefix sub` →
`prefix-sub`. If the prefix also works standalone (`crawl`, `webdb`,
`doctor`, `webminer`, …), gate it with a `known_subs` allowlist so bare
usage and positional args pass through untouched.
3. Register the kebab form in `preferred_spaced_command_form()` (and the bare
prefix in `preferred_prefixed_group_form()` when the bare prefix is
invalid) so users get a "Use 'browser4-cli prefix sub' instead" hint.
4. Single-word commands without subcommands (`goto`, `close`, `eval`, …) stay
bare kebab — no prefix, no spaced form.
5. Plugin tool domains are already invoked spaced as `plugin <domain> <method>`
(dynamic discovery via `/mcp/tools`, no registration needed).
6. Plugins can declare a **named CLI command** without any CLI change: set
`ToolSpec.cliName` (spaced form, e.g. `"profile import"`) on the tool spec.
The CLI discovers these from `GET /mcp/tools/specs` at startup and renders
them as first-class commands with argument parsing (`browser4-cli profile
import --source chrome`). No `CommandDef` needed — the spec's `arguments`
define the `--key value` options.
### Adding a `browser4-cli` command
1. **`commands.rs`** — Add `CommandDef`: CLI name kebab-case, MCP tool `browser_`-prefixed snake_case, map args in `tool_params_fn`
2. **`MCPToolController.kt`** — Add frontend alias so `browser_my_tool` resolves to internal name `my_tool`
3. **Backend tool** — Reuse existing when possible; if new capability needed add `@MCP` method in `WebDriver.kt`, implement in concrete driver. Add explicit `BrowserTabToolExecutor` case only for non-trivial parameter mapping
4. **`main.rs`** — Update only for: custom dispatch, dynamic tool-name selection, stale-session recovery, `no_snapshot_commands()`, or custom batch handling in `compile_batch_request()`
5. **Docs** — Update `skills/browser4-cli/SKILL.md`; extensive docs → `skills/browser4-cli/references/<topic>.md`
6. **Tests** — `commands.rs` unit tests → controller mapping tests → `e2e.rs` → `MCPToolControllerE2ETest.kt`
7. **Common failures:** missing backend alias, omitted `sessionId`, forgetting `no_snapshot_commands()`/`batch_supported`, element-ref parameter name mismatches, snake_case/camelCase normalization
### REST-based commands (swarm, crawl)
- `tool_name_fn` returns `""`; dispatch entirely in `main.rs` via custom `handle_*`
- HTTP in `http.rs`: `submit_*` → POST `/api/<resource>`, `get_*_result` → GET `/api/<resource>/{id}/result`
- Backend: `@RestController` + `@Service` + `ConcurrentHashMap` task store + `CoroutineScope`
- Return task UUID from POST; CLI polls for completion. No MCP alias needed.
### Snapshot-related commands
Category `Category::Snapshot`:
- `htmlsnapshot get` / `query` — HTML retrieval with pagination (`-limit`, `-offset`)
- `htmlsnapshot grep` — regex search (`-i`, `-v`, `-F`, `-w`, `-A/B/C`, `--selector`)
- `htmlsnapshot inspect` — CSS selector discovery for recurring patterns
- `htmlsnapshot summary` — compressed Web Page Summary Index
- `snapshot` — live a11y snapshot with `--boxes`, `--stdout`, `--limit`
### Modifying install/uninstall/upgrade code
After changing `cli/browser4-cli/src/daemon.rs`, run install-scenario e2e tests:
```bash
cargo test --test e2e -- --nocapture --level EXTENDED --enable-all --scenario '*install*'
```
## PowerShell Cross-Platform Compatibility
- Use `$IsWindows`, `$IsLinux`, `$IsMacOS` for platform branching
- Avoid Windows-only cmdlets; use `Join-Path` / `[System.IO.Path]::Combine()`
- Prefer `$env:HOME` over `$env:USERPROFILE`
- Shebang: `#!/usr/bin/env pwsh`
- **When fixing one `.ps1`, check siblings for the same issue**
## Test Script Portability
Scripts under `browser4-tests/tests-production/` and `bin/test-production.ps1` test globally-installed `browser4-cli`. They must **never** depend on: git, repo root, source code, Maven/Cargo build outputs. Use `$PSScriptRoot` for sibling references. Repo-awareness must be opt-in with clear error messages when absent.
## Coworker Automation
File-queue system for task-driven AI workflows (`coworker/`). Task files (Markdown with optional `Title:`/`Prompt:` headers) route through state directories: `0draft/` → `1ready/` → `2working/` → `3complete/` (or `3aborted/`, `4review/`, `5approved/`). See [Coworker SKILL.md](coworker/SKILL.md).
## Definition of Done
- [ ] Build and related tests pass
- [ ] No new high-noise logs or warnings
- [ ] New/changed logic has tests (main path + edge case)
- [ ] No secrets or private endpoints committed
- [ ] No arbitrary version changes (follow parent BOM)
- [ ] Documentation updated for public behavior changes
- [ ] Performance impact assessed if >5%
## Common Issues
| Issue | Solution |
|---|---|
| `.ps1` scripts don't run on Linux | `sudo apt-get install -y powershell`, then `pwsh script.ps1` |
| `mvnw` no execute permission | `chmod +x mvnw` |
| JDK version mismatch | JDK 25+ in `JAVA_HOME` |
| Windows parameter escaping | `-D"key.with.dots=value"` |
| Port 18182 in use | Override `server.port` in root `application.properties` |
| JaCoCo reports empty / coverage floor never trips | The surefire `argLine` in the root `pom.xml` must use late binding `@{jacocoArgLine}`, never `${jacocoArgLine}`: the property is declared empty, so `${...}` is substituted to `""` while the effective model is built — before `prepare-agent` sets it — and the agent never attaches (`Skipping JaCoCo execution due to missing execution data file`). Verify with `mvn -X -Pquality-gate -pl :browser4-common test` and look for `-javaagent:` on the surefire fork command line |
| BrowserProtocol retry log storms | Use existing retry utilities, lower log level |
| `browser4-cli` (debug, Windows) aborts with `STATUS_STACK_OVERFLOW` / `exit -1073741571` on `click`/`dblclick` | Windows gives the main thread a 1 MB stack reserve (Linux/macOS ~8 MB) and the debug async chain is deep; `cli/browser4-cli/build.rs` links every Windows target with `/STACK:8388608`. Keep that flag and `test_windows_binary_reserves_a_linux_sized_main_thread_stack` (it reads the PE header back). If it recurs, localize with `docs-dev/fake-mcp-server.ps1` — no browser needed. Background: [docs-dev/cli-e2e-test-coverage-analysis.md](docs-dev/cli-e2e-test-coverage-analysis.md) and [the issue draft](coworker/tasks/issues/draft/2026/1001/20261001-224111-windows-click-stack-overflow.issues.md) |
## Documentation Update Rule
When a user says **"update documents"** (or "update docs", "refresh documentation"), update ALL of the following that reference the changed feature:
1. **`README.md`** and **`README.zh.md`** — root-level project readmes
2. **`skills/browser4-cli/SKILL.md`** — primary CLI skill document
3. **`skills/browser4-cli/references/*.md`** — reference docs (htmlsnapshot.md, x-sql.md, etc.)
4. **`cli/browser4-cli/README.md`** — CLI-specific README
5. **`cli/browser4-cli/src/help.rs`** — CLI help text generation
6. **`cli/browser4-cli/src/tips.rs`** — CLI tips/hints shown to users
7. **Any other `.md` files** in `docs/`, `skills/`, or project root that reference the changed command or feature
When adding a new CLI option or changing command behavior, always check these locations.
## Documentation References
- [Testing Taxonomy](docs/TESTING.md)
- [Build from Source](docs/build-from-source.md)
- [Configuration Guide](docs/config.md)
- [CLI Skill Guide](skills/browser4-cli/SKILL.md)
- [ARIA Snapshots](docs/aria-snapshots.md)
- [HTML Snapshot](docs/htmlsnapshot-inspect-summary.md)
- [Eval Command Output](docs/eval-command-output.md)
- [Load Options Guide](docs/load-options-guide.md)
- [Crawl Checkpoint & Resume](docs/crawl-checkpoint-resume.md)
- [Mock Site](docs/mocksite.md)
- [QL Functions Guide](docs/ql-functions-guide.md)
- [Coworker Automation](coworker/SKILL.md)
---
*Last updated: 2026-08-25*
More agent context in platonai/Browser4
9 other files this repository gives its agents.
CLAUDE.md
Skill
- browser4-cliskills/browser4-cli/SKILL.md
- browser4-codingskills/browser4-coding/SKILL.md
- browser4-devskills/browser4-dev/SKILL.md
- browser4-experienceskills/browser4-experience/SKILL.md
- browser4-fix-bugskills/browser4-fix-bug/SKILL.md
- browser4-pluginskills/browser4-plugin/SKILL.md
- browser4-seoskills/browser4-seo/SKILL.md
- browser4-web-minerskills/browser4-web-miner/SKILL.md
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
Reports can't be read right now.
Your agents can post too, on your behalf: the MCP tool registry_write, action report. How to connect one.

