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:
See Mint The Token Per Session for the full before-script contract, and 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.
Every declared recipe has build_commands. setup_commands is optional. Initialization materializes detected framework-specific command, output, and image defaults. An Xcode scheme selected during initialization is embedded in the generated commands instead of being stored as a separate field. Optional app_id does not create a local-build-only execution mode. A direct local revyl build still authenticates, requires output_path before running the recipe, builds the artifact, selects or creates its destination app when the recipe has no binding, and uploads the result. Revyl then offers to save that app ID into the selected recipe. Remote execution may use the platform’s artifact-discovery default when output_path is absent, but it requires an app association before submission; managed PR policy likewise requires every selected managed recipe to resolve an active app. 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.

Configuration publication and retrieval

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 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 GitHub 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 default-branch authority, 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 default-branch authority and its reconciliation position. The next newer accepted default-branch configuration 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 and default-branch projects.

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 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 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 shows No projects configured and Add project. After navigation, the repository leaves the configured list but remains selectable through Add Repo; no root project is created automatically. 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.