EVE Core › Docs › EVE CoreGuard Integration Guide

API & integration

EVE CoreGuard Integration Guide: Connecting Your LLM Pipeline in Under 30 Minutes

This guide walks through the complete process of integrating EVE CoreGuard's AI governance API into an existing LLM pipeline. Whether you are running a FastAPI service, a batch inference worker, or a real-time chat application, the same integration pattern applies: evaluate the proposed action before it reaches the model, and enforce the decision on the way out. By the end of this guide your pipeline will produce ALLOWED, BLOCKED, or MODIFIED decisions with a signed decision record on every request. For a complete API reference, see the EVE CoreGuard API Reference.

1. Prerequisites

Before you begin, ensure you have the following:

  • Python 3.9+ — the SDK supports CPython 3.9 through 3.13
  • An EVE CoreGuard API key — keys have the form eve_sk_...; request access on the CoreGuard page
  • The API base URL — the SDK defaults to https://api.evecore.com; https://api.eveaicore.com reaches the same production platform. Pass a different base_url only for a private deployment
  • An action type that is bound to a policy pack — the server chooses the governing pack from your organization and proposed_action["type"] (for example loan_approval → lending_v1). policy_set is an optional assertion; see the policy-pack reference. With eve-coreguard 0.2.10 (the version currently on PyPI), evaluate() sends policy_set="lending_v1" whenever the argument is omitted, so a non-lending or custom-bound action type comes back as a signed BLOCK (COREGUARD.POLICY_BINDING_MISMATCH). On 0.2.10, pass the bound pack’s policy_id as policy_set explicitly; 0.2.11 omits it.

2. Installation

Install the EVE CoreGuard Python SDK from PyPI:

Terminal
pip install eve-coreguard

To pin a range in a requirements.txt or pyproject.toml:

requirements.txt
eve-coreguard>=0.1.0,<1.0.0

The SDK has zero required dependencies: HTTP transport uses the Python standard library (urllib). Offline verification of asymmetric (Ed25519 / ECDSA) decision records needs the cryptography package, which the verify extra installs: pip install "eve-coreguard[verify]".

Offline verification: with the verify extra, verify_decision_record() checks a decision record’s content hash and signature against the published public key, without calling the API. Legacy hmac- records verify only with the shared secret, which is not independent third-party verification.

3. Environment Variables

The SDK does not read environment variables itself: every setting is a CoreGuardClient constructor argument (api_key, base_url, timeout, max_retries, raise_on_veto). Keeping the key in the environment is still the right pattern; your code reads it and passes it in. The names below are the convention this guide uses:

.env
# Required — read by YOUR code and passed to CoreGuardClient(api_key=...)
COREGUARD_API_KEY=eve_sk_xxxxxxxxxxxxxxxxxxxxxxxx

# Optional — passed as base_url=...; omit to use the SDK default
COREGUARD_BASE_URL=https://api.evecore.com

Secret management: never commit COREGUARD_API_KEY to source control. Use a secrets manager (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault, or Kubernetes Secrets) and inject it at runtime. CoreGuardClient raises CoreGuardError at construction if api_key is empty, so a missing key fails at startup rather than on the first request.

4. Synchronous Integration Pattern

CoreGuardClient is the SDK’s client. Insert one evaluate() call before each consequential model action in your existing pipeline. A policy refusal is an ordinary result (result.blocked), not an exception; exceptions mean the decision could not be obtained, and you fail closed:

Python — Synchronous Pattern
import os
from eve_coreguard import CoreGuardClient, CoreGuardError

# Create once at module level and reuse.
client = CoreGuardClient(
    api_key=os.environ["COREGUARD_API_KEY"],
    base_url=os.environ.get("COREGUARD_BASE_URL", "https://api.evecore.com"),
)

def process_loan_request(user: dict, action: dict, context: dict) -> dict:
    # Step 1: evaluate the proposed action before touching the model.
    # action["type"] (e.g. "loan_approval") selects the bound pack server-side.
    try:
        result = client.evaluate(
            tenant_id="bank_001",
            user=user,
            proposed_action=action,
            context=context,
        )
    except CoreGuardError as e:
        # No decision was obtained (network, auth, quota) — fail closed.
        log_error(e)
        return {"error": "governance_unavailable"}

    if result.blocked:
        # Policy refusal — return the rule ids that fired.
        return {"error": "blocked",
                "violations": [v.policy_id for v in result.policy_violations]}

    # Step 2: apply any field edits CoreGuard made before invoking the model.
    if result.verdict == "MODIFIED":
        action = apply_modifications(action, result.modifications)

    # Step 3: invoke your model — governance is complete.
    llm_response = your_llm_client.generate(action)

    # Step 4: keep the decision id with your record — it is your evidence handle.
    return {
        "response": llm_response,
        "decision_id": result.decision_id,
        "decision": result.verdict,
    }

The returned EvaluationResult carries decision (status, action), risk (score, level, factors), policy_violations (each with policy_id and description), modifications, and audit (the signed record), plus the convenience properties verdict, allowed, blocked, decision_id, signature and policy_version. Store decision_id alongside every decision record.

5. Using EVE CoreGuard from an Async Application

The SDK provides no async client; CoreGuardClient is synchronous. Evaluation is a single HTTP round trip, so in an asyncio app such as FastAPI run the call in a worker thread to keep the event loop free — use asyncio.to_thread() (or FastAPI’s run_in_threadpool):

Python — Calling the sync client from FastAPI
import os, asyncio
from fastapi import FastAPI, HTTPException
from eve_coreguard import CoreGuardClient, CoreGuardError

app = FastAPI()
cg = CoreGuardClient(api_key=os.environ["COREGUARD_API_KEY"])

@app.post("/api/v1/decisions")
async def make_decision(payload: dict):
    # Offload the blocking call to a thread so the event loop stays free.
    try:
        result = await asyncio.to_thread(
            cg.evaluate,
            tenant_id=payload["tenant_id"],
            user=payload["user"],
            proposed_action=payload["proposed_action"],
            model_output=payload.get("model_output"),
            context=payload.get("context", {}),
        )
    except CoreGuardError:
        raise HTTPException(status_code=503, detail="governance unavailable")

    if result.blocked:
        raise HTTPException(status_code=422, detail={"status": "BLOCKED",
                            "decision_id": result.decision_id})
    return {"status": result.verdict, "risk_level": result.risk.level}

Client lifecycle: create CoreGuardClient once at startup and reuse it. Each evaluate() is an independent HTTPS request over the standard library; the client retries 5xx responses up to max_retries with exponential backoff and does not keep a connection pool.

6. Webhook Setup for Audit Events

Decisions are returned synchronously by evaluate(), with their signed record; there is no per-decision webhook event. Webhooks deliver governance and system events — for example governance.charter.veto, governance.action, system.rate_limit_exceeded and status.incident.opened. List every type with GET /api/sdk/webhooks/event-types. The SDK has no webhook helpers; register endpoints over HTTP.

Registering a Webhook Endpoint

cURL — Register webhook
curl -X POST https://api.evecore.com/api/sdk/webhooks \
  -H "Authorization: Bearer $COREGUARD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-siem.example.com/coreguard-events",
    "events": ["governance.charter.veto", "governance.action"]
  }'

The response returns the endpoint’s signing secret once; store it as COREGUARD_WEBHOOK_SECRET. In production the URL must use https://, and URLs that resolve to private, loopback or other reserved addresses are refused.

Verifying Webhook Signatures

Every delivery carries an X-EVE-Webhook-Signature header: the hex HMAC-SHA256 of the raw request body, keyed with the endpoint secret. X-EVE-Event-Type, X-EVE-Event-ID and X-EVE-Timestamp accompany it. Verify the signature before processing the event:

Python — Webhook Signature Verification
import hashlib, hmac, json, os
from fastapi import Request, HTTPException

WEBHOOK_SECRET = os.environ["COREGUARD_WEBHOOK_SECRET"].encode()

async def verify_coreguard_webhook(request: Request) -> bytes:
    body = await request.body()
    expected = hmac.new(WEBHOOK_SECRET, body, hashlib.sha256).hexdigest()
    received = request.headers.get("X-EVE-Webhook-Signature", "")
    if not hmac.compare_digest(expected, received):
        raise HTTPException(status_code=401, detail="Invalid webhook signature")
    return body

@app.post("/coreguard-events")
async def coreguard_webhook(request: Request):
    body = await verify_coreguard_webhook(request)
    event = json.loads(body)
    # Forward to your SIEM or compliance store
    await siem_client.ingest(event)
    return {"received": True}

7. Docker Deployment

Pass EVE CoreGuard credentials as environment variables at container runtime. Never bake them into the image:

Dockerfile
FROM python:3.11-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .

# COREGUARD_API_KEY (and optionally COREGUARD_BASE_URL) are injected at runtime — NOT here
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
docker run — inject secrets at runtime
docker run \
  -e COREGUARD_API_KEY="$(vault kv get -field=api_key secret/coreguard)" \
  -p 8080:8080 \
  your-org/your-llm-service:latest

8. Kubernetes Sidecar Pattern

The Python SDK calls the hosted CoreGuard API; on Kubernetes you inject COREGUARD_API_KEY from a Secret exactly as in the Docker example. The EVE sidecar is a separate, private-preview component and is not an endpoint for the SDK: it is an egress governance forward proxy and Envoy ext_authz backend (HTTP on port 9001, gRPC on 9002) that runs CoreGuard evaluation inside the pod and signs a decision certificate for each request it authorizes. Use it when you want enforcement at the mesh or egress layer rather than in application code. Contact us for the sidecar build and Helm chart.

Kubernetes — inject the API key into your service
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
      - name: llm-service
        image: your-org/llm-service:latest
        env:
        - name: COREGUARD_API_KEY
          valueFrom:
            secretKeyRef:
              name: coreguard-credentials
              key: api-key

9. Error Handling

Policy outcomes are results, not exceptions: a BLOCKED or MODIFIED decision comes back as an EvaluationResult (HTTP 200). Exceptions mean no decision was obtained. All of them subclass CoreGuardError and are importable from eve_coreguard:

Exception / outcome Meaning Recommended Action
result.blocked Policy refusal (including an unbound action type or a policy_set mismatch) Reject the action; return result.policy_violations to the caller
result.verdict == "MODIFIED" Policy requires changes before proceeding Apply result.modifications, then continue
AuthError Invalid or expired API key (HTTP 401) Fail closed; rotate the key and alert
PaymentRequiredError Subscription past due or restricted (HTTP 402) Fail closed; inspect client.subscription_state
RateLimitError Rate limit exceeded (HTTP 429) Back off for e.retry_after seconds; queue the request
PolicySetNotFoundError The asserted policy_set is unknown Fix the assertion or omit it; check client.list_policies()
CoreGuardError Any other failure, including network errors and timeouts (e.status_code is 0 when no response arrived) Fail closed — reject the action; log and alert
VetoError Raised only by verify() when the client was built with raise_on_veto=True Do not deliver the verified output

Fail-closed discipline: EVE CoreGuard is a mandatory gateway, not an optional filter. If the governance layer is unreachable, the action must be rejected — not allowed through on a best-effort basis. Fail-open behavior in a governed pipeline creates an audit gap that regulators treat as a compliance failure.

10. Testing Your Integration

The SDK does not ship a mock client. For unit tests, pass a test double into your code: the integration only depends on evaluate() returning an object with blocked, verdict, policy_violations, modifications and decision_id, and you can build a real EvaluationResult from a response dictionary:

Python — Unit test with a stub client
from eve_coreguard import EvaluationResult

class StubClient:
    def __init__(self, response: dict):
        self._response = response
    def evaluate(self, **kwargs):
        return EvaluationResult.from_dict(self._response)

def test_blocked_loan_is_rejected(monkeypatch):
    stub = StubClient({
        "decision": {"status": "BLOCKED"},
        "policy_violations": [{"policy_id": "DTI_LIMIT", "description": "DTI above limit"}],
    })
    monkeypatch.setattr("myservice.client", stub)

    result = process_loan_request(
        user={"id": "u_test"},
        action={"type": "loan_approval", "amount": 50000},
        context={"credit_score": 720, "debt_to_income": 0.52},
    )
    assert result["error"] == "blocked"
    assert "DTI_LIMIT" in result["violations"]

For end-to-end tests, call the real API with a test key and ask for the signed evidence with include_evidence=True. Records signed with an asymmetric key verify offline with the public key alone — no shared secret:

Python — Offline evidence verification (public key only)
import os
from eve_coreguard import CoreGuardClient, verify_decision_record, fetch_public_key_pem

client = CoreGuardClient(api_key=os.environ["COREGUARD_API_KEY"])
decision = client.evaluate(
    tenant_id="bank_001",
    proposed_action={"type": "loan_approval", "amount": 50000},
    context={"credit_score": 720, "debt_to_income": 0.30, "employment_verified": True},
    include_evidence=True,
)

# One call: fetches /.well-known/eve-pubkey if no key is supplied.
check = client.verify_evidence_offline(decision.signed_governance)
assert check.valid, check.reason

# Or verify a STORED record later, with an explicitly pinned public key:
pubkey = fetch_public_key_pem("https://api.evecore.com")
check = verify_decision_record(stored_record, public_key_pem=pubkey)
assert check.valid and check.independently_verifiable

# Legacy hmac- records are shared-secret only (NOT third-party verifiable):
# verify_decision_record(stored_record, hmac_key=os.environ["COREGUARD_HMAC_KEY"])

Frequently Asked Questions

How long does it take to integrate EVE CoreGuard into an existing LLM pipeline?

The critical path is short: install the package (pip install eve-coreguard), create a CoreGuardClient with your API key, and insert one evaluate() call before the action you want governed. The SDK handles authentication, serialization and retries of 5xx responses. Webhook delivery, async services and offline evidence verification are additional steps.

What environment variables does EVE CoreGuard require?

None: the SDK reads no environment variables. You pass api_key (and optionally base_url, timeout, max_retries) to CoreGuardClient. This guide reads the key from COREGUARD_API_KEY and the optional base URL from COREGUARD_BASE_URL in application code, and stores the webhook signing secret as COREGUARD_WEBHOOK_SECRET.

Can EVE CoreGuard be integrated into an async Python application?

Yes, through a worker thread. The SDK ships a single synchronous client, CoreGuardClient; there is no async client. In an asyncio app such as FastAPI, call it with asyncio.to_thread() (or FastAPI’s run_in_threadpool) so the event loop stays free. The client retries 5xx responses with exponential backoff.

How do I deploy EVE CoreGuard in a Kubernetes environment?

Your service calls the hosted API through the SDK, with COREGUARD_API_KEY injected from a Kubernetes Secret. For enforcement at the mesh or egress layer instead of in code, the EVE sidecar (private preview) runs as an Envoy ext_authz backend and forward proxy inside the pod; contact us for the build and Helm chart.

Ready to Integrate?

Get your sandbox API key and start testing EVE CoreGuard in your pipeline today. No credit card required — provisioned in under 24 hours.

Part of the EVE AI Core control plane Deterministic AI Governance Control Plane → Policy decisions that return the same result for the same input every time, before execution.