Skip to main content
Geval integrates like any CLI: actions/checkout gives the job your repo files, you point geval check at a contract and a signals JSON file, then you interpret the exit code. There is no npm package for this engine—use the release binary.

What you must provide

Important: GitHub Actions can read any file you commit. You do not have to regenerate signals.json in CI unless you want fresh metrics every run. Choose one:
  • Committed signals — Commit .geval/signals.json (or signals/signals.json). In the workflow, skip any “generate” step and run: ./geval check --contract .geval/contract.yaml --signals .geval/signals.json
  • Generated signals — Add a step that writes signals.json (e.g. python scripts/export_from_langsmith.py > signals.json). Your script is your integration; Geval only needs valid JSON matching Signals and rules.
If you use LangSmith (or anything else), only the script that builds JSON changes—the geval check line stays the same.
Let the job fail when Geval returns BLOCK (exit 2). For REQUIRE_APPROVAL (exit 1), the job also fails unless you add custom logic (below).
If you use committed signals, replace the generate step with nothing and set --signals to the committed path, e.g. --signals .geval/signals.json. Exit codes: 0 = PASS, 1 = REQUIRE_APPROVAL, 2 = BLOCK. See Exit codes.

Optional: REQUIRE_APPROVAL does not fail the job (custom policy)

If you want BLOCK to fail CI but REQUIRE_APPROVAL to pass the job (so humans decide outside CI), you must capture the exit code in bash. GitHub’s default bash uses errexit (-e): if ./geval check exits non‑zero, the script stops and a following echo "exitcode=$?" never runs—so do not rely on that pattern. Correct pattern:
Do not combine continue-on-error: true on the same step with echo "exitcode=$?" without set +e—the step will exit before echo runs.

Handling REQUIRE_APPROVAL: extra logic

Exit code 1 means Geval’s merged outcome is REQUIRE_APPROVAL (a human or process should review before you treat the change as fully cleared). GitHub does not have a built-in “REQUIRE_APPROVAL” status—you choose what happens: fail the check, pass the check but label the PR, notify Slack, gate an Environment, or record an approval file with geval approve.

1) Single job: fail only on BLOCK, label PR on REQUIRE_APPROVAL

Run check with set +e, map the code to a decision output, fail the step only when 2. A second step adds a label only when decision == require_approval.
Create the label geval:needs-approval once in the repo (or use gh label create). You can require that label to be removed before merge via a separate process, or use branch rules that require another check.

2) Follow-up job using needs (Slack, email, etc.)

Expose a job output so a second job runs only when the decision is require_approval.
Replace the echo step with slackapi/slack-github-action, email, or your internal webhook.

3) GitHub Environments (manual approvers)

For deployment pipelines, attach a job to an Environment that has Required reviewers in repository settings. That job can run after Geval reports require_approval, or you can treat Geval BLOCK as “do not deploy” and use Environment approval only for production deploys—not a substitute for encoding Geval’s REQUIRE_APPROVAL in YAML, but a common combo.

4) Recording approval with geval approve

After a human agrees, someone can run locally or in a trusted workflow:
Commit approval.json or upload it as an artifact if your org’s policy expects an audit trail. geval reject writes a parallel record. See approve & reject. Wiring “merge only if approval file exists” is your policy layer (branch rules, required check, or a second workflow).

5) Failing CI on REQUIRE_APPROVAL (strictest)

If 1 and 2 should both fail the PR check, run geval check with no special handling—the default shell will exit non‑zero for both. No extra logic needed.

Optional: post geval explain on the PR

Use the GitHub CLI (needs pull-requests: write and GH_TOKEN):
Run explain after you know signals.json exists (same paths as check). If you only want a comment when check fails, wrap in if: conditions.

Multiple contracts

Optional --combine-contracts (default worst_case): check.

Artifacts

geval check writes decision JSON under .geval/decisions/. Upload that folder as a workflow artifact if you want audit history in CI. See Decision artifacts.

See also

Exit codes · approve & reject · GitLab CI · Installation · Troubleshooting