lenses/
Captured handler binding
Section titled “Captured handler binding”A captured host uses versioned metadata to bind a lens to an approved handler in the same installation. The declaration supplies no execution capability by itself.
version: 1id: movie-detailsname: Movie detailshandler: movie.movieDetailRequired fields are version, id, name and handler; description and result are optional.
The ID is a lowercase letter followed by lowercase letters, digits or hyphens, at
most 64 characters. The name is at most 128 characters; description at most 512.
Fields are strict. Aliases, tags, malformed UTF-8, nested paths, duplicate IDs and
undeclared handlers are refused. Hosts accept at most 32 flat .yml/.yaml files,
8 KiB each and 64 KiB aggregate. IDs conflicting across installations are unavailable.
Owner World definitions and owner saves take precedence.
An opening passes JSON object arguments through the retained handler.
The handler returns a JSON object within 1 MiB, 32 nesting levels and 65,536
characters per string. result: json is the default and returns data only.
With result: content, the handler returns optional focus (up to 256 unique
entity ID strings, each at most 1,024 UTF-8 bytes), data (any JSON value),
presentation (items, table or json) and complete (boolean, default true).
Unknown fields are refused. Content lenses require the retained cypher_query
grant alongside handler approval. The host reads owned focus on access; missing,
ambiguous or inaccessible IDs are excluded and mark the result incomplete.
complete: false also marks it incomplete. A presentation preference selects an
existing compatible host view; guest HTML and executable references are refused.
Background envelopes are snapshots. Losing ownership of any already projected
focus entity invalidates the stored envelope at its next admission check.
The host retains the same target and serialized arguments through refresh, rechecks
owner World and approval on reads, and disables cache reuse. API calls inside the
handler require their own operation and credential approvals.
This is independent of the selected sandbox backend. The Me implementation exposes
it through /api/v1/lenses/{id}/invoke and the JSON view endpoint. Add
background=true or waitSeconds for deferred execution. Preparation retains the
selected target and serialized arguments; queued work cannot select a new revision.
Completion and every result response recheck admission. Revocation clears stored
data; new approval cannot revive an old run. Results and handles are in memory.
The reference host limits active work to 64 runs globally and eight per owner, returning HTTP 429 at capacity. Cancelled workers consume capacity until they exit. It retains up to 200 settled runs and cancels overdue work using the configured background timeout. Cancellation cannot undo completed effects. See hosted execution for supported routes and limits.
Host-specific legacy definitions
Section titled “Host-specific legacy definitions”The definitions below describe the compatibility runtime. Captured Worlds do not execute Realm-provided legacy module, CypherScript, fixed-query or anchor lenses.
Named focused experiences a realm installs alongside its types, producers and apps. Each .yml
file serializes one Lens. The host discovers world-authored lenses first and then installed-realm
lenses; a world lens with the same id shadows the realm definition. This is the same precedence
model as realm-bundled apps and lets a world customize an installed experience without modifying
the realm repository.
id: account-healthname: Account Healthdescription: Live account health assembled from the CRM and support systems.params: - name: accountId type: STRING label: Account required: truespec: kind: cypherscript script: | const accountId = String(lensArgs.accountId || ""); const result = await gateway.kg.query({ cypher: `MATCH (a:Account {accountId:$accountId})-[:HAS_TICKET]->(t:SupportTicket) RETURN a.name AS account, collect(t) AS tickets`, params: JSON.stringify({ accountId }), }); const rows = (result && result.rows) ? result.rows : (result || []); await gateway.lens.present({ content: JSON.stringify({ kind: "account-health", rows, }) });presentation: href: /apps/account-health.htmlFields:
| Field | Required | Description |
|---|---|---|
id |
Yes | Stable lens id. A world override uses the same id. |
name |
Yes | Human-readable name. |
description |
No | Routing and catalogue description. |
params |
No | Declared inputs. Types are STRING, INT, DATE, DURATION, or BOOLEAN; each parameter may declare label, default, and required. |
spec |
Yes | Execution definition selected by kind (below). |
persona |
No | Optional personality slug carried by the opened view. |
schedule |
No | Optional cron expression for refresh/change handling. |
presentation |
No | Optional top-level surface and/or app href. |
Supported spec.kind values:
| kind | Shape | Use |
|---|---|---|
cypherscript |
script |
JavaScript/CypherScript that can combine Virtual Cypher, gateway integrations and bounded gateway.ai.* calls. |
module |
className, plus inline source or sibling module; optional presentKind/dataType |
A typed program Lens whose retrieve() returns focus plus structured data. |
fixed |
key, optional params |
A host-registered fixed query. |
anchor |
ref |
A typed graph-node anchor. |
A realm-shipped Lens is code, not mutable per-world or per-principal state: its definition is refreshed when the realm is updated. One opening’s arguments, focus, presentation, Watch snapshots and other scoped state remain in the world. An app should invoke a named Lens or view through the host’s typed invocation surface; it should not accept or submit arbitrary Cypher or JavaScript from a browser.
A CypherScript Lens may depend on a reusable node view by referencing the view name as a label
inside gateway.kg.query, including an inline parameter map. View expansion happens before Virtual
Cypher planning, so the view owns the composable graph selection while the Lens owns procedural
classification and presentation. For example, a DiseaseTrialRuns view that returns one
TrialSearchRun node can be consumed as:
const result = await gateway.kg.query({ cypher: `MATCH (run:DiseaseTrialRuns {registryQuery:'Long COVID'}) MATCH (run)-[:RETURNED]->(trial:ClinicalTrial) RETURN trial`, params: JSON.stringify({}),});Only identity-preserving node views compose this way. A tabular/projection view is terminal: invoke it directly through the named-view surface rather than using its name as a label in a larger query.

