Every surface you touch, from first click to filed bug.
Map a flow, it becomes code, the code runs, failures become bugs.
Teach it like a person
Show it the job in a real browser, or hand it the mouse and answer its questions. Either way, it learns your app.
You drive, it watches
Drive a real hosted browser. Every click, drag and keystroke is recorded as a replayable step. Save the steps as a flow and it can repeat the job without you.
It drives, reading the screen
Give it a goal and it operates the mouse itself. It reads the screen with OCR, not the page's code, so canvas apps and hostile SPAs work the same as plain HTML. Where the DOM has no selector, it designs steps anchored to on-screen text: ocr-click and ocr-type.
It asks, you answer, it remembers
When it is unsure it asks you mid-run. The run pauses, your answer resumes it, and the answer is kept in the workspace, so it never asks the same question twice.
Every run ends with an explicit PASS / FAIL / UNMEASURED verdict against success criteria derived from your prompt. And a saved flow can go back to the agent with instructions to extend it.
Mapping sessions
- Drive it by hand (click, drag, type); each step lands on the timeline with a durable locator (role and name, label, placeholder or text, with a live uniqueness count) and a screenshot. Locators descend into iframes, pierce shadow DOM and reject generated ids; a step is never a bare pair of coordinates. Reorder, remove, then save as a named flow.
- Or type a goal, like
Go to {site} and sign in with {email}/{password}. The operator drives it via OCR, stamped withdecided_byand cost. Credentials fill in at run time, never stored in the flow. - Or drag a rectangle on the page and attach an instruction: capture that region's text as a value, assert it shows something, or branch on it.
Flows
Every saved session becomes a flow (name, site, steps, status). Replay it, send it to Automate, or run its test.
| Flow | Site | Steps | Test code | Last run |
|---|---|---|---|---|
| Sign in with email + password Go to {site} and sign in with {email}/{password} | app.example.com | 7 | generated | passed |
| Add item to cart and checkout | shop.example.com | 12 | generated | failed |
Illustrative: not a customer flow.
Automate job
Flow: Sign in with email + password
Status: running → done
File: src/sign-in-with-email-password.spec.js
Assertions by: deepseek/deepseek-chat
Automate jobs
An Automate job turns a flow into real Playwright test code (navigation, fills, clicks, assertions), with the proposing model recorded on the job. It opens in the IDE to read, edit, or hand to chat.
IDE
A file tree and code editor next to the chat agent. Generated tests are ordinary .spec.js files: open, edit, save, nothing locked behind the UI.
- "Run this test" executes the open file, like a flow's Run test button.
- Ask the agent to explain, fix the last failure, or iterate until it passes.
test('sign in with email + password', async ({ page }) => {
await page.goto(env.baseUrl);
await page.getByLabel('Email').fill(params.email);
await page.getByLabel('Password').fill(params.password);
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page.getByText('Welcome back')).toBeVisible();
});
Runs
A run records status, duration and error, plus a screenshot, a trace and the network capture (HAR) to scrub through, not just a red dot. Documents fetched during a run are verified by their magic bytes, not their file extension.
| Run | Flow | Env | Status | Duration | Error |
|---|---|---|---|---|---|
| run_2f81 | Sign in with email + password | staging | passed | 4s | · |
| run_2f82 | Add item to cart and checkout | staging | failed | 9s | Timeout waiting for "Order confirmed" |
Illustrative. Runs report three states, not two: see why UNMEASURED exists.
Bugs
A failed run auto-files a bug (title, flow, environment, error, link to screenshot and trace). Repeat failures collapse onto one bug by fingerprint, so a flaky step does not become ten tickets. Triage starts from evidence, not a report to reproduce.
What causes the flake in the first place: field data from 31 real end-to-end suites.
Checkout: "Order confirmed" not visible
run_2f82 · staging · open
Timeout waiting for "Order confirmed": 30000ms exceeded.
Maintenance
Every flow whose last run failed shows up here, linked to its test. Empty list means everything passed.
1 flow needs maintenance, last run failed:
- Add item to cart and checkout · open test
Environments
Pick a named environment (staging, prod, or custom) from a dropdown next to every "Run test" action. Base URLs and parameters live here, so the same flow runs anywhere. Each workspace drives its own isolated browser; nothing is shared between tenants.
The same recorded flow runs four ways
QA is the entry point, not the ceiling. Nothing is re-recorded to switch mode.
Test
Deploy it, fan it out, file the bug. Runs →
Data entry
Once per spreadsheet row, with evidence per row. Bulk data entry →
Scrape
On a schedule, durable and auditable. Long-running scraping →
API
A site with no API gets one. Website → API →
A running total, not a mystery invoice.
Every screen shows spend and model, the same number the product header keeps live. Calls are logged, not estimated after the fact.
Illustrative, cost accrues per model call.
Run our production workload against a real government portal
Parcel Perfect is our own product: it harvests septic records from county portals, and it runs on QA Reef. The button below runs one real lookup against Garfield County, Colorado's public records portal, right now: it finds a septic case, reads the parcel number from the county's own metadata, pulls one document, verifies and hashes the bytes, then discards them. Every value that appears below comes from that run, at the moment you click.
Public records portal, no login, no CAPTCHA, nothing circumvented. The document is verified and thrown away; this demo never stores anything and never bulk-harvests. More detail on the live demo page.