Skip to main content
The CLI uses a .revyl/ directory for project configuration:

config.yaml

revyl init writes the local project config. A minimal project has a stable project ID and may add session behavior, named build profiles, and PR review policy. Device commands do not require this file. revyl device start also accepts legacy session settings without migration and does not validate unrelated build or PR-review settings. See Auth And Session Prep for discovery and session behavior. revyl build, revyl config validate, and revyl config push still require the canonical format shown below.
See Mint The Token Per Session for the full before-script contract. session.before_script runs before iOS and Android device sessions, but not Web sessions. For Web, use session.auth_bypass.sign_in for worker-minted sign-in; any data a Web proof needs must already exist in the preview environment, for example seeded by the preview’s own deploy or a test-login route. See Auth And Session Prep for how those blocks attach on revyl device start. This example deliberately uses EAS. Expo recipes that run expo prebuild followed by Xcode or Gradle do not need Expo authentication solely because their framework is Expo.

Section Reference

Path globs are trimmed, use forward slashes, contain 1-1,024 characters, and have no leading or trailing slash, repeated slash, NUL, or ./.. path segment. Invalid values are rejected when the configuration is validated or saved. Label filters must already be trimmed and cannot be empty, ! by itself, or duplicated.

Build Configuration

Profiles name complete build intents such as development, pull-request, or release. Each profile owns its iOS and/or Android recipe. There is no authored active profile: commands accept an explicit profile or resolve one only when the choice is deterministic.
Executable recipes require build_commands; setup_commands is optional. Initialization materializes detected mobile command, output, and image defaults. Web configuration is manual: add build.profiles.<name>.web.app_id for URL registration and device start, and add your own build_commands and output_path for bundle builds. revyl init does not guess a Web framework, package manager, preview host, or CI workflow. See Web recipes. An Xcode scheme selected during initialization is embedded in the generated commands instead of being stored as a separate field. revyl build runs in the cloud by default and requires app_id before submission; it can discover the artifact when output_path is absent. Managed PR recipes likewise require an active app. Local execution requires output_path, authenticates, and uploads the result. Interactive local builds can select or create an app after building; non-interactive builds require app_id in advance. See Build Configuration. Build-level env, secrets, and caches are defaults. Recipe environment values override matching build-level keys; secret names are de-duplicated; and caches with the same key merge their paths. A name cannot be both an effective environment key and a secret reference.

Artifact-First CI

If CI already produced the artifact, skip the config-driven build step and upload it directly:

Development Runtime

The project config has no hotreload block and stores no active profile or platform. A revyl dev start applies explicit --profile and --platform values first. Without --profile, it prefers one unique development-like profile, where dev or development must be a complete token, and then infers only a sole eligible profile or platform. Remaining ambiguity prompts in an interactive terminal and fails with the valid choices in a non-interactive session. The framework identifies the runtime family. One resolved profile/platform recipe supplies the app and build definition for the dev context, including its initial local or remote build and subsequent rebuilds. Expo dev-client scheme and prefix information belongs to the selected build artifact metadata rather than the current checkout.

Project Settings

Project commands select the nearest .revyl/config.yaml between the current directory and the active Git worktree root. Use -C <directory> to select from another directory. config show expects the project config format and directs legacy files to migration. Migration only mutates local project files. A successfully prepared legacy migration uses one concise clean-or-lossy human summary; a write creates an exact-byte backup. JSON --check contains the complete migration proposal and migration ledger. The default mode asks for confirmation; --check creates no backup and writes nothing; and --write skips confirmation. A write creates an exact-byte config backup, creates only missing conflict-free .revyl/tests/<alias>.yaml files, and then atomically replaces the config. An existing alias file is preserved byte-for-byte only when it points to the same remote test; any other conflict stops migration because the destination is unsafe to write. When authenticated, migration may reuse or interactively select a project from the verified repository, resolve enabled PR-build app names to exact platform app IDs, and resolve legacy PR workflow names through exact, case-sensitive read-only lookup. Missing, duplicate, or inaccessible workflow names are omitted and reported, including the implicit smoke workflow used by the legacy smoke_every_pr preset. The retired top-level workflow alias cache is reported and removed. An enabled PR build whose app or framework cannot be resolved is omitted and prominently reported as lossy rather than silently removed. Inspect JSON --check before writing; afterward, compare the reported backup or ask a coding agent to reconcile omissions. Migration never creates or attaches a server project, pulls or publishes configuration, or otherwise mutates server state. Edit .revyl/config.yaml directly for ordinary changes and run revyl config validate; the config commands have no separate command for mutating individual YAML keys. Validation does not publish: when connected validation succeeds, it reports whether the configuration is published and, when it is not, names the publish step (revyl config push, or a commit on the repository’s default branch for Git-managed projects). When the local file lacks enabled PR review or Proof of Changes, that step first asks you to configure pr_review with its build settings and proof_of_changes.enabled: true; publishing alone does not add those settings.

Configuration publication and retrieval

GitLab.com and public HTTPS self-managed GitLab repositories use the same configuration commands. Connect the automation account and install the project webhook in Revyl first. The Git origin supplies the instance and subgroup path; self-managed HTTPS ports are preserved. Standard SSH origins assume HTTPS port 443, so use an HTTPS origin when the API uses a different port. revyl config push publishes typed configuration meaning, not raw YAML, and revyl config pull retrieves the server configuration. Neither operation is part of test sync. Push requires a readable canonical project config, authentication, a stable project.id, a supported GitHub or GitLab origin, and verified access to the exact repository. A failed prerequisite names the exact config migrate, config pull or init, auth login or auth status, github status or github connect, Git-origin or repository-access repair, config validate, or retry command needed to recover. Pull accepts the same project config, or—when no config exists—uses the verified repository and nearest configured project root to create the complete config. Pull never converts or overwrites a legacy or invalid file. When an existing config differs from the server, pull creates an exact-byte backup, atomically replaces the file, and reports the backup path without an interactive diff or confirmation. If the local project was deleted and exactly one active replacement owns that same root, pull backs up and replaces the stale file without trusting its retired ID. Revyl stores these top-level groups from the project configuration:
  • project.id
  • session, including its timeout, before-script declaration, and auth-bypass references
  • build.framework and every named build profile, including each iOS or Android recipe, app association when present, commands, output, caches, non-secret environment values, secret references, image, and timeout
  • optional pr_review, including triggers, managed-profile or external-CI build selection, proof policy, workflow references, and strict build-check behavior
Comments, YAML formatting, local tests, the repository remote URL, invocation directory, and any transient profile/platform selection are not stored as part of the project configuration aggregate. Secret references are stored by name; secret values are not sent in this contract. The server independently verifies the authenticated GitHub repository and repository-relative project root, recompiles the supplied typed contract, and checks referenced resources. Manual publication atomically replaces the whole aggregate using the state observed immediately before the write. Under authority from the repository’s default branch, ordinary manual publication is rejected: use revyl config validate, commit the designated file, and let reconciliation publish it. revyl config push --force deliberately replaces the aggregate once while preserving that authority and its reconciliation position. The next newer accepted configuration on that branch can replace that override. --force is a no-op when authority is already manual. revyl config authorize-cursor-proof is separate from configuration publication. It records server-owned human authority only after live Cursor repository access is confirmed; it does not change authored configuration, hashes, or authority, and works for both manual projects and projects managed from the repository’s default branch.

Project roots and deletion

Project roots and config paths are immutable identity. To correct a root:
  1. Delete the manual project from Settings → Integrations → GitHub.
  2. Choose Add project root and enter the correct root.
  3. Run revyl -C <replacement-root> config pull to create or safely replace its local config.
A Git-managed project cannot be deleted directly. Remove its designated config file from the repository’s default branch and wait for successful reconciliation to return it to manual authority, then delete it explicitly. Removing the file alone preserves the project, its configuration, and its automation. Deletion archives only that project. It preserves the repository connection, GitHub installation, repository report destination, frozen and historical results, and already-frozen review and build work, which may finish. Pending Cursor proof that has not launched is the exception: deletion removes its live authorization, so it fails closed. Deleting the last project opens the dashboard’s form for a new project root, and nothing is created until you save it. After navigation, the repository leaves the configured list but remains selectable through Add Repo. There is no CLI project-delete command. A stale local file remains usable for local-only commands. Connected project-configuration surfaces—config validate, config push, config pull, GitHub setup/status, Cursor authorization, and TUI publication—identify the retired project and explain how to create or pull the replacement instead of retrying its ID. Automatic pull recovery is limited to one exact same-root replacement; otherwise Revyl does not assume the old root.

Environment Variable Overrides

These environment variables configure CLI defaults, credentials, and integration behavior:

.gitignore Defaults

The .revyl/.gitignore generated by revyl init uses an allowlist approach: everything inside .revyl/ is ignored by default except for the shared project files listed below. Committed (shared with your team):
  • .revyl/config.yaml — project configuration
  • .revyl/tests/** — local test definitions
  • .revyl/.gitignore — the ignore rules themselves
Everything else under .revyl/ (device sessions, MCP artifacts, PID files, etc.) is local runtime state and stays out of version control automatically.

Test Aliases

Test aliases are managed as files in .revyl/tests/. Each file maps to a remote test via _meta.remote_id. Explicit revyl config migrate externalizes conflict-free legacy tests: entries as stub files; ordinary config and test commands never migrate them implicitly.