Install
Signs you in, wires the beryl MCP server into the agent you pick, and installs the beryl-test skill.
npx @beryl-so/cli@latest initMCP setup lists the agents and their flags. Needs Node 20.19 or newer. To install permanently:
npm install -g @beryl-so/cli
beryl --versionAuthenticate
beryl login opens beryl.so/cli/connect. Approve the code in your terminal and the token lands in ~/.config/beryl/config.json.
beryl login
beryl whoamiWithout a browser:
--otp, or Enter at the prompt, emails a 6-digit code. A new email gets an account; a Google sign-in gets no code.--email <addr> --code <digits>finishes that flow without a prompt, for agents.--token <pat>uses an existing token from beryl.so → Account → Personal access tokens.BERYL_API_KEYskipsloginentirely.
A token carries your full account access. beryl tokens revoke kills one, beryl logout --revoke does both.
Cloud runs
A job authors the tests from your document, and the suite runs in Beryl's cloud browsers.
beryl projects create https://app.example.com
beryl jobs create "Cover the checkout flows" --file ./checkout-flows.md
beryl jobs get <job-id>
beryl runs trigger --watch
beryl projects reportFor a login-gated site, add --auth gated. Tests sign in as durable test accounts (beryl accounts) whose mail lands in the project mailbox (beryl mailbox). To fix a test, edit its plain-JSON plan and submit it with beryl tests recompile, which proves the change with a replay before it saves.
Exit codes
0success1failure2usage error3authentication error
--watch streams progress and exits non-zero unless every test passed.
Configuration
Config stores your token and API URL. Scoped commands take --workspace and --project by id, name, or URL. Leave them out and the CLI reads BERYL_WORKSPACE / BERYL_PROJECT, then falls back to your only one.
The CLI pins nothing to a folder, so two sessions in the same directory can target different projects.
Global flags on every command: -V, --version · --json · --api-url · --token · -h, --help.
beryl init
Set up Beryl in this repo: sign in and wire up your coding agent
Set up Beryl in this repo: sign in and wire up your coding agent (interactive)
Signs you in, wires the beryl MCP server into the coding agent you pick, and writes the beryl-test skill. Pick an agent with --claude, --cursor, --vscode and/or --opencode. With no flag it prompts (Enter picks Claude); with no flag and no TTY it wires nothing and prints the flags. --claude also wires the Claude DESKTOP app when installed, which needs a quit and reopen to pick the config up. --scope user (default) configures everything per-user, matching where your login token lives; --scope project writes config committed to the repo. Safe to re-run: it refreshes the skill to this CLI's version and skips whatever is already set up.
--scope <user|project>: Where to wire:user(default) is per-user,projectis committed to the repo. Every teammate still runsberyl loginto authenticate--claude: Wire Claude Code (claude mcp add -s user, or a committed .mcp.json under--scopeproject), plus the Claude desktop app when it is installed--cursor: Wire Cursor, plus a repo-local .cursor/rules/beryl.mdc authoring rule, since Cursor reads no skills dir--vscode: Wire VS Code's user mcp.json (or .vscode/mcp.json under--scopeproject), plus a Beryl section in .github/copilot-instructions.md for Copilot--opencode: Wire ~/.config/opencode/opencode.json (or the repo's opencode.json under--scopeproject), in opencode's own config shape
npx @beryl-so/cli@latest init
beryl init --claude
beryl init --cursor --opencode
beryl init --vscode --scope projectberyl guide
Print the Beryl test guide
Print the Beryl test guide
The guide to durable, healable tests: where new tests come from (jobs create), the ActionPlan shape, outcome assertions, natural-language intent, test accounts and the project mailbox ({{login_email}}, {{mailbox_address}}, {{inbox_address}} + await_email), and the run-fix loop. Same content as the beryl-test skill beryl init installs. Skip if a loaded beryl-test skill states v0.91.1; else call this first (works without logging in).
MCP tool: guide
beryl guideberyl login
Authenticate the CLI with your Beryl account
Authenticate the CLI with your Beryl account (interactive)
Signs in via your browser (a code you confirm at beryl.so) and stores a personal access token in the CLI config. Pass --otp (or --email) to skip the browser and sign in with an emailed one-time code instead. A new email gets an account created automatically. Pass --token to use an existing token from Account → Personal access tokens. Pass --email plus --code (the 6 digits from the email, e.g. read from a beryl inbox) to complete the OTP flow without a prompt. In CI, prefer the BERYL_API_KEY environment variable.
--token <string>: Use an existing personal access token--otp: Skip the browser and sign in with an emailed code--email <string>: Email for the one-time code sign-in (default: your last sign-in, or your git user.email, offered as the prompt default)--code <string>: The emailed 6-digit code. Skips the prompt for non-interactive use (requires--email; also skips sending a fresh code, so pair it with a code already requested viaberyl login,beryl signup, or the API)--token-name <string>: Name for the minted token (default: CLI on <hostname>)
beryl login
beryl login --otp
beryl login --token beryl_pat_…
beryl login --email [email protected]
beryl login --email [email protected] --code 123456 --jsonberyl signup
Register a new Beryl account (emails a 6-digit verification code)
Register a new Beryl account (emails a 6-digit verification code)
Creates a passwordless account for the email and sends it a 6-digit code. Finish with beryl login --email <addr> --code <the 6 digits>, which verifies the account, creates its workspace, and signs the CLI in. With an inbox from beryl mailbox create as the address, an agent can provision a fresh account end-to-end with no human at a prompt.
MCP tool: signup
--email <string>: Email address for the new account (required)
beryl signup --email [email protected] --jsonberyl logout
Remove the stored token from the CLI config
Remove the stored token from the CLI config
MCP tool: logout
--revoke: Also revoke the token server-side so it can never be used again
beryl whoami
Show the signed-in account
Show the signed-in account
MCP tool: whoami
beryl tokens
Manage the personal access tokens that authenticate the CLI and CI.
List your personal access tokens
MCP tool: tokens_list
Mint a new personal access token (shown once)
MCP tool: tokens_create
name: A label for the token
--expires-at <string>: Expiry as an ISO timestamp (default: never)
Revoke a personal access token
MCP tool: tokens_revoke
token-id: Token id fromberyl tokens list
Remove an already-revoked token from your list
MCP tool: tokens_dismiss
token-id: Token id fromberyl tokens list
beryl workspaces
Create and manage workspaces, and pick the one your commands act on by default.
List workspaces you belong to
MCP tool: workspaces_list
Show one workspace
MCP tool: workspaces_get
Also accepts --workspace (see Configuration).
Create a workspace
MCP tool: workspaces_create
name: Workspace name
--domain <string>: Company domain to associate--visible-to-org: Let anyone on your email domain discover and join it
Rename a workspace or change its visibility
MCP tool: workspaces_update
--name <string>: New name--visible-to-org: Toggle org discoverability--autofix: Toggle autofix
Also accepts --workspace (see Configuration).
Delete a workspace and everything in it
MCP tool: workspaces_delete
--force: Skip the confirmation prompt
Also accepts --workspace (see Configuration).
Show the workspace's action history (who did what, when)
MCP tool: workspaces_history
Also accepts --workspace (see Configuration).
Leave a workspace you are a member of
MCP tool: workspaces_leave
--force: Skip the confirmation prompt
Also accepts --workspace (see Configuration).
beryl members
Manage who belongs to a workspace and their roles.
List workspace members
Also accepts --workspace (see Configuration).
Change a member's role
user-id: Member's user idrole: OWNER, USER or VIEWER
Also accepts --workspace (see Configuration).
Remove a member from the workspace
user-id: Member's user id
--force: Skip the confirmation prompt
Also accepts --workspace (see Configuration).
beryl invites
Send, list, and revoke workspace invitations, and accept ones sent to you.
Invite someone to the workspace by email
email: Invitee email
--role <OWNER|USER|VIEWER>: Role (default USER)
Also accepts --workspace (see Configuration).
List the workspace's outstanding invitations
Also accepts --workspace (see Configuration).
Revoke a pending invitation
invitation-id: Invitation id
Also accepts --workspace (see Configuration).
List invitations sent to you
Accept an invitation (by id, or by the token from the invite email)
invitation: Invitation id or emailed token
Decline an invitation
invitation-id: Invitation id
beryl projects
Create and manage projects: a site you author tests for and run.
List projects in the workspace
MCP tool: projects_list
Also accepts --workspace (see Configuration).
Show one project, including its current exploration state
MCP tool: projects_get
Also accepts --workspace and --project (see Configuration).
Create a project for a URL, or an empty one with just --name
MCP tool: projects_create
url: Root URL of the site to test. Omit to create an empty project (see--name)
--name <string>: Name for an empty project when no URL is given. Add a URL later withberyl envs update <env-id>--auth <public|gated>: Whether the site needs a login (gated) or not (public). Default: detected from the site, and only asked when detection is genuinely unsure--force-new-login: Ignore any reusable saved login
Also accepts --workspace (see Configuration).
beryl projects create https://app.example.com
beryl projects create https://app.example.com --auth gated
beryl projects create --name "Acme production"Rename a project
MCP tool: projects_rename
name: New name
Also accepts --workspace and --project (see Configuration).
Turn auto quarantine on or off and tune when it mutes and releases a test
With auto quarantine on, the end of every run checks the tests that ran: a test that failed --failures times in the last --days days with a pass in between is quarantined (straight failures are a regression and never are), and a quarantined test, manual or auto, is released after --passes first-attempt passes in a row. Pass on|off and/or any of the numbers; projects get shows the current values.
MCP tool: projects_quarantine
state: on | off; omit to only tune the numbers
--failures <number>: Failures in the window that quarantine a test (1-50, default 3)--days <number>: Window in days (1-90, default 7)--passes <number>: Passes in a row that release a test (1-50, default 5)
Also accepts --workspace and --project (see Configuration).
beryl projects quarantine on
beryl projects quarantine on --failures 3 --days 7 --passes 5
beryl projects quarantine --passes 3
beryl projects quarantine offTurn self-heal on or off for a project and limit its time and runs
Self-heal is off by default: a failed test fails right away. With it on, a run holds a failed test that has passed before while a heal agent tries to repair its plan against the app, and the test passes if the repair is proven by a replay. --minutes caps the heal agent's time on one failed test (from 1 up to the platform limit, 5 unless the server is configured otherwise; the proving replay comes on top; 0 goes back to that limit) and --max-per-run caps how many failed tests one run may heal (0 removes the cap); past it the rest fail without a heal. A test turned off with tests heal <id> off never heals. projects get shows the current values.
MCP tool: projects_heal
state: on | off; omit to only change the limits
--minutes <number>: Minutes the heal agent may spend on one failed test (0 = the platform limit, 5 by default)--max-per-run <number>: Failed tests one run may heal (0 = no cap)
Also accepts --workspace and --project (see Configuration).
beryl projects heal on
beryl projects heal on --minutes 2 --max-per-run 5
beryl projects heal --max-per-run 0
beryl projects heal offTurn project surfaces on or off
Surfaces are web-desktop, web-tablet, web-mobile, android, ios; a new project has web-desktop only. --add turns surfaces on and --remove turns them off, keeping the rest. Listing surfaces sets the exact set instead, and is refused when it would turn off a surface that is on unless you pass --replace. At least one surface stays on. Prints the set before and after. Turning a surface off removes no tests: delete a surface's tests to stop running them. android and ios test the app named by each environment's app id for that surface (envs update --app-id android=<package> --app-id ios=<bundle id>) from its newest uploaded build (config files upload app.apk, config files upload App.zip --kind ios_build), on Beryl's Android and iOS workers.
MCP tool: projects_surfaces
surfaces...: The exact set to enable: web-desktop | web-tablet | web-mobile | android | ios
--add <strings>: Turn this surface on (repeatable)--remove <strings>: Turn this surface off (repeatable)--replace: Let a listed exact set turn off surfaces that are on now
Also accepts --workspace and --project (see Configuration).
beryl projects surfaces --add android --add ios
beryl projects surfaces --remove web-tablet
beryl projects surfaces web-desktop web-mobile --replaceTurn the findings gate on each run on or off
With the gate on (new-since-green), every run also reports a findings gate: failed when the environment's Site Health has a finding first seen after the last green run or came back after it (every current finding if there is no green run yet), unknown when Site Health has not run there or is not recording findings (its issue tracker must be connected). The gate sits next to the test verdicts and never changes one, nor the exit code of runs watch; read it from findings_gate on runs get. Off by default.
MCP tool: projects_findings_gate
mode: off | new-since-green
Also accepts --workspace and --project (see Configuration).
beryl projects findings-gate new-since-green
beryl projects findings-gate offDelete a project and all its tests and runs
MCP tool: projects_delete
--force: Skip the confirmation prompt
Also accepts --workspace and --project (see Configuration).
Send the agent back in to run/heal existing tests and discover new flows
--watch: Stream the agent's exploration live--timeout <number>: With--watch: max minutes to wait
Also accepts --workspace and --project (see Configuration).
Aggregate quality report across recent runs (pass rates, per-test history, trend)
MCP tool: projects_report
--runs <number>: How many recent runs to aggregate--env <string>: Limit to one environment id
Also accepts --workspace and --project (see Configuration).
Check whether a saved login can be reused for a URL before creating a project
MCP tool: projects_reusable_auth
url: The URL you plan to test
Also accepts --workspace (see Configuration).
beryl envs
Manage a project's environments: the URLs and auth Beryl runs tests against.
List a project's environments
MCP tool: envs_list
Also accepts --workspace and --project (see Configuration).
Show one environment
site_health_runs_reset_fields and site_health_tracker_reset_fields name stored Site Health settings that were invalid and fell back to defaults (* = all of them). Scheduled and CI runs, or ticket filing, auto-close and the digest, stop until they are saved again: envs update with any --health-* flag rewrites the run settings, any --tracker-* flag the tracker settings.
MCP tool: envs_get
env-id: Environment id
Also accepts --workspace and --project (see Configuration).
Add an environment (e.g. staging) to a project
MCP tool: envs_create
name: Environment nameurl: Root URL for this environment
--auth <public|gated>: Whether this environment needs a login
Also accepts --workspace and --project (see Configuration).
Update an environment's name, URL, app ids, auth settings, Site Health screen sizes, schedule, CI and pages, or issue tracker settings
MCP tool: envs_update
env-id: Environment id
--name <string>: New name--url <string>: New root URL--app-id <strings>: App id for an app surface, as surface=id (android=com.acme.app, ios=com.acme.App), repeatable: that surface's tests install the newest uploaded build of it; "ios=" clears it. Warns, naming the uploaded ids, when no uploaded build has it--auth <public|gated>: New auth choice--viewport <all|phone|tablet_portrait|tablet_landscape|desktop|desktop_wide>: Screen size the Site Health visual checks run at, repeatable; replaces the set. Pass--viewport allto reset to all five.--health-schedule <off|daily|weekly>: Run Site Health on a schedule (default off)--health-time <string>: Time of day scheduled runs start, 24h, in--health-timezone(default 09:00)--health-day <mon|tue|wed|thu|fri|sat|sun>: Day weekly runs start (default mon)--health-timezone <string>: IANA timezone for the schedule, e.g. Europe/Berlin (default UTC)--health-ci <off|every_build|main_only|deploy_only>: Which CI buildshealth run --cichecks; other builds skip and pass (default off)--health-ci-fail-on <high|medium|never>: Lowest finding severity that fails the CI build; never reports only (default high)--health-ci-tickets <on|off>: CI runs file tracker tickets; off leaves the findings to the PR (default off)--health-pages <homepage|paths|sitemap|crawl>: Pages a run checks: the homepage,--health-pathlist, sitemap.xml, or a crawl from the homepage (default homepage)--health-path <strings>: Page path for the paths mode, repeatable; replaces the list.noneclears it--health-crawl-depth <number>: Link hops from the homepage in crawl mode, 1-5 (default 2)--health-max-pages <number>: Most pages one run checks, homepage included, 1-100 (default 25)--health-include <strings>: Path pattern a page must match, e.g. '/blog/*', repeatable; replaces the list.noneclears it--health-exclude <strings>: Path pattern to skip, repeatable; replaces the list.noneclears it--health-logged-in <strings>: Path pattern checked signed in with the environment's saved test sign-in, repeatable; the rest run logged out.noneclears it--health-retries <number>: Extra attempts when a page check fails or times out, 0-3 (default 1)--tracker <linear|off>: Tracker Site Health files tickets in;offstops filing for this environment (connect it first withhealth tracker connect)--tracker-team <string>: Tracker team id (seehealth tracker teams)--tracker-project <string>: Tracker project id inside the team (seehealth tracker projects);noneclears it--tracker-label <strings>: Label put on every ticket, repeatable; replaces the set (default beryl)--tracker-priority <strings>: Severity to tracker priority, repeatable, e.g. high=urgent. Priorities: urgent, high, medium, low, none (default high=high, medium=medium, low=low)--tracker-threshold <high|medium|low>: Lowest severity filed automatically; the rest go to the digest (default high)--tracker-digest <off|daily|weekly>: Digest of findings that were not filed (default weekly)--tracker-digest-to <ticket|slack>: Where the digest goes: one digest ticket, or the Slack alert channel (default ticket)--tracker-auto-close <on|off>: Close a ticket once a run no longer sees its finding (default on)--tracker-reopen <on|off>: Reopen the same ticket when a fixed finding comes back; off files a new one (default on)--tracker-reopen-closed <on|off>: Reopen a ticket closed in the tracker while the check still fails (default on)--tracker-max-tickets <number>: New tickets one run may file, 0-100; the rest go to the digest (default 10)--tracker-assignee <string>: Tracker user id (a person or an agent user) new tickets go to;noneclears it--tracker-min-runs <number>: Runs in a row a finding must show in before a manual run files it (default 1)--tracker-min-runs-scheduled <number>: Same, for scheduled and CI runs (default 2)--tracker-pause <on|off>: Pause all ticket creation and updates without disconnecting
Also accepts --workspace and --project (see Configuration).
beryl envs update <env-id> --tracker linear --tracker-team <team-id>
beryl envs update <env-id> --app-id android=com.acme.app --app-id ios=com.acme.App
beryl envs update <env-id> --tracker-threshold medium --tracker-max-tickets 5
beryl envs update <env-id> --tracker-priority high=urgent --tracker-pause on
beryl envs update <env-id> --health-schedule daily --health-time 06:00 --health-timezone Europe/Berlin
beryl envs update <env-id> --health-pages crawl --health-max-pages 25 --health-exclude '/blog/*'
beryl envs update <env-id> --health-ci main_only --health-ci-fail-on mediumDelete an environment
MCP tool: envs_delete
env-id: Environment id
--force: Skip the confirmation prompt
Also accepts --workspace and --project (see Configuration).
beryl schedule
Manage the schedules on which Beryl runs a project's tests automatically. A project can hold many independent schedules; each has its own environment, cadence (daily or weekly), local run time, timezone, and target groups (none = every active test).
List the project's schedules
MCP tool: schedule_list
Also accepts --workspace and --project (see Configuration).
Add a schedule (daily, or weekly on a given day)
MCP tool: schedule_add
--frequency <daily|weekly>: How often (default daily)--day <number>: Weekly only: day of week, 0=Monday … 6=Sunday--hour <number>: Hour of day 0-23--minute <number>: Minute 0-59--tz <string>: IANA timezone (e.g. America/Los_Angeles)--groups <string>: Comma-separated group names or ids the schedule targets (the run covers the union of their active tests at fire time); omit to run every active test--env <string>: Environment id to run against (default: the project's default environment)
Also accepts --workspace and --project (see Configuration).
beryl schedule add --frequency daily --hour 6 --tz UTC
beryl schedule add --env <env-id> --frequency daily --hour 6 --tz UTC
beryl schedule add --groups "Smoke,Checkout" --frequency weekly --day 0 --hour 9 --minute 15 --tz UTCChange a schedule's cadence, time, timezone, groups, or environment
MCP tool: schedule_update
schedule-id: Schedule id (see schedule list)
--frequency <daily|weekly>: How often (default daily)--day <number>: Weekly only: day of week, 0=Monday … 6=Sunday--hour <number>: Hour of day 0-23--minute <number>: Minute 0-59--tz <string>: IANA timezone (e.g. America/Los_Angeles)--groups <string>: Comma-separated group names or ids the schedule targets (the run covers the union of their active tests at fire time); omit to run every active test--env <string>: Move the schedule to this environment id--all-tests: Target every active test (clears the schedule's groups)
Also accepts --workspace and --project (see Configuration).
Remove a schedule (its tests and groups stay)
MCP tool: schedule_remove
schedule-id: Schedule id (see schedule list)
Also accepts --workspace and --project (see Configuration).
beryl tests
Author, inspect, version, and heal a project's tests: the checks Beryl runs on each run.
List the project's tests with their latest result
Prints a concise table by default (title / status / id / last result / last run). Pass --wide for every field, or --json for the raw records. Returns every test unless --page is given; pass --page to walk a large project a slice at a time.
MCP tool: tests_list
--env <string>: Filter by environment id--group <string>: Show only tests in this group (by name; seeberyl groups list)--wide: Show all columns, not the concise default--access <string>: Only read or only write tests--page <number>: Return only this 1-indexed page instead of every test--page-size <number>: Tests per page when--pageis given (default 20, max 100)--status <string>: With--page, show only this bucket: passed, failing (failed or errored), failed, errored, cancelled, or quarantined--ungrouped: With--page, show only tests carrying no group--q <string>: With--page, show only tests whose title contains this text (case-insensitive)
Also accepts --workspace and --project (see Configuration).
Show one test
Returns the test's metadata row (status, flags, per-environment last result), not the plan. tests plan prints the stored JSON plan, tests script the rendered Playwright spec.
MCP tool: tests_get
test-id: Test id
Also accepts --workspace and --project (see Configuration).
Print a test's current step plan (JSON)
Returns the stored json_plan of the test's current version. tests get returns the metadata row, tests script the rendered Playwright spec.
MCP tool: tests_plan
test-id: Test id
Also accepts --workspace and --project (see Configuration).
Replace a test's step plan (creates a new version)
Accepts an ActionPlan (the shape tests plan returns), including the optional before and after sections. after runs on pass and on fail, so cleanup happens even when the test goes red. Pass --description when the re-authored plan changes what the test proves; omit it to keep the test's existing intent. Saves the edit with NO replay: it rides into the next run unproven; tests recompile is the verify-first alternative.
MCP tool: tests_set_plan
test-id: Test id
--file <string>: Plan JSON file, or - for stdin--plan <json>: The plan inline, instead of--file--description <string>: One to three sentences stating what this test proves: the immutable outcome Beryl's healing checks against. State the purpose, not the steps; the one observable signal that's true only if the flow worked. Omit to keep the test's existing intent.
Also accepts --workspace and --project (see Configuration).
beryl tests plan 4f… > plan.json # edit, then:
beryl tests set-plan 4f… --file plan.json
beryl tests set-plan 4f… --plan '{"steps":[{"action":"goto","url":"/pricing"}]}'Rename a test
MCP tool: tests_rename
test-id: Test idtitle: New title
Also accepts --workspace and --project (see Configuration).
beryl tests rename 4f… "Checkout happy path"Edit what a test proves, the target heal judges against
The intent is the plain-language statement of what the test proves; heal judges every repair against it. It belongs to the test, so every surface of the test gets a new version carrying the new text (same plan, recorded as your edit; see tests versions). The plan is NOT regenerated: change the steps with tests set-plan. Re-explore keeps matching the same test after an edit.
MCP tool: tests_set_intent
test-id: Test idintent: New intent text
Also accepts --workspace and --project (see Configuration).
beryl tests set-intent 4f… "Proves a shopper can check out and sees an order number."Replace the groups a test belongs to
Groups are project-defined labels used to filter, run, or schedule a slice of the suite (beryl runs trigger --group <name>). This REPLACES the whole set: pass every group you want, or none to clear it. Names must already exist in the project (beryl groups list); an unknown name is an error, never a new group. Every surface of the test carries the same set.
MCP tool: tests_set_groups
test-id: Test id
--group <strings>: Group name, repeatable. Omit entirely to clear the set.
Also accepts --workspace and --project (see Configuration).
beryl tests set-groups 4f… --group Checkout --group Smoke
beryl tests set-groups 4f…Mark a test read or write
read: the test only reads the app. write: it creates, edits, renames, deletes or toggles something that persists. The label is yours to set; Beryl does not infer it from the plan. A write test must clean up in after, ending with a proof expect. The label covers every surface of the test, so each surface's plan must clean up.
MCP tool: tests_set_access
test-id: Test idaccess: read | write
Also accepts --workspace and --project (see Configuration).
beryl tests set-access 4f… write
beryl tests set-access 4f… readAdd groups to one or more tests, keeping the groups they already have
The additive counterpart of tests set-groups: every listed test gains the given groups and loses none, so you don't need to know what each test already carries. Names must already exist in the project (beryl groups list); an unknown name is an error, never a new group.
MCP tool: tests_add_groups
test-ids...: One or more test ids
--group <strings>: Group name to add, repeatable (at least one)
Also accepts --workspace and --project (see Configuration).
beryl tests add-groups 4f… 9a… --group Smoke
beryl tests add-groups 4f… --group Checkout --group SmokeMute flaky tests: they keep running, but their failures stop failing the run
A quarantined test still executes and its result is still recorded and visible. Its red lands in the run's quarantined_count and gates neither the run's verdict nor exit codes, so it can't red-light a deploy. Use it on a persistently flaky test instead of deleting it (which destroys the history) or asking support to deactivate it (which stops it running at all). After the project's release threshold of consecutive clean passes (default 5) the test reports rehab_ready: a suggestion while auto quarantine is off, the actual release once projects quarantine on has turned it on. off un-quarantines. Several ids are one call; tests already in the requested state are left alone rather than rejected. Who quarantined what is recorded, readable with beryl tests events.
MCP tool: tests_quarantine
state: on | offtest-ids...: One or more test ids
Also accepts --workspace and --project (see Configuration).
beryl tests quarantine on 4f…
beryl tests quarantine on 4f… 9a… 1c…
beryl tests quarantine off 4f…Who quarantined, grouped or renamed a test, and why
Lifecycle history for one test, newest first: quarantine and release (by a person or by auto-quarantine, with the run and failure streak behind it), group changes, and renames. Plan edits are NOT here: those are versions, and beryl tests versions can restore them.
MCP tool: tests_events
test-id: Test id
--limit <number>: How many events (default 100, max 500)
Also accepts --workspace and --project (see Configuration).
beryl tests events 4f…
beryl tests events 4f… --limit 20Delete tests, their version history, and their results
Several ids are deleted together in one transaction: an unknown id fails the whole call and nothing is deleted.
MCP tool: tests_delete
test-ids...: One or more test ids
--force: Skip the confirmation prompt
Also accepts --workspace and --project (see Configuration).
beryl tests delete 4f… --force
beryl tests delete 4f… 9a… 1c…Validate + verify an edited plan against the live site before persisting
Unlike tests set-plan (which saves the edit and lets it ride into the next run), this replays the edited plan against the live site before anything persists. A deterministic replay failure (verdict drop) REJECTS the edit (persisted:false, the prior plan stays live) and returns the failure evidence (over MCP the screenshot is image content). Verdict flag (the runner errored, no verdict on the flow) persists the plan but reports it unverified. Returns 429 with Retry-After 30 when the 2 inline-verify slots are saturated (wait and retry).
MCP tool: tests_recompile
test-id: Test id
--file <string>: Plan JSON file, or - for stdin--plan <json>: The plan inline, instead of--file
Also accepts --workspace and --project (see Configuration).
List a test's version history
MCP tool: tests_versions
test-id: Test id
--limit <number>: Page size--cursor <number>: Continue from a previous next_cursor
Also accepts --workspace and --project (see Configuration).
Show one specific version of a test (including its plan)
MCP tool: tests_version
test-id: Test idversion-no: Version number
Also accepts --workspace and --project (see Configuration).
Diff two versions of a test's plan
MCP tool: tests_diff
test-id: Test idfrom: From version numberto: To version number
Also accepts --workspace and --project (see Configuration).
Restore a test to an earlier version
Copies the named older version's plan forward as a NEW head version, unlike tests reset, which flips authored_by back to system and leaves the plan untouched.
MCP tool: tests_restore
test-id: Test idversion-no: Version number to restore
Also accepts --workspace and --project (see Configuration).
Discard user edits and return the test to its latest system-authored version
Flips authored_by back to system WITHOUT changing the plan (the next regeneration overwrites it), unlike tests restore, which copies an older version's plan forward as a new version.
MCP tool: tests_reset
test-id: Test id
Also accepts --workspace and --project (see Configuration).
Turn self-healing on or off for a test
Only matters while the project's self-heal is on (projects heal on); it is off by default, and then no test heals.
MCP tool: tests_heal
test-id: Test idstate: on or off
Also accepts --workspace and --project (see Configuration).
Pass/fail history, streak, and stability for a test
MCP tool: tests_history
test-id: Test id
--limit <number>: How many runs of history--env <string>: Filter by environment id
Also accepts --workspace and --project (see Configuration).
Print the rendered Playwright spec for a test
Fetches the banked test's rendered .spec.ts: the executable spec. tests plan returns the stored JSON plan it is rendered from, tests get the metadata row.
MCP tool: tests_script
test-id: Test id
Also accepts --workspace and --project (see Configuration).
beryl tests script 4f…Export tests as Playwright .spec.ts files in a ZIP
Writes the ZIP to disk. With --inline, nothing is written: the result carries the same files as {files: [{filename, content}]}.
MCP tool: tests_export
test-ids...: One or more test ids
--out <string>: Output file (default beryl-tests.zip)--inline: Return the files in the result instead of writing a ZIP
Also accepts --workspace and --project (see Configuration).
beryl groups
Manage a project's test groups: labels a test can carry any number of, used to filter, run, or schedule a slice of the suite. Groups are created only here (or in Settings → Groups); assigning a test to an unknown name is an error.
List the project's test groups and how many tests each holds
MCP tool: groups_list
Also accepts --workspace and --project (see Configuration).
Create a group
MCP tool: groups_create
name: Group name (unique per project)
Also accepts --workspace and --project (see Configuration).
beryl groups create SmokeRename a group (tests keep their membership)
MCP tool: groups_rename
group: Current group name or idname: New name
Also accepts --workspace and --project (see Configuration).
Delete a group: its tests stay; a schedule targeting only this group goes with it
MCP tool: groups_delete
group: Group name or id
--force: Skip the confirmation prompt
Also accepts --workspace and --project (see Configuration).
beryl runs
Trigger a run of a project's tests (e.g. in CI), then watch, inspect, and download results.
Trigger a test run (whole suite, a subset, or one environment)
Runs execute in Beryl's cloud. With --watch the CLI follows live progress and exits 0 only if every test passed, so wire it straight into CI. A run with a heal-eligible failure completes only after Beryl has tried to heal it: a repaired test is re-run inside the same run and counts as passed (reported as healed), so the final counts, the report and the completion email all reflect the repair. A project runs one run at a time: a run triggered while another is in flight comes back queued with its queue_position and starts on its own, in trigger order, when the runs ahead of it finish (--watch waits through the queue).
MCP tool: runs_trigger
--test <strings>: Run only these test ids (repeatable)--group <strings>: Run only the active tests in these groups (by name, repeatable, union of members), resolved to ids before the run so the run records exactly what it ran. Cannot be combined with--test.--env <string>: Environment id to run against--url-override <string>: Replace the base URL (preview deploys)--header <strings>: Send a custom request header on every navigation, KEY=VALUE (repeatable). Reaches auth-walled preview deploys, e.g.--headerx-vercel-protection-bypass=<token>--watch: Follow progress and exit non-zero on failure--timeout <number>: With--watch: max minutes to wait. A test that waits for an asynchronous process (a wait_until step) can run for minutes, so set this generously for a suite that has one.--fail-fast: With--watch: cancel the run and exit 1 on the first failing test, instead of waiting for the rest of the suite. Built for CI gates; off by default--retries <number>: Retry a failing test up to N times (0 disables); omit for the default--commit <string>: Commit sha of your app this run tests, shown on the run. Detected automatically in GitHub Actions and GitLab CI (or from BERYL_COMMIT_SHA); this overrides it--branch <string>: Branch of your app this run tests, shown on the run. Detected automatically in GitHub Actions and GitLab CI (or from BERYL_BRANCH); this overrides it
Also accepts --workspace and --project (see Configuration).
beryl runs trigger --watch
beryl runs trigger --url-override https://preview-123.example.com --watch --timeout 30
beryl runs trigger --url-override https://preview-123.example.com --header x-vercel-protection-bypass=<token> --watch
beryl runs trigger --test 4f… --test 9a…
beryl runs trigger --group Smoke --group Checkout --watch
beryl runs trigger --retries 0 --watch
beryl runs trigger --commit $(git rev-parse HEAD) --branch main --watchShow the run in flight and the runs waiting behind it
A project runs one run at a time. Returns active (the pending or running run, or null) and queued, the waiting runs in the order they will start, each with its queue_position. Cancel a waiting run with runs cancel.
MCP tool: runs_queue
Also accepts --workspace and --project (see Configuration).
List recent runs
Returns the 50 most recent runs unless --page is given; pass --page to walk the full history a slice at a time.
MCP tool: runs_list
--env <string>: Filter by environment id--page <number>: Return only this 1-indexed page instead of the 50 most recent runs--page-size <number>: Runs per page when--pageis given (default 8, max 100)
Also accepts --workspace and --project (see Configuration).
Show one run with its per-test results
Over MCP the failure screenshots come back as viewable image content, so an agent can look at the page that broke instead of guessing from the error string. Set screenshots to false to skip fetching them. Ignored outside MCP (the terminal cannot show an image). Returns the run row with every per-test result unless --page is given; pass --page to read a large run a slice at a time, optionally narrowed by --status, --group or --q, which keeps the output readable rather than saving a round trip. With --page the match total and page counts come back under results_page. Paged results are the run's settled tests only: anything still running, healing or queued is left out. A result carries heal when Beryl healed it: its steps were rewritten with the intent unchanged, proved in a browser and it re-ran green; version_no is the revision it wrote (see tests diff) and rationale the agent's reason. A red that Beryl tried and failed to heal carries heal_attempt: status is how the heal ended, reason why, and heal_job_id the job. A red that Beryl did not try to heal carries heal_skip_reason saying why. runs report returns the generated report document, runs explain an AI explanation of one failed result.
MCP tool: runs_get
run-id: Run id
--screenshots: Attach failure screenshots as image content (MCP only; default true)--page <number>: Return only this 1-indexed page of results instead of every result--page-size <number>: Results per page when--pageis given (default 20, max 100)--status <string>: With--page, show only this bucket: passed, failed, errored, cancelled, or quarantined--group <string>: With--page, show only results whose test is in this group (by name; seeberyl groups list)--ungrouped: With--page, show only results whose test carries no group--q <string>: With--page, show only results whose test title contains this text (case-insensitive)
Also accepts --workspace and --project (see Configuration).
Follow a run until it finishes
Replays what already happened, then follows live. Exits 0 only if every test passed.
MCP tool: runs_watch
run-id: Run id
--timeout <number>: Max minutes to wait--fail-fast: Cancel the run and exit 1 on the first failing test, instead of waiting for the rest of the suite. Built for CI gates; off by default
Also accepts --workspace and --project (see Configuration).
Cancel an in-flight run, or take a queued one out of the queue
MCP tool: runs_cancel
run-id: Run id
Also accepts --workspace and --project (see Configuration).
Show the generated report for a run
Returns the run's stored generated report (404 until it has been generated). causes groups the failures: every test that failed inside the same signup steps (a fresh {{inbox_address}} user) is one signup cause, so a broken signup reads as one problem; each other failure is its own test cause. runs get returns the raw run row with per-test results.
MCP tool: runs_report
run-id: Run id
Also accepts --workspace and --project (see Configuration).
Get a run's results with signed artifact URLs, or download them to disk
With neither --dir nor --out, writes nothing: returns the JSON manifest, whose screenshot, DOM snapshot, trace and frame URLs are short-lived signed links any HTTP client can fetch. With --dir, fetches the artifact bytes (screenshots, DOM snapshots, the Playwright trace zip, and the filmstrip frames of the failing tests) into <dir>/<test-result-id>/ alongside a run.json manifest. With --out, writes only the manifest. The URLs expire, so fetch rather than stash them.
MCP tool: runs_download
run-id: Run id
--dir <string>: Write run.json plus the artifact files into this directory--all-frames: With--dir: also fetch the filmstrip frames of passing tests--out <string>: Write the JSON to a file instead of stdout
Also accepts --workspace and --project (see Configuration).
beryl runs download 7c1… --dir ./beryl-run
beryl runs download 7c1… --out run.jsonExplain, with AI, why a test result failed
Takes a single test-RESULT id (not a run id) and returns an AI failure explanation for that result. runs get lists a run's results and their ids.
MCP tool: runs_explain
result-id: Test result id (fromberyl runs get)
Also accepts --workspace and --project (see Configuration).
beryl health
Site Health, or how your site reads to search engines and visitors: content, speed, links, security, and a visual check of layout at phone, tablet and desktop sizes, graded from a real check of your live pages.
Show the latest Site Health report, or one report by id
A check runs automatically when a project or environment gets its URL. While one is in flight the report comes back with status queued/running and no grades yet, plus the stage a running check is on; call again to pick up the finished result. Visual findings sit in the layout category, which also grades them per screen size (screens: phone, tablet, desktop) and as mobile (phone and tablet only). Each carries a key, the selector, measured values, the viewports it shows at and a fix hint in recommendation. The performance category grades Google PageSpeed on mobile and on desktop separately (speeds, each with its own Core Web Vitals) and takes the worse of the two; one that couldn't be measured is left out. A category's unchecked lists checks this run couldn't determine (e.g. robots.txt timed out): they neither pass nor fail. Pass --report for a single-page check started with health run --path. site_health_runs_reset_fields and site_health_tracker_reset_fields name stored settings that were invalid and fell back to defaults (* = all of them): scheduled and CI runs, or ticket filing, stop until they are saved again with envs update.
MCP tool: health_get
--env <string>: Environment id (defaults to the project's default environment)--report <string>: Report id (fromhealth run)--run <string>: Run id: every page of one run, finding counts and the CI gate verdict--screenshots: Include the annotated screenshots (as images over MCP, data URIs in--json)
Also accepts --workspace and --project (see Configuration).
Run a fresh Site Health check, or a visual check of one page
Queues a check and returns immediately (or, with --wait, once it finishes; a check takes one to three minutes). Without --path it is the full Site Health run of the environment URL. With --path it runs only the visual checks (clipping, overlap, tap targets, scroll traps, content stability, scroll-through) on that page, logged out unless it matches the environment's --health-logged-in patterns, at the chosen --viewport sizes (default: the environment's configured set). Returns the in-flight report instead of stacking a second one of the same scope. A full run also checks the environment's configured pages (see envs update --health-pages); each page gets its own report, grouped under the homepage report's run_id.
With --ci it starts a CI run, waits for every page, prints a Markdown summary you can post as the PR comment, and exits 1 when findings at or above the environment's fail-on severity exist, a page couldn't be checked, or the run failed. Builds that the environment's CI mode doesn't cover skip and exit 0; if the stored run settings are invalid it exits 1 rather than skipping. CI runs file tracker tickets only when --health-ci-tickets is on.
MCP tool: health_run
--env <string>: Environment id (defaults to the project's default environment)--path <string>: Page path to check, e.g. /pricing--viewport <phone|tablet_portrait|tablet_landscape|desktop|desktop_wide>: Screen size, repeatable: phone (390x844), tablet_portrait (768x1024), tablet_landscape (1024x768), desktop (1440x900), desktop_wide (1920x1080)--wait: Wait for the check to finish--screenshots: Include the annotated screenshots (as images over MCP, data URIs in--json)--ci: CI run: wait, print a PR-ready summary, exit 1 at or above the fail-on severity--branch <string>: Branch of the CI build (default: read from the CI environment)--deploy: The CI build is a deploy (for--health-cideploy_only)
Also accepts --workspace and --project (see Configuration).
beryl health run
beryl health run --path /pricing --viewport phone --wait
beryl health run --ci
beryl health run --ci --deploy --env <env-id>Mark a visual finding as intended, so it stops counting against the grade
Takes the finding's key from health get. The finding stays in the report, flagged intended, and is left out of the grade on this report and every later run of the environment. --clear removes the mark.
MCP tool: health_intended
key: Finding key
--env <string>: Environment id (defaults to the project's default environment)--clear: Remove the mark
Also accepts --workspace and --project (see Configuration).
Show how Site Health files findings as issue tracker tickets for an environment
Returns the environment's tracker settings with every default filled in, the workspace's connection (status: disconnected means the token expired or was revoked; ticket changes queue until you reconnect), the number of queued changes, open tickets (filed in the tracker), unfiled_tickets the tracker hasn't accepted yet with its last_sync_error, digest findings, and last_sync: what the latest run filed, updated, closed or skipped. reset_fields names stored settings that were invalid and fell back to defaults (* = all of them); filing, auto-close and the digest stop (last_sync.skipped: settings_invalid) until they are saved again. Change settings with envs update --tracker-*.
MCP tool: health_tracker_status
--env <string>: Environment id (defaults to the project's default environment)
Also accepts --workspace and --project (see Configuration).
List the findings Site Health tracks in the issue tracker, with their tickets
One row per finding: status watching (seen, waiting for enough runs in a row), digest (not filed), open, closed (with close_reason fixed, intended or tracker) or stale (its page is gone), plus the ticket key and URL once filed and queued when a change is waiting to reach the tracker.
MCP tool: health_tracker_tickets
--env <string>: Environment id (defaults to the project's default environment)--status <watching|digest|open|closed|stale>: Only rows in this status
Also accepts --workspace and --project (see Configuration).
Get the link that connects an issue tracker to the workspace
Returns an authorize URL for a workspace admin to open in a browser. Once approved, Beryl files tickets as its own app user, and any changes queued while disconnected are applied. Then pick a team with envs update --tracker-team.
MCP tool: health_tracker_connect
--tracker <linear>: Issue tracker (default linear)
Also accepts --workspace (see Configuration).
Remove the workspace's issue tracker connection
Deletes the stored tokens. Tickets already filed stay in the tracker; to stop filing for one environment only, use envs update --tracker off or --tracker-pause on.
MCP tool: health_tracker_disconnect
--tracker <linear>: Issue tracker (default linear)--force: Skip the confirmation prompt
Also accepts --workspace (see Configuration).
List the teams of the connected issue tracker
MCP tool: health_tracker_teams
--tracker <linear>: Issue tracker (default linear)
Also accepts --workspace (see Configuration).
List a tracker team's projects
MCP tool: health_tracker_projects
--tracker <linear>: Issue tracker (default linear)--team <string>: Team id (seehealth tracker teams) (required)
Also accepts --workspace (see Configuration).
beryl jobs
Test-creation jobs: the cloud agent follows a prompt, reads any document it comes with, and authors tests.
Create tests from a prompt, with an optional document, on Beryl's cloud
Queues a job from a prompt (what to test; a line is enough) and an optional document (Markdown, plain text, PDF or DOCX: --file, --text, or --content-base64 with --filename): the agent explores the environment, drafts one flow per scenario the prompt asks for, reading the document when there is one, and authors one test per enabled surface of the project. The agent signs in as the environment's default test account, or the one --account names, and the tests it saves sign in as that account too. New tests get no groups. A job runs once and ends done, partial (some tests saved, the rest listed with why) or failed; jobs retry authors what a partial or failed job left out, jobs clone runs the whole document again. With --ci (or a project CI token as BERYL_TOKEN, which always creates CI jobs) the job never pauses for input: a scenario behind a login it cannot pass is skipped with the reason. The prompt and document are sent to the LLM that drives the agent, so leave out anything you would not share with it.
MCP tool: jobs_create
prompt: What to test: the instruction the agent follows; a line is enough
--file <string>: Path to a document (PRD, release notes) the agent reads with the prompt--text <string>: The document as text, instead of a file--content-base64 <string>: A binary document (PDF, DOCX) base64-encoded, instead of a file; needs--filename--filename <string>: With--content-base64: the document's name; its extension sets the type--env <string>: Environment id to explore (defaults to the project's default)--account <string>: Label of the test account to sign in as (seeaccounts list); defaults to the environment's default account--ci: Non-interactive job for CI: never waits for a captured session, skips what it blocks
Also accepts --workspace and --project (see Configuration).
beryl jobs create "Cover the checkout flow: add an item, pay by card, see the confirmation" --env <env-id>
beryl jobs create "Draft a test for each scenario in the release notes" --file ./release-notes.md
beryl jobs create "Cover the admin console" --file ./admin-console.md --account admin
BERYL_TOKEN=beryl_ci_... beryl jobs create "Cover the brief" --file ./brief.md --ci --workspace <ws-id> --project <project-id>List the project's test-creation jobs
MCP tool: jobs_list
Also accepts --workspace and --project (see Configuration).
Show a job's status and the tests it created
MCP tool: jobs_get
job-id: Job id
Also accepts --workspace and --project (see Configuration).
Run a job again: queue a new job with the same prompt, document, environment and account
The prompt and document are sent to the LLM that drives the agent, so leave out anything you would not share with it.
MCP tool: jobs_clone
job-id: Job id to clone
Also accepts --workspace and --project (see Configuration).
Author only what a partial or failed job left out, optionally with an edited prompt or document
Queues a new job that authors each scenario the job drafted but has no test on some surface, and each scenario it skipped, on the surfaces that miss them. The new tests join the same flows. --prompt replaces the job's instruction and --file or --text its document; anything not passed is reused from the job. The prompt and document are sent to the LLM that drives the agent, so leave out anything you would not share with it.
MCP tool: jobs_retry
job-id: Job id to retry
--prompt <string>: An edited instruction for the agent--file <string>: Path to an edited document (Markdown or plain text)--text <string>: The edited document as text, instead of--file
Also accepts --workspace and --project (see Configuration).
beryl jobs retry <job-id>
beryl jobs retry <job-id> --prompt "Refund lives under Orders; test it there"
beryl jobs retry <job-id> --file ./brief-v2.mdDelete a job; the flows and tests it created stay
MCP tool: jobs_delete
job-id: Job id
--force: Skip the confirmation prompt
Also accepts --workspace and --project (see Configuration).
beryl explorations
Inspect the agent's exploration runs: how it crawled a site and authored its tests.
List the agent's exploration passes for a project
Also accepts --workspace and --project (see Configuration).
Show one exploration: authored tests, abandoned flows, coverage, frontier
exploration-id: Exploration id
Also accepts --workspace and --project (see Configuration).
List every step the agent took in an exploration
exploration-id: Exploration id
Also accepts --workspace and --project (see Configuration).
Cancel an in-flight exploration
Stops a running exploration without touching the project or its tests: the lever for a runaway/non-convergent pass burning agent budget.
exploration-id: Exploration id
Also accepts --workspace and --project (see Configuration).
Stream an exploration live: watch the agent explore and author tests
Replays every recorded step on connect, then follows live until the exploration ends. Exits 0 only if it completed; a failed or cancelled exploration, or a stream that keeps closing without a final status, exits 1.
exploration-id: Exploration id
--timeout <number>: Max minutes to wait
Also accepts --workspace and --project (see Configuration).
beryl config
Manage the variables, secrets, and files the agent can use while exploring and running.
List the project's config variables (visible to the agent during runs)
MCP tool: config_vars_list
Also accepts --workspace and --project (see Configuration).
Create or update a config variable
MCP tool: config_vars_set
key: Variable namevalue: Variable value
--env <string>: Scope to one environment id
Also accepts --workspace and --project (see Configuration).
Show one config variable
Returns the variable row with its value in plaintext (variables are not secret). A sensitive value lives in config secrets, readable only via config secrets get --reveal.
MCP tool: config_vars_get
key: Variable key or id
Also accepts --workspace and --project (see Configuration).
Delete a config variable
MCP tool: config_vars_delete
key: Variable key or id
--force: Skip the confirmation prompt
Also accepts --workspace and --project (see Configuration).
List the project's secrets (values are never returned); a test account's password is managed on the account, not here
MCP tool: config_secrets_list
Also accepts --workspace and --project (see Configuration).
Create a secret (write-only; re-setting a key replaces it)
MCP tool: config_secrets_set
key: Secret namevalue: Secret value (or - to read from stdin)
--env <string>: Scope to one environment id
Also accepts --workspace and --project (see Configuration).
Show one secret's metadata, or reveal its value with --reveal
Returns metadata only by default; --reveal is a logged, member-gated decrypt (unlike config vars get, which returns its value in plaintext).
MCP tool: config_secrets_get
key: Secret key or id
--reveal: Return the decrypted value: the explicit read that lets the agent drive a real login while authoring. Member-gated; every reveal is logged--env <string>: With--reveal: prefer the row scoped to this environment id when the key exists at both scopes (matches what a run against that environment resolves)
Also accepts --workspace and --project (see Configuration).
Delete a secret
MCP tool: config_secrets_delete
key: Secret key or id
--force: Skip the confirmation prompt
Also accepts --workspace and --project (see Configuration).
List uploaded files: fixtures tests attach and Android and iOS app builds
MCP tool: config_files_list
Also accepts --workspace and --project (see Configuration).
Show one uploaded file's metadata
MCP tool: config_files_get
file: File name or id
Also accepts --workspace and --project (see Configuration).
Upload a file: a fixture an upload step attaches, or an Android or iOS app build
The bytes go straight to storage over a short-lived URL, never through the API, up to 1 GB. An .apk uploads as an Android build (or pass --kind android_build): Beryl reads its package name, version and native ABIs, refuses one the emulators cannot run (an .aab, a split APK, a too-new minSdk, ARM-only native code on x86 emulators). An iOS simulator build (the .app folder zipped, or EAS's .tar.gz) uploads with --kind ios_build: Beryl reads its bundle id and version and refuses an .ipa, a device build or one with no arm64 slice. App tests of an environment whose app id for that surface matches install the newest build; the upload warns when no environment has the build's app id. Beryl keeps the newest 5 builds per app per environment. Upload after each build, e.g. in CI.
MCP tool: config_files_upload
file: Path to the local file
--env <string>: Scope to one environment id--kind <fixture|android_build|ios_build>: fixture: a file tests attach. android_build: an Android APK (the default for .apk). ios_build: a zipped or tarred iOS simulator .app
Also accepts --workspace and --project (see Configuration).
beryl config files upload ./fixtures/avatar.png
beryl config files upload ./android/app/build/outputs/apk/release/app-release.apk
beryl config files upload ./MyApp.zip --kind ios_buildGet a short-lived download URL for a file
MCP tool: config_files_download
file-id: File id
Also accepts --workspace and --project (see Configuration).
Delete an uploaded file
MCP tool: config_files_delete
file-id: File id
--force: Skip the confirmation prompt
Also accepts --workspace and --project (see Configuration).
beryl mailbox
The project's standing email addresses, where its tests receive sign-in mail.
The project's mailbox address
Returns the address {{mailbox_address}} resolves to, creating it on first ask. Every test that reads mail receives here, at its own +tag alias of this mailbox: a plan cites {{inbox_address}}, minted per execution and read by that test alone, so parallel tests never consume each other's codes. A test never types the bare address (the save refuses it); only an account's own signup and sign-in plans (accounts signup, accounts set-login) may fill it. Every alias minted is listed by mailbox identities, and a plan that signs up with one must delete the account in its after section.
MCP tool: mailbox_get
Also accepts --workspace and --project (see Configuration).
List the project's mailboxes
MCP tool: mailbox_list
Also accepts --workspace and --project (see Configuration).
The +tag addresses Beryl minted for this project's tests, and how each cleanup ended
Every {{inbox_address}} a run rendered is recorded: which test and run minted it, and what the runner saw of its teardown (clean, skipped, failed, unverified, or none when the plan has no after section). This is the list of identities that may still exist on the site under test. Rows are kept for 30 days.
MCP tool: mailbox_identities
--run <string>: Only addresses minted by this run id--test <string>: Only addresses minted by this test id--limit <number>: Newest N rows (default 100, max 500)
Also accepts --workspace and --project (see Configuration).
beryl mailbox identities
beryl mailbox identities --run run_123 --jsonAdd a second mailbox to the project
Only needed when a flow requires two genuinely separate inboxes at the same time (both sides of an invite handshake). For an address the site has not seen before, cite {{inbox_address}} in the plan instead: it aliases the existing mailbox and costs nothing to manage.
MCP tool: mailbox_create
--label <string>: What this mailbox is for, e.g. 'invitee'--default: Make it the project's default
Also accepts --workspace and --project (see Configuration).
beryl mailbox create --label inviteeDelete a mailbox and every email it has received
Destructive: the address is configured into the site under test, so removing it breaks every test that signs in through it.
MCP tool: mailbox_delete
mailbox-id: Mailbox id fromberyl mailbox list
--force: Skip the confirmation prompt
Also accepts --workspace and --project (see Configuration).
Read the latest email in a mailbox (waits for one to arrive)
Waits up to --timeout-s for a matching email and returns it (one blocking request; the server caps the wait at 50s, so re-run to keep waiting). With --extract-code, also asks the server to pull the one-time code out of the email (AI-assisted when the email is ambiguous; code is null if none was found). Use --recipient-contains to read only one +tag alias's mail when several identities share the mailbox. Exits non-zero if nothing arrives before the timeout. Waits for and returns ONE latest matching email. mailbox emails lists what has already arrived, without waiting.
MCP tool: mailbox_read
mailbox-id: Mailbox id fromberyl mailbox list
--timeout-s <number>: Seconds to wait for a matching email (0 = don't wait; max 50, default 30)--since <string>: Only emails received after this ISO timestamp--from-contains <string>: Only emails whose sender contains this--subject-contains <string>: Only emails whose subject contains this--recipient-contains <string>: Only mail delivered to an address containing this (a +tag alias)--extract-code: Also return the one-time code found in the email ascode
Also accepts --workspace and --project (see Configuration).
beryl mailbox read mbx_123 --timeout-s 45 --json
beryl mailbox read mbx_123 --subject-contains code --extract-code --jsonList the emails a mailbox has received
Returns the already-received emails without waiting. mailbox read blocks for a matching one and returns just it.
MCP tool: mailbox_emails
mailbox-id: Mailbox id fromberyl mailbox list
--since <string>: Only emails received after this ISO timestamp--limit <number>: Return only the most recent N emails (newest first)
Also accepts --workspace and --project (see Configuration).
beryl third-party-integrations
Test a site's own integrations (Connect Slack) against Beryl's accounts on those providers.
The third party providers this project's tests can connect to
Lists the providers set up on this Beryl deployment. A test may use third_party_authorize / await_third_party / send_third_party only for a provider listed here; anything else is refused at save time.
MCP tool: third_party_integrations_list
Also accepts --workspace and --project (see Configuration).
The channel this project's tests pick when the app asks where to post
Returns the project's own destination on Beryl's provider account (for Slack, a channel), creating it on first ask. When a test connects the app, it picks this channel in the app's settings; await_third_party then waits for the app's message there. recorded_app_ids maps each environment id to the app whose first message was seen there; an environment accepts only its own app once recorded. Pass env and app to record that app yourself (a Slack app id, A...), which send_third_party needs to know whose bot to mention. A 409 means the provider is not set up on this deployment (see third-party-integrations list).
MCP tool: third_party_integrations_target
--provider <string>: Provider key fromthird-party-integrations list, e.g. slack (required)--env <string>: Environment id to recordappfor (withapp)--app <string>: The connected app's id on the provider, e.g. a Slack app id (withenv)
Also accepts --workspace and --project (see Configuration).
beryl third-party-integrations target --provider slack
beryl third-party-integrations target --provider slack --env <env-id> --app A0123ABCDberyl accounts
Durable identities on the site under test: what an authenticated test signs in as.
List the test accounts an environment's tests sign in as
Every test account on the project, with the identity label a plan's auth_label names. The row marked * is the default: what a plan gets when it sets requires_auth without an auth_label. Below them, grouped as throwaway, the newest accounts test executions created for themselves through {{inbox_address}}: which run and test minted each, and how its teardown ended. They are kept for 30 days.
MCP tool: accounts_list
--env <string>: Only accounts on this environment id--throwaway-limit <number>: How many of the newest throwaway accounts to show (default 50, max 500, 0 hides them)
Also accepts --workspace and --project (see Configuration).
Show one test account: origin, lifetime, sign-in state
One test account by id. type is its origin: captured (a session from the Chrome plugin), provisioned (Beryl signed it up; lifetime permanent or throwaway), or provided (your own account).
MCP tool: accounts_get
account-id: Account id fromberyl accounts list
Also accepts --workspace and --project (see Configuration).
beryl accounts get acc_123Add a test account: the customer's own, or one Beryl signs up
Two kinds. --type provided records a dedicated account you already have on the site: pass --email and --password, and it is usable immediately. --type provisioned reserves one Beryl will sign up itself, addressed at the project mailbox; --lifetime says whether it is kept (permanent, the default) or a throwaway. It starts pending and becomes usable after beryl accounts signup. A captured account (a signed-in session from the Beryl Chrome extension) is not created here: capture it with the extension (https://chromewebstore.google.com/detail/beryl/nnjhiapfdhhmmjabnafdaomdmhlolfkp), then give it a probe with beryl accounts set-login --probe. Works for Google-only apps too: bank a dedicated Google test account as provided and author its sign-in plan through Google's form. The first account an environment gets is its default whatever you pass.
MCP tool: accounts_create
--type <provided|provisioned>: Whose account this is (default: provided when--passwordis given)--lifetime <permanent|throwaway>: provisioned only: keep it, or a throwaway (default permanent)--label <string>: Identity label a plan's auth_label names (default 'default')--email <string>: provided only: the account's email--password <string>: provided only: stored encrypted as a project secret, never returned--login-method <password|magic_link|otp>: How tests sign in as it (default password)--env <string>: Environment id (default: the project's)--default: Make this the environment's default
Also accepts --workspace and --project (see Configuration).
beryl accounts create --email [email protected] --password 'hunter2'
beryl accounts create --type provisioned --login-method otp
beryl accounts create --email [email protected] --password 'hunter2' --label admin
beryl accounts create --email [email protected] --password 'hunter2' # Google-only appStore a signed-in session as a captured test account
Usually done by the Beryl Chrome extension (https://chromewebstore.google.com/detail/beryl/nnjhiapfdhhmmjabnafdaomdmhlolfkp) from a signed-in tab; this takes the same session JSON from a file or inline: {schema_version: 2, final_url, cookies (CDP shape), local_storage, session_storage, indexed_db}. Upserts by --label on the environment, so capturing an existing label replaces its session. Cookies for other domains are dropped and listed. A captured account cannot sign itself in: give it a probe with beryl accounts set-login --probe, then prove it with beryl accounts check. Its session is never served back to a client.
MCP tool: accounts_capture
--file <string>: The captured session, as JSON (path, or - for stdin)--session <json>: The captured session inline, instead of--file--label <string>: Identity label a plan's auth_label names (default 'default')--email <string>: The signed-in user's email--env <string>: Environment id (default: the project's)--default: Make this the environment's default
Also accepts --workspace and --project (see Configuration).
beryl accounts capture --file session.json --label adminStore a test account's signup plan and sign it up on its environment
Runs the app's signup form once in a real browser and, if it ends logged in, marks the account ready. The plan is an ordinary ActionPlan of the SIGNUP flow. Type {{mailbox_address}} into the email field and {{login_password}} into the password field. Both resolve at replay time, and an await_email step reads the project mailbox, so a verification code works. The plan is kept on the account, so the same identity can be signed up again on a new environment. For an account that already exists on the site, store its sign-in with accounts set-login instead.
MCP tool: accounts_signup
account-id: Account id fromberyl accounts list
--file <string>: The signup ActionPlan, ending logged in, as JSON (path, or - for stdin)--plan <json>: The signup ActionPlan inline, instead of--file
Also accepts --workspace and --project (see Configuration).
beryl accounts signup acc_123 --file signup-plan.jsonStore the sign-in plan a run replays once, plus the probe that proves it
Session mode: instead of every authenticated test signing in for itself, the account signs in ONCE at the start of a run and every test rides that session. This stores the two plans that makes possible.
--file (or --plan inline) is the SIGN-IN plan (not the signup): it must end logged in. Type {{login_email}} into the email field and {{login_password}} into the password field; an emailed code or magic link arrives at the account's own address, so an await_email step reads it with no human involved.
--probe is the liveness check: a two-step plan (goto a gated page, then a POSITIVE assertion that only holds when signed in: the account menu, a 'Sign out' control). It is replayed in a fresh browser carrying only the captured session. It is REQUIRED, and not a formality: assertions like hidden, count 0, and a URL match on a redirect all pass against a logged-out page, so without a positive signal a dead session would run every test logged-out and still report the run green.
A captured account (from the Beryl Chrome extension) takes --probe alone: it rides the captured session and cannot sign itself in, so there is no --file or --plan.
--surface android stores the sign-in Android tests use instead, beside the web one; Beryl proves it on an Android worker the first time a signed-in android test runs. A test-creation job saves one itself when it meets the app's login screen, so this is for fixing or replacing it.
Storing only stores. Run beryl accounts check to prove it against the live app.
MCP tool: accounts_set_login
account-id: Account id fromberyl accounts list
--file <string>: The sign-in ActionPlan, as JSON (path, or - for stdin). Required except for a captured account--plan <json>: The sign-in ActionPlan inline, instead of--file--probe <json>: The liveness probe plan (JSON, a path, or - for stdin): goto a gated page, then assert something only a signed-in user sees (required)--base-hash <string>: The login_plan_hash fromberyl accounts get-login. The write is rejected if the stored plan changed since. Omit only when writing the first plan--surface <android|ios>: An app surface: store (or read) the sign-in through the app's own screens. Both plans are plans for that device (device android or ios, starting with a launch); a signed-in app test restores the session this sign-in saved on the device
Also accepts --workspace and --project (see Configuration).
beryl accounts set-login acc_123 --file signin.json --probe probe.json
beryl accounts set-login acc_123 --file signin.json --probe probe.json --base-hash 9f2c…
beryl accounts set-login acc_456 --probe probe.json # captured account
beryl accounts set-login acc_123 --surface android --file app-signin.json --probe app-probe.json
beryl accounts set-login acc_456 --probe '{"steps":[{"action":"goto","url":"/account"},{"action":"expect","selector":"text=Sign out","expect_kind":"visible"}]}'Read the stored sign-in plan, its probe, and the hash a safe write must cite
The login plan is readable, not just writable: it heals, so overwriting without reading first can clobber a repair you never saw. Pass login_plan_hash back as --base-hash on the next accounts set-login.
MCP tool: accounts_get_login
account-id: Account id
--surface <android|ios>: An app surface: store (or read) the sign-in through the app's own screens. Both plans are plans for that device (device android or ios, starting with a launch); a signed-in app test restores the session this sign-in saved on the device
Also accepts --workspace and --project (see Configuration).
Sign in now and prove the session survives into a fresh browser
Replays the stored sign-in plan, captures the session it produces, then injects that session into a clean browser and runs the probe. Green here is the same green a run gets, because it is the same code path. A failure tells you which half broke: SESSION_LOGIN_FAILED means the sign-in itself did not complete (fix the plan); SESSION_PROOF_FAILED means the sign-in worked but the session did not survive the move to a fresh browser, so this app keeps its credential somewhere that cannot be carried (a service worker, a WebAuthn binding). In that case the account is marked unsupported: its session-mode tests fail at setup with SESSION_UNSUPPORTED on every run until re-authored with auth_mode "inline" and their own sign-in steps; inline tests are unaffected. Blocks for two browser replays.
MCP tool: accounts_check
account-id: Account id
Also accepts --workspace and --project (see Configuration).
beryl accounts check acc_123Change a test account's password, login method, or default flag
MCP tool: accounts_update
account-id: Account id
--email <string>: New email--password <string>: New password (re-marks the account ready)--login-method <password|magic_link|otp>: How tests sign in as it--default: Make this the environment's default
Also accepts --workspace and --project (see Configuration).
Delete a test account
Removes the identity. Tests naming it in auth_label start failing with a clear reason rather than silently signing in as somebody else.
MCP tool: accounts_delete
account-id: Account id
--force: Skip the confirmation prompt
Also accepts --workspace and --project (see Configuration).
beryl account
View and update your personal account profile.
Show your account profile
Update your profile
--name <string>: New display name--newsletter: Toggle the newsletter subscription
Preview what deleting your account would remove or leave
beryl feedback
Send product feedback to the Beryl team.
Send product feedback to the Beryl team
message: Your feedback
beryl billing
Review a workspace's plan usage, subscription, and invoices; upgrade or switch plans.
List the plans: price, cloud run minutes, storage, overage terms
Show plan usage: cloud run minutes, storage held, and this month's overage
Also accepts --workspace (see Configuration).
Get a Stripe Checkout link that moves a Free workspace onto Team or Business
--plan <string>: team or business (required)
Also accepts --workspace (see Configuration).
Switch a paid workspace between Team and Business in place (prorated)
--plan <string>: team or business (required)
Also accepts --workspace (see Configuration).
Show the workspace's subscription
Also accepts --workspace (see Configuration).
List recent invoices
--limit <number>: How many invoices
Also accepts --workspace (see Configuration).
Get a Stripe billing-portal link for the workspace
Also accepts --workspace (see Configuration).
beryl version
Show the running CLI version, API URL, and Node version
Show the running CLI version, API URL, and Node version
Answers "which build am I actually talking to?" (the one question a long-lived beryl mcp process can't otherwise answer, since it loads source at spawn and never hot-reloads). Needs no login, so it still works when a token is missing or broken. Also reports whether the running build is behind npm's latest (best-effort: update_available is null when the registry can't be reached, and the check is skipped entirely under BERYL_NO_UPDATE_CHECK).
MCP tool: version
beryl version
beryl version --jsonberyl mcp
Run the Beryl MCP server (stdio): every CLI command as an agent tool
Run the Beryl MCP server (stdio): every CLI command as an agent tool
Exposes the CLI's commands as MCP tools over stdio, so coding agents (Claude Code, Cursor, …) can create projects, trigger runs, watch the agent, and edit tests. Authenticate via BERYL_API_KEY or a prior beryl login.
claude mcp add beryl -- beryl mcp