IVD uses ComplyEdge TrustLint on LLM-facing artifacts: offline EU AI Act screening in CI, optional runtime checks, and a public trust surface.
Tenant slug: ivd
| Layer | Mechanism | API key in repo? | Blocks merge? |
|---|---|---|---|
| Offline gate | trustlint check via ./scripts/compliance/check.sh |
No | Yes (CI compliance job) |
| Runtime enforcement (CI probe) | POST /v1/check via ./scripts/compliance/runtime_check.sh |
No (BYOK env only) | No (opt-in local / scheduled) |
| Runtime enforcement (MCP tools) | POST /v1/check around every tool call in mcp_server/registry.py → mcp_server/compliance.py |
No (COMPLYEDGE_API_KEY in the server env) |
N/A — blocks the tool call |
| Public proof | Live seal + trust JSON | No | N/A |
ivd_scaffold → ivd_validate → trustlint check (offline) → CI green
↓ optional BYOK
runtime_check.sh → /v1/check → audit trail → badge + trust page
| Surface | URL |
|---|---|
| Enforcement seal (SVG) | https://api.complyedge.io/v1/public/badge/ivd.svg |
| Trust JSON | https://api.complyedge.io/v1/public/trust/ivd |
| Trust page | https://trust.complyedge.io/ivd |
| Origin site (badge host) | https://ivdframework.dev |
| Overview on site | https://ivdframework.dev/#complyedge |
The seal reflects live runtime audit data (checks in 24h / 7d). It is not a static marketing badge.
Recipes, templates, all *_intent.yaml, and root ivd_system_intent.yaml — see .trustlint.yaml for exact globs.
Agent workflow: ivd_scaffold → ivd_validate → ./scripts/compliance/check.sh → declare done. Recipe: ivd_load_recipe compliance-trustlint.
ivd and store the API key in env only — COMPLYEDGE_API_KEY (GitHub Actions secret for optional runtime job, never in git).curl -s -X PATCH https://api.complyedge.io/v1/tenant/trust \
-H "Authorization: Bearer $COMPLYEDGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"trust_public_enabled": true, "public_slug": "ivd", "display_name": "IVD Framework", "website_url": "https://ivdframework.dev"}'
export COMPLYEDGE_API_KEY=ce_...
./scripts/compliance/runtime_check.sh
When the MCP server’s environment has COMPLYEDGE_API_KEY, every tool call is checked
twice by call_tool (the single dispatch all 33 tools pass through):
| Check | direction |
text |
|---|---|---|
| Before the tool runs | prompt |
tool name + JSON arguments |
| Before the result returns | output |
the tool’s result |
Each check sends agent_id (ivd-mcp), jurisdiction (EU) and context:
| Field | Remote (SSE / StreamableHTTP) | Local (stdio) |
|---|---|---|
user_id |
ivdkey:<sha256 prefix of the IVD API key> (never the key) |
local:<login> |
user_role |
mcp_client |
maintainer |
session_id |
Mcp-Session-Id header or SSE session_id |
omitted |
A block returns the rule ID and audit event instead of the tool’s answer. If ComplyEdge
cannot be reached the call goes through and the skip is logged on stderr (fail-open).
Without the key nothing is sent. Optional: COMPLYEDGE_API_URL (default
https://api.complyedge.io), COMPLYEDGE_AGENT_ID, COMPLYEDGE_JURISDICTION,
COMPLYEDGE_TIMEOUT_S (default 15: a cold ComplyEdge instance can take ~8 s to answer, and a check that times out is skipped, verdict and Log ID with it). Tests: mcp_server/tests/unit/test_runtime_compliance.py.
ComplyEdge keeps a keyed fingerprint of each checked text, never the text. Every check
returns an event_id (the Log ID), and a Log ID only proves something next to a copy
of the text. IVD keeps none, so every checked tool call returns both Log IDs in the
result’s _meta, outside the text:
{"_meta": {"complyedge": {"input_event_id": "...", "output_event_id": "..."}}}
A Log ID is null when that check did not run (ComplyEdge unreachable, or an input
block that stopped the call). Without the key there is no _meta. The text you receive
is exactly the text that was checked, so store each Log ID next to your copy:
| Log ID | Text it covers |
|---|---|
| input | <tool name> <arguments as JSON with sorted keys> |
| output | the tool result’s text |
A text longer than 50,000 characters is checked on its first 50,000. Later,
POST /v1/audit/verify with a Log ID and your copy answers whether they match
(how audit reconciliation works).
Tests: mcp_server/tests/unit/test_complyedge_log_ids.py.
| Job | Path | Secret required |
|---|---|---|
compliance |
./scripts/compliance/check.sh |
None |
compliance-runtime (optional) |
./scripts/compliance/runtime_check.sh |
COMPLYEDGE_API_KEY |
Offline gate is the auditable merge blocker. Runtime is opt-in proof for live trust metrics.
pip install 'trustlint>=2.0.1'
./scripts/compliance/check.sh
pytest mcp_server/tests/unit/test_compliance_trustlint.py -q
export COMPLYEDGE_API_KEY=ce_...
./scripts/compliance/runtime_check.sh
recipes/compliance-trustlint.yaml<BEGIN-COMPLYEDGE v1.0> in .cursorrulesdocs/integrations/COMPLYEDGE.md