Skip to main content
The Revyl Maestro runner embeds Maestro’s published YAML parser and execution engine with a custom Revyl device driver. Maestro still interprets the flow and evaluates its assertions; the driver sends supported native operations through Revyl’s authenticated device API and its existing viewer control channel.
This is a source-installed runner, not a plugin for stock maestro test. The native actions listed below have been verified against synthetic apps on staging Android emulators and iOS simulators. Viewer-channel text input has loopback integration coverage, not live-device verification. Supported and deployment-gated commands are distinct; this is not full Maestro compatibility.
For released device lifecycle commands, use the device quickstart. A session UUID or viewer URL does not establish an ADB connection or make stock Maestro discover the device.

How it connects

The runner is a separate JVM application. It does not require local Android SDK/ADB, Xcode, a Maestro device-side driver installation, or Revyl’s AI test runner. It does not provide the stock CLI’s workspace selection, sharding, or reporting features.

Source access and session preparation

Get the standalone Maestro driver and follow its README to build the revyl-maestro launcher with Java 21 before loading runtime credentials. There is no package registry release yet. Repository access is required; contact Revyl support if you need access.
Select an existing, running Revyl session with your app already installed and launched. Keep its session UUID, and provide REVYL_API_KEY through the runner’s environment or your secret manager. Never put a key into the YAML flow or command-line arguments. Session ownership is checked by the backend on attachment and every proxied operation. Text input obtains its session-bound control connection from the authenticated backend; do not supply a viewer or worker URL yourself.

Write a supported flow

The sample flow requires an app whose initial screen contains a visible Continue button. Tapping it must produce the visible text Welcome:
Replace the app ID, selectors, and expected outcome with your app’s actual values. The example deliberately omits launchApp: the app must already be running. A saved screenshot is supporting evidence, not a replacement for an assertion. From the source package directory, run the built launcher against the exact session:
Use --platform ios for an iOS session. This command interacts with a real device when configured with real credentials. Keep the runner’s exit code in CI; parse errors, unsupported commands, failed assertions, and transport failures must fail the job. Keep screenshots private.

Supported native subset

The runner supports hierarchy-backed assertVisible and assertNotVisible, single selector or coordinate taps, and PNG screenshots. extendedWaitUntil polls an assertion, while waitForAnimationToEnd performs a bounded screenshot comparison rather than proving a specific final state. Assertions use the native accessibility hierarchy, not an independent visual or occlusion check. Native resource IDs and text can differ between platforms; adapt selectors rather than assuming an Android ID is an iOS accessibility ID. Screenshot names must be unique simple names without paths or extensions. takeScreenshot: smoke writes a private .revyl-maestro/smoke.png file; existing files are rejected rather than overwritten. These platform claims concern Android emulators and iOS simulators, not physical iOS devices. Native flows verified long press, repeated taps, focused deletion, Enter, Home, appearance changes, and deep links on both platforms, plus Android Back. Local clipboard commands also ran in those flows. The complete flow is checked before attachment. The limits are 999 source commands and 1000 expanded commands, counting each repeated tap or Backspace. Optional commands, scripts/expressions, hooks, nested flows, general repeat/retry blocks, retryTapIfNoChange, and waitUntilVisible are rejected. Unsupported driver operations also fail explicitly during execution.

Launch is intentionally narrow

Stock Maestro’s default launch stops the app and changes permissions. The current Revyl proxy does not provide that complete lifecycle contract. The only supported form requests neither operation:
Do not add clear-state/keychain flags or launch arguments. Preparing the app before running the flow is the simpler path.

Text input through the viewer channel

inputText and pasteText use Revyl’s existing manual-input control channel on Android emulators and iOS simulators. They do not depend on a new focused-input endpoint or worker capability. pasteText sends the value from an earlier setClipboard or copyTextFrom; it does not read the device’s OS clipboard. Literal and dynamically copied input must be nonempty valid Unicode, at most 16 KiB UTF-8. Control characters are rejected except tab, newline, and carriage return. Passing this validation does not guarantee the device transport supports every character. The runner requests input at current focus without clearing or tapping. Android uses the worker’s text provider; iOS uses its paste path. These are the viewer’s existing behaviors, not a stronger native text contract:
  • Focus and selection: the worker’s skip_tap option permits a refocusing fallback when passthrough is unavailable. The adapter does not deliberately tap a field, but cannot guarantee caret or selection preservation on every worker. Focus the intended field before input and assert the resulting value.
  • Completion: the runner waits for the matching completion acknowledgment, not just receipt. This means the handler returned successfully, not that the app’s field value was verified. A missing, failed, or invalid acknowledgment stops the flow without replaying the input or sending later mutations.
  • Viewer interaction: close the live viewer while running a flow with input. A connected viewer’s WebRTC data channel can receive the acknowledgment instead of the runner’s WebSocket. A timeout may mean text was already inserted; inspect the device before rerunning the flow.
  • Character support: Android fallback transports have different character limits. iOS input can change the device clipboard, and the pasteboard fallback can show a paste-permission dialog. Unicode validation is not proof of reliable insertion across those paths.
  • Privacy: the existing worker input path can log or record typed text. Do not use it for passwords, tokens, or other sensitive content. Adapter diagnostics omit text and control-connection credentials, but cannot change server-side recording behavior.
This adapter path has offline WebSocket and Maestro runtime coverage. Successful live text insertion through it has not been verified; the staging checks for other native commands do not establish text-input compatibility.

Deployment-gated gestures

A swipe that ignores Maestro’s requested duration is not an equivalent gesture. The following commands require new worker contracts and authenticated backend relay support. They have offline parser/runtime and installed-launcher coverage, but their successful execution is not verified or enabled on current staging. Before any flow mutation, authenticated worker health must identify the same connected workflow and platform and advertise every required capability as boolean true. Missing, false, malformed, or unavailable capabilities reject the whole flow, including taps or launches preceding the gated command. Current staging checks confirmed that gated swipe flows were rejected with the preceding tap counter and input value unchanged on both platforms. Verified clear, app stop/kill/reset, keychain, permissions, orientation, keyboard dismissal, media, recording, proxy, airplane mode, AI, and WebView operations also remain unsupported.

Evidence, retries, and cleanup

The adapter adds no HTTP retries, input replay, or Maestro recovery-tap retries. A timeout can still mean an action executed; inspect the device before repeating it. Existing worker-side retry behavior is unchanged, so this is not an end-to-end exactly-once guarantee. Avoid destructive flows and concurrent controllers. The runner only attaches and detaches. It never allocates, installs, resets, or stops the borrowed Revyl session. The job that owns the allocation must release it separately, including after test failures:
Do not submit this flow to Revyl’s own YAML test runner: its schema and execution model are different. For broader Maestro compatibility, retain your current execution environment until a verified connection and command contract is available.

Next steps