Trust elements
Two canvas elements operate on trust registries. Trust Check runs TRQP queries against a registry at request time and exposes the results to OPA policies. Trust Recorder writes agent-registration records into registries as requests pass through the surface.
For conceptual background, see Trust registries.
Trust Check
Drop a Trust Check element on a surface edge to run a TRQP query against a trust registry at request time. The Trust Check stage runs all configured queries in parallel and writes results into input.trust_check_results for OPA evaluation.
Three placements are available, each checking a different agent:
| Placement | Agent checked | Availability |
|---|---|---|
| Access Point → Managed Agent edge (caller leg) | The inbound caller. | All protocols. |
| Managed Agent → Transit Point edge (Transit Point target leg) | The agent at that Transit Point’s destination. Runs only for requests the managed agent sends through that Transit Point. | New Trust Checks on A2A Transit Points only. |
| Managed Agent → External edge, from the Managed Agent to its A2A proxy or gateway node (Managed Agent target leg) | The managed agent’s own target. | Only when the Managed Agent’s Endpoint Type is via A2A Proxy or via Gateway Connection. |
Caller-leg results are written to input.trust_check_results.caller. Results from either target leg are written to input.trust_check_results.target.
Each Transit Point has its own Trust Check, and a request sees only the results of the Transit Point it goes through. A Transit Point with no Trust Check runs no target-leg check: the gateway does not fetch the destination’s agent card for trust, verify its identity, or query a trust registry for it. Trust Check audit records for these requests name the Transit Point by its alias.
A Trust Check on the Managed Agent’s own target leg runs only for an A2A proxy or gateway target. On a Direct URL target, its panel shows This Trust Check blocks Save on a URL target: remove it, switch the target, or move the checks to a Transit Point edge.
For the OPA fields these results populate, see OPA policies reference.
Trust Checks copied to Transit Points
From 1.0.2, each Transit Point runs only its own Trust Checks. The earlier surface-wide target-leg Trust Check is copied onto every Transit Point of the surface, so traffic is checked as before until you review each copy. Open each surface that shows a Transit Points need Trust Check review banner, then keep or remove each copy. See Agent validation via a trust registry.
A surface with copied Trust Checks shows a banner above the canvas that counts the Transit Points to review, for example 2 Transit Points need Trust Check review. When some of them belong to other variants, the banner says so, and you switch to each variant to review it. Each copied Trust Check carries a warning badge on the canvas, and its panel and fullscreen editor show Review this migrated Trust Check with a Keep button.
| Action | Effect |
|---|---|
| Keep | Clears the review flag. The Transit Point keeps running the copied queries. Editing the queries and saving them in the fullscreen editor also clears the flag. |
| Remove Trust Check | Removes the copy. The Transit Point then runs no target-leg Trust Check. |
Save the surface to apply either action.
On an MCP Transit Point, a copied Trust Check is read-only. Its panel shows “Trust Checks can’t be changed on an MCP Transit Point; keep or remove this migrated copy.”, and its button opens the queries as View Queries…. New Trust Checks cannot be added to an MCP Transit Point.
Removing a copy stops that Transit Point’s checks, so a policy that denied on their results now allows its traffic. A rule that only looks for failed results also allows a request when no checks ran. To require that checks ran, see Require target-leg checks in policy.

Panel
The sidebar panel lists the configured queries by number and record type, with each query’s name when it has one. On a Transit Point it notes Applies to this Transit Point only. Open the fullscreen editor to add or edit queries. Each Trust Check allows a maximum of 10 queries.
Query fields
Each query in the fullscreen editor has these fields.
| Field | Required | Description |
|---|---|---|
| Trust Registry | Yes | Trust registry to query. Selected from your configured trust registries. |
| Record Type | Yes | Authorization: is this entity authorised to perform this action on this resource? Recognition: does this authority recognise this entity? |
| Authority ID | Yes (target leg). Auto on caller leg. | Issuer or Authority DID selected from the gateway’s configured Issuers and Authorities. On the caller leg, leaving this blank defaults to the verified agent-identity-credential issuer ({{ input.agent.identity_issuer_did }}). On the target leg, an explicit selection is required. |
| Entity ID | No | Named-subject dropdown. On the caller leg: the caller’s agent DID (default, {{ input.agent.did }}), the gateway’s managed-identity DID ({{ input.extension_identity.did }}), or the caller’s verified identity credential issuer DID ({{ input.agent.identity_issuer_did }}). On the target leg: the target’s agent DID (default, {{ input.agent.did }}). |
| Action | Yes (Authorization only) | TRQP action string. Required for Authorization queries. Optional for Recognition queries; defaults to is when blank. |
| Resource | Yes (Authorization only) | TRQP resource string. Required for Authorization queries. Optional for Recognition queries; defaults to ownedAgent when blank. |
The id field is auto-generated for each query and used by OPA to address results in input.trust_check_results.{caller|target}[]. It is not editable in the UI.
Validation constraints
- Each Trust Check allows a maximum of 10 queries.
- Authority ID must be non-blank on the target leg.
- On the caller leg, a stored
{{ … }}template other than the verified-issuer default is invalid. Replace it with an explicit Issuer or Authority selection. - Action and Resource are required for Authorization queries and must not be blank.
- Query
idvalues are auto-generated and must be unique within a Trust Check.
Template syntax
All four query fields accept {{ }} templates resolved against the input.* JSON the gateway builds for the same request. Templates follow the OPA input namespace, so a value from the policy input is available using the same path you would use in a Rego rule.
{{ input.agent.provider_did }} → resolved DID of the agent's department/provider
{{ input.agent.did }} → effective caller DID
{{ input.source_auth.claims.sub }} → JWT subject claim (jwt_bearer auth only)
{{ input.http.path }} → request pathA || fallback operator is supported for fields that may be absent:
{{ input.extension_identity.did || input.agent.did }}The right-hand side is used only when the left-hand side is missing or null. A non-scalar value (array, object) or a malformed template short-circuits with TEMPLATE_RESOLUTION_FAILED and does not fall through to the right-hand side.
When a template fails to resolve, the element produces ok = false with error.code = TEMPLATE_RESOLUTION_FAILED and no TRQP network call is made.
Result fields
Each element in input.trust_check_results.caller and input.trust_check_results.target has this shape:
{
"id": "tc-caller-1",
"trust_registry_id": "tr-main",
"query_type": "recognition",
"ok": true,
"error": null,
"name": "Verify caller department",
"authority_id": "did:web:authority.example.com",
"entity_id": "did:web:caller.example.com",
"action": "is",
"resource": "ownedAgent",
"query_resolved": true
}| Field | Type | Description |
|---|---|---|
id | string | Mirrors TrustCheckElement.id. Use this to address the result in Rego. |
trust_registry_id | string | The registry the query ran against. |
query_type | string | "recognition" or "authorization". |
ok | boolean | true when the trust registry allowed the request. false for both clean denials (NOT_RECOGNIZED, NOT_AUTHORIZED) and stage failures. |
error | object or null | null only when ok is true. Present for all other outcomes: clean denials (NOT_RECOGNIZED, NOT_AUTHORIZED) and stage failures alike. |
error.code | string | One of the error codes below. |
error.message | string | Human-readable detail. For TRUST_REGISTRY_PROBLEM_REPORT, this is the registry-supplied problem report code; Rego can branch on it without the gateway taking a position on whether it represents a denial or a transport error. |
name | string or null | Mirrors TrustCheckElement.name when set. Absent from the wire when the element has no name. |
authority_id | string or null | The TRQP authority DID as actually sent. Post-template-substitution when query_resolved is true; raw template string on TEMPLATE_RESOLUTION_FAILED. Absent for AGENT_CARD_UNAVAILABLE, TRUST_REGISTRY_METADATA_UNAVAILABLE, IDENTITY_VP_VERIFICATION_FAILED, and TARGET_AGENT_IDENTITY_UNAVAILABLE — the pipeline did not reach the resolution step on those paths. |
entity_id | string or null | The TRQP entity DID as actually sent. Absent on the same four codes as authority_id. |
action | string | The TRQP action as sent. For recognition queries with no operator-set value, the wire default "is" is used. Always present. |
resource | string | The TRQP resource as sent. For recognition queries with no operator-set value, the wire default "ownedAgent" is used. Always present. |
query_resolved | boolean | true when every template placeholder resolved. false when the executor fell back to raw template strings because resolution failed (TEMPLATE_RESOLUTION_FAILED) or because agent card or trust-registry metadata was unavailable. Always present. |
Error codes
| Code | Category | Meaning |
|---|---|---|
NOT_RECOGNIZED | Clean denial | Recognition query returned a negative verdict — the registry answered that it does not recognise the entity. authority_id, entity_id, action, and resource are populated; query_resolved is true. |
NOT_AUTHORIZED | Clean denial | Authorization query returned a negative verdict — the registry answered that the entity is not authorised. Same field population as NOT_RECOGNIZED. |
TRUST_REGISTRY_UNREACHABLE | Stage failure | Outbound TRQP transport could not be established (registry not found, no DIDComm connection, or stale connection). |
QUERY_FAILED | Stage failure | Transport delivered the exchange but it failed in a way that does not fit a more specific category (for example, a low-level send error). |
TRUST_REGISTRY_PROBLEM_REPORT | Stage failure | Registry responded with a DIDComm problem report. The registry-supplied code is in error.message; Rego can branch on it without the gateway taking a position on whether the code represents a denial or an error. |
TRUST_REGISTRY_PARSE_ERROR | Stage failure | Registry response was delivered but could not be parsed into the expected TRQP shape. Distinct from QUERY_FAILED so schema or version drift is observable independently. |
QUERY_TIMEOUT | Stage failure | The per-element timeout_secs budget elapsed before a response was received. Only emitted when the element carries an explicit timeout override. |
TEMPLATE_RESOLUTION_FAILED | Stage failure | A {{ }} template could not be resolved against the request context. No network call was made. authority_id and entity_id carry the raw template strings; query_resolved is false. |
AGENT_CARD_UNAVAILABLE | Stage failure | Target agent card could not be fetched. One result per configured element is synthesised. authority_id and entity_id are absent from the wire. Target leg only. |
TRUST_REGISTRY_METADATA_UNAVAILABLE | Stage failure | The element’s query template references a trust-registry metadata field the request context doesn’t populate. On the target leg, this is provider_did or trust_registry_did missing from the target’s agent card. On the caller leg, this is did, provider_did, trust_registry_did, or authority_did missing from the caller’s request payload. Fires only for elements whose template actually references the missing field; peer elements with resolvable templates run normally. authority_id and entity_id are absent. Both legs. |
IDENTITY_VP_VERIFICATION_FAILED | Stage failure | Target agent card was fetched, but the agent-identity-credential/v1 Verifiable Presentation it carries failed cryptographic verification (bad proof, expired, or no VCIssuer configured). input.agent.did is cleared so the unverified DID never reaches OPA. authority_id and entity_id are absent. Target leg only. |
TARGET_AGENT_IDENTITY_UNAVAILABLE | Stage failure | Target agent card was fetched, but it carries no agent-identity-credential/v1 Verifiable Presentation at all. input.agent.did is cleared. authority_id and entity_id are absent. Target leg only. |
Rego patterns
Address a result by id rather than array index:
# Allow only when the named element passed
allow if {
some r in input.trust_check_results.caller
r.id == "tc-caller-1"
r.ok == true
}Deny on any stage failure:
deny if {
some r in input.trust_check_results.caller
r.error != null
}Branch on a registry-level problem report code:
deny if {
some r in input.trust_check_results.caller
r.error.code == "TRUST_REGISTRY_PROBLEM_REPORT"
r.error.message == "AGENT_NOT_RECOGNIZED"
}Require target-leg checks in policy
Attach the policy below with a Policy element on the Managed Agent → Transit Point edge. Inbound requests carry no Transit Point results, so the same rule on the Access Point denies every inbound request. A request through a Transit Point with no Trust Check carries no target-leg results. A rule that only denies on a failed result, such as deny if { some r in input.trust_check_results.target; not r.ok }, therefore finds nothing to deny on a request through that Transit Point. When a policy depends on target-leg checks, also require that they ran:
allow if {
count(input.trust_check_results.target) > 0
every r in input.trust_check_results.target { r.ok }
}To depend on one specific check, address its result by id, as in the first pattern above.
Trust Recorder
The Trust Recorder element writes agent-registration records into one or more trust registries on the response leg (Managed Agent → Access Point). It runs after the managed agent responds, so the agent’s DID from the reply is available to record. Each entry targets one registry and names the Authority that acts as the trust anchor for its records. For the steps to set one up, see Record your agents in a trust registry.
The Trust Recorder’s fullscreen editor has a collapsed How do Issuer, Authority and Entity relate? panel that summarises the fields below:
- Authority: the trust anchor that asserts every record the entry writes.
- Entity: who a record is about, either the agent’s DID or the entry’s Issuer.
- Issuer (this entry): the DID recorded as the Entity of custom records whose Entity Target is Issuer DID. It does not sign records or set the Authority.
- Surface Issuer: the Issuer selected in the Surface node’s Issuer setting. It matters only for entries whose Authority is Use surface Issuer.
Entry fields
Each row in the entry list configures one registry target.
| Field | Required | Default | Description |
|---|---|---|---|
| Trust Registry | Yes | — | Trust registry to write records into. Selected from your configured trust registries. |
| Issuer | Yes | — | Recorded as the Entity of custom records whose Entity Target is Issuer DID. It does not sign records or set the Authority. Selected from your configured Issuers. |
| Authority | Yes | Explicit DID | Trust anchor asserting these records. Explicit DID: select one of your configured Authorities or Issuers. An Issuer acts as the authority under its own DID. Use surface Issuer: records are written with the surface’s Issuer DID, resolved at write time. The entry is skipped, and writes no records, when the surface has no Issuer selected or its Issuer has been deleted. In that case the Trust Recorder panel and the entry show a warning that points to the Surface node’s Issuer setting. A stored DID that matches no configured Authority or Issuer shows as Custom (from JSON API) until you select one. |
| Built-in triple | No | On | Checkbox. When on, the gateway writes an ownedAgent record: [Authority] Agent DID is ownedAgent. The agent DID is auto-filled from the response. |
Records written for a managed agent carry the agent’s display name, taken from the surface name, as context. The gateway also publishes Authority and Issuer names to the registry. See How names reach the trust registry.
Custom resources
Each entry can include additional custom records. Custom resources extend the standard owned-agent record with operator-defined registrations.
| Field | Required | Default | Description |
|---|---|---|---|
| Action | Yes | — | The action the record authorises or recognises (for example is, invoke). |
| Resource | Yes | — | The resource URI or identifier the action applies to (for example ownedAgent, paymentAgent). |
| Entity Target | No | Agent DID | Which DID is written as the entity_id on the record. Options: Agent DID, Issuer DID. |
| Record type | No | recognition | Type of TrAdmin record. Options: recognition, authorization. |
Last outcome
On a saved surface, the Trust Recorder panel and its fullscreen editor show a Last outcome row: the most recent recording attempt among the surface’s managed agents. It shows the status, the reason when one applies, how long ago the attempt ran, and the record counts across all entries (created, already existed, failed). Before the first attempt it shows No attempt yet.
| Status | Meaning |
|---|---|
| Recorded | At least one record was written or already existed, and none failed. |
| Partly recorded | Some records were written or already existed, and others failed or were skipped. |
| Failed | No record was written. The reason is No response from the registry, Registry rejected the record, or Registry error. |
| Skipped | The entry was not written. The reason is Trust registry not found, Trust registry not connected, Surface has no Issuer, or Registry error. |
| Not attempted yet | The surface has a Trust Recorder and no outcome is stored yet. |
The status is the recorder’s last known outcome, not a live check of the trust registry. The gateway keeps one status per surface and managed agent. Deleting the surface, or adding, removing, or changing its Trust Recorder entries, clears the status until the next response. The Identities page shows the same status for each managed agent. See How identities are named and listed.
Related
- Access Point reference: Trust Check on the caller leg.
- Managed Agent reference: Trust Check on the Managed Agent leg.
- OPA policies reference: how Trust Check results appear as
input.trust_check_resultsin Rego. - Trust registries: conceptual background on TRQP queries and trust registry connections.
Glad to hear it. Thanks for letting us know.
Sorry to hear that. Thanks for letting us know.
Still stuck? Ask the community on Discord or contact us.