Configuration
Explorbot reads its settings from explorbot.config.js or explorbot.config.ts in your project root.
Quick start
Section titled “Quick start”import { createGroq } from '@ai-sdk/groq';
const groq = createGroq({ apiKey: process.env.GROQ_API_KEY,});
export default { web: { url: 'http://localhost:3000', }, ai: { model: groq('openai/gpt-oss-20b'), },};To set up a provider — OpenAI, Anthropic, Groq, Cerebras, Google, or Azure — see AI providers.
Rules are markdown files that change how an agent behaves. They live in rules/, one folder per agent:
rules/ researcher/ # Rules for the Researcher agent check-tooltips.md tester/ # Rules for the Tester agent wait-for-toasts.md admin-credentials.md planner/ # Rules + styles for the Planner agent no-delete-tests.md styles/ normal.md psycho.md curious.mdEach rule file is plain markdown. Its content is appended to the agent’s prompt.
Configuring rules
Section titled “Configuring rules”Add a rules array to any agent’s config. Each entry is either a filename (loads for all URLs) or an object mapping a URL pattern to a filename:
ai: { agents: { tester: { rules: [ 'wait-for-toasts', // loads rules/tester/wait-for-toasts.md for all URLs { '/admin/*': 'admin-credentials' }, // loads rules/tester/admin-credentials.md only on /admin pages ], }, researcher: { rules: [ 'check-tooltips', // loads rules/researcher/check-tooltips.md { '/users/*': 'user-testing' }, // loads rules/researcher/user-testing.md for /users and subpages ], }, planner: { rules: [ { '/checkout/*': 'payment-rules' }, // loads rules/planner/payment-rules.md for checkout pages ], }, },}URL patterns work the same as knowledge files: *, /exact, /path/*, ^regex$, and glob patterns.
Planning styles
Section titled “Planning styles”The Planner and Chief agents cycle through styles — different testing approaches applied on each planning round. Built-in styles are normal, psycho (stress-testing), and curious (coverage gaps).
To change a style, extract the built-in ones and edit them:
npx explorbot extract-rules plannerThis copies the planner’s built-in rules, including the styles/ folder, to rules/planner/. Edit them freely. Explorbot loads your rules/ directory first and falls back to the built-in styles.
Set which styles to use, and their order, in config:
ai: { agents: { planner: { styles: ['normal', 'psycho', 'curious'], // default order }, },}Rules vs knowledge vs systemPrompt
Section titled “Rules vs knowledge vs systemPrompt”| Mechanism | Purpose | URL-aware | File-based |
|---|---|---|---|
| Rules | Agent-specific instructions | Yes | Yes (rules/<agent>/) |
| Knowledge | App domain info (credentials, data) | Yes | Yes (knowledge/) |
| systemPrompt | Quick inline instructions | No | No (in config) |
Rules and systemPrompt work together: rules from files load first, then systemPrompt is appended.
Handle slow pages
Section titled “Handle slow pages”playwright: { timeout: 60000, waitForNavigation: 'networkidle',}Use cheaper models for simple tasks
Section titled “Use cheaper models for simple tasks”ai: { model: groq('openai/gpt-oss-20b'), // Default: fast and smart model agents: { // Fastest model for summarization 'experience-compactor': { model: groq('llama-3.1-8b-instant') }, },}Run in Docker or CI
Section titled “Run in Docker or CI”playwright: { show: false, args: [ '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage', ],}Trace AI calls with Langfuse
Section titled “Trace AI calls with Langfuse”ai: { langfuse: { enabled: true, publicKey: process.env.LANGFUSE_PUBLIC_KEY, secretKey: process.env.LANGFUSE_SECRET_KEY, },}See Observability for details.
Agent configuration
Section titled “Agent configuration”Each agent takes its own model and system prompt.
Available agents
Section titled “Available agents”| Agent | Purpose |
|---|---|
tester | Executes test scenarios |
planner | Generates test plans |
researcher | Analyzes page structure |
navigator | Handles browser navigation |
pilot | Supervises test execution, detects stuck patterns |
driller | Drills page components to learn interactions |
captain | Orchestrates user commands |
experience-compactor | Compresses experience data |
quartermaster | Accessibility analysis |
historian | Session recording, generates CodeceptJS or Playwright test files |
rerunner | Heals failing steps when re-running generated tests |
analyst | Writes the end-of-session markdown report |
fisherman | Prepares test data through API requests |
scout | Retrieves relevant documentation for the Planner |
chief | API test planning |
curler | API test execution |
Agent options
Section titled “Agent options”agents: { tester: { model: groq('openai/gpt-oss-20b'), // Override default model enabled: true, // Enable/disable agent rules: ['wait-for-toasts'], // Load rules from rules/tester/ systemPrompt: '...', // Append to system prompt (inline) beforeHook: { /* ... */ }, // Run before agent executes afterHook: { /* ... */ }, // Run after agent completes },}| Option | Type | Description |
|---|---|---|
model | LanguageModel | Model instance for this agent (overrides default) |
enabled | boolean | Enable or disable the agent |
rules | Array<string | Record<string, string>> | Rule files to load from rules/<agent>/ (URL-aware). See Rules |
systemPrompt | string | Additional instructions appended to the agent’s prompt (inline fallback) |
beforeHook | Hook | HookPatternMap | Code to run before agent execution |
afterHook | Hook | HookPatternMap | Code to run after agent execution |
Some agents take extra options: pilot accepts stepsToReview (recent steps reviewed per check, default 5); planner accepts styles (see Planning styles) and docsWeight (share of scenarios grounded in documentation when Scout is enabled, default 70); scout accepts dirs (see Scout agent); rerunner accepts healLimit (max heal attempts, default 3) and recipes (custom heal recipes, see Rerunning Tests). Researcher and Historian options are documented below.
See Agent hooks for hook configuration.
Researcher agent options
Section titled “Researcher agent options”The Researcher takes all standard agent options plus options that control interactive exploration:
| Option | Type | Description |
|---|---|---|
maxExpandableClicks | number | Maximum expandable elements clicked during deep analysis (default: 10) |
errorPageTimeout | number | Seconds to wait for a loading page to settle before error-page detection (default: 10, 0 disables the wait) |
focusSections | string[] | CSS selectors that narrow research to a matching element when present (e.g. an open modal or drawer). First match wins. Applies only to the per-section fallback used after a truncated research response. |
ai: { agents: { researcher: { maxExpandableClicks: 15, focusSections: ['[role="dialog"]'], }, },}See Researcher agent for full documentation and examples.
Historian agent options
Section titled “Historian agent options”| Option | Type | Description |
|---|---|---|
framework | 'codeceptjs' | 'playwright' | Output format for generated test files. Default: 'codeceptjs'. |
ai: { agents: { historian: { framework: 'playwright', }, },}With 'playwright', runs are saved as @playwright/test .spec.ts files using the actual Playwright calls captured at runtime. See Automated tests.
See AI providers for recommended models and provider setup.
Fisherman agent
Section titled “Fisherman agent”Fisherman prepares test data over the API before a scenario runs, and can also answer questions about data that already exists without creating or changing anything. Pilot reaches this read-only capability through its askApi(question) tool, calling it to check whether suitable data is already there — or to get the exact name or id of an existing record — before deciding whether to create anything through precondition(). In replicate mode, where Fisherman learns the API by watching browser traffic instead of reading a spec, the read endpoints it can query come from successful GET requests observed in the browser, alongside the write endpoints already captured from XHR traffic. The endpoint list shown to the model names only the path and its query-parameter names, never their values; the underlying capture on disk holds the full request URL and headers — what write captures already hold — but no response body.
Scout agent
Section titled “Scout agent”Scout retrieves documentation relevant to the page being planned and hands it to the Planner as a <docs_context> block, so scenarios can be grounded in what the application documents say. It is opt-in and needs documentation collected beforehand:
ai: { agents: { scout: { enabled: true, // Opt in — Scout never runs without this dirs: ['docs'], // Extra markdown directories to search, beyond the spec bundle }, planner: { docsWeight: 70, // Roughly 70% of scenarios exercise documented behavior, the rest explore beyond it }, },},| Option | Type | Description |
|---|---|---|
enabled | boolean | Turn Scout on. Default: off. |
dirs | string[] | Markdown directories added to the corpus, resolved relative to the project |
The corpus combines the application spec bundle (--spec / EXPLORBOT_SPEC / dirs.spec, set by explorbot docs collect) with the dirs above. Scout scans it with the same bash + readFile tools Captain uses: the corpus is loaded into an in-memory sandbox and the model itself runs rg (or grep — whichever is installed) to explore it. One of the two must be on PATH — Scout fails loudly when neither is found. Pages already injected for the current URL as <application_spec> are excluded from the Scout corpus, so the two blocks never duplicate each other. Files under dirs that carry no page URL are listed as hand-written notes for Scout to inspect when they are relevant.
Playwright settings
Section titled “Playwright settings”Browser selection
Section titled “Browser selection”playwright: { browser: 'chromium', // Most compatible // browser: 'firefox', // Better privacy testing // browser: 'webkit', // Safari/iOS testing}Viewport and window size
Section titled “Viewport and window size”playwright: { windowSize: '1920x1080', viewport: { width: 1920, height: 1080, },}Browser context options
Section titled “Browser context options”playwright: { ignoreHTTPSErrors: true, bypassCSP: true, userAgent: 'Mozilla/5.0 (Explorbot)', locale: 'en-GB', colorScheme: 'dark', basicAuth: { username: 'user', password: 'pass' }, emulate: { ...devices['iPhone 13'] },}The browser session (cookies, localStorage) is restored when you launch with --session — see commands.md.
Loading Indicators
Section titled “Loading Indicators”For SPAs, domcontentloaded can happen before the application finishes loading page data. Use spinnerSelectors to tell Explorbot which loading indicators should be treated as part of page readiness:
playwright: { waitForTimeout: 5000, spinnerSelectors: ['.spinner', '.loading', '[aria-busy="true"]'],}Explorbot waits for domcontentloaded, then races Playwright networkidle, visible configured spinners becoming hidden, or timeout before capturing the page state. If no configured spinner is visible on a page, the spinner rule is ignored for that page.
Directory Structure
Section titled “Directory Structure”The default layout:
your-project/├── explorbot.config.js├── knowledge/ # Domain hints (you create these)│ └── login.md├── rules/ # Agent-specific rules (you create these)│ ├── tester/│ │ └── wait-for-toasts.md│ └── planner/│ └── styles/ # Custom planning styles├── experience/ # Learned patterns (auto-generated)│ └── abc123.md└── output/ # Test results (auto-generated) ├── states/ ├── research/ ├── plans/ ├── tests/ ├── reports/ └── docs/Change the paths:
dirs: { spec: './test/spec', knowledge: './test/knowledge', experience: './test/experience', output: './test/output',}Environment variables
Section titled “Environment variables”Keep secrets in environment variables:
GROQ_API_KEY=gsk_...LANGFUSE_PUBLIC_KEY=pk-...LANGFUSE_SECRET_KEY=sk-...Reference them in config:
const groq = createGroq({ apiKey: process.env.GROQ_API_KEY });
export default { ai: { model: groq('openai/gpt-oss-20b'), langfuse: { enabled: true, publicKey: process.env.LANGFUSE_PUBLIC_KEY, secretKey: process.env.LANGFUSE_SECRET_KEY, }, },};Config file locations
Section titled “Config file locations”Explorbot looks for a config file in this order:
explorbot.config.jsexplorbot.config.mjsexplorbot.config.tsconfig/explorbot.config.jsconfig/explorbot.config.mjsconfig/explorbot.config.tssrc/config/explorbot.config.jssrc/config/explorbot.config.mjssrc/config/explorbot.config.ts~/.explorbot/config.js(or.mjs,.ts) — the global installation, extended per site by~/.explorbot/sites/<host>/explorbot.config.js
Or pass a custom path:
npx explorbot explore /dashboard --config ./custom/path/config.jsThe EXPLORBOT_* variables sit between the two files: they are used when the working directory has no config of its own, and they win over the global installation, so a machine-wide setup never overrides what a single command asked for. Whatever wins is used as a whole — configs never merge with each other.
Env files fill in rather than override: the .env of the working directory is read first, then ~/.explorbot/.env supplies only the keys still unset, so a project key and a real environment variable both beat a global one.
Running from anywhere: the global installation
Section titled “Running from anywhere: the global installation”npx explorbot init --global configures AI models and keys once in ~/.explorbot, so explorbot commands work in any directory without a project. Every explored site gets its own folder that persists between runs:
~/.explorbot/├── config.js # AI models and keys, shared by every site├── .env└── sites/ ├── app.example.com/ │ ├── explorbot.config.js # this site's settings, extends config.js │ ├── site.json # base URL, first and last run │ ├── knowledge/ │ ├── experience/ │ └── output/ # states, plans, reports, tests └── localhost_3000/The folder name is the host and port of the site, lowercased, with characters invalid in directory names replaced by _.
Global mode runs with full project semantics — experience is read and written, the Historian saves generated tests, reports land in the site’s output/ — so the tool keeps learning your app across runs.
The site comes from the URL of the command, or from EXPLORBOT_URL:
npx explorbot explore https://app.example.com/login # registers the site on first visitnpx explorbot explore app.example.com/dashboard # later runs: reference it by hostnpx explorbot sites # list registered sitesA dirs section in the global config is ignored in favor of the layout above. A web.url is allowed and acts as the default site for commands that pass no URL of their own.
Per-site configuration
Section titled “Per-site configuration”~/.explorbot/config.js holds what every site shares — models, keys, reporter settings. Anything one site needs differently goes in its own explorbot.config.js, written into the site folder the first time that site is explored:
// Config for https://app.example.com// Extends ~/.explorbot/config.js — set only what differs.const config = { web: { url: 'https://app.example.com', },
ai: { model: 'openrouter/anthropic/claude-sonnet-5', },
playwright: { show: true, },};
export default config;The two are merged section by section, and the site wins. A site that overrides ai.model keeps the global ai.visionModel. Use it to give a slow or unusual app a stronger model, a visible browser, or its own reporter settings, without changing how every other site runs.
web.url is required, and must be the site the folder belongs to — it is what makes the file readable on its own rather than meaningful only by where it sits. Explorbot refuses to run when it is missing or names a different site, instead of quietly ignoring the mismatch. To configure a different site, explore it and edit the config in its own folder.
dirs and the base URL stay owned by the layout above and cannot be overridden. The file is never rewritten once created, and a site without one simply uses the global config.
Per-site configs apply to the global installation only. A directory with its own explorbot.config.js and the EXPLORBOT_* environment mode below both resolve to a single config with nothing to extend.
Running without a config file
Section titled “Running without a config file”When the working directory has no config file and EXPLORBOT_AI_PROVIDER (or EXPLORBOT_AI_MODEL) is set, Explorbot synthesizes a configuration from EXPLORBOT_* environment variables, in preference to a global installation. Output goes to the site folder ~/.explorbot/sites/<host>/ (EXPLORBOT_OUTPUT overrides it, EXPLORBOT_EPHEMERAL=1 sends it to a temp directory instead), experience is written there and reused by later runs against the same host unless the run is ephemeral, and the Historian is off. This is meant for one-liner CI jobs, demos, and coding agents — see Agentic Usage for the variable list and the trade-offs.
Full configuration reference
Section titled “Full configuration reference”export default { // Application URL (required — or set playwright.url instead) web: { url: 'http://localhost:3000', },
// API testing (optional) api: { baseEndpoint: 'http://localhost:3000/api/v1', spec: ['http://localhost:3000/api/openapi.json'], headers: { 'Content-Type': 'application/json' }, // bootstrap: async ({ headers, baseEndpoint }) => { ... }, // teardown: async ({ headers, baseEndpoint }) => { ... }, },
// Browser automation settings (url is inherited from web.url if not set) playwright: { browser: 'chromium', // 'chromium' | 'firefox' | 'webkit' show: false, // Show browser window windowSize: '1280x720', // Browser window size slowMo: 0, // Slow down actions (ms) timeout: 30000, // Default timeout (ms) waitForNavigation: 'load', // 'load' | 'domcontentloaded' | 'networkidle' waitForTimeout: 1000, // Wait after navigation (ms) spinnerSelectors: [], // Loading indicators to wait for before page capture ignoreHTTPSErrors: false, // Ignore HTTPS certificate errors userAgent: 'custom-agent', // Custom user agent string viewport: { width: 1280, height: 720, }, args: ['--disable-gpu'], // Browser launch arguments chromium: { args: [] }, // Chromium-specific args firefox: { args: [] }, // Firefox-specific args webkit: { args: [] }, // WebKit-specific args },
// AI provider settings ai: { model: groq('openai/gpt-oss-20b'), // Default model instance (required) visionModel: groq('meta-llama/llama-4-scout-17b-16e-instruct'), // Model for screenshot analysis; setting it enables vision features decisionModel: { provider: 'openrouter', model: 'typesafe/jev-1.13' }, // Optional; see providers docs config: {}, // Additional provider config langfuse: { // Observability settings enabled: true, publicKey: 'pk-...', secretKey: 'sk-...', baseUrl: 'https://cloud.langfuse.com', }, agents: { // Per-agent configuration tester: { model: groq('openai/gpt-oss-20b'), enabled: true, rules: ['wait-for-toasts', { '/admin/*': 'admin-creds' }], systemPrompt: '...', // Inline fallback }, planner: { styles: ['normal', 'psycho', 'curious'], rules: [{ '/checkout/*': 'payment-rules' }], }, researcher: { // Researcher-specific options model: groq('openai/gpt-oss-20b'), // Override default model enabled: true, // Enable/disable agent systemPrompt: '...', // Additional instructions maxExpandableClicks: 10, // Max expandable elements clicked in deep analysis errorPageTimeout: 10, // Seconds to wait for page to settle (0 disables) focusSections: [], // CSS selectors that narrow per-section research }, pilot: { stepsToReview: 5 }, // Recent steps the Pilot reviews navigator: { /* ... */ }, captain: { /* ... */ }, driller: { /* ... */ }, 'experience-compactor': { /* ... */ }, quartermaster: { /* ... */ }, historian: { /* ... */ }, fisherman: { /* ... */ }, scout: { enabled: true, dirs: ['docs'] }, // Documentation retrieval for the Planner rerunner: { /* ... */ }, analyst: { /* ... */ }, }, },
// HTML processing settings html: { minimal: { include: ['form', 'button', 'input'], exclude: ['script', 'style'], }, combined: { include: ['*'], exclude: ['script', 'style', 'svg'], }, text: { include: ['p', 'h1', 'h2', 'h3', 'span'], exclude: ['nav', 'footer'], }, },
// Action execution settings action: { delay: 1000, // Delay between actions (ms) retries: 3, // Retry failed actions timeout: 3000, // Max time a single click/fill may block (ms) },
// Regex to detect dynamic URL segments (IDs, slugs) for plan deduplication // Built-in patterns (numeric, UUID, ULID, hex) are always active // dynamicPageRegex: 'your-custom-pattern',
// Directory paths dirs: { spec: 'spec', // Application specification bundle knowledge: 'knowledge', // Domain knowledge files experience: 'experience', // Learned patterns output: 'output', // Test results and logs },
// Experience recording experience: { disabled: true, // Stop writing experience; reading still works maxReadLines: 100, // Lines of experience injected into prompts },};See also
Section titled “See also”- API testing — API testing setup and commands
- AI providers — provider setup examples
- Decisions — the optional decision model and its fallbacks
- Agents — agent descriptions and workflows
- Agent hooks — custom code before and after an agent runs
- Researcher agent — Researcher configuration and usage
- Planner agent — planning styles and customization
- Knowledge files — domain knowledge format
- Application specs — reusable application documentation format
- Observability — Langfuse integration