greenroom
Quickstart

Web quickstart

Connect your app, merge three setup files, then verify a test PR.

By the end of this page, every pull request in your repository gets walked by Greenroom and receives a QA handoff. Install the GitHub App, add the workflow and two config files, merge setup, then open a test PR.

1. Install the GitHub App

Install the Greenroom GitHub App on the repository you want covered. The app requests read access to contents and pull requests, and permission to post the handoff as a GitHub Check run. It never comments on your pull request, never gets write access to your code, and never will.

2. Add the workflow

Create .github/workflows/greenroom.yml. The job calls Greenroom's reusable workflow; your prepare script builds and serves the preview, and Greenroom walks it:

name: Greenroom
on:
  pull_request:
    types: [opened, synchronize, reopened]

permissions:
  contents: read

jobs:
  greenroom:
    permissions:
      contents: read
      id-token: write
    # Greenroom's reusable workflow, pinned to a reviewed commit. The job is
    # defined there, so a pull request cannot change what it does.
    uses: justindc100/greenroom-action/.github/workflows/pass.yml@3b2754eafa6ed5f4d122a0bb3ea7dee7005f65b8
    with:
      platform: web
      app-id: my-app
      # Review build commands and test-environment variables before merging.
      prepare: |
        npm ci && npm run build
        npx --yes serve@14.2.4 -l 4173 -s dist > serve.log 2>&1 &
        for i in $(seq 1 30); do curl -sf http://127.0.0.1:4173/ >/dev/null && break; sleep 1; done
        curl -fsS http://127.0.0.1:4173/ >/dev/null
      target-url: http://127.0.0.1:4173/
      artifact-path: dist
      # Source upload is off by default. Enable only after repository and
      # Greenroom workspace policy have both been reviewed.
      source-upload-allowed: "false"

Two details in that file are deliberate and worth keeping:

  • The job is Greenroom's reusable workflow, pinned to a commit SHA. Greenroom trusts a run by the workflow identity in its OIDC token, and only its own published commits are trusted. Because the job is defined in Greenroom's repository, a pull request cannot alter what it does; prepare is the one thing you control, and it runs with no credentials beyond the job's OIDC identity.
  • Policy comes from the base revision. The reusable workflow reads .greenroom/environment.json and .greenroom/state-contract.json from the PR's base commit, not from the PR itself. A pull request cannot loosen its own allowlist or rewrite its own contract to hide a defect.

3. Add the environment manifest

Create .greenroom/environment.json. This is your attestation of what environment Greenroom is allowed to touch:

{
  "schemaVersion": "1.0",
  "classification": "test",
  "isolated": true,
  "resetStrategy": "ephemeral_deployment",
  "networkControl": "playwright",
  "allowedHosts": ["127.0.0.1", "api.example.test", "fonts.googleapis.com", "fonts.gstatic.com"],
  "productionHosts": ["api.example.com"],
  "sandboxPurchases": false
}

Web runs require networkControl: "playwright": the browser itself enforces the allowlist, and any request to a host you did not list ends the walk with a contained violation.

List every host your app actually touches, including font and analytics CDNs. This is the number one first-run failure. A missing fonts.googleapis.com ends the pass after one action with "off-allowlist network request was contained". That behavior is correct, and the fix is to complete your allowlist, not to widen policy.

A host may not appear in both allowedHosts and productionHosts. The manifest is rejected outright if it does, because an allowlisted production host would mean the virtual user can reach real customer data.

The manifest reference documents every field.

4. Add the state contract

Create .greenroom/state-contract.json. The contract tells Greenroom what screens exist and how your router maps source to screens, which lets it scope a diff to exactly the screens it changes:

{
  "schemaVersion": "1.0",
  "routerKind": "hash-spa",
  "graphPaths": ["src/views.js"],
  "entryState": "home",
  "states": [
    { "id": "home", "route": "#/", "goal": "Reach the home screen" },
    { "id": "checkout", "route": "#/checkout", "goal": "Complete a purchase with a saved cart" }
  ],
  "transitions": [
    { "id": "home-to-checkout", "from": "home", "to": "checkout" }
  ]
}

Give each state an observable outcome. The driver pursues the selected state goals; the workflow goal is not automatically added as a separate task. A transition to checkout does not prove a purchase completed, and existing history does not prove a new item was saved. See testing a completed journey.

Ship this file at onboarding, not later. Without it, Greenroom can still walk whatever goals a run requests, but coverage authority stays requested-goal-only and a clean run can never conclude better than inconclusive. The contract is what upgrades "nothing went wrong" to "the changed screens were covered and passed". See the state contract reference.

5. Merge setup, then open a test pull request

Review and merge the three setup files into the base branch first. The policy files must exist on the base revision before a pass can start. Then open a separate test PR that changes a mapped screen.

Every run walks the screens your diff touched and posts the handoff. Model routing is fixed per role by Greenroom's reviewed defaults; a per-app route override is something the Greenroom operator applies after measuring your app, not an automatic screening step. The report anatomy page shows what comes back.

Let your coding agent set it up

If you work with Claude Code or Codex, point it at the Greenroom onboarding skill and ask it to set up Greenroom on the repository. The skill is a procedure plus a zero-dependency helper: the agent detects your framework and router, gathers the hosts the app actually contacts (the allowlist mistake above included), drafts the three files with the pin this page quotes, runs the same checks as --check, and stops with a reviewable diff and the short list of steps only you can do (install the App, merge setup, open the test PR). It never commits, pushes, or touches a secret value.

On this page