KDCube
← Engineering
KDCube Engineering · Concept

The Pinboard of Proxies

Objects from many apps sit together on one board without merging their databases. Every durable card is a proxy: canvas owns the card; the provider named by the ref owns the object.

23 June 2026Engineering12 minConceptThe Pinboard
pinboardcanvasobject_refnamed servicesportable contextingress protocolbase_revision

The KDCube pinboard (canvas) lets objects from many apps sit together without merging their databases. A memory, conversation, generated file, metric, or object from your own provider appears as a card with one durable identity: its canonical object_ref.

The board owns the card: placement, cached display metadata, comments, and revision history. The provider named by the ref owns the object, its schema, permissions, bytes, lifecycle, and actions.

There is one important refinement. Raw text or an uploaded item has no provider object yet. Canvas first hosts it as a versioned cnv: object and then stores a card pointing to that new ref. Therefore every durable card is a proxy to a canonical object, but the object may be owned by another app or by canvas itself.

THE RULE

The board never infers what a ref means. It preserves identity and routes back to the owner.

00 Highlights

The concepts the article builds on, in one place:

ConceptThe takeaway
Card vs objectCanvas owns the card — placement, cached display metadata, comments, revisions. The provider named by the ref owns the object.
Canonical object_refOne durable identity per object; within a board it is the dedup key. The same ref may sit on several boards.
cnv: hostingRaw content has no provider object yet: canvas hosts it as a versioned canvas-owned object first, so every durable card points to a canonical ref.
Two ingress shapespayload.object_ref pins an existing ref; payload.content.text hosts then pins. Structure is the discriminator — there is no payload_type.
Hints never select behaviorkind, namespace, label, icon, color are presentation/resolver hints only.
Display ≠ resolve ≠ openCached metadata keeps the board readable; provider truth is authoritative; open routes through the gateway to the provider, which names the target surface.
Materialization ownershipProvider bytes → runtime workspace → timeline projection. Not canvas, not the scene, and not ReAct-owned.
base_revisionOptimistic concurrency on board mutations — one client cannot silently overwrite another.
Portable contextBoards and selections move refs plus provenance, never copied bytes.

01 What a pin stores

ONE CARD · THE PROXY AND ITS OWNERPINBOARD · THE CARD (CANVAS-OWNED)object_refmem:record:mem_456canonical identityprovenancememory search surfacesourcerectx, y, width, heightlayouttitlecached display titleboard readabilitycomments“use in the proposal”canvas-owned noteTITLE AND PREVIEW ARE DISPLAY CACHES, NOT TRUTHmemory providerowns the objectschema · data · actions · policypermissions · lifecycle · bytesROUTES BACKCANVAS OWNS THE CARD · THE PROVIDER NAMED BY THE REF OWNS THE OBJECT
Canvas owns the card; the provider named by the ref owns the object.

Common refs include:

mem:record:<id>                              memory record
conv:conversation:<conversation_id>          conversation
conv:fi:conv_<conversation_id>.<path>        conversation file
cnv:<board-name>                             named board
cnv:<board-name>@<revision>                  immutable board revision
cnv:canvas/users/.../objects/.../v000001.md  canvas-hosted content

The card does not store a portable copy of provider data. Its title and preview are display caches, not the source of truth.

Within one board, the canonical ref is the identity key. Adding the same ref again is a no-op; if its card was trashed, the operation restores it. The same ref may still appear on several boards because deduplication is per board, not global.

02 One board, many owners

ONE BOARD · MANY OWNERSPINBOARDmem:record:…memoryconv:conversation:…conversationconv:fi:…/report.pdfconversation filecnv:…/notecanvas-hostedacme:ticket:…your appmemory providerconversation & file ownercanvas provideryour app providerKIND, NAMESPACE, LABEL, ICON, COLOR ARE PRESENTATION HINTS — THEY NEVER SELECT BEHAVIORTHE CARD SHAPE IS GENERIC · THE BOARD DOES NOT UNDERSTAND EACH DOMAIN
Different provider refs share one neutral board.

The board can display all of them because the card shape is generic. It does not need to understand each domain. kind, namespace, object_kind, label, icon, and color are presentation/resolver hints. They never select behavior.

03 How a pin reaches the board

The browser flow has one owner at every hop.

INGRESS · ONE OWNER AT EVERY HOPsource surface“I offer this objector text”scene hostvalidates · stamps source · routescanvasstores the cardkdcube.canvas.ingressexisting object_refpreserve it in a cardraw contenthost a cnv: object, then pin its refTWO PACKET SHAPES · NO payload_typeproviderresolves display and actions when requestedTHE SCENE STAMPS payload.source · CANVAS NEVER GUESSES WHAT A REF MEANS
The source, scene, canvas, and provider keep separate responsibilities.

Agents do not need a special canvas API for this. An agent harness with the generic named-service tools can call:

any agent harnessCALL
named_services.upsert_object(
  namespace="cnv",
  object_kind="canvas.card",
  ...
)

The canvas provider enforces the same revisions and object contract regardless of whether the caller is a widget or an agent.

04 The canonical ingress protocol

There are two structural packet shapes. There is no payload_type.

Pin an existing provider object:

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

Host raw text as a canvas-owned object:

kdcube.canvas.ingressJSON
{
  "type": "kdcube.canvas.ingress",
  "payload": {
    "title": "Selection",
    "content": {
      "mime": "text/markdown",
      "text": "Selected text to place on the canvas."
    },
    "presentation": {
      "label": "provided text",
      "object_kind": "cnv:provided:text"
    }
  }
}

The rules are exact:

  • payload.object_ref means pin an existing canonical ref unchanged.
  • payload.content.text means host the content under canvas ownership, obtain a versioned cnv: ref, then pin that ref.
  • The shape is an intent discriminator, not a domain type or routing key.
  • presentation is optional and cosmetic.
  • The scene stamps/normalizes payload.source because it knows the mounted surface and runtime.
  • kdcube.canvas.ingress.drag_start and kdcube.canvas.ingress.drag_end are transient browser drag wrappers, not alternate durable payloads.

05 Display, resolve, and open are different steps

The board must remain readable before it contacts every provider, so a card can show cached title/preview metadata. Provider truth remains authoritative.

OPEN A PIN · THE ROUND TRIP TO THE RICH APPpinboard UIscene_object_action(open)scene object-action gatewaycapabilities → object.resolveother actions → object.actionmemory providervalidates caller and objectcapabilities · presentationui_event.target_surface = sdk.memory.viewersceneemits kdcube.surface.commandwaits for target readiness and acknowledgementmemory vieweropens the recordTHE CANVAS NEVER PARSES mem: TO SELECT THE VIEWER · THE PROVIDER DECIDES
A card routes through its provider back to the rich app.

The pinboard app operation is currently named scene_object_action because the scene/pinboard boundary can act on any object present in the scene. Under that gateway, providers still receive the generic object.resolve or object.action operation. The canvas never parses mem: to select the memory viewer.

06 Materializing a pin for an agent

Showing a card in a browser and materializing its object for an agent are different concerns.

MATERIALIZE A PIN FOR AN AGENT · FOUR OWNERScanonical object_refthe durable identityprovider resolverobject.get · namespace bytesruntime workspaceref → plain local file;timeline projectionblock.produce · block.rendercanonical identity retainedbounded, owner-defined contextwhat the agent actually seesAN AGENT HARNESS EXPOSES THE READ/PULL CONTROLS IT SUPPORTSREACT IS ONE CONSUMER — react.read · react.pull — THE CONCEPT IS NOT REACT-OWNEDPROVIDER OWNS BYTES · WORKSPACE OWNS LAYOUT · TIMELINE OWNS MODEL-VISIBLE BLOCKS
Object materialization belongs to runtime workspace and timeline projection.

The ownership is deliberate:

providerowns bytes, object semantics, and representation policy
runtime workspaceowns safe local layout and ref-to-file materialization
timeline projectionowns bounded model-visible blocks
agent adapterexposes the model-facing read/pull controls it supports

KDCube exposes this reusable core through sdk/runtime/harness/events, sdk/runtime/harness/timeline, and sdk/runtime/harness/workspace. ReAct is one adapter and exposes react.pull and react.read; ported agents can use the same primitives without adopting the ReAct protocol. The materialization concept itself is not ReAct-owned, and the canvas does not perform it.

07 Who works the board

People and agents use the same durable board through different surfaces.

People:

  • drag memories, conversations, files, and provider objects onto a board;
  • paste an image from the clipboard — onto the board as a file pin, or into a note at the caret as inline markdown;
  • annotate and arrange cards;
  • read pins in place: notes render chat-parity markdown (copyable code plates, inline images, link previews for bare URLs), preview text is freely selectable, image pins show thumbnails, and HTML pins render live in a sandboxed frame;
  • select several cards and send their refs to chat;
  • search pins across boards;
  • open a proxy back in its rich app.

The in-place previews keep the neutrality rule intact: the bytes behind an image thumbnail or an HTML preview arrive through the owning provider’s download object action — the board renders what the owner returns and still never parses a ref to decide behavior.

Agents:

  • discover canvas with named_services.provider_about(namespace="cnv");
  • list boards through named_services.list_objects;
  • search card snapshots with named_services.search_objects;
  • inspect schema and valid mutations through named_services.object_schema;
  • add/update objects through named_services.upsert_object;
  • read referenced objects through the runtime materialization controls exposed by their harness.

These generic named-service tools are available to any configured agent, not only ReAct.

08 Named boards are portable context

NAMED BOARDS · PORTABLE CONTEXTcnv:researchnamed boardcnv:research@42immutable revisionselected cardsa hand-picked set“use these”refs + provenance move,never copied bytesconversation contextpreserve refs · resolve by ownermaterialize on demandcite provenancePORTABLE CONTEXT WITHOUT TURNING CANVAS INTO A WAREHOUSE
Named boards and selections become reusable conversation context.

Boards have stable names and immutable revisions:

cnv:research
cnv:research@42
cnv:incident-481

A board may mix memory refs, conversation refs, generated files, canvas-hosted notes, metrics, and domain objects. Sending a board or selection to chat moves the refs plus provenance. The receiving agent can then inspect only what the turn needs, through each owning provider. This is portable context without turning canvas into a warehouse.

09 Canvas named-service contract

The current cnv provider exposes provider.about, object.list, object.search, object.schema, and object.upsert. The corresponding model-callable generic tools are:

named_services.provider_aboutdiscovers the canvas provider and what it hosts
named_services.list_objectsdiscovers boards
named_services.search_objectssearches indexed card snapshots
named_services.object_schemaexplains object kinds and mutation payloads
named_services.upsert_objectapplies card, comment, suggestion, deletion, replacement, and layout operations where allowed
THE CONTRACT

Mutations against a visible board include base_revision. That optimistic concurrency boundary prevents one client from silently overwriting another.

10 Rules that keep canvas neutral

Canvas must:

  • preserve the full canonical ref;
  • keep provenance visible;
  • version board mutations;
  • require the expected base_revision for concurrent writes;
  • route actions through the provider;
  • keep a card valid even when its resolver is temporarily unavailable.

Canvas must not:

  • infer an action from a prefix, kind, label, icon, or color;
  • own another provider's schema or permissions;
  • store signed transport URLs as object identity;
  • copy every referenced object into its own database;
  • treat cached card metadata as provider truth.

11 Integration checklist

Scene configuration

  • mount the pinboard widget with its app, runtime, route, and surface identity;
  • declare pin/attach/open drop targets;
  • configure the scene_object_action gateway;
  • deliver namespace presentation config for consistent labels, icons, and colors.

Canvas provider

  • expose the cnv named-service endpoint;
  • support board listing, card search, schema discovery, and revision-fenced upserts;
  • host raw content as versioned canvas-owned objects;
  • index card snapshots when semantic search is configured.

Object providers

  • issue canonical refs;
  • implement object.resolve and object.action for UI capabilities/actions;
  • expose object bytes/get behavior if agent materialization is supported;
  • optionally implement block.produce and block.render for owner-defined timeline/model representation.

Agent configuration

  • grant only the generic named-service tools needed by that agent;
  • publish accurate tool traits and provider schemas;
  • expose read/pull controls appropriate to that harness;
  • keep authorization at every provider and fenced runtime boundary.

12 Regression path

drop memory/file/conversation on pinboard
  -> kdcube.canvas.ingress or pin surface command is visible
  -> cnv object.upsert succeeds at expected base_revision
  -> card keeps the canonical ref
  -> pin index updates

drop raw text
  -> canvas hosts a versioned cnv: object
  -> card points to the hosted ref

open a memory pin
  -> pinboard calls scene_object_action(open)
  -> memory provider returns sdk.memory.viewer
  -> scene routes kdcube.surface.command
  -> viewer acknowledges and opens

ask a configured agent about cnv:research
  -> agent lists boards / searches card snapshots through generic tools
  -> deeper object reads use runtime workspace/timeline materialization
  -> provider controls model-visible representation

Bad signs:

card remains "Resolving..." despite a registered provider
unsupported action chosen from card kind instead of provider capabilities
canvas_revision_conflict during an ordinary single-client write
duplicate card for the same ref on one board
raw content has no durable cnv: ref
agent materializer branches on namespace names

· Closing

The pinboard is a board of proxies, not a second database. It gives many independent objects one shared spatial context while keeping ownership intact. The card belongs to canvas. The referenced object belongs to its provider, including canvas when canvas hosted raw content. The provider decides actions; the runtime workspace and timeline project objects for agents; the scene routes the user back to the rich surface.

That separation is why one neutral board can hold an ecosystem without having to understand every app inside it.

· Read more

KDCUBE · ENGINEERING
23 JUNE 2026 · UPDATED 13 AUGUST 2026 · THE PINBOARD