@revyl/verify 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,71 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.0 (2026-11-11)
4
+
5
+ - Early access: run `instruction()` and `validation()` on your own model. `open('ios', { model: 'anthropic/claude-sonnet-5-5' })` runs every step on Claude with the key from `ANTHROPIC_API_KEY`; a step's `{ model }` overrides it. Built-in providers: Anthropic, OpenAI, Google, OpenRouter, Groq, Cerebras, xAI and Ollama, each reading its usual key variable; `anthropic/` and `openai/` also honour `ANTHROPIC_BASE_URL` and `OPENAI_BASE_URL` for proxies and gateways. `{ id, baseURL, apiKey, headers }` reaches any OpenAI-compatible endpoint, with the key taken only from `apiKey`. Your model names elements and Revyl's grounding model finds them. `StepResult.model` reports turns and tokens. Revyl's agent remains the default.
6
+ - Custom agents: `localAgent({ model, grounding, maxTurns, modelTimeout })` with the exported `anthropic()` and `openaiCompatible()` adapters, or your own `ModelAdapter`, passed as `{ agent }`.
7
+ - New errors `MODEL_KEY_MISSING` (thrown before any session starts) and `MODEL_ERROR`, whose messages name the next step for a rejected key, an unknown model, a rate limit, or a model without image input or tool calls.
8
+ - Early access: exact device actions on Web, iOS and Android: `tap`, `type`, `swipe`, `pressKey`, `back` (Web and Android), `openUrl`, `launchApp` (iOS and Android), `locate` and `screenSize`, by device coordinates or a described target. A call a platform doesn't support throws `NOT_AVAILABLE_ON_PLATFORM` naming the alternative. `swipe` directions are finger motion on every platform, so `'up'` scrolls content down; on Web, Verify sends Revyl the matching page direction.
9
+ - Fix healthy sessions failing with `SESSION_ENDED` right after a step was accepted. Revyl can answer the first `step_status` polls with 404 "Live step not found" while it is still listing the step's run; Verify now keeps polling for about 10 seconds. If the step still can't be found, it raises `STEP_FAILED` naming the step and leaves the session open, because the step may still be running. Other 404s still raise `SESSION_ENDED`.
10
+ - `npx @revyl/verify init` writes an example that runs on a brand-new account. When you leave the app id empty for iOS or Android, the config targets the device's built-in Settings app by bundle id (`com.apple.Preferences` or `com.android.settings`), and the example opens About and checks the operating system version. It no longer writes a placeholder app id that failed with `CONFIG_INVALID`, and the generated config no longer reads `REVYL_APP_ID`.
11
+ - `init` asks iOS first and defaults to it instead of web.
12
+ - A Web target needs a Web app id: `init` with web and no `--app-id` writes no files, explains how to create the Web app in the dashboard or with `revyl app create --platform web`, and prints the `init` command to run next.
13
+ - `init`'s "Next" list names only commands that can pass: `node verify/example.mts`, and for Mac only once your organization has access.
14
+ - `init` writes the example as `verify/example.mts`, so `node verify/example.mts` runs as an ES module whether `package.json` says `"type": "commonjs"` (what `npm init -y` writes on npm 11), `"type": "module"`, or nothing. As `verify/example.ts` it failed with `Cannot use import statement outside a module` in a CommonJS project.
15
+ - `init --help` prints init's options instead of `Unknown option '--help'`.
16
+ - Add `verify login`, which signs in through the browser, and `verify logout`, which removes `~/.revyl/credentials.json`, so you don't need the Revyl CLI for either. `verify --help` explains that `init`, `login` and the first `open()` sign you in through the browser.
17
+ - Sign-in and missing-credential errors point to `npx @revyl/verify login` instead of the separately installed Revyl CLI.
18
+ - Classify the hosted refusal `computer_platform_at_capacity` (the computer already runs as many children of that platform as it can, such as a second Web child on a Mac) as `COMPUTER_LIMIT` with that `reason`. Earlier versions report it as `SESSION_BUSY`.
19
+ - Map Web runtime target errors on HTTP 409 (`target_not_found`, `stale_target` and similar) to `ACTION_FAILED` instead of `SESSION_BUSY`.
20
+ - Docs: a new "Use your own model" guide (`docs/own-model.md` in the package), exact-action sections with runnable scripts in the web and mobile guides, and the `examples/byo-model` project.
21
+ - Docs: a computer's lifetime is two hours from create, not 60 minutes; `expiresAt` / `expires_at` is the authoritative deadline.
22
+ - Docs: the Web page explains how to create the Web app, starting with the dashboard, and drops the note about Revyl turning Web off. Getting started describes the new `init` and how the Python and Go SDKs sign in. The Go README has a runnable iOS Settings example.
23
+ - Docs: Linux computers are no longer offered in the README, the package docs or the examples, and the README drops its Security and Telemetry sections (SECURITY.md is unchanged). `platform: 'linux'` still works; nothing is deprecated.
24
+
25
+ ## Go 0.3.0 (2026-11-11)
26
+
27
+ Published as the `go/v0.3.0` tag.
28
+
29
+ - Early access: run `Instruction` and `Validation` on your own model, as in TypeScript 0.4.0. `verify.WithModel("anthropic/claude-sonnet-5-5")` on `Open` or on one step reads the provider's usual key variable. The eight providers, `ANTHROPIC_BASE_URL` and `OPENAI_BASE_URL` with or without `/v1`, and `verify.WithCustomModel(verify.CustomModel{...})` for any OpenAI-compatible endpoint. `StepResult.Model` reports turns and tokens, cached input included.
30
+ - Custom agents: `verify.WithAgent(verify.LocalAgent{...})` with `verify.Anthropic` and `verify.OpenAICompatible`, or your own `ModelAdapter`.
31
+ - New errors `ErrModelKeyMissing` (returned before any Revyl request) and `ErrModelError`, with the same next-step hints as TypeScript.
32
+ - Early access: exact device actions on Web, iOS and Android: `Tap`, `Type`, `Swipe`, `PressKey`, `Back` (Web and Android), `OpenURL`, `LaunchApp` (iOS and Android), `Locate` and `ScreenSize`, by `verify.Point` or `verify.Element("...")`. They take a `context.Context`, and one cut off by its deadline returns `ErrActionUncertain`. `Swipe` directions are finger motion on every platform, so `SwipeUp` scrolls content down; on Web, Verify sends Revyl the matching page direction.
33
+ - `Open`, `Instruction` and `Validation` now take option values (`OpenOption`, `StepOption`, `ValidationOption`). Existing `OpenOptions{...}`, `StepOptions{...}` and `ValidationOptions{...}` literals still compile; a call that spread a `[]OpenOptions`, `[]StepOptions` or `[]ValidationOptions` slice with `...` must pass the options one by one.
34
+ - Map Web runtime target errors on HTTP 409 (`target_not_found`, `stale_target` and similar) to `ErrActionFailed` instead of `ErrSessionBusy`.
35
+ - Same fix as 0.4.0: a `step_status` 404 "Live step not found" right after a step was accepted is retried for about 10 seconds and then returns `ErrStepFailed`, instead of `ErrSessionEnded`. The session stays open.
36
+ - Classify the hosted refusal `computer_platform_at_capacity` as `ErrComputerLimit` with that reason, like 0.4.0.
37
+ - Computer refusals name the Go methods and point to `Exec` instead of `exec()`, and `Navigate` on a computer is refused that way instead of suggesting `OpenURL`.
38
+ - README: a runnable iOS Settings quick start, how the Go SDK uses a login saved by the other SDKs, a computer's two-hour lifetime, and Linux computers are no longer offered (`verify.Linux` still works).
39
+
40
+ ## Python 0.2.0 (2026-11-11)
41
+
42
+ - Early access: run `instruction()` and `validation()` on your own model, as in TypeScript 0.4.0. `open(target, model="anthropic/claude-sonnet-5-5")` runs every step on it with the key from the provider's usual variable, and a step's `model=` overrides it. The eight providers, `ANTHROPIC_BASE_URL` and `OPENAI_BASE_URL` with or without `/v1`, and `CustomModel(id, base_url, api_key, headers, provider, grounding)` for any OpenAI-compatible endpoint. Works on the sync and asyncio APIs. `StepResult.model` reports turns and tokens, cached input included.
43
+ - Custom agents: `local_agent(model, grounding=, max_turns=, model_timeout=, max_image_side=)` with `anthropic()` and `openai_compatible()`, or your own `ModelAdapter`, passed as `agent=`.
44
+ - New error codes `MODEL_KEY_MISSING` (raised before any Revyl request) and `MODEL_ERROR`, with the same next-step hints as TypeScript.
45
+ - Early access: exact device actions on Web, iOS and Android, on `Session` and `AsyncSession`: `tap`, `type`, `swipe`, `press_key`, `back` (Web and Android), `open_url`, `launch_app` (iOS and Android), `locate` and `screen_size`, by `Point(x, y)` or a described target. `swipe` directions are finger motion on every platform, so `"up"` scrolls content down; on Web, Verify sends Revyl the matching page direction.
46
+ - Map Web runtime target errors on HTTP 409 (`target_not_found`, `stale_target` and similar) to `ACTION_FAILED` instead of `SESSION_BUSY`.
47
+ - Same fix as 0.4.0: a `step_status` 404 "Live step not found" right after a step was accepted is retried for about 10 seconds and then raises `STEP_FAILED`, instead of `SESSION_ENDED`. The session stays open.
48
+ - Classify the hosted refusal `computer_platform_at_capacity` as `COMPUTER_LIMIT` with that `reason`, like 0.4.0.
49
+ - `navigate()` on a computer raises `NOT_AVAILABLE_ON_PLATFORM` pointing to `exec()` and file operations, like the other device calls, instead of suggesting `open_url()`.
50
+ - Print progress to stderr by default, like TypeScript: `[verify] <platform>: …` lines with the session link as soon as it is known, `ready`, and each instruction or validation's outcome and duration. Step text is not printed. Pass `log=False` to turn the lines off, or `log=callback` to receive them. An explicit `log=None` now means the default.
51
+ - README: a computer's two-hour lifetime, and Linux computers are no longer offered (`Target(platform="linux")` still works).
52
+
53
+ ## 0.3.2 (2026-11-11)
54
+
55
+ - Fix `npx @revyl/verify init` in pnpm projects: it now runs `pnpm add -D`. pnpm 9 and 10 rejected `--dev`, and pnpm 12 read it as "install only devDependencies", saved Verify under `dependencies` without installing it, and removed the project's other dependencies from `node_modules`.
56
+ - Fix `init` in Yarn projects: Yarn 3 and 4 get `--mode=skip-build` (the old `skip-builds` was rejected), Yarn 1 gets `--ignore-scripts`, and Yarn 2 gets a plain `add --dev`.
57
+ - `init` passes your environment to the package manager, so Corepack, proxy, registry and npm configuration variables reach the install.
58
+ - Add a `default` condition to the package exports of `@revyl/verify` and `revyl-verify`, so `verify.config.ts` loads in Yarn Plug'n'Play projects and CommonJS `require('@revyl/verify')` resolves through Node.js require(esm) on Node.js 22.12 and later.
59
+ - The `verify` CLI exits with `Verify needs Node.js 22.18 or later` on older Node.js instead of running `init` and writing a script that Node cannot load.
60
+
61
+ ## Python 0.1.0 (2026-11-06)
62
+
63
+ First PyPI release of `revyl-verify` (import `revyl_verify`, Python ≥3.10), published from the `py/v0.1.0` tag with PyPI trusted publishing and attestations.
64
+
65
+ - Includes the Python surface described under 0.3.0 below: typed sync and asyncio sessions, `bundle_id` mobile targets, web and mobile instructions and validations, screenshots, encoded (`argv_b64`/`path_b64`) computer operations, hosted child sessions, `attach()` and `current_computer()`.
66
+ - Sign in automatically on the first interactive `open()`, `attach()` or `current_computer()` call through the Revyl browser approval flow, saving the login to `~/.revyl/credentials.json` for the Revyl CLI and other SDKs. Non-interactive runs and `CI` stay key-only and never open a browser.
67
+ - Verified live on production: the iOS Settings quickstart (`bundle_id="com.apple.Preferences"`) through a first-run browser sign-in, and a Mac `exec`/file round trip, from the built wheel in a clean virtual environment.
68
+
3
69
  ## 0.3.1 (2026-11-03)
4
70
 
5
71
  - Docs: runnable `.mts` quickstart uses the built-in iOS Settings app, explains how to target an uploaded app with `appId`, clarifies that the Python SDK is not published to PyPI yet, and documents Web availability requirements.
package/README.md CHANGED
@@ -1,16 +1,8 @@
1
1
  # Verify
2
2
 
3
- Verify runs end-to-end checks in a real browser, iOS simulator, or Android emulator on Revyl. You describe what the agent should do and what must be true afterward, instead of maintaining selectors and coordinates that break when a screen changes. Use it from a script, a coding agent, or the test runner you already have. Mac and Linux computers are also available for commands, files, and screenshots, not natural-language steps.
3
+ ![Terminal output from one Verify script beside a Mac computer's Terminal window showing the macOS version, and the screens the script reached in a cloud browser, an Android emulator, and an iOS simulator](https://raw.githubusercontent.com/RevylAI/verify/v0.4.0/docs/images/verify-hero.webp)
4
4
 
5
- Every run gives you a link to watch the target. The session keeps its report and available recording, and the SDK keeps instruction and validation results in order. A failed check leaves evidence you can inspect.
6
-
7
- ## Install and run
8
-
9
- ```bash
10
- npm install @revyl/verify
11
- ```
12
-
13
- Save this as `verify/check.mts`:
5
+ Verify runs end-to-end checks in a cloud browser, iOS simulator, or Android emulator on Revyl. You write what the agent should do and what must be true afterward, in plain sentences, and call it from a script, a coding agent, CI, or the test runner you already use. When you know exactly what to press, you can tap, type and swipe yourself instead. Verify also opens Mac computers for commands, files, and screenshots.
14
6
 
15
7
  ```ts
16
8
  import { open } from '@revyl/verify';
@@ -25,148 +17,106 @@ try {
25
17
  }
26
18
  ```
27
19
 
28
- Use `appId` when you want to target your own uploaded app.
29
-
30
- Run the script:
31
-
32
- ```bash
33
- node verify/check.mts
34
- ```
20
+ You maintain sentences instead of selectors and coordinates that break when a screen changes, and every run prints a session link that keeps the report and available recording after the session closes.
35
21
 
36
- On the first interactive run, Verify opens the Revyl browser approval flow once and saves the login in `~/.revyl/credentials.json` for the CLI and SDK to share.
22
+ ## Quick start
37
23
 
38
- Verify prints a live session URL and progress like this:
24
+ Paste this prompt into your coding agent, and it sets up Verify in the project's language:
39
25
 
40
26
  ```text
41
- [verify] ios: starting ios session https://app.revyl.ai/sessions/…
42
- [verify] ios: ready
43
- [verify] ios: ✓ instruction "Open General, then About" (12.0s)
44
- [verify] ios: ✓ validation "The screen shows the operating system version" (9.8s)
45
- [verify] ios: closed
46
- ```
27
+ Set up Verify in this project.
28
+
29
+ Read https://docs.revyl.com/verify.md and follow it. It's the current Revyl guide for this, so prefer it over anything you remember about Revyl.
47
30
 
48
- The URL is live during the run and keeps the report and available recording after it closes. A failed instruction or validation throws a typed error and includes the same URL. In CI, Verify never opens a browser: provide `REVYL_API_KEY` as a secret.
31
+ Use the SDK for this project's language: @revyl/verify on Node.js 22.18 or later for Node.js or TypeScript, revyl-verify on Python 3.10 or later for Python (install it with pip or uv), or the github.com/RevylAI/verify/go module for Go. Write the iOS Settings example in that language: open the com.apple.Preferences bundle, run one instruction, and run one validation that checks the operating system version. Ask before starting a paid cloud session, then run the example.
49
32
 
50
- For Web, use `open({ platform: 'web', app: { appId, url } })`; for a computer, use `open({ platform: 'mac' })`. Web targets need Web enabled for your organization; new self-serve organizations don't have it yet. `revyl app create --platform web` reports `Web is not enabled for this organization`; contact Revyl to enable it.
33
+ You're done when the example has opened iOS Settings, the operating system version validation has passed, and the session has closed.
51
34
 
52
- ## Scaffold a config (optional)
35
+ Ask me before anything that needs my login or approval.
36
+ ```
53
37
 
54
- Use `init` when you want named targets in `verify.config.ts` and a generated `verify/example.ts` script:
38
+ Or set it up yourself:
55
39
 
56
40
  ```bash
57
41
  npx @revyl/verify init
58
42
  ```
59
43
 
60
- `init` detects your package manager, asks before adding `@revyl/verify` as a dev dependency, creates `verify.config.ts` and `verify/example.ts`, and prints the command that runs the example. Use `--yes` to accept installation without a prompt, or `--no-install` when Verify is already installed. It is optional; installing the package is enough to use inline targets.
44
+ `init` adds Verify to your project, asks what to open, writes `verify.config.ts` and an example script, signs you in through the browser on the first interactive run, and prints the command that runs the example. With no app id, the iOS and Android examples open the built-in Settings app, so they run on a new account before you upload anything. To skip the config, run `npm install @revyl/verify` and save the example above as `verify/check.mts`, then run `node verify/check.mts`. [Getting started](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/getting-started.md) covers sign-in, your own app, and [CI](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/ci.md).
61
45
 
62
- The generated project starts with a named target. Use `--platform web`, `--platform ios`, `--platform android`, or `--platform mac` when you want to skip the platform question. Web and mobile targets need a Revyl app id; a Mac target does not. The generated config is ordinary TypeScript, so edit it when the example needs a pinned build, a public Web URL, or a different target.
46
+ For finished projects, see [`examples/`](https://github.com/RevylAI/verify/tree/v0.4.0/examples/): a [web store](https://github.com/RevylAI/verify/tree/v0.4.0/examples/web-store/), [mobile Settings](https://github.com/RevylAI/verify/tree/v0.4.0/examples/mobile-settings/), a [Mac workspace](https://github.com/RevylAI/verify/tree/v0.4.0/examples/mac-workspace/), a small [agent platform](https://github.com/RevylAI/verify/tree/v0.4.0/examples/agent-platform/) that runs web and iOS side by side, and [your own model](https://github.com/RevylAI/verify/tree/v0.4.0/examples/byo-model/) (with [Python](https://github.com/RevylAI/verify/blob/v0.4.0/python/examples/byo_model.py) and [Go](https://github.com/RevylAI/verify/blob/v0.4.0/go/examples/byomodel/main.go) versions).
63
47
 
64
- See the [TypeScript getting-started guide](https://github.com/RevylAI/verify/blob/v0.3.1/packages/verify/docs/getting-started.md), the [Python SDK guide](https://github.com/RevylAI/verify/blob/v0.3.1/python/README.md), and the [Go SDK guide](https://github.com/RevylAI/verify/tree/go/v0.2.0/go).
48
+ ## Exact actions
65
49
 
66
- ## CI
50
+ Tap, type, swipe and press keys yourself, by a description Revyl locates on screen or by coordinates, in the same script as your steps:
67
51
 
68
- For a normal GitHub Actions job, install from the lockfile with `npm ci` and pass `REVYL_API_KEY` from repository secrets to the script that runs Verify:
69
-
70
- ```yaml
71
- - uses: actions/checkout@v5
72
- - uses: actions/setup-node@v5
73
- with:
74
- node-version: 24
75
- cache: npm
76
- - run: npm ci
77
- - run: node verify/example.ts
78
- env:
79
- REVYL_API_KEY: ${{ secrets.REVYL_API_KEY }}
52
+ ```ts
53
+ await session.type({ target: 'Email field' }, 'demo@example.com'); // Revyl finds the element you describe
54
+ await session.pressKey('enter');
55
+ await session.swipe('up'); // scrolls the content down
56
+ await session.tap({ x: 196, y: 640 }); // or device coordinates
57
+ await session.instruction('Accept the terms if they are shown'); // the agent where it's fuzzy
58
+ await session.validation('The welcome screen is shown');
80
59
  ```
81
60
 
82
- On a `revyl-macos` job, `currentComputer()` attaches to the runner's existing computer without taking ownership. The runner releases the computer; closing the Verify attachment still cleans up hosted children. See the [CI guide](https://github.com/RevylAI/verify/blob/v0.3.1/packages/verify/docs/ci.md) and [computer API](https://github.com/RevylAI/verify/blob/v0.3.1/packages/verify/docs/api.md#inside-a-revyl-macos-github-actions-job).
83
-
84
- ## Reference authentication
85
-
86
- Use manual setup when you need to control the package manager or keep the generated files out of the project:
87
-
88
- ```bash
89
- revyl auth login
90
- npx @revyl/verify whoami
91
- ```
61
+ `back`, `openUrl`, `launchApp`, `locate` and `screenSize` round them out; [which call works where](#which-call-works-where) shows the platform limits. Early access. In TypeScript (`@revyl/verify` 0.4.0), Python (`revyl-verify` 0.2.0) and Go (v0.3.0); the [Python](https://github.com/RevylAI/verify/blob/v0.4.0/python/README.md#exact-actions) and [Go](https://github.com/RevylAI/verify/blob/v0.4.0/go/README.md#exact-actions) READMEs show them with each language's names. The [web](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/web.md#exact-actions) and [mobile](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/mobile.md#exact-actions) guides have runnable scripts, and [api.md](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/api.md#exact-actions) lists every call.
92
62
 
93
- The SDK resolves credentials in this order: a usable stored CLI login marked `local_auth_override`, `REVYL_API_KEY`, then another usable stored CLI login. In CI, use a secret manager rather than putting a key in source, command arguments, or logs. `whoami` checks the credentials without starting a session.
63
+ ## Your own model
94
64
 
95
- ## TypeScript
65
+ Steps run on Revyl's agent unless you pass a model. Then the agent loop runs on your machine with your key, and Revyl provides the device and finds the elements your model names:
96
66
 
97
67
  ```ts
98
- import { open } from '@revyl/verify';
99
-
100
- const session = await open('ios');
101
- try {
102
- await session.instruction('Open General, then About');
103
- await session.validation('The screen shows the operating system version');
104
- } finally {
105
- await session.close();
106
- }
107
- ```
108
-
109
- For Web, use a public HTTPS URL in the target config. For iOS and Android, point the target at an app or build in Revyl. The [API guide](https://github.com/RevylAI/verify/blob/v0.3.1/packages/verify/docs/api.md) covers target options, step results, screenshots, reports, and cleanup.
110
-
111
- ## Go
68
+ const session = await open('ios', { model: 'anthropic/claude-sonnet-5-5' }); // key from ANTHROPIC_API_KEY
69
+ await session.instruction('Open General, then About');
70
+ await session.instruction('Open Privacy', { model: 'openai/gpt-5.5' }); // or per step
112
71
 
113
- Inside a function returning `error`, with a bounded `ctx`:
114
-
115
- ```go
116
- session, err := verify.Open(ctx, verify.Target{Platform: verify.IOS, BundleID: "com.apple.Preferences"})
117
- if err != nil {
118
- return err
119
- }
120
- defer func() { _ = session.Close(ctx) }()
121
- if _, err := session.Instruction(ctx, "Open General, then About"); err != nil {
122
- return err
123
- }
124
- _, err = session.Validation(ctx, "The screen shows the operating system version")
125
- return err
72
+ await open('ios', { model: { id: 'qwen-3.8-27b', baseURL: 'https://api.cerebras.ai/v1', apiKey: process.env.CEREBRAS_API_KEY } });
126
73
  ```
127
74
 
128
- Go calls return errors instead of throwing. The [Go reference](https://github.com/RevylAI/verify/tree/go/v0.2.0/go) covers context deadlines, screenshots, computer operations, and hosted sessions.
75
+ In TypeScript (`@revyl/verify` 0.4.0), Python (`revyl-verify` 0.2.0) and Go (v0.3.0); the [Python](https://github.com/RevylAI/verify/blob/v0.4.0/python/README.md#your-own-model) and [Go](https://github.com/RevylAI/verify/blob/v0.4.0/go/README.md#your-own-model) READMEs show them with each language's names. Built in: `anthropic`, `openai`, `google`, `openrouter`, `groq`, `cerebras`, `xai` and `ollama`; anything OpenAI-compatible works through `baseURL`. Early access; [Use your own model](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/own-model.md) covers the providers, picking a model, what Revyl still sees, limits and troubleshooting.
129
76
 
130
- ## Python
77
+ ## Packages
131
78
 
132
- The Python SDK isn't published to PyPI yet; install it from source using the instructions in the [Python SDK guide](https://github.com/RevylAI/verify/blob/v0.3.1/python/README.md).
79
+ | Package | Install | Status |
80
+ | --- | --- | --- |
81
+ | [`@revyl/verify`](https://www.npmjs.com/package/@revyl/verify) | `npm install @revyl/verify` | TypeScript SDK and the `verify` CLI (`init`, `login`, `logout`, `whoami`). Published on npm, Node.js 22.18 or later. |
82
+ | [`revyl-verify`](https://www.npmjs.com/package/revyl-verify) (npm) | `npm install revyl-verify` | Alias of `@revyl/verify` at the same version. |
83
+ | [Go module](https://github.com/RevylAI/verify/tree/go/v0.3.0/go) | `go get github.com/RevylAI/verify/go@v0.3.0` | Published as the `go/v0.3.0` tag, Go 1.26.9 or later. Calls return errors instead of throwing. |
84
+ | [`revyl-verify`](https://pypi.org/project/revyl-verify/) (PyPI) | `pip install revyl-verify` or `uv add revyl-verify` | Python SDK, published on PyPI. Python 3.10 or later, sync and asyncio APIs, no CLI; see the [Python guide](https://github.com/RevylAI/verify/blob/v0.4.0/python/README.md). |
133
85
 
134
- ```python
135
- from revyl_verify import Target, open
86
+ ## Platforms
136
87
 
137
- with open(Target(platform="ios", bundle_id="com.apple.Preferences")) as session:
138
- session.instruction("Open General, then About")
139
- session.validation("The screen shows the operating system version")
140
- ```
88
+ | Platform | Instructions / validations | Exact actions | Commands / files / processes | PNG screenshot |
89
+ | --- | :---: | :---: | :---: | :---: |
90
+ | Web | Yes | Yes | — | Yes |
91
+ | iOS simulator | Yes | Yes | — | Yes |
92
+ | Android emulator | Yes | Yes | — | Yes |
93
+ | Mac computer | — | — | Yes | Yes |
141
94
 
142
- Python supports synchronous and asyncio APIs, but it has no bundled CLI. The [Python reference](https://github.com/RevylAI/verify/blob/v0.3.1/python/README.md) covers both APIs and computer operations.
95
+ ### Which call works where
143
96
 
144
- ## Platforms
97
+ | Call | Web | iOS | Android | Mac computer |
98
+ | --- | --- | --- | --- | --- |
99
+ | `tap`, `type`, `swipe`, `pressKey`, `locate`, `screenSize` | Yes | Yes | Yes | No, use `exec()` and files |
100
+ | `back()` | Yes, browser history | No, tap the on-screen back control | Yes, the system back button | No |
101
+ | `openUrl(url)` | Yes, loads an http(s) URL in the tab | Yes, a URL or deep link | Yes, a URL or deep link | No |
102
+ | `launchApp(bundleId)` | No, use `openUrl` or `navigate` | Yes | Yes | No |
103
+ | `navigate(url)` | Yes | No, use `openUrl` | No, use `openUrl` | No |
104
+ | `instruction`, `validation`, your own model | Yes | Yes | Yes | No, use `exec()` |
105
+ | `screenshot()` | Yes | Yes | Yes | Yes |
106
+ | `exec`, files, processes | No, open a Mac computer | No, open a Mac computer | No, open a Mac computer | Yes |
145
107
 
146
- | Platform | Instructions / validations | Commands / files / processes | PNG screenshot |
147
- | --- | :---: | :---: | :---: |
148
- | Web | Yes | — | Yes |
149
- | iOS simulator | Yes | — | Yes |
150
- | Android emulator | Yes | — | Yes |
151
- | Mac computer | — | Yes | Yes |
152
- | Linux computer | — | Yes | Yes |
108
+ Coordinates are in iOS points, Android pixels and Web CSS pixels, from the top-left corner. A call a platform doesn't support throws `NOT_AVAILABLE_ON_PLATFORM`, and its message names the alternative.
153
109
 
154
- Computer targets are early access and use commands, files, processes, and screenshots rather than natural-language agent steps. They have a server-bounded lifetime. See [computer setup](https://github.com/RevylAI/verify/blob/v0.3.1/packages/verify/docs/computers.md).
110
+ Web is available to every organization. Mac computers are early access and have a server-bounded lifetime; see [computers](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/computers.md).
155
111
 
156
112
  ## Documentation
157
113
 
158
- - [Documentation index](https://github.com/RevylAI/verify/tree/v0.3.1/packages/verify/docs/) · [API](https://github.com/RevylAI/verify/blob/v0.3.1/packages/verify/docs/api.md) · [CI](https://github.com/RevylAI/verify/blob/v0.3.1/packages/verify/docs/ci.md) · [Coding agents](https://github.com/RevylAI/verify/blob/v0.3.1/packages/verify/docs/agents.md)
159
- - [End-to-end results and limitations](https://github.com/RevylAI/verify/blob/v0.3.1/packages/verify/docs/end-to-end.md)
160
- - [Examples](https://github.com/RevylAI/verify/tree/v0.3.1/examples/): [Web store](https://github.com/RevylAI/verify/tree/v0.3.1/examples/web-store/) · [Mobile Settings](https://github.com/RevylAI/verify/tree/v0.3.1/examples/mobile-settings/) · [Mac workspace](https://github.com/RevylAI/verify/tree/v0.3.1/examples/mac-workspace/)
161
- - [Contributing](https://github.com/RevylAI/verify/blob/v0.3.1/CONTRIBUTING.md) · [Security](https://github.com/RevylAI/verify/blob/v0.3.1/SECURITY.md) · [Releasing](https://github.com/RevylAI/verify/blob/v0.3.1/RELEASING.md)
114
+ The [documentation](https://github.com/RevylAI/verify/tree/v0.4.0/packages/verify/docs/) covers the [API](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/api.md), [configuration](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/configuration.md), [web](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/web.md), [mobile](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/mobile.md), [computers](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/computers.md), [CI](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/ci.md), [your own model](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/own-model.md), [errors and troubleshooting](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/errors.md), [coding agents](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/agents.md), and [live end-to-end results](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/end-to-end.md). The npm package ships these pages in `node_modules/@revyl/verify/docs/`, with an [llms.txt](https://github.com/RevylAI/verify/blob/v0.4.0/packages/verify/docs/llms.txt) index, so a coding agent can read the docs for the version you installed. The Revyl docs site has an overview at [docs.revyl.com/verify](https://docs.revyl.com/verify).
162
115
 
163
- ## Troubleshooting
116
+ ## Status
164
117
 
165
- - **`NOT_AVAILABLE_ON_PLATFORM`:** the requested method is not available for that target. Computer targets do not run instruction or validation steps; Web and mobile targets do not expose computer commands or files.
166
- - **`COMPUTER_LIMIT`:** computer admission was refused because of queued work or a concurrency limit. Verify does not retry creation or stop a definitely refused start.
167
- - **Blank first screen:** mobile startup uses a bounded, best-effort blank-frame observation, not a rendered-readiness guarantee. Begin with an instruction that reaches the screen your workflow needs.
168
- - **A validation report looks successful but the assertion failed:** inspect each step's `effective_status` and `validation_result`, and compare `validations_passed` with `total_validations` rather than transport counters.
118
+ Verify is at 0.x, so APIs can still change between minor releases; the [changelog](https://github.com/RevylAI/verify/blob/v0.4.0/CHANGELOG.md) records each release. Mac computers are early access. See [Contributing](https://github.com/RevylAI/verify/blob/v0.4.0/CONTRIBUTING.md) and [Releasing](https://github.com/RevylAI/verify/blob/v0.4.0/RELEASING.md) to work on Verify.
169
119
 
170
120
  ## License
171
121
 
172
- [Apache 2.0](https://github.com/RevylAI/verify/blob/v0.3.1/LICENSE).
122
+ [Apache 2.0](https://github.com/RevylAI/verify/blob/v0.4.0/LICENSE).
@@ -0,0 +1,7 @@
1
+ export interface ModelImage {
2
+ png: Uint8Array;
3
+ width: number;
4
+ height: number;
5
+ }
6
+ /** Shrinks a PNG by the smallest whole factor that keeps its longer side within maxSide, averaging each block of pixels. */
7
+ export declare function fitPng(bytes: Uint8Array, maxSide: number): ModelImage;
@@ -0,0 +1,29 @@
1
+ import { PNG } from 'pngjs';
2
+ /** Shrinks a PNG by the smallest whole factor that keeps its longer side within maxSide, averaging each block of pixels. */
3
+ export function fitPng(bytes, maxSide) {
4
+ const source = PNG.sync.read(Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength));
5
+ const factor = Math.ceil(Math.max(source.width, source.height) / maxSide);
6
+ if (factor <= 1)
7
+ return { png: bytes, width: source.width, height: source.height };
8
+ const width = Math.floor(source.width / factor);
9
+ const height = Math.floor(source.height / factor);
10
+ const target = new PNG({ width, height });
11
+ const area = factor * factor;
12
+ for (let y = 0; y < height; y += 1) {
13
+ for (let x = 0; x < width; x += 1) {
14
+ const sums = [0, 0, 0, 0];
15
+ for (let dy = 0; dy < factor; dy += 1) {
16
+ const row = (y * factor + dy) * source.width;
17
+ for (let dx = 0; dx < factor; dx += 1) {
18
+ const offset = (row + x * factor + dx) * 4;
19
+ for (let channel = 0; channel < 4; channel += 1)
20
+ sums[channel] += source.data[offset + channel];
21
+ }
22
+ }
23
+ const out = (y * width + x) * 4;
24
+ for (let channel = 0; channel < 4; channel += 1)
25
+ target.data[out + channel] = Math.round(sums[channel] / area);
26
+ }
27
+ }
28
+ return { png: PNG.sync.write(target), width, height };
29
+ }
@@ -0,0 +1,97 @@
1
+ import type { ModelAdapter } from './model.js';
2
+ /** A point in device units: iOS points, Android and Web pixels, from the top-left corner. */
3
+ export interface Point {
4
+ x: number;
5
+ y: number;
6
+ }
7
+ /** An element described in words, which Revyl's grounding model locates on the current screen. */
8
+ export interface Target {
9
+ target: string;
10
+ }
11
+ export type Location = Point | Target;
12
+ export type SwipeDirection = 'up' | 'down' | 'left' | 'right';
13
+ export type DeviceAction = {
14
+ kind: 'tap';
15
+ at: Location;
16
+ } | {
17
+ kind: 'type';
18
+ at: Location;
19
+ text: string;
20
+ clear: boolean;
21
+ } | {
22
+ kind: 'swipe';
23
+ direction: SwipeDirection;
24
+ from?: Location;
25
+ } | {
26
+ kind: 'key';
27
+ key: 'enter' | 'backspace';
28
+ } | {
29
+ kind: 'back';
30
+ } | {
31
+ kind: 'open_url';
32
+ url: string;
33
+ };
34
+ /** What the agent loop needs from a session. DeviceSession provides it. */
35
+ export interface AgentControls {
36
+ readonly platform: 'ios' | 'android' | 'web';
37
+ capture(signal: AbortSignal): Promise<{
38
+ png: Uint8Array;
39
+ screenToken?: string;
40
+ }>;
41
+ screenSize(signal: AbortSignal): Promise<{
42
+ width: number;
43
+ height: number;
44
+ }>;
45
+ perform(action: DeviceAction, screenToken: string | undefined, signal: AbortSignal): Promise<Point | undefined>;
46
+ }
47
+ /**
48
+ * model: the model gives screenshot coordinates, and only device actions reach Revyl.
49
+ * revyl: the model names the element and Revyl's grounding model finds it, so element descriptions reach Revyl too.
50
+ */
51
+ export type Grounding = 'model' | 'revyl';
52
+ export interface LocalAgentOptions {
53
+ model: ModelAdapter;
54
+ /** Defaults to 'revyl'. */
55
+ grounding?: Grounding;
56
+ /** Model turns an instruction may take, each ending in one action. Defaults to 20, at most 100. */
57
+ maxTurns?: number;
58
+ /** Milliseconds one model call may take, retries included. Defaults to 60000. */
59
+ modelTimeout?: number;
60
+ /** The longest screenshot side sent to the model, in pixels. Defaults to 1280. */
61
+ maxImageSide?: number;
62
+ }
63
+ export interface LocalAgent {
64
+ readonly model: ModelAdapter;
65
+ readonly grounding: Grounding;
66
+ readonly maxTurns: number;
67
+ readonly modelTimeout: number;
68
+ readonly maxImageSide: number;
69
+ }
70
+ /** One model turn of a local step. */
71
+ export interface ModelTurn {
72
+ /** The action the model chose, as text, such as 'tap "General"' or 'verdict true'. */
73
+ action: string;
74
+ /** Whether the action ran; a failed action is reported back to the model on its next turn. */
75
+ ok: boolean;
76
+ modelMs: number;
77
+ actionMs: number;
78
+ inputTokens: number;
79
+ outputTokens: number;
80
+ }
81
+ /** How a step ran on your model instead of Revyl's agent. */
82
+ export interface ModelRun {
83
+ /** The model's name, such as 'anthropic/claude-sonnet-5-5'. */
84
+ id: string;
85
+ grounding: Grounding;
86
+ turns: ModelTurn[];
87
+ inputTokens: number;
88
+ outputTokens: number;
89
+ }
90
+ /** Runs instructions and validations on a model you choose, on your machine. Revyl only receives device actions. */
91
+ export declare function localAgent(options: LocalAgentOptions): LocalAgent;
92
+ /** Runs one instruction or validation through the agent's model. The caller enforces the step deadline through signal. */
93
+ export declare function runLocalStep(type: 'instruction' | 'validation', task: string, agent: LocalAgent, controls: AgentControls, signal: AbortSignal, log: (line: string) => void): Promise<{
94
+ passed: boolean;
95
+ reason?: string;
96
+ run: ModelRun;
97
+ }>;