API & integration
EVE CoreGuard Python SDK
The eve-coreguard Python SDK provides a typed, ergonomic interface to the EVE CoreGuard governance decision engine. Install it from PyPI, configure your API key, and your first governance-enforced evaluation is running in under five minutes.
Contents
Installation
The SDK requires Python 3.9 or later. It has zero required dependencies — it uses only the Python standard library (urllib) for HTTP transport. Install from PyPI:
The package is published on PyPI: pypi.org/project/eve-coreguard.
To pin to a specific version (recommended for production):
For projects using pyproject.toml:
[project]
dependencies = [
"eve-coreguard>=0.1.0,<1.0.0",
]
Verify the installation:
Quick Start — 5 Lines
The following example evaluates a loan approval against the lending_v1 policy pack and prints the disposition. evaluate() takes keyword arguments directly — there is no request object to construct:
from eve_coreguard import CoreGuardClient
client = CoreGuardClient(api_key="eve_sk_...")
result = client.evaluate(
tenant_id="bank_001",
proposed_action={"type": "loan_approval", "amount": 250000},
model_output={"decision": "approve", "confidence": 0.91},
context={"credit_score": 580, "debt_to_income": 0.52},
policy_set="lending_v1",
)
print(result.verdict) # ALLOWED | BLOCKED | MODIFIED
API key security: Never hardcode your API key in source code. Load it from an environment variable: api_key=os.environ["COREGUARD_API_KEY"]. See Configuration for all available options.
Configuration
The CoreGuardClient accepts the following constructor parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
| api_key | str | required | Your EVE CoreGuard API key. Recommended to load from environment variable COREGUARD_API_KEY. |
| base_url | str | https://api.evecore.com | Base URL for the EVE CoreGuard API (https://api.eveaicore.com reaches the same platform). Override for on-premises or private cloud deployments. |
| timeout | float | 30.0 | Request timeout in seconds. |
| max_retries | int | 3 | Maximum number of retries on transient 5xx errors. Uses exponential backoff. |
| raise_on_veto | bool | False | If True, verify() raises VetoError on a hard-veto or charter violation instead of returning a result. |
Load the API key from the environment rather than hardcoding it:
import os
from eve_coreguard import CoreGuardClient
client = CoreGuardClient(api_key=os.environ["COREGUARD_API_KEY"])
evaluate() Parameters
Call client.evaluate() with keyword arguments. They map directly to the POST /v1/decisions/evaluate request body.
| Parameter | Type | Description | |
|---|---|---|---|
| tenant_id | str | required | Organization/tenant identifier. Recorded on the decision certificate. |
| proposed_action | dict | required | The action being evaluated. Include type plus pack-specific fields (e.g. amount). |
| model_output | dict | recommended | The AI model's recommendation, e.g. {"decision": "approve", "confidence": 0.91}. |
| context | dict | optional | Domain-specific signals the policy evaluates (e.g. credit_score, debt_to_income). Defaults to empty dict. |
| policy_set | str | optional | Optional assertion; omitted from the request unless set (0.2.11+; 0.2.10 and earlier always sent "lending_v1"). The server binds the pack from proposed_action["type"]; a mismatch is a signed BLOCK (COREGUARD.POLICY_BINDING_MISMATCH). See PolicyInfo.bound_action_types from list_policies(). On 0.2.10, pass the bound pack’s policy_id explicitly for any non-lending or custom-bound action type. |
| include_evidence | bool | optional | Default False. When True, the server attaches the signed governance evidence record; it is exposed as result.signed_governance, the input to verify_evidence_offline(). |
| user | dict | optional | Actor context, e.g. {"id": "u_001", "role": "loan_officer"}. Defaults to an SDK client identity. |
| request_id | str or None | optional | Idempotency key. Auto-generated (UUID4) when omitted. |
| timestamp | str or None | optional | ISO 8601 timestamp. Defaults to the current UTC time. |
Full example
result = client.evaluate(
tenant_id="bank_001",
user={"id": "u_892", "role": "loan_officer"},
proposed_action={
"type": "loan_approval",
"applicant_id": "app_7823",
"amount": 85000,
},
model_output={"decision": "approve", "confidence": 0.88},
context={"credit_score": 712, "debt_to_income": 0.31, "employment_verified": True},
policy_set="lending_v1",
request_id="req_unique_0001", # idempotency key (optional)
)
EvaluationResult Fields
The evaluate() method returns a frozen EvaluationResult dataclass with the following structure (plus convenience properties .verdict, .allowed, .blocked, .decision_id, .signature, .audit_hash):
| Field | Type | Description |
|---|---|---|
| decision.status | str | Final disposition: "ALLOWED", "BLOCKED", or "MODIFIED". Also exposed as result.verdict. |
| decision.action | str | Resolved action, e.g. "deny_loan_approval". |
| risk.score | float | Risk score, 0.0–1.0. |
| risk.level | str | "LOW", "MEDIUM", or "HIGH". |
| risk.factors | list[str] | Human-readable risk factors that fired. |
| policy_violations | list[PolicyViolation] | Violations that fired. Each has .policy_id and .description. Empty for ALLOWED. |
| regulatory_impact | list[RegulatoryImpact] | Each maps a violation to a regulation: .regulation (e.g. ECOA), .risk, .severity. |
| counterfactual | Counterfactual or None | Thresholds that would have produced ALLOWED (.credit_score_required, .max_dti_allowed, .employment_required). |
| liability_prevented | LiabilityEstimate or None | Estimated exposure prevented (.estimated_exposure, .reason). |
| modifications | list[Modification] or None | Field edits applied for MODIFIED decisions (.field_name, .original_value, .modified_value, .reason). |
| audit | AuditRecord | The signed Decision Certificate. See Decision Certificates for the full schema. |
| audit.audit_id | str | Unique certificate identifier. Also exposed as result.decision_id. |
| audit.signature | str | Tagged signature over the canonical audit record, with the algorithm carried in the prefix: kms-ecdsa-p384-<hex> on the hosted service, hmac-<hex> for legacy and self-hosted symmetric records, also ed25519- and ecdsa-p256-. A verifier must dispatch on the prefix rather than assume one algorithm. Also result.signature. |
Error Handling
The SDK uses a structured exception hierarchy. All exceptions inherit from CoreGuardError:
from eve_coreguard import (
CoreGuardClient,
CoreGuardError,
AuthError, # 401 — invalid or expired API key
PaymentRequiredError, # 402 — subscription past due / restricted
RateLimitError, # 429 — rate limit exceeded (has .retry_after)
PolicySetNotFoundError, # 404 — policy_set does not exist
VetoError, # raised by verify() when raise_on_veto=True
)
client = CoreGuardClient(api_key=os.environ["COREGUARD_API_KEY"])
try:
result = client.evaluate(tenant_id="bank_001", proposed_action=action)
except AuthError:
# Rotate API key; alert on-call
raise
except RateLimitError as e:
# Back off for e.retry_after seconds
time.sleep(e.retry_after)
except PolicySetNotFoundError:
# Unknown policy_set — check list_policies()
raise
except PaymentRequiredError:
# Subscription past due — inspect client.subscription_state
raise
except CoreGuardError as e:
logger.error(f"CoreGuard evaluation failed: {e} (status {e.status_code})")
raise
Output Verification & Policy Discovery
Beyond decision enforcement, the same client verifies AI-generated text through the 43-stage governance pipeline, and discovers the policy packs available to your tenant.
Verify AI output
vr = client.verify(
ai_output="The current prime rate is 8.5%.",
confidence=0.9,
domain="financial", # factual | financial | legal | medical | safety | creative | general
)
print(vr.passed, vr.blocked, vr.crd) # bool, bool, CRD score
if vr.blocked:
print(vr.veto.type, vr.veto.reason)
Discover policy packs
# List the catalog (optionally filter by regulatory domain)
for p in client.list_policies(domain="fair_lending"):
print(p.policy_id, p.version, p.rule_count)
# Fetch metadata for one pack
pack = client.get_policy("lending_v1")
print(pack.jurisdiction, pack.notes)
Advanced Usage
Batch Evaluation
The decision API evaluates one action per call. For high-throughput scenarios, evaluate concurrently with a thread pool — each call is an independent, idempotent HTTP request:
from concurrent.futures import ThreadPoolExecutor
from eve_coreguard import CoreGuardClient
client = CoreGuardClient(api_key=os.environ["COREGUARD_API_KEY"])
def check(app):
return client.evaluate(
tenant_id="bank_001",
proposed_action=app["action"],
context=app["context"],
policy_set="lending_v1",
)
with ThreadPoolExecutor(max_workers=8) as pool:
for app, res in zip(application_batch, pool.map(check, application_batch)):
if res.blocked:
handle_blocked(app, res)
Custom Policy Sets
Organizations on Enterprise plans may have custom policy packs deployed in their own namespace (org:<org_id>). A custom pack governs a decision once your org admin binds an action type to it; you then call evaluate() exactly as for a built-in pack, and the binding — not policy_set — selects it. (policy_set remains an optional assertion; a value that does not match the bound pack is a signed BLOCK.) 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.
result = client.evaluate(
tenant_id="regional_bank_07",
# loan_approval is governed by the custom pack your org admin bound it to
user={"id": "u_100", "role": "underwriter"},
proposed_action={"type": "loan_approval", "amount": 420000},
# required on 0.2.10 (it would otherwise send "lending_v1"): the custom pack's
# policy_id, as listed by client.list_policies()
policy_set=custom_policy_id,
)
Offline Proof Verification
Every decision can be verified locally, with no server call: the SDK recomputes the content hash and checks the signature. Which key you need depends on which artifact you hold — the two are not interchangeable.
For a hosted decision record, verification is asymmetric: it needs only EVE’s public key and no shared secret, so the party checking the record is not the party that produced it. This gives publicly verifiable evidence of record integrity and signing-key possession (not, by itself, legal non-repudiation):
# A governed decision, with the signed evidence plane included
decision = client.evaluate(request_id="req-001", tenant_id="org_abc", proposed_action={"type": "loan_approval", "amount": 50000}, policy_set="lending_v1", include_evidence=True)
# Hosted records: verify against the PUBLISHED PUBLIC KEY — no shared secret, no
# network. The key is auto-fetched from /.well-known/eve-pubkey if not supplied.
result = client.verify_evidence_offline(decision.signed_governance)
print(f"Valid: {result.valid} | algorithm: {result.algorithm} | independent: {result.independently_verifiable}")
# Legacy / self-hosted symmetric proof bundle — DEPRECATED, and NOT independent
# proof: it needs the server's shared signing key, so anyone able to verify can
# also forge. Kept only for pre-existing HMAC records.
proof = client.get_proof("proof_abc123")
is_valid = CoreGuardClient.verify_proof(proof.raw, signing_key=key_hex)
print(f"Proof valid: {is_valid}")
# Export a batch of records for compliance review
export = client.export_audit(action_type="loan_approval", limit=100)
print(export.count, "records")
To verify certificates, chains, and ITI snapshots without any EVE CoreGuard client (the auditor/regulator path), use the dedicated offline verifier: pip install eve-governance.
Changelog
Current release. Patch: the institutional-mandate verification surface is now importable from the package root. No API, wire, verdict or verification behavior changed.
- 0.2.9 shipped
eve_coreguard/mandate.pywith the full offline authority-verification surface but never exported it, sofrom eve_coreguard import verify_mandate_authorityraisedImportErrorwhile onlyfrom eve_coreguard.mandate import …worked. - Added to the package root and
__all__:verify_mandate_authority,mandate_claim,compute_mandate_state_digest,select_governing_generation,MandateGeneration,MandateVerification. The submodule import keeps working.
Patch: __version__ now matches the packaged version. No API, wire, verdict or verification behavior changed.
- Fixes 0.2.8 shipping with
eve_coreguard.__version__ == "0.2.7"— the release bump touchedpyproject.tomland left the module attribute behind, so an audit record naming the verifying tool would have reported the wrong version. 0.2.8is otherwise identical; upgrade only if you read__version__.
Default API endpoint is now https://api.evecore.com. Backward compatible — no wire, verdict, or verification behavior changed.
- The default
base_urlforCoreGuardClientandTrustClientis nowhttps://api.evecore.com, the canonical EVE API hostname. https://api.eveaicore.comreaches the same production platform — same service, same database, same signing key — and remains fully supported with no deprecation date.- Hostname is not an input to tenant resolution, policy evaluation, authority, certificates, idempotency or execution-token validity. Certificates issued before this release verify offline unchanged.
Offline verification of AWS-KMS-signed decision records (ECDSA P-384) — additive; no verdict or wire behavior changed for existing records.
- The offline verifier now recognizes the
kms-ecdsa-p384-<hex>signature tag (AWS KMSECC_NIST_P384/ECDSA_SHA_384, DER-encoded): it recomputes the SHA-384 digest ofcontent_hashand checks the signature against the published public key — no KMS or AWS access required. - Adds
test_kms_verify.pywith akms_vector.jsontest vector. Existingecdsa-p384/ecdsa-p256/hmacverification is unchanged; a tampered record still fails.
Offline verifier broadening for over-bound records. No verdict or wire behavior changed.
verify_decision_recordfalls back to a full-record content hash when the fixedeve.decision.v3/v4signed-field reconstruction does not match, recognizing “over-bound” records whose signature legitimately covers more fields than the fixed set. A tampered record still fails both reconstructions, so verification is never weakened.- Published to PyPI and verified byte-reproducible from tag
eve-coreguard-v0.2.6.
License-metadata correction and canonical entry-point alignment. No verdict, verification, or wire behavior changed.
- Restores the correct proprietary package metadata (the 0.2.4 build carried a stray MIT classifier that contradicted the
LICENSEfile). PyPI versions are immutable, so the correction shipped as a new version. - The public API is now
CoreGuardClientonly; theEVEfacade is removed. Usefrom eve_coreguard import CoreGuardClient.
Published to PyPI. Offline verification for the eve.decision.v3 decision-record schema.
- Adds offline verification for the
eve.decision.v3schema: request, response, and rule-results digest checking plus public-key signature verification. - No breaking API changes from the 0.1.x line; the
evaluate()keyword interface is unchanged.
Offline-verification reliability fix.
- Fixes a critical bug where
fetch_public_key()failed because the base URL was never set, causing offline ECDSA P-384 verification to silently fail. - Adds
test_evidence.pycovering round-trip, tamper, fail-closed, and auto-fetch paths. - Removes the unused
[async]install extra; honestverify_chain()docstring. (0.2.1 restored the[async]extra to match the published package metadata; it only installsaiohttp.)
Independent offline decision-evidence verification.
- New
evidence.py:verify_decision_record(),fetch_public_key_pem(),recompute_content_hash()— recompute the SHA-256 content hash locally and check the ECDSA P-384 signature with no server call. - New
verifyinstall extra (pip install "eve-coreguard[verify]", pullscryptography>=41). - LICENSE now included in the source distribution.
Policy catalog discovery.
client.list_policies(domain=...)andclient.get_policy(policy_id)for discovering available policy packs.- New typed
PolicyInfomodel (policy_id, version, domain, jurisdiction, rule_count). - SDK test suite grows to 33 tests.
Initial public release.
- Synchronous
CoreGuardClientwithevaluate()for decision enforcement. verify()for running AI output through the 43-stage governance pipeline.- Audit & proof retrieval:
get_proof(),get_recent_proofs(),export_audit(), and the staticCoreGuardClient.verify_proof()for offline HMAC verification. - Typed, frozen result models:
EvaluationResult,VerifyResult,ProofBundle. - Automatic retry with exponential backoff on 5xx errors.
- Exception hierarchy:
CoreGuardError,AuthError,PaymentRequiredError,RateLimitError,PolicySetNotFoundError,VetoError. - Zero required dependencies (stdlib
urllibtransport); 28 tests at launch. - Compatible with Python 3.9, 3.10, 3.11, 3.12, 3.13.
For upcoming releases and the full commit history, see the GitHub repository. Bug reports and feature requests are welcome via GitHub Issues or [email protected].