KDCube
← Engineering
KDCube Engineering · Concept

The Scene: A Host for Cooperating App Surfaces

The browser control plane where independent app surfaces become one workspace. The scene knows where a surface is mounted and how to reach it; the owning app knows what its objects mean.

24 June 2026Engineering14 minConceptThe Footlights
sceneapp surfacesevent claimssurface commandscontext dragcanvas ingressruntime routing

A KDCube scene is the browser control plane where independent app surfaces become one workspace. It mounts widgets, connects each widget to its configured runtime, routes claimed events, brokers context drag/drop, and forwards object actions to the app that owns the object.

The scene is not the apps, their databases, or their object model. Chat, pinboard, memories, news, stats, Connection Hub, and a new surface from your own app can appear together without becoming one frontend monolith.

THE SCENE · ONE STAGE, MANY INDEPENDENT SURFACESUSERChatPinboardMemoriesNewsStatsConn HubYour AppSCENE HOST · THE STAGE MACHINERYruntime registrysurface registryevent brokerdrag brokerSURFACE COMMANDS · OBJECT-ACTION GATEWAY · PRESENTATION CONFIGconfigured runtime Aapps and providersconfigured runtime Bapps and providersEXPLICIT RUNTIME / APP / TENANT / PROJECT ROUTESTHE SCENE KNOWS WHERE A SURFACE IS MOUNTED · THE OWNING APP KNOWS WHAT ITS OBJECTS MEAN
The scene composes independent app surfaces.
THE RULE

The scene knows where a surface is mounted and how to reach it. The owning app knows what its objects mean and which actions are allowed.

00 Highlights

The concepts the article builds on, in one place:

ConceptThe takeaway
Composition, not absorptionThe scene owns mounting and browser routing; provider semantics — refs, schemas, actions — stay with the owning app.
Four registriesRuntimes, components, context drop targets, surface-command contracts: most scene behavior is explicit configuration.
Runtime-wise routingEvery claim and command carries component → app → runtime alias → tenant → project. Two runtimes are never silently one.
Claim-based eventsComponents declare interests; the broker forwards matches only. Missing delivery is one of four visible conditions — no hidden fallback subscription.
Drag moves refsContext drag carries the canonical ref plus provenance, never domain data; the provider's response decides the open target.
Commands move the userA declared surface command summons/focuses another surface, with readiness waits and acknowledgements.
Two ingress shapespayload.object_ref pins an existing ref; payload.content.text is hosted as a cnv: object first. No payload_type.
Three backend contractsApp surfaces, generic named-service tools, and workspace/timeline projection are separate — the scene and canvas are not materializers.

01 What the scene owns

The scene owns composition and browser routing:

  • runtime aliases, origins, tenants, and projects;
  • mounted components, iframe routes, and surface identities;
  • target-surface ownership and summon/focus behavior;
  • docked, floating, and ready/not-ready surface state;
  • namespace presentation config used for labels, icons, and colors;
  • context drag/drop overlays and delivery;
  • claim-based event routing;
  • surface-command contracts and acknowledgements;
  • an object-action gateway that forwards the complete object_ref.

The scene does not own provider semantics:

  • it does not parse mem:, conv:conversation:, conv:fi:, or cnv: to choose behavior;
  • it does not infer actions from a namespace, kind, color, or icon;
  • it does not copy provider schemas into the host;
  • it does not decide how provider objects are materialized for an agent;
  • it does not subscribe for a component that never declared an event claim.

A deployment may declare composition policy such as “this surface accepts mem:* drops.” That controls which drop targets are offered. It does not make the scene the owner of mem: semantics. The actual open/action still goes through the provider with the full canonical ref.

02 Four registries make the host concrete

Most scene behavior is explicit configuration.

FOUR REGISTRIES · THE CALL BOARDRUNTIMESdefaultorigin · tenant · projectdevorigin · tenant · projectCOMPONENTSchatapp · runtime · route · surfaceRefpinboardapp · runtime · route · surfaceRefmemoriesapp · runtime · route · surfaceRefstatsapp · runtime · route · surfaceRefCONTEXT DROP TARGETSchatattachpinboardpinmemoriesopen through provider actionSURFACE COMMAND CONTRACTSprovider target_surfacecomponent alias + local commandTWO SHIPPED HOSTS: THE WEBSITE READS A BROWSER SCENE CONFIG · THE WORKSPACE APP RECEIVES ITS MAPA COMPONENT REMAINS AN IFRAME SERVED BY ITS OWNING APP · THE SCENE ONLY MOUNTS IT
The four scene registries.

KDCube ships two real scene-host patterns:

  • The website reads a browser scene config and mounts widgets from configured runtime origins.
  • The workspace app (bundle) receives its component map from surfaces.as_consumer.ui.scene.components through its scene_surface_config operation.

In both cases, a component remains an iframe served by its owning app. Even the pinboard is a surface owned and served by an app; the scene only mounts it.

03 Runtime-wise routing is explicit

A scene may mount surfaces from more than one KDCube runtime. This is explicit browser composition, not implicit provider federation.

RUNTIME-WISE ROUTING · EXPLICIT COMPOSITION, NOT FEDERATIONWEBSITE SCENEchatruntime: demopinboardruntime: demomemoriesruntime: demostatsruntime: devdemo runtimedemo.kdcube.techdemo-tenant / demo-projectdev runtimedev.kdcube.techdemo-tenant / demo-marchcomponent → app → runtime alias → tenant → projectTHE ROUTE SELECTS ORIGIN, RELAY, OPERATION ENDPOINT, PRESENTATION CONFIG, GATEWAYTHE SCENE NEVER SILENTLY TREATS TWO RUNTIMES AS ONE
Components route through their configured runtime.

Every event claim and command therefore carries a concrete ownership route: component → app → runtime alias → tenant → project. That route selects the iframe origin, event relay, API/app operation endpoint, namespace presentation config, and object-action gateway. The scene never silently treats two runtimes as one.

04 Events: components claim, the scene routes

The scene event broker is claim based and transport agnostic. A component declares the event types it consumes; the host supplies the configured relay and routes matching events.

EVENTS · COMPONENTS CLAIM, THE SCENE ROUTEScomponent bootsreceives scene config,claims event interestsaccounting.usagekdcube.stats.snapshotcanvas.patch.appliedscene event brokermatches runtime + claim,forwards only to matching subscribersmatching componentupdates locally or refreshes via its APIMISSING DELIVERY IS ONE OF FOUR VISIBLE CONDITIONSNO CLAIM WAS SENTSCENE REJECTED THE CLAIMRUNTIME ALIAS MISMATCHNO SUBSCRIBER MATCHEDCLAIM-BASED AND TRANSPORT-AGNOSTIC · NO HIDDEN FALLBACK SUBSCRIPTION
Components declare event claims; the scene routes matches.

The core scene broker does not require one particular relay technology. Concrete hosts choose transports according to the events they need:

  • The workspace scene keeps an authenticated Socket.IO Data Bus leg for session-routed service events and an SSE leg with project_events=true for tenant/project broadcasts.
  • The website scene opens per-runtime SSE relays for the claims made by its mounted widgets.

Those are deployment integrations, not a universal rule that every scene must open two connections. There is no hidden fallback subscription: missing delivery is diagnosable as one of the four visible conditions in the figure above.

05 Context drag moves refs, not domain data

Cross-surface drag is a browser interaction, not durable Event Bus state. The source offers context, the scene displays eligible targets, and the selected target receives an attach, pin, or provider-owned open.

CONTEXT DRAG · REFS MOVE, DOMAIN DATA DOES NOTsource surfacekdcube-context-drag-startcontexts: [mem:record:…]scene drag brokernormalizes context · overlaysready targets · summon railsattachsurface command to chatpinsurface command to pinboardopenscene_object_action(open)owning providervalidates the object, returnsui_event.target_surfacescene summons owner surfaceCANDIDATE TARGET PATTERNS IN CONFIG ARE UI HINTSTHE PROVIDER RESPONSE IS AUTHORITATIVEOPENING mem:record RESOLVES TO sdk.memory.viewer BECAUSE THE PROVIDER SAYS SO
Context drag is brokered by the scene.

For example, opening mem:record:<id> can resolve to sdk.memory.viewer. The scene does not derive that target from mem:. The memory provider returns it. Candidate target patterns in scene config are UI hints; the provider response is authoritative.

06 Surface commands move the user

Drag moves context. A surface command asks the scene to summon, focus, or update another mounted surface. The shipped consent flow is a concrete example:

SURFACE COMMANDS · THE SHIPPED CONSENT FLOWchat consent cardkdcube.surface.commandtarget: connection_hub.connectionsscenematches a declared contract,waits until the frame is readyConnection Hubopens the provider card,applies the selectionSUMMON / FOCUSACKNOWLEDGE: command_id + ok · then “applied”THE CONTRACT IS DECLARED IN SCENE CONFIGA standalone chat can use the same intent by opening the served Connection Hub pagewith the corresponding deep link — scene composition adds in-page routing without changing provider policy.DRAG MOVES CONTEXT · A SURFACE COMMAND MOVES THE USER
A declared surface command opens Connection Hub.

The contract is declared in scene config. A standalone chat can use the same intent by opening the served Connection Hub page with the corresponding deep link; scene composition adds in-page routing without changing provider policy.

07 Canvas ingress has two structural shapes

The canonical ingress message is kdcube.canvas.ingress.

CANVAS INGRESS · TWO STRUCTURAL SHAPES, NO payload_typepayload.object_refan existing canonical refpayload.content.textraw text or an uploadpreserve & pinthe ref, unchangedhost as cnv: objectversioned, canvas-owned; pin its refone proxy cardon the boardTHE SCENE STAMPS payload.source · presentation IS OPTIONAL AND COSMETICdrag_start / drag_end ARE TRANSIENT BROWSER WRAPPERS, NOT DURABLE PAYLOADS
Canvas ingress preserves the provider ref or hosts raw content.

To pin an existing object:

kdcube.canvas.ingressJSON
{
  "type": "kdcube.canvas.ingress",
  "payload": {
    "object_ref": "mem:record:mem_fc12861ede7c4944ad5df99541185189",
    "title": "Spreadsheet compatibility note",
    "preview": "Use image charts when portability matters.",
    "presentation": {
      "label": "memory",
      "namespace": "mem",
      "object_kind": "mem:record"
    }
  }
}

To place raw text:

kdcube.canvas.ingressJSON
{
  "type": "kdcube.canvas.ingress",
  "payload": {
    "title": "Selected explanation",
    "content": {
      "mime": "text/markdown",
      "text": "Text selected in the source surface."
    }
  }
}

The structure is the discriminator:

  • payload.object_ref means preserve and pin an existing canonical ref;
  • payload.content.text means ask canvas to host the content as a versioned canvas-owned cnv: object, then pin that ref;
  • there is no payload_type;
  • presentation is optional and cosmetic;
  • the scene normalizes/stamps payload.source;
  • browser wrappers kdcube.canvas.ingress.drag_start and kdcube.canvas.ingress.drag_end exist only for the transient drag lifecycle.

For an existing object, the pinboard stores a proxy card with the unchanged ref, layout, cached display metadata, and annotations. For raw content, canvas first becomes the owner of a durable object; the resulting card still points to an object ref.

08 Backend participation: three separate contracts

A scene surface can participate through only the capabilities it needs. The three contracts below should not be conflated.

1. App surfaces

An app may provide widget routes mounted by the scene; API or app operations used by those widgets; Event Bus claims/producers; Data Bus integrations; scheduled jobs; MCP endpoints; and named-service providers with object resolvers. MCP and API surfaces do not require named services. Named services are the optional generic object/action contract for a domain.

2. Agent-facing named-service tools

Any agent harness can receive the fixed generic tools:

named_services.provider_about      named_services.object_schema
named_services.list_objects        named_services.object_action
named_services.search_objects      named_services.host_file
named_services.get_object          named_services.upsert_object
                                   named_services.delete_object

The platform owns this bounded tool grammar and routing. Each provider owns its namespace ontology, canonical ref format, object kinds, schemas, searchable scopes, filters, actions, presentation, authorization, and effects. ReAct is one agent adapter that currently exposes these tools over the shared agent harness. They are not ReAct-only.

3. Runtime workspace and timeline projection

Turning an object ref into bounded readable context is a runtime workspace and timeline concern. Provider operations such as object.get, block.produce, and optional block.render supply bytes and owner-defined representation. The shared implementation boundary is explicit: sdk/runtime/harness/events/resolver.py resolves a canonical ref to authorized bytes or an action, sdk/runtime/harness/workspace/pull.py materializes authorized refs, sdk/runtime/harness/workspace/layout.py separates runtime output from user-visible artifacts, and sdk/runtime/harness/timeline/projection.py validates provider-owned projections.

providerowns object bytes and representation policy
runtime workspace / timelineowns materialization and projection
agent adapterexposes whichever model-facing read/pull tools it supports

ReAct is one adapter and exposes react.pull and react.read. Ported agents can use the same resolver, timeline, and workspace contracts without importing the ReAct protocol. Owner-specific rehosters and representation policy remain with their providers. The scene and canvas are not materializers.

09 What to test

load scene
  every configured component mounts once
  each component reports the expected app/runtime/tenant/project

drag memory/file/conversation to pinboard
  scene routes kdcube.canvas.ingress or a pin surface command
  canvas upserts one card for the canonical ref on that board
  card resolves through the provider

drag a conversation onto chat
  the existing chat surface opens it
  no second chat instance appears

run a chat turn
  accounting.usage reaches the usage subscriber
  kdcube.stats.snapshot reaches the stats subscriber
  no hidden fallback subscription is required

open a memory pin
  pinboard calls scene_object_action
  provider returns sdk.memory.viewer
  scene summons/focuses the memory viewer

send a Connection Hub surface command
  scene queues until the frame is ready
  sender receives the host acknowledgement
  target surface applies and acknowledges the payload

Bad signals:

expected event reached the host but had no claimed subscriber
card remains "Resolving..." with a registered provider
provider open response has no target_surface
normal single-user pin produces canvas_revision_conflict
drag creates a second chat instance
host branches on a namespace prefix to decide behavior

· Why this matters

The scene makes KDCube feel like one product while keeping app ownership intact. A new app (bundle) joins by declaring surfaces, routes, claims, and command contracts. If it exposes domain objects, its provider keeps ownership of those refs and actions. The scene composes; it does not absorb the domain.

new app joins
  -> serves a widget
  -> declares a surface
  -> optionally claims/emits events
  -> optionally exposes API, MCP, or named services
  -> scene mounts and routes it

That is the extension point: many independently owned apps, one coherent workspace, and no host that needs to learn every domain.

· Read more

KDCUBE · ENGINEERING
24 JUNE 2026 · THE FOOTLIGHTS