Skip to content

lenses/

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.

lenses/movie-details.yml
version: 1
id: movie-details
name: Movie details
handler: movie.movieDetail

Required 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.

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.

lenses/account-health.yml
id: account-health
name: Account Health
description: Live account health assembled from the CRM and support systems.
params:
- name: accountId
type: STRING
label: Account
required: true
spec:
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.html

Fields:

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.