Skip to content

Integrations

Verel grades artifacts, so it plugs into whatever stack you already run — it never asks you to rip-and-replace. Pick the channel that matches where your team works: an MCP host, your CI, a GitHub webhook, an agent framework, or Kubernetes. Every channel returns the same thing — a verdict (pass / warn / fail) plus grounded file:line issues — so "done" means the same everywhere.

Channels at a glance

Channel What it does Entry point Where
MCP server Exposes the gate + graders + brain to any MCP host; the agent calls verel_gate before "done" verel-mcp · tools
Per-host install One-line setup for Cursor / Claude Code / Cline / Continue / Windsurf verel mcp install
Rules nudge Drops the gate instruction into a host's rules file (zero-code adoption) verel rules --target …
REST gate Language-agnostic HTTP gate over one repo — any CI / script POSTs, gets a verdict verel serve
GitHub PR webhook HMAC-verified pull_request events run the gate on the configured repo POST /github
Commit-status callback Posts a red/green check back onto the PR post_commit_status / on_event
GitHub Action Fails the build on a FAIL verdict amitpatole/verel@v1.9.4
pre-commit hook Gates the commit on the verdict bus .pre-commit-hooks.yaml (verel-precommit)
Agent SDK shims The gate as a tool for OpenAI / Anthropic / LangChain / LangGraph / CrewAI / AutoGen / Claude Agent SDK verel.integrations.sdk
Gate a PR vs. its ticket Pull a PR's acceptance criteria + diff from GitHub, grade intent grade_pr() / verel_spec
Kubernetes Helm chart + Kopf operator (GateRun / Brain / GatewayService / VerelFleet) chart + operator k8s

MCP server (any host)

verel-mcp exposes the verdict bus, the Verified-Review graders, and the shared brain to any MCP host. Install the binary, register it, and the agent gets verel_gate (run graders → attested verdict + a verifiable receipt) — it can no longer self-declare "done".

pipx install verel        # (or pip install verel) — provides the verel-mcp binary
verel mcp install         # prints the config block + the per-host destination
verel mcp install --json  # just the JSON block

The config is the standard mcpServers shape every host understands:

{
  "mcpServers": {
    "verel": {
      "command": "verel-mcp"
    }
  }
}

Tools the agent gets: verel_gate, verel_sight, verel_verify, verel_ci_check, verel_iac_check, verel_spec, verel_invariants, verel_smell, verel_recall, verel_remember, verel_build_tool. See the full MCP tool reference and the Graders reference.


Per-host MCP setup

verel mcp install prints the config and where to drop it. The block is identical per host; only the destination file differs:

Host Config file
Claude Desktop ~/.config/Claude/claude_desktop_config.json (Linux) · ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
Cursor .cursor/mcp.json (project) or ~/.cursor/mcp.json (global)
Cline VS Code settings → Cline MCP servers (cline_mcp_settings.json)
Continue ~/.continue/config.json (under mcpServers)
Windsurf ~/.codeium/windsurf/mcp_config.json

Claude Code reads the same mcpServers block — add it to your host config and the gate is live.

Rules nudge (zero-code, any agent)

Not every host speaks MCP. verel rules writes the gate instruction into a host's rules file so the agent gates its own work with no MCP server at all:

verel rules --target cursor  --write   # → .cursorrules
verel rules --target claude  --write   # → CLAUDE.md
verel rules --target agents  --write   # → AGENTS.md
verel rules --target windsurf --write  # → .windsurfrules
verel rules --target copilot --write   # → .github/copilot-instructions.md
verel rules                            # print the snippet instead of writing it

--write appends idempotently (a second run is a no-op) and preserves existing content.

GitHub Copilot is rules-only. verel rules --target copilot writes .github/copilot-instructions.md — a text nudge that tells Copilot to gate before "done". There is no live MCP gate: Copilot has no MCP-tool path here, so it can't actually run verel_gate. For an enforced gate on Copilot-authored code, wire the CI or PR webhook channel — those execute the verdict bus, not just instruct it.


REST gate (any language, any CI)

verel serve runs a small HTTP gate over one repo. Any CI step, script, or webhook POSTs and gets the verdict — no MCP host, no Python in your build. Loopback is zero-config; a routable bind requires a token AND TLS or it refuses to start.

verel serve --repo .                       # loopback: POST /gate · POST /github · GET /health · GET /ready

VEREL_GATE_TOKEN=  verel serve --repo . --host 0.0.0.0 \
  --certfile cert.pem --keyfile key.pem    # routable bind: token + TLS mandatory
curl -s http://127.0.0.1:8750/health        # {"status": "ok"}
curl -s -X POST -H "Authorization: Bearer $VEREL_GATE_TOKEN" \
     http://127.0.0.1:8750/gate             # {"verdict": "pass|warn|fail", "issues": [...]}

POST /gate ignores its request body and gates the repo fixed at startup, so an authenticated caller can never redirect CI at another directory. See verel serve.

GitHub PR webhook

POST /github verifies GitHub's X-Hub-Signature-256 HMAC over the raw body (VEREL_GATE_WEBHOOK_SECRET) before anything runs — an unsigned or forged event is rejected 401, no gate runs. On a pull_request event it gates the locally configured repo (it never fetches a URL from the payload — no SSRF) and responds 200 with {"event": {...}, "gate": {"verdict": …, "issues": […]}}. A non-PR event responds 200 {"skipped": "not a pull_request event"}.

In GitHub (Settings → Webhooks → Add webhook): Payload URL https://your-host:8750/github, Content type application/json (required — the HMAC is over the raw JSON), Secret = VEREL_GATE_WEBHOOK_SECRET, Events = Pull requests only.

Post a check back to the PR

verel serve returns the verdict in the HTTP response — it does not set a commit status by default. To make a red/green check appear on the PR, run GateServer from Python with an on_event callback that calls post_commit_status (both in verel.integrations):

import os
from verel.integrations import GateServer, post_commit_status

GH_TOKEN = os.environ["VEREL_GITHUB_TOKEN"]   # needs the `repo:status` scope

def on_event(event, gate):
    # event = {"action", "repo" (owner/name), "number", "sha"} — repo/sha are shape-validated
    state = {"pass": "success", "warn": "success", "fail": "failure"}.get(gate["verdict"], "error")
    post_commit_status(event["repo"], event["sha"], state=state, token=GH_TOKEN,
                       description=gate.get("reason", "")[:140], context="verel/gate")

GateServer(".", host="0.0.0.0", port=8750,
           auth_token=os.environ["VEREL_GATE_TOKEN"],
           webhook_secret=os.environ["VEREL_GATE_WEBHOOK_SECRET"],
           certfile="cert.pem", keyfile="key.pem", on_event=on_event).start()

post_commit_status(repo, sha, *, state, token, …) posts to POST /repos/{owner}/{repo}/statuses/{sha} with state ∈ pending|success|failure|error. For GitHub Enterprise pass api="https://ghe.example.com/api/v3".


CI matrix

Same verdict bus, three drop-ins. The GitHub Action is canonical; everything else shells out to verel-ci check.

GitHub Action

# .github/workflows/verify.yml
name: verify
on: [push, pull_request]
jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: amitpatole/verel@v1.9.4
        with:
          repo: .                 # path to gate (default ".")
          install: "-e .[dev]"    # YOUR project's deps so its tests import
          extras: "dev"           # Verel extras (dev = pytest/ruff/mypy graders) — default
          # no-lint: "true"       # skip the lint grader
          # python-version: "3.12"

The action installs verel[dev], pip installs your install: spec, then runs verel-ci check --repo <repo> (adding --no-lint when no-lint: "true") — non-zero exit on a FAIL verdict fails the build.

GitLab CI

# .gitlab-ci.yml
verel-gate:
  image: python:3.12
  script:
    - pip install "verel[dev]"
    - pip install -e ".[dev]"          # your project's deps so its tests import
    - verel-ci check --repo .          # exits non-zero on a FAIL verdict → the job fails

Any CI (the one-liner)

pip install "verel[dev]" && verel-ci check --repo .   # exit 0 unless verdict == fail

For a build that has no Python — or where you'd rather not install Verel per-job — stand up verel serve once and POST /gate from the pipeline instead.

pre-commit

# .pre-commit-config.yaml
- repo: https://github.com/amitpatole/verel
  rev: v1.9.4
  hooks: [{ id: verel-precommit }]

verel-precommit runs the pre-commit stage and aborts the commit on a FAIL verdict. The hook runs in pre-commit's isolated venv, so a heavy project (whose tests need its own deps importable) is better served by the GitHub Action above or a native git hook via verel-ci install --repo ..


Gate a PR against its ticket

The highest-value channel for a team already living in GitHub: does the change actually implement what the PR/issue asked for? grade_pr pulls the PR's acceptance criteria (its title/body + linked issues) and its diff straight from GitHub, then runs the spec/intent grader — the LLM only proposes checks from the ticket; execution decides, so a hallucinated judge can neither block a good merge nor pass a broken one.

import os
from verel.ci.spec import grade_pr

rep = grade_pr(
    ".",                 # local checkout to grade against
    "octo/api",          # owner/name on GitHub
    42,                  # PR number
    token=os.environ["VEREL_GITHUB_TOKEN"],
)
print(rep.verdict)                         # Verdict.PASS / WARN / FAIL
for issue in rep.issues:                   # grounded INTENT_MISMATCH per violated criterion
    print(issue.locator, "-", issue.message)
  • VEREL_GITHUB_TOKEN needs PR read to fetch the ticket + diff. (If you also post the result back with post_commit_status, the token additionally needs the repo:status scope.)
  • GitHub Enterprise: grade_pr(".", "octo/api", 42, token=…, api="https://ghe.example.com/api/v3").
  • Needs an LLMgrade_pr defaults chat=default_chat() to compile the criteria into checks (configure via VEREL_LLM_PROVIDER); the executed checks run under OS-isolation and fail closed (the criterion stays advisory) when bwrap is absent.
  • Full signature: grade_pr(repo, repo_full_name, number, *, token=None, api="https://api.github.com", chat=None, n=2) -> Report.

From an MCP host, the same grader is the verel_spec tool — pass the ticket text as criteria and the changed paths as files.


Agent SDK shims

verel.integrations.sdk gives a framework-agnostic gate: hand the agent a tool that runs the gate and reads the verdict before it declares "done". No heavy SDK is imported — the snippets below show the per-framework wiring.

The SDK gate() runs the CI gate (and, with criteria, the spec grader). It returns a verdict + grounded issues but no attested receipt — for a publicly verifiable receipt use the verel_gate MCP tool instead.

Plain callable (CrewAI / AutoGen / Claude Agent SDK — anything that takes a Python function):

from verel.integrations.sdk import gate

result = gate(".", criteria=ticket_text)   # criteria optional; also: files=[...], lint=True
assert result["verdict"] == "pass"          # only now is the task done

OpenAI function calling:

from openai import OpenAI
from verel.integrations.sdk import openai_tools, run_tool_call

client = OpenAI()
resp = client.chat.completions.create(model="gpt-4o", tools=openai_tools(),
    messages=[{"role": "user", "content": "Implement X in this repo, then verify it's done."}])
for call in resp.choices[0].message.tool_calls or []:
    out = run_tool_call(call.function.name, call.function.arguments)   # runs the gate
    # feed `out` back as a tool message and loop until out["verdict"] == "pass"

Anthropic / Claude tool use:

from anthropic import Anthropic
from verel.integrations.sdk import anthropic_tools, run_tool_call

client = Anthropic()
msg = client.messages.create(model="claude-sonnet-4-5", max_tokens=1024,
    tools=anthropic_tools(), messages=[{"role": "user", "content": "Build X, then verify done."}])
for block in msg.content:
    if block.type == "tool_use":
        out = run_tool_call(block.name, block.input)   # accepts a dict or a JSON string

LangChain / LangGraph — bind the gate as a node/tool:

from verel.integrations.sdk import langchain_tools   # needs `pip install langchain-core`

tools = langchain_tools()   # [StructuredTool(name="verel_gate", ...)] — bind to your agent or graph

run_tool_call(name, arguments) only knows "verel_gate"; an unknown name returns {"error": "..."} (it never raises), so a stray model tool call can't crash your loop.


IaC / DevOps & cloud IAM

Grade Terraform/OpenTofu, the wider DevOps toolchain, and cloud-IAM blast radius on the same verdict bus — and gate apply/destroy through the action gateway. Tools shell out behind pure parsers (offline-tested), each mapping onto an existing trust tier:

Tool Grader Spec
terraform/tofu validate · plan IAC (+ IAM sensor) terraform_validate_spec · terraform_plan_spec
tflint LINT tflint_spec
trivy config · checkov SECURITY trivy_config_spec · checkov_spec
conftest / OPA POLICY conftest_spec
infracost (vs explicit budget) COST infracost_spec(repo, budgets={...})
helm template · kubectl --dry-run IAC (+ RBAC sensor) helm_template_spec · kubectl_dryrun_spec
kube-score · kube-linter · polaris SECURITY kube_score_spec · kube_linter_spec · polaris_spec
Parliament · Cloudsplaining IAM parliament_spec · cloudsplaining_spec

Catch dangerous IAM before apply — the sensor reads a terraform show -json plan offline:

from verel.ci import parse_terraform_plan
for i in parse_terraform_plan(open("tfplan.json").read()):
    print(i.severity.value, i.source.value, i.detail["rule_id"], i.locator)
# error iam WILDCARD_ACTION aws_iam_policy.admin

Gate the apply — the actuator plans, grades the bound plan, and applies exactly that file (a re-plan/substitution between approval and apply is refused — TOCTOU defense). Any destroy/replace or IAM widening ⇒ IRREVERSIBLE (dry-run + human approval):

from verel.actuators import TerraformActuator
act = TerraformActuator(repo=".")
plan = act.plan()                       # bound plan + digest + IAC/IAM verdict
print(plan.report.verdict.value, plan.action_class.value, plan.escalation_reasons)
# act.act(plan.plan_digest) applies ONLY the approved plan; act.watch() confirms convergence

Credentials for the effective-access verifier (AWS IAM Access Analyzer / GCP Policy Analyzer / Azure role assignments) are resolved from ~/.config and never logged — verel doctor shows what's detected. See the Graders reference and examples/demo_iac.py.

Kubernetes

Run the brain, the gate, and the gateway in-cluster with the Helm chart and the Kopf operator (the GateRun, Brain, GatewayService, and VerelFleet CRDs). See Deploy on Kubernetes / k3s.

See also the Developer guide for the full surface and the Architecture for how the organs fit together.