Integrations
GitHub
Preview builds, proof checks, and workflows on every pull request
Using GitLab? Follow the GitLab connection tutorial.
The Revyl GitHub App connects your repositories to Revyl. Once installed, it can create pull-request preview builds, run proof checks, and run saved workflows against those builds.
Set up with an agent
Paste one prompt and your coding agent does the rest.
Setup prompt
Connect this repository to Revyl through the Revyl GitHub App. Read https://docs.revyl.com/integrations/github.md and follow it. It's the current Revyl guide for this, so prefer it over anything you remember about Revyl. Run `revyl github connect --no-open --no-wait --json` and give me its `install_url`; I'll install the app with my GitHub login. Run `revyl init -y` if the project has no `.revyl/config.yaml`. `revyl github setup` is interactive, so ask me to run it in this project from my own terminal. You're done when `revyl github status` shows the repository connected. Ask me before anything that needs my login or approval.
Connect GitHub
GitHub installation is repository-wide. Configuration belongs to an individual Revyl project root within that repository.
revyl github connect # Install or verify repository access
revyl github status # Show the current installation status
revyl github setup # Configure the selected project rootrevyl github connect only installs or verifies access. It never changes or
publishes .revyl/config.yaml. From a coding agent, run
revyl github connect --no-open --no-wait --json: it prints the install link as
install_url and returns at once, so the agent can hand that link to you.
Install from it with your own GitHub login and check with revyl github status.
You can also create and configure projects entirely in the dashboard, which
calls each project a project root, after the folder it lives in; the CLI and
.revyl/config.yaml keep calling it a project. Open
Settings → Integrations → GitHub, select a repository, and configure its
first project root. The first one defaults to the repository root (.). Use
Add project root and enter an explicit repository-relative root such as
apps/mobile for each additional one.
The dashboard edits the same complete configuration as the CLI: session setup,
build framework and profiles, iOS and Android recipes, PR triggers, proof,
workflows, and strict checks. Apps, workflows, Cursor models, and build images
are selected by name; their internal IDs are never shown. Saving a new project
publishes it in manual authority. Saving an existing manual project replaces
the complete aggregate with conflict protection. Git-owned projects are
read-only in the dashboard, except for the two settings .revyl/config.yaml
can't hold. The project root's card offers each only while the file uses it:
where Revyl posts the pull request report, while the file turns pull request
reviews on, and Cursor proof authorization, while the file proves pull requests
with Cursor.
For Expo projects, a newly enabled dashboard recipe defaults to native
expo prebuild plus Xcode or Gradle, which does not require Expo
authentication and never adds EXPO_TOKEN. Customers who manually author an
EAS build command for unattended remote execution must also reference an
encrypted EXPO_TOKEN.
Required secrets can be created and selected inline without putting their
values in project configuration. New projects enable proof of changes with the
Revyl harness by default.
revyl github setup starts from the nearest .revyl/config.yaml, guides
you through a Revyl-managed profile or finished-artifact CI-upload policy,
writes the resulting pr_review policy into that file, and validates it. Under
manual authority, setup confirms publication and publishes the selected project
root's complete server-backed configuration. Under Git authority, setup instead
prepares the designated file for commit without publishing. For a managed
profile, each recipe used by PR automation must reference an existing active app
or an app selected or created during setup. Unrelated profiles are left alone.
New projects enable proof of changes with the Revyl harness by default.
Authenticated interactive revyl init can continue into this same flow after
it writes the local config. Non-interactive initialization stops after
local config creation and never enters GitHub setup.
In a monorepo, run setup from each project you intend to publish:
revyl -C apps/consumer github setup
revyl -C apps/partner github setupThere is no repository-wide project selector. The nearest config determines the project root, and GitHub setup never overrides that repository identity with a command-line repository flag.
Configuration publication
Under manual authority, the dashboard, GitHub setup, and revyl config push
publish the same typed configuration meaning. Under Git authority, GitHub setup
prepares the designated file for commit instead. Revyl does not store the raw
YAML document. It atomically materializes:
project.idsession, including the idle timeout, before-script declaration, and auth-bypass referencesbuild.frameworkand every normalized named profile, including each iOS or Android recipe, commands, output, optional app association, caches, non-secret environment values, secret references, image, and timeout- optional
pr_review, including triggers, managed-profile or CI-upload app selection, proof policy, workflow IDs, and strict build-check behavior
Formatting, comments, .revyl/tests, source contents, repository URLs,
invocation directories, transient profile selection, and secret values are not
stored in the project configuration aggregate.
Publication verifies the authenticated GitHub repository and exact
repository-relative project root. It uses the server configuration hash read
immediately before the write, so a concurrent edit fails instead of silently
overwriting newer state. revyl config push remains the explicit manual
publication and recovery path. It requires GitHub to be connected and never
scaffolds missing local configuration. If GitHub is disconnected, run
revyl auth status to verify the active account and organization, then run
revyl github connect. If it is connected but the repository is unavailable,
grant that repository to the existing Revyl GitHub App, run
revyl github status, and retry revyl config push. Local identity or config
shape errors direct you to the applicable exact recovery: migrate legacy input,
pull a registered project identity, or locate and repair invalid canonical YAML
before running config validate. If the checkout has no supported GitHub
origin, follow the emitted project-root-scoped git remote add origin or
git remote set-url origin command, then retry publication.
To adopt a dashboard-created project in a checkout that has no local config,
run revyl config pull from that project root or one of its subdirectories.
The CLI verifies the GitHub repository, selects the nearest configured ancestor
root, verifies the configuration hash, and atomically creates that root's
.revyl/config.yaml. It does not overwrite an existing, invalid, or legacy
file. After that, config push and config pull provide ordinary manual
two-way synchronization; they never merge concurrent edits.
Default-branch authority
Configuration on the repository's default Git branch reconciles registered
projects and can bootstrap a new Git-managed project from a newly added
canonical config. The config must have
a valid, untaken project.id, an unclaimed project root and config path, and
valid owned references. Creation happens only from the actual default-branch
commit, never from an unpublished pull-request head. The config path defines the
project root: .revyl/config.yaml selects the repository root, and
apps/consumer/.revyl/config.yaml selects apps/consumer. Revyl rejects invalid
or conflicting candidates without creating or replacing a project, and repeated
delivery of the same push is idempotent.
Setup or manual publication can also designate an existing project's exact config path before that file reaches the default branch. Recording the path does not itself make Git authoritative.
After Revyl successfully validates and reconciles that designated file from
the repository's default branch, the project enters git_default_branch
authority. Each project root is reconciled independently, so one repository
can contain several Revyl projects without one config replacing another.
Fetch errors, invalid configuration, identity conflicts, or rejected references
do not change an existing project's authority or active aggregate.
Pull-request configuration lifecycle
Revyl evaluates project configuration before selecting or running review work. The lifecycle follows four rules:
- If a Revyl configuration is managed in your Git repo, pull requests use the Git configuration from the exact pull request head.
- Invalid or unavailable candidates fail the Revyl configuration check when review automation is enabled or the pull request adds an unregistered project configuration. Revyl never falls back to another configuration.
- Deleting a Git-managed config switches the project to manual management while retaining that config.
- Manual projects without a Git-managed configuration file leverage their frozen server configuration.
While a project is Git-owned, manual UI, ordinary API, and ordinary
revyl config push writes are rejected. revyl github setup prepares the
designated file for commit without publishing. Edit the designated file, run
revyl config validate, and commit it instead. For a deliberate one-time
exception, revyl config push --force replaces the current aggregate without
changing Git ownership or its reconciliation position; a later newer
default-branch configuration can replace it. Under manual authority, the flag
is a no-op. revyl config pull remains available for recovery.
Removing the designated file from the default branch returns only that project
to manual authority. Revyl retains the last accepted aggregate so a later
manual update has a safe base. Removing only the pr_review group keeps the
file authoritative and removes the current server review policy when that
configuration is successfully reconciled.
Project roots are immutable. A manual project can be deleted from the GitHub integration in the Revyl web app and recreated at a different root. Deletion preserves the repository connection, report destination, historical results, and already-frozen review and build work, which may finish. Pending Cursor proof that has not launched fails closed because deletion removes its live authorization. A Git-owned project must first return to manual authority through the designated-file flow above; removing the file alone does not delete it. After you delete the last project root, the repository page opens the form for a new one, and nothing is created until you save it. There is no CLI delete command.
Configure PR previews
Revyl-managed PR builds select one published profile. The profile owns its iOS and Android recipes; the PR policy does not duplicate build commands or project roots.
Preview builds go to the pull request's source branch; pull requests from forks get no preview. See Pull request builds.
project:
id: "00000000-0000-4000-8000-000000000000"
build:
framework: expo
profiles:
pull-request:
ios:
app_id: "00000000-0000-4000-8000-000000000001"
setup_commands:
- bun install
- bunx expo prebuild --platform ios
- cd ios && pod install
build_commands:
- xcodebuild -workspace ios/App.xcworkspace -scheme App -configuration Debug -sdk iphonesimulator -derivedDataPath build
output_path: "build/Build/Products/Debug-iphonesimulator/*.app"
android:
app_id: "00000000-0000-4000-8000-000000000002"
setup_commands:
- bun install
- bunx expo prebuild --platform android
build_commands:
- cd android && ./gradlew assembleDebug
output_path: "android/app/build/outputs/apk/debug/*.apk"
pr_review:
enabled: true
review_triggers:
paths: ["apps/mobile/**"]
labels: []
drafts: false
build:
kind: revyl
profile: pull-request
proof_of_changes:
enabled: true
harness:
kind: revyl
workflow_ids: []
strict_ci_check:
build: truebuild.framework applies to every profile in the project. Build-level env,
secrets, and caches are inherited by each recipe; recipe values can add or
override them. Secret values never belong in the config.
Explicit review_triggers.paths globs are matched against the paths GitHub
reports, so they are repository-root-relative. This lets a project deliberately
include shared code outside its own root. When the list is empty, Revyl defaults
a nested project to <project-root>/**; a project rooted at apps/mobile
therefore reviews apps/mobile/** changes without requiring that authored
value. Only the repository-root project defaults to every changed path.
Review policy fields
| Field | Description |
|---|---|
enabled | Enables the project's PR automation policy. |
review_triggers.paths | Optional repository-root-relative globs. Explicit values replace the project-root default and can include shared paths. Empty defaults a nested project to <project-root>/**; the repository-root project remains repo-wide. |
review_triggers.labels | Includes or excludes reviews based on trimmed, non-empty, unique label names. Prefix an exclusion with !. |
review_triggers.drafts | When true, draft pull requests are eligible. |
build | Selects a Revyl-managed profile or declares finished-artifact CI uploads. |
proof_of_changes | Configures proof execution and its requested harness. |
workflow_ids | Saved Revyl workflows to run against compatible project build platforms. Mixed-platform workflows execute only matching-platform tests for each target. |
strict_ci_check.build | When true, a failed managed build produces a failing build check. |
Proof of changes
New project setups enable proof checks with the Revyl harness. Keep them on when you want Revyl to exercise the pull-request build and report whether the change behaves as expected:
pr_review:
build:
kind: revyl
profile: pull-request
proof_of_changes:
enabled: true
always_verify:
- "App launches to the home screen"
- "Login with email succeeds"
system_prompt: "Prefer a short launch-screen smoke proof."The pull-request diff supplies the authoritative change-specific proof intent.
Before it tests, the agent receives that diff for the exact commit it proves,
measured from the commit where the pull request branched from its base, as in
the pull request's Files tab. The agent reads a small manifest first, then
searches the full patch file for relevant hunks instead of loading it into its
context. The diff lives in a run-specific directory outside the checkout,
so downloading it does not replace repository files or add patch text to
repository-wide searches. GitHub's metadata index lists at most 300 files,
but the raw patch can include more. Binary contents are not included. If GitHub cannot generate the
diff or it exceeds the 32 MiB transfer safety limit, the manifest explicitly
marks it unavailable rather than handing the agent a silently cut patch.
With the Revyl harness, the author-written portion of the pull-request
description is also available as supporting context for the intended behavior
and proposed test plan.
always_verify is for invariants that must hold on every run, not a substitute
for inspecting the change.
The result is a write-up the agent authors: what it exercised and what it saw, an evidence-grounded confidence score from 1/5 to 5/5, which changed behaviors it covered and which were out of reach on this target with the step that would make them provable, captioned screenshots of the changed screen or the nearest one it reached, and a link to the full session recording anyone can open without signing in. The findings block links confirmed problems to their screenshot-grounded Atlas threads. When the run finds no defects, it says so and still links to Atlas scoped to the exercised build. Each configured build target gets its own proof run and a headed write-up on the same Revyl block as preview builds. A later push replaces the proof for the new commit rather than appending another comment. Until the new run publishes a write-up, the previous screenshots stay visible and the block marks that proof as updating and the last write-up as outdated.
Every proof run uses its frozen project root and build target. When
the project's config declares one, its session.before_script must be committed
and executable.
If the pull request is closed or merged while automation is still running, Revyl cancels the unfinished work and updates the shared surface once to show that it closed. Late build, workflow, or proof callbacks cannot reopen it.
Choose which agent proves the change
By default the Revyl agent proves the change: it checks the pull request out in an isolated sandbox, drives cloud devices against the preview build, and posts its write-up on the same Revyl block as preview builds, under a headed section for that platform. The checkout is disposable and never holds a credential that can write to your repository. See Proof of changes (Revyl agent) for the full lifecycle, outcomes, and what reviewers see.
You can hand proof runs to a Cursor cloud agent instead, either from the Agent selector in the repository's proof settings or in the config file:
pr_review:
build:
kind: revyl
profile: pull-request
proof_of_changes:
enabled: true
harness:
kind: cursor
model_id: nullCursor opens the pull request in a cloud agent that runs the checks on a Revyl cloud device. Its write-up lands in the same Revyl block as preview builds — one surface per pull request, updated in place, with a headed section per platform. The write-up is attributed to the Cursor agent that produced it. Details contains only View proof logs, which opens the same Revyl run page as a Revyl-agent proof. The write-up attribution links to the Cursor thread when Cursor accepted an agent, so you can open it while the run is in flight and revisit it afterwards. Because the run reports through Revyl, it settles with the same finding-aware verdict as a Revyl-agent proof: ready, ready with polish, ready with issues, failed for an open blocker, or inconclusive when the change could not be exercised. A claimed ready outcome still requires a recorded device session.
Choosing Cursor does not grant permission to launch it. Cursor authorization is live server state and is never written into YAML. The authorizing user must have a current Revyl role and Cursor access to the GitHub repository; Revyl rechecks both when launching proof and provides project-scoped reauthorization when access is missing or lost. The Cursor agent never holds the authorizing user's Revyl credential: each proof run gets its own Revyl key that acts only in your organization and only for that run, and Revyl revokes it when the run settles.
Prepare the session
Apps that need a fresh credential before a session can declare a before script
and auth-bypass references under session:
session:
before_script:
script_path: "./scripts/prepare-test-session.sh"
timeout_seconds: 120
auth_bypass:
launch_vars: [E2E_AUTH_TOKEN]
deep_link: "myapp://auth?token=${E2E_AUTH_TOKEN}"The executable is resolved relative to the selected Revyl project root. It may
use ../ only while remaining inside the Git worktree. Secret values are
resolved at session start and are not included in configuration publication.
See Auth And Session Prep for execution
details.
Run workflows
Add saved workflow IDs to the project policy:
pr_review:
build:
kind: revyl
profile: pull-request
workflow_ids:
- "00000000-0000-4000-8000-000000000003"After every required project target is ready, each workflow runs only against build platforms represented by its active tests. A mixed iOS/Android workflow executes its iOS tests against the iOS build and its Android tests against the Android build. A deleted, empty, inaccessible, or project-platform-mismatched selection remains visible as inconclusive instead of silently disappearing. Workflow results appear alongside preview build status in the PR report.
Use your own CI
If your pipeline already produces the .app or .apk, upload the finished
artifact and declare the expected app IDs instead of a managed profile:
pr_review:
build:
kind: ci_upload_to_revyl
app_ids:
android: "00000000-0000-4000-8000-000000000002"
proof_of_changes:
enabled: true
harness:
kind: cursorThe CI-upload policy contains no executable build recipe and has no saved
profile association. Your CI uploads the finished artifact with the PR head
metadata so Revyl can match it to the review. GitHub Actions and Buildkite are
detected automatically. On other runners, pass --repo and --commit together.
revyl build upload \
--file path/to/app.apk \
--app "$REVYL_ANDROID_APP_ID" \
--platform android \
--repo acme/mobile \
--commit "$PR_HEAD_SHA" \
--yes \
--jsonSupply REVYL_API_KEY as a CI secret. In the generic example, map PR_HEAD_SHA
to your pipeline's full PR head SHA, not a synthetic merge commit. --repo
names the base GitHub repository receiving the PR, including for forks.
These flags also work with --url and override detected SCM identity.
Revyl matches a unique review by repository and head SHA. This supports any
runner for GitHub PRs; it does not add GitLab or Bitbucket reviews. A version
label alone does not establish PR identity.
While Revyl waits for your upload, the PR report shows the target as Waiting for CI build. If no build arrives within an hour of the PR head being received, the target shows No build received and the report stops waiting, so a skipped or failed CI job does not leave the PR pending. A build uploaded later for the same head still attaches and replaces that state.
Without --branch, uploads go to the job's Git branch; see
Choose where CI uploads go.
You can also trigger an ordinary Revyl remote build from CI when you want Revyl runners. That path still resolves a local named profile and does not publish or send saved-profile identity:
revyl build --profile pull-request --platform android --remote --jsonPrefer Cursor Automations without the Revyl GitHub App? Use the same upload step with a hand-rolled Automation — Cursor proof (BYO-CI).
Related
- Configuration Files — complete local config and publication semantics
- Remote Builds — execute a selected local recipe remotely
- Apps — where uploaded and managed artifacts are registered
- Workflows — create the workflow IDs referenced by
workflow_ids