Skip to content
Vraelis/Docs
Ways to run/Gate a release in CI
Sign inCreate account
Overview
Getting started with VraelisVerify, approve, run, re-checkWhat you can check
Connect an AI assistantThe command lineThe APIGate a release in CIWebhooks
Approving a planRun activityCompletionFindingsRepairRe-checks
SystemsGuaranteesMemory
← Back to vraelis.comDevelopersChangelogContact support

Ways to run

Gate a release in CI

Run a check from a CI job and ship only when the decision is verified.

Outcome
A release goes out only when the claim held on the live app.
Does not do
A CI job cannot approve a plan. The first check of a claim waits until a person approves it at the link.

Gate on the decision, never the run state. A finished run is not a pass. In CI the exit code is what an if-statement reads.

With the CLI

A CI step

# In CI: gate the deploy on the DECISION, not on the command finishing.
curl -fsS https://vraelis.com/install | sh
vraelis verify --url "$PREVIEW_URL" --claim "$CLAIM" --wait --json > result.json
# The approval link is printed to the log; the job waits until a person approves.
# exit 0 verified   exit 1 failed   exit 2 blocked, or could not run
#
# Blocked is not a pass. A run that merely finished is not a pass.
# Only exit 0 should ship.

# On a failure, hand the repair prompt straight to a coding agent:
vraelis result "$(jq -r .verification_id result.json)" --repair-prompt | claude -p
Exit codeWhat it means
0Verified. The claim held on the live app, with evidence.
1Failed. The claim did not hold; a repair prompt is attached.
2Blocked, or the tool could not run at all.

The job needs VRAELIS_API_KEY in its environment, from a key with launch access, and Node 18 or newer. The CLI does not open a browser in CI: the approval link goes to the log. Create an API key

The first check of a claim

A CI job has no person at the terminal, and a key cannot approve a plan, so the first check of a claim waits on the link until someone approves it or --timeout runs out. Re-checks of that approved plan need no new approval within 24 hours of the approval, up to 10 times, on the same address. A new preview URL is a different address, so its first check waits for a person again. The gate below splits the two cases instead.

A gate that calls the API

The CLI collapses “blocked” and “could not run” into 2, because a gate should treat “I could not check” the same as “no verdict.” A hand-rolled gate that polls the API can split those out, exiting 3 when no decision is reached in the window.

gate.mjs

// gate.mjs: ship only on "verified". The exit code gates the deploy.
// 0 verified   1 failed   2 blocked   3 no decision reached   4 the plan still needs a person to approve it
import { randomUUID } from "node:crypto";

const API = "https://vraelis.com/api/v1/verifications";
const headers = {
  "content-type": "application/json",
  "x-api-key": process.env.VRAELIS_API_KEY,
  "idempotency-key": randomUUID(),
};
const request = { deployment_url: process.env.PREVIEW_URL, claim: process.env.VRAELIS_CLAIM };
const post = (body) => fetch(API, { method: "POST", headers, body: JSON.stringify(body) });

// A submit with no reviewed_plan_id returns review_required, not a run: no verification_id, nothing charged.
// A key cannot approve the plan, so the job hands the link to a person and stops.
const planId = process.env.VRAELIS_REVIEWED_PLAN_ID;
if (!planId) {
  const plan = await (await post(request)).json();
  console.error("A person approves this plan first: " + plan.approve_url);
  process.exit(4);
}

// The approved plan is what starts a run, and this response is the first to carry a verification_id.
const { verification_id } = await (await post({ ...request, reviewed_plan_id: planId })).json();

// While running, decision is absent; keep polling until it lands.
let decision = null, out;
for (let i = 0; i < 120 && decision === null; i++) {
  await new Promise((r) => setTimeout(r, 5000));
  out = await (await fetch(API + "/" + verification_id, { headers })).json();
  decision = out.decision ?? null;
}

// Gate on the decision, never the run state. A finished run is not a pass.
switch (decision) {
  case "verified": process.exit(0);
  case "failed":   process.exit(1);
  case "blocked":  process.exit(2);
  default:         process.exit(3); // no decision within the polling window
}
Exit codeWhat it means
0verified
1failed
2blocked
3no decision reached
4the plan still needs a person to approve it
VariableWhat it holds
VRAELIS_API_KEYAn API key with launch access.
PREVIEW_URLThe deployment to check.
VRAELIS_CLAIMThe sentence that has to hold.
VRAELIS_REVIEWED_PLAN_IDThe approved plan's id. Unset on the first run, so the gate prints the approval link and exits 4.
Honest boundaryNothing watches your deployments. A check runs when a person, a CI job or an AI assistant starts one, so put it before the release step.

Related

  • The command line →
  • The API →
  • Re-checks →
← PreviousThe APINext →Webhooks
© 2026 Vraelisvraelis.comSecurityPrivacyCookiesTermsAcceptable use

On this page

With the CLIThe first check of a claimA gate that calls the API
CopiedCopy failed