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
| Input | Where it comes from |
|---|---|
| Contract + policies | Usually committed (e.g. .geval/contract.yaml, .geval/policies/*.yaml). Same files as local geval check. |
signals.json | Either already in the repo (commit it) or created in the workflow by a script that talks to LangSmith, Braintrust, your API, etc. |
signals.json in CI unless you want fresh metrics every run. Choose one:
- Committed signals — Commit
.geval/signals.json(orsignals/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.
geval check line stays the same.
Recommended: simple PR gate (fail on BLOCK)
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).
--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 defaultbash 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:
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 code1 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.
| Exit | Meaning | Typical automation |
|---|---|---|
0 | PASS | No extra action; merge allowed per your rules |
1 | REQUIRE_APPROVAL | Comment, label, notify, or require GitHub Environment reviewers |
2 | BLOCK | Fail the job; do not merge until policies pass |
1) Single job: fail only on BLOCK, label PR on REQUIRE_APPROVAL
Run check withset +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.
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.
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 reportsrequire_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:
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)
If1 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):
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
--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.