- The QA tab — a full QA surface on your project’s pages: author tests in plain English, organize them into suites and collections, run them against named environments on a fleet of QA workers, and read rich run reports with screenshots and session replay.
ai_qa_testtargets — agent-driven browser tests declared in yourBUILD.rbsfiles and run withrbs test, right in your workspace.
go_test, vitest_test,
and friends verify your code deterministically; QA verifies the running product.
How a QA run works
Each step of a test is routed to a specialized agent:- Action steps are performed by an action agent: it reads the page (the full accessibility tree, page text, and a screenshot), decides the next moves, and performs them as real input events. It batches sensibly — a whole form is filled and submitted in one pass — and waits adaptively for the page to settle rather than sleeping.
- Assertions (
/verify,Expect:) go to an assertion agent that judges strictly: an exact value you pin down must appear exactly as written — currency symbols, separators, and casing included. Garbled or truncated text never satisfies an assertion about that text. Assertions about how the page looks — layout, readability, broken assets — are judged by a design-review agent with a defect taxonomy. - Extractions (
/extract) read one value off the page, following your instructions to the letter (“digits only”, “without the currency symbol”), and bind it to a variable later steps can reference.
Writing tests in plain English
A QA test is a small text file: a frontmatter block, then one step per line. The step editor in the QA tab writes this format for you, and validates every line as you type.Step forms
List markers (
1., -, *) are cosmetic, and lines starting with # are
comments.
Frontmatter
Variables and literals
{name}references a variable. Values come from the test’s per-environment variables plus anything an earlier/extractbound. A reference with no value fails the step and names the fix — it never silently passes through."quoted text"and[Label:value]are literals — exact ground truth the page must match verbatim.[Plan:Standard Plan]reads naturally in the step while pinning the exact value.
/commands,
and malformed /extract lines are errors, and every problem in the file is
reported at once with its line number. Using {a_variable} before the step
that extracts it is caught at edit time, not at run time. The editor marks the
offending step cards, and Run stays disabled until the test parses.
The QA tab
QA lives on your project’s pages in ReasonOS, as a QA item in the Build rail. It is enabled per project under Project Settings → QA. The surface is organized as collections → suites → tests:- Collections are the top-level grouping — typically an area of the product (“checkout”, “onboarding”) — and carry schedule settings.
- Suites group related tests and define a run order: stages that run
top to bottom, each either in order or in parallel. By default,
state-producing tests (those that
save state as) run in a first serial stage, then everything that depends on them runs in parallel. - Tests are the plain-English files above, with tabs for Steps, Runs, Schedule, Variables, and Config (target platforms, persona, saved-state behavior).
Environments
A QA run executes against a named environment — execution context you define in the QA tab (conventionallylocal, staging, production):
- For web, an environment is a base URL: where that build of your product is hosted. Steps can open relative paths (“Open /checkout”) and resolve against it.
- For iOS and Android, an environment registers an app build per platform — a URL, its SHA-256 digest, a version, and the app id. The build is fetched and digest-verified before anything is installed; a mismatched artifact fails the run rather than launching the wrong binary.
{base_url},
test credentials, expected copy — so the same test runs against local, staging,
and production with the right values in each.
Personas
Personas are defined in Project Settings → QA and picked per test. A persona describes who is using the product — “a first-time shopper in a hurry”, “a power user who knows the keyboard shortcuts” — and shades how the action agent behaves: a first-time user reads before clicking. A persona never changes what a step requires; assertions are judged the same for everyone.Saved states
Tests hand sessions to each other through saved states. A test that ends withsave state as: shopper-logged-in captures the browser session — cookies
and local storage — under that name (with an optional lifetime like for 7d).
Another test declaring starts from: shopper-logged-in restores it before its
first step and begins signed in, instead of re-walking the login flow. Only a
passing run saves its state, so a broken session is never handed on. An
expired or missing state fails the dependent run loudly rather than silently
starting fresh.
Saved states are captured and restored today, and suites order state-producing
tests first automatically. A browsable list of captured states in the QA tab is
still in progress — the Saved states panel currently explains the feature
rather than listing entries.
Running QA
From the QA tab
- Run this test on a test’s header.
- Run the suite / Run the collection on their pages — these execute the stored run order, stage by stage.
platforms: web, ios produces one leg per platform
under a single report, which rolls up to the worst status.
If a worker is lost mid-run, the run is not left spinning: the platform hands
the job to another worker, and a run that could not be completed is marked
failed with the reason.
iOS and Android execution is early: today a mobile leg installs the
environment’s registered, digest-verified build and launches it. Agent-driven
interaction on mobile — tapping, typing, reading the screen — is in progress;
those steps currently fail with an explicit “not supported yet” reason rather
than silently passing.
On a schedule, or on events
Schedule settings live on collections (suites can inherit or detach) and support cadences of every 15 minutes, hourly, and daily. Event triggers can start a run on pull-request activity or when a push lands on the project’s default branch. Scheduled and event-triggered runs execute against thestaging environment.
Scheduling is newly landed and still rolling out; some Schedule pages in the
UI may still describe runs as manual-only. A deploy-gate trigger (“run before
promoting a build”) is planned but not available yet.
Reading results
While a run executes
An in-progress run streams itself live: the page replays in the report as the DOM changes, the model’s reasoning appears token by token under the step it belongs to, and steps flip from running to passed or failed as they settle. A run’s report is available within a second of it starting.The run report
Every run — live or historical — has a report:- A status tile: passed / failed / running, the environment, platform, how the run was started, and timing.
- A failed reason for failing runs — the judging agent’s verdict, written as a bug report a developer can act on: the exact text, element, or console/network evidence observed, and what was expected instead.
- Per-step results with elapsed time. Each action step expands into “what the agent did” — the individual interactions it performed — with a screenshot beside each one. Each step also carries the frame the agent was looking at, the assertion’s reasoning, and any extracted value. Clicking a step opens a detail view with the captured frame, the parsed step, the error, and the agent’s reasoning, with previous/next navigation.
- A session replay: a DOM-level recording of the whole session (not a video), replayable with a timeline. The recording is captured invisibly — the page under test sees no injected scripts.
QA test definitions are currently stored with the project and edited in the QA
tab. Storing them as committed files in the branch’s
.reasonos/qa/ tree — so
tests version with the code they test — is planned.QA targets in your build: ai_qa_test
For QA checks that belong in the workspace itself, rbs ships an agent-driven
test rule. An ai_qa_test target starts your app, hands an AI agent a real
Chrome browser (driven through Chrome DevTools), and has it execute your steps
and report pass or fail — as a normal test target.
Build the app target first, then run the QA target like any other test:
run_targets binary in the background, connects the
browser tooling, runs the agent through the steps, prints its step-by-step
report, and passes or fails the target on the agent’s verdict. The background
processes are stopped when the run ends.
Two requirements:
- A model API key in the environment —
ANTHROPIC_API_KEY,OPENAI_API_KEY,XAI_API_KEY, orGEMINI_API_KEY. - Chrome and a Node.js toolchain available to the workspace (the browser tooling is fetched on first use).
ai_qa_test is a thin wrapper over the general ai_task rule, which can wire
any MCP tool server into an agent-executed target — the QA wrapper just
preconfigures the browser.
Because
ai_qa_test targets are ordinary test targets, a broad rbs test //... sweep will execute them — starting servers, a browser, and a model
session. Keep them in their own package or CI job and run them deliberately
rather than inside every unit-test sweep.QA, rbs test, and CI
They compose: CI runs your ordinary tests on every change;
ai_qa_test
targets add agent-level checks you can invoke from the same build graph; and
the QA tab continuously exercises what’s actually deployed, with evidence a
person can review.