Templates let agents and clients call named operations instead of writing raw QQL. Variables use {name} syntax. JWT claims are available as {claims.<field>}.
Enable
Section titled “Enable”qql-go serve --templates templates.yamlTemplate File Format
Section titled “Template File Format”templates: search_docs: description: "Search documents" query: "QUERY '{query}' FROM docs LIMIT {limit} USING HYBRID"
search_medical: description: "Search medical records by specialty" query: "QUERY '{query}' FROM medical LIMIT {limit} WHERE specialty = '{specialty}'"
tenant_scroll: description: "Scroll caller's tenant data" query: "SCROLL FROM docs LIMIT {limit}" require_claims: [org_id] # JWT claims that must be present
tenant_search: description: "Search with tenant isolation via claim" query: "QUERY '{query}' FROM docs LIMIT {limit} WHERE org_id = '{claims.org_id}'"Invoking a Template
Section titled “Invoking a Template”Templates are invoked with a special TEMPLATE statement:
curl -X POST http://localhost:50051/qql.QQL/Exec-H "Content-Type: application/json"-H "Authorization: Bearer <jwt>"-d '{"query": "TEMPLATE search_docs query="vector database" limit=10"}'Variable Substitution
Section titled “Variable Substitution”| Syntax | Source |
|---|---|
{variable} | Request parameter |
{claims.<field>} | JWT claim value |
Example with claim substitution:
If the JWT contains org_id = "acme-corp" and the template has:
query: "QUERY '{query}' FROM docs WHERE org_id = '{claims.org_id}' LIMIT {limit}"The gateway resolves to:
QUERY 'search' FROM docs WHERE org_id = 'acme-corp' LIMIT 10require_claims
Section titled “require_claims”Templates with require_claims fail if the token is missing any listed claim:
require_claims: [org_id, department]This ensures templates that embed claim values always have the data they need.
Security
Section titled “Security”Templates interact with the policy engine normally:
- The resolved QQL query is subject to all policy rules
- AST injection (tenant filters, limit caps) applies after template resolution
- A template that resolves to a
DROPstatement is still denied if the policy doesn't allowDROP