The agent query relay
How an LLM agent reads the worldview — proposal, decision, admitted intent, governed effect, and results that re-enter as gated evidence.
A model never queries anything directly. It requests named declared queries; ordinary
Tarski decision rules ratify or deny; an admitted intent executes the read at a pinned head
under the interface’s projection; and the result re-enters the lineage as an observation
feeding the next turn. Reads get the same governance as writes — and the whole path
replays deterministically.
The read loop
- Request. The platform composes a reserved query-request section into each
relay-participating interface’s response schema. The model’s reply may carry an array
of
(query_name, bindings)— onlyagent-exposed declared queries are nameable; free-form query text is refused. - Capture → proposal. The runtime stamps a relay envelope on the model-call result
and derives typed proposal atoms with no mapper involved:
proposal.query_requested.<query_name>(…)carrying the binding values. - Decision. Your rules approve or deny — joining on binding values, sessions, consent facts, budgets. Approval is never implicit; even trivial approval is an explicit, auditable rule.
- Admission.
intent.query_executederives only from committed decisions. The admitted intent pins the full execution contract: query digest, canonical bindings, head, and projection identity. Pinned query IR is durably retained, so hot-reload between admission and execution can never swap in a different query. - Execution. The
worldview.queryeffect runs the engine at the pinned head under the interface’s projection. Success appends aworldview.query_resultobservation; failure appends typedworldview.query_failed— so rules can react to failed reads. - Results, gated.
queryresult.outcomerows are trusted lifecycle metadata (session, request id, digests, outcome class — never row contents). The data rowsqueryresult.<query_name>are fallible-relay-class: no trusted fact withoutdecision.accepted.*, no intent withoutdecision.approved.*. Even one bit of “the query was non-empty” cannot touch the world without an approval.
Independent reads batch into one turn and execute concurrently at the same head. The proposal and result families are system-owned — app declarations or mapper writes into them are load errors, and externally submitted observations claiming those kinds are rejected at ingress. Identity is replay-deterministic (request ids derive from the capture digest), so a clean-store replay reproduces an entire multi-hop deliberation with identical digests.
Wiring it in the manifest
[capabilities]
worldview_query = true
[capabilities.intents."intent.query_execute"]
capability = "worldview.query"
identity_keys = ["session_id", "request_id"]
Relay-participating llm.complete bindings name their interface (binding the session
contract and projection); consultation bindings set model_consultation = true — the
narrow carve-out that lets trusted queryresult.outcome lifecycle rows drive a follow-up
model turn.
Budgets and denials
Budgets are decision rules, not configuration magic:
-- two reads per session; deny with a reason a PM can read
decision.rejected.triage.query_execute(session, req, "budget_exhausted") :-
proposal.query_requested.impacted_services(session, req, root),
triage.session_query_count(session, n),
n >= 2.
A backstop invariant (admitted query intents per session ≤ budget) makes over-approval an impossible state. Denial reports flow into the session’s next-turn context, so the model learns a read was refused — with the reason.
Authoring patterns that matter
- The consultation guard. Any model-consultation turn that re-derives over
queryresult.outcomemust be guarded on “no unsettled requests in the session” — otherwise the changing results section re-admits the producing turn every round and the agent loops. - Compound queries over multi-hop. Queries are full Datalog programs; pre-join in one declared query instead of chaining reads.
- Prove the loop with fixtures.
tarski fixture template query-relay <query>mints a complete request/result lifecycle; digest refresh keeps recorded identities honest. The incident-response example ships fixtures for approved, denied, budget-exhausted, and failed reads.
Model context, curated
Each turn’s context assembles in prefix-stable order — prompt bundle, ontology schema
section (“the menu of reads”), the declared ambient world slice, the session’s
query-results section (results and denials), request arguments — every section
digest-stamped and joined into the provider request digest. New results change only the
tail, keeping provider prompt caches warm. Studio’s model-turn context manifest and
GET /v1/queries/turns/{turn_id}/context disclose exactly what a turn saw.