How to read this post. Each section opens with a small ownership table — Platform means the runtime fully absorbs it, Bundle means the author writes it, Shared means a handoff. Shared rows split the third column into two clearly labelled sub-rows — a gold Platform line for what the runtime supplies, a teal Bundle line for what the author declares — so the responsibility split is visible at a glance.

1. Edge & access control

CapabilityOwnerWhere the seam lives
HTTP / SSE / Socket.IOPlatformchat-ingress (port 8010) terminates HTTP / SSE / Socket.IO; chat-proc (port 8020) mounts bundle REST & MCP under /api/integrations/bundles/{tenant}/{project}/{bundle_id}/…. Bundles never bind a port.
JWT / Cognito / SSOPlatformIngress validates the token, mints a conversation id, and threads (tenant, project, user) into runtime context. Normal bundle workflows receive identity context rather than owning raw JWT parsing.
Antivirus / file scanPlatformClamAV in chat-ingress, pre-admission. Uploads are scanned before any bundle code runs.
Multi-tenancy & RBACShared
PlatformEnforces the tenant boundary at the gateway, in runtime context, in Postgres, in file paths, and in Redis namespaces (infra/namespaces.py).
BundleDeclares role gates on each decorator (allowed_roles, user_types); the platform enforces them.

The edge is fully platform-owned for one practical reason: it's the part that has to be uniformly safe across every bundle on the runtime. A bundle that authored its own JWT path or its own ClamAV bypass would compromise the whole tenant. So the seam is high — the bundle starts after ingress has authenticated, scanned, and routed. See Communication for the full ingress shape and Deployment for the multi-tenant runtime.

2. Isolation & secrets

CapabilityOwnerWhere the seam lives
Code execution / sandboxPlatformpy-code-exec sidecar with the UID-1001 split-container model. Bundle calls into it via run_exec_tool / build_exec_output_contract in chat/sdk/tools/exec_tools.py. Bundle never sandboxes itself.
Secrets (sync + async)Platforminfra/secrets/manager.py resolves named secrets and audits the read. Bundle pulls via get_secret(...) from chat/sdk/config.py. Raw env vars and KMS handles never reach bundle code.
Per-task dependenciesBundle@venv(requirements=[…]) runs a function in a per-bundle subprocess venv (hash-cached). Bundle picks the deps; platform builds + caches.

The isolation seam is the topic of an earlier post in this series: the executor runs without network or platform secrets, and a trusted supervisor mediates approved tool calls. From the bundle author's side, the contract is one function call. Everything beneath — split containers, supervisor RPC, network policy, syscall surface — is platform infrastructure. See also Security.

3. Economics, observability, governance

CapabilityOwnerWhere the seam lives
Budgets & accounting ledgerShared
PlatformReservation-then-commit, wallet, ledger in infra/accounting/ and chat/sdk/infra/economics/. Admits, meters, and rejects atomically.
BundleDeclares app_quota_policies in configuration() — what each tier is allowed to spend.
Metrics servicePlatformDedicated metrics service on port 8002 with turn-level cache and aggregator.
Structured loggingPlatformAgentLogger is injected into bundle context. Bundle logs through the injected logger; correlation ids and turn ids are attached automatically.
Audit trailPlatformPer-turn append-only audit on every admission decision, tool call, model call, and reservation/commit.

Economics is the most consequential shared seam on the platform. The bundle controls policy (a free tier gets 50 model calls/day; an enterprise tier gets per-project budgets per skill); the platform owns enforcement (atomic Redis-Lua reserve, ledger commit, hard reject). Bundles can't accidentally bypass quotas because the admission check sits outside their code path. Economics covers the full ledger model.

4. Storage, knowledge, retrieval

CapabilityOwnerWhere the seam lives
Artifact & file storageShared
PlatformOwns the backends — storage/storage.py, AIBundleStorage, knowledge space, conversation index. Bundle code normally goes through SDK storage/retrieval APIs rather than S3 clients or ad hoc pgvector access.
BundlePicks layout and what to write — paths for turn artifacts, naming conventions for uploads, KB source globs.
Knowledge base / pgvector RAGPlatformSchema, embedding service (infra/embedding/), retrieval pipeline. Bundle configures sources and the embedding model; ingestion + search are platform calls.
Citation / source poolPlatformCitation pool + provenance live in chat/sdk/retrieval/. Bundle emits citation deltas through self.comm; rendering and pool maintenance are platform.

The storage seam is deliberately a layer: the bundle never picks an S3 bucket name or talks to pgvector directly, but it does name its own paths, pick its own KB sources, and decide what to write. Concepts introduces the artifact taxonomy that the platform's source pool, turn log, and citation system depend on. ReAct's conversation memory layers use the same artifact/provenance discipline; the standalone User Memory subsystem adds user-owned durable records on top when a bundle enables it.

5. Lifecycle & configuration

CapabilityOwnerWhere the seam lives
Bundle loader & hot-reloadPlatforminfra/plugin/agentic_loader.py, bundle_store.py, bundle_registry.py, git_bundle.py. kdcube reload <bundle_id> swaps the bundle module in place without restarting the runtime.
Descriptors → props → overridesShared
PlatformResolves assembly.yamlbundles.yaml → Redis broadcast → bundle defaults, then re-broadcasts effective props on every admin override.
BundleReads self.bundle_props — never the descriptor files directly (that's an anti-pattern called out in agents.json).
One-time initBundleasync on_bundle_load(...) runs once per process per (tenant, project). Default implementation builds the bundle UI if declared.
Live prop changesBundleasync on_props_changed(*, previous_props, current_props, reason, …) fires after effective props change. For cache busts only — not heavy work.

Hot-reload is the property that makes the whole bundle model practical: an admin pushes a new bundle version, the loader registers the new module, in-flight turns drain, new turns admit against the new code. The bundle doesn't write any of that. What the bundle does write is the two lifecycle hooks above — both of them small, both of them optional. See Configuration for the descriptor / prop / override flow.

6. Scheduling & background work

CapabilityOwnerWhere the seam lives
Scheduled jobsShared
PlatformProc-resident scheduler (chat/sdk/processor_scheduler_backend.py) with Redis lock semantics — span={system | instance | process} guarantees a single owner per (span, job) across replicas.
BundleDecorates a method @cron(...) with expr_config, tz_config, and a span. The platform gates it through the canonical enabled.cron.<alias> bundle prop.
Background job streamShared
PlatformOwns RedisBackgroundJobStream — fair claim across procs, retry semantics, progress / log channel to the chat surface.
BundleEnqueues work through the jobs stream and consumes it via one async @on_job(...) dispatcher. SDK mixins expose handle_job(...) helpers instead of adding more decorated handlers.

Off-turn work uses the same handoff pattern as the rest of the platform: span-aware cron, a Redis-locked scheduler, and a generic background job stream. Together they let a bundle declare a nightly KB re-index, a durable maintenance job, or an event-driven background workflow without standing up its own queue. User Memory reconciliation currently uses widget-submitted background work plus the bundle's single @on_job dispatcher; a bundle could also schedule similar maintenance with @cron.

7. Communication surfaces (REST / widgets / UI / MCP)

CapabilityOwnerWhere the seam lives
REST endpointsShared
PlatformMounts the method under /api/integrations/bundles/{tenant}/{project}/{bundle_id}/{operations|public}/{alias}, enforces role gates, and handles the chosen auth mode (none / bundle / header_secret).
BundleDecorates the handler @api(method, alias, route, user_types, roles, public_auth).
Dashboard sidebar widgetsShared
PlatformThe chat-web-app renders the widget card in the sidebar and threads the bundle's @api behind it.
BundleStacks @ui_widget(icon, alias, ...) on top of the underlying @api.
Source-folder UIShared
PlatformBuilds declared source folders, materializes optional shared_sources, stores built assets under bundle storage, and serves normal or public widget routes with SPA fallback.
BundleShips React/Vite or HTML source under ui.main_view or ui.web_app_widgets.<alias>, and uses the runtime config handshake for tenant/project/bundle-aware API calls.
Public widget launchSharedFor Telegram Mini Apps and similar surfaces, the platform serves static assets from /public/widgets/{alias}. The bundle must protect every public data/action API itself, for example by verifying Telegram WebApp initData.
MCP serverShared
PlatformMounts the bundle-served MCP endpoint with streamable-http transport, negotiates the session, and proxies the wire protocol.
BundleDecorates the method @mcp(alias, route, transport='streamable-http') and owns the MCP request auth check inside the method — validates request.headers itself. Public APIs can make the same choice with bundle-owned auth; operations APIs stay platform-authenticated.
MCP client (tools)Platformcreate_tool_subsystem_with_mcp wires upstream MCP servers into the bundle's tool registry.

The same decorator-driven model surfaces REST, widgets, UIs, and MCP. The bundle author writes the handler and the widget source; the platform handles routing, role enforcement, static-asset serving, the chat-web-app integration, MCP transport negotiation, and source-folder builds. Public widget routes are only for loading the app shell; product data still goes through an authenticated bundle API. Integrations documents the surface in depth, and Communication covers the streaming contracts the chat surface uses.

8. Agent runtime, memory, tools, skills, streaming

CapabilityOwnerWhere the seam lives
Agent loop (ReAct v3)Shared
PlatformShips ReAct v3 with a timeline-first turn model, continuations, cache/compaction discipline, tool scheduling, artifact streaming, and a custom channeled protocol. ReAct is not provider-native tool calling: the runtime parses channels such as thinking, structured decisions, code, artifacts, and other typed events, then schedules them.
BundleEither inherits the ReAct-capable entrypoint stack or builds its own loop inside execute_core. The bundle still receives the same runtime context either way.
ReAct memory modelPlatformTimeline blocks, turn log, sources pool, working summaries, compaction summaries, indexed internal notes, workspace refs, and read/search tools are platform-owned ReAct memory layers.
User Memory subsystemShared
PlatformOwns the durable user-memory tables, scoring/search/store layer, Memory widget, snapshots, restore, and reconciliation job mechanics.
BundleOpt-in by deriving from the memory entrypoint mixin and configuring memory.{announce,tools,widget,reconciliation,snapshots}. ReAct can consume the hotset/search tools when enabled.
Tool registryShared
PlatformOwns the tool subsystem, SDK tools, MCP adapters, runtime binding, and approved tool execution in the main process, subprocess runtime, and isolated generated-code runtime. This is a security boundary: generated code can call approved KDCube tools through the runtime, not arbitrary platform internals.
BundleShips its own tools/ package plus tools_descriptor.py for runtime registration, aliases, MCP exposure, and per-tool runtime policy.
Skill resolutionShared
PlatformOwns the KDCube skills registry and resolver in chat/sdk/skills/skills_registry.py. Skills are KDCube instruction bundles defined with SKILL.md metadata, selected per consumer, and injected into ReAct, codegen, or content generators.
BundleShips skills/ plus skills_descriptor.py; declares which custom skills exist, which imports they allow, and which skills are visible per role or surface.
Channeled streaming & saturated widgetsShared
PlatformOwns the channeled streamer, repeated-channel instance handling, citation replacement, and live widget adapters. Saturated widgets such as exec and web search receive structured parts as soon as they are detected: objective, code, contract, execution status, search queries, result rows, and fetch/read results.
BundleReuses SDK widgets or adds bundle-specific subscribers and UI components. The bundle defines the domain payload; the platform handles transport, ordering, storage, and live delivery.
Multimodal context & artifactsShared
PlatformNormalizes text, uploads, images, files, generated artifacts, source previews, and tool outputs into the turn timeline and artifact store so agents can reason over multimodal context without each bundle reinventing storage or preview logic.
BundleDecides which media types it accepts, which renderers/tools it exposes, and how the UI should present bundle-specific artifacts.
LLM router / providersPlatformModelServiceBase in infra/service_hub/inventory.py; provider matrix in chat/sdk/providers.py; infra/llm/ for the transport. Bundle picks role models in configuration().

The agent runtime is where the platform offers the most and the bundle can still replace the most. A ReAct bundle gets the layered conversation memory model, cache discipline (covered here), attention area (here), and channel-aware streaming (here). It also gets the KDCube skills subsystem, approved tool execution across runtimes, multimodal turn context, and live saturated widgets that behave like client-side components while being driven by model/tool events. A bundle that derives from the memory mixin can expose user-owned durable memories through the Memory widget, optional hotset projection into ReAct ANNOUNCE, and optional memory search/read/write tools. A bundle that needs a different loop overrides execute_core and drives its own LangGraph; storage, auth, economics, tools, skills, widgets, jobs, and observability still come from the platform.

9. The SDK contract at a glance

Across all eight sections above, the bundle author writes against a small, stable surface. Here are the decorators and lifecycle hooks. Every one of them is documented in the SDK reference; their full signatures live in kdcube_ai_app/infra/plugin/agentic_loader.py.

Decorator / hookWhat one line tells the platform
@agentic_workflowThis class is a bundle entrypoint. Inject (config, pg_pool, redis, comm_context, …).
@bundle_id("id@version")Declarative identity for the loader.
@apiMount this method as a REST endpoint with role gating + auth mode.
@ui_widgetSurface the @api in the chat sidebar with an icon.
@mcpServe this as an MCP endpoint (bundle-owned auth).
@cronRun periodically with a span; platform locks across procs and gates through enabled.cron.<alias>.
@on_jobConsume from the background job stream.
@venvRun this function in a subprocess venv with declared deps.
configurationRole models, embedding, execution, UI, MCP services, quota policies, optional memory subsystem config.
on_bundle_loadOne-time init per process per (tenant, project).
on_props_changedCache-bust hook after admin overrides.
execute_coreThe agentic entrypoint — the actual turn.
One platform gating model. Surface enablement lives under canonical bundle props: enabled.bundle, enabled.api["alias.METHOD"], enabled.widget.alias, enabled.mcp.alias, and enabled.cron.alias. Missing keys mean "use the decorator/code default"; explicit falsy values return 404 for API/MCP/widget surfaces, skip cron reconciliation, or disable the whole bundle. The same effective-props mechanism covers every surface a bundle exposes.
Practical bundle checklist. Put application decisions in the bundle: decorators, tools, skills, UI source folders, public-auth policy, and configuration defaults. Let the platform own the uniform parts: tenant/project routing, authenticated operations, public static-widget serving, source-folder builds, background job claiming, memory tables, economics, and isolated execution. If a widget must run in both KDCube and Telegram, make the transport decision at runtime: KDCube mode calls /operations/{alias} with platform auth; Telegram mode calls /public/{telegram_alias} and sends verified initData.

10. Two bundles, same seam

The same boundary supports both ends of the spectrum.

On one end: kdcube.copilot is a focused documentation-reader bundle. It prepares a ks: knowledge space, exposes curated docs/source paths, and lets ReAct answer product and architecture questions with precise references. The same bundle can now opt into economics, durable User Memory, and a Telegram WebApp with two sections — memory management and Telegram user administration — without owning a separate server.

On the other end: the reference versatile bundle is a larger example application. It builds its own LangGraph StateGraph, runs an MCP server with a header-token auth scheme, ships tools_descriptor.py and skills_descriptor.py, integrates Telegram delivery, registers widgets, exposes the shared User Memory widget, and demonstrates bundle-owned tools. The bundle author wrote application logic. The platform — the same platform — supplied ingress, auth, accounting, isolation, hot-reload, observability, the loader, and the SDK seams the bundle decorates against.

The handoff is clearest in two places. First, BaseEntrypoint.__init__ in chat/sdk/solutions/chatbot/entrypoint.py — the constructor shows the platform-injected runtime inputs (config, pg_pool, redis, comm_context, event_filter, ctx_client, continuation_source). The base class then initializes platform helpers such as logger, models_service, kv_cache, and effective bundle_props. The bundle decides what to do with that context.

Second, the loader: agentic_loader.py introspects the bundle's decorators and registers routes, schedules, MCP transports, and widget cards on the runtime. The bundle never registers a URL itself. One decorator line is the entire contract for "mount me here, with these roles, gated by this flag."

The platform absorbs the parts that have to be safe and uniform across every bundle. The bundle decides everything that's application-specific. The contract that connects them is small enough to fit on one screen.

Where to go next

If you're sizing KDCube against your problem: Platform overview for the system shape, SDK reference for the decorator surface, Configuration for descriptors and props, Economics for the budget model, Security for the isolation story, and Deployment for the multi-tenant runtime.

If you're a coding agent: agents.json is the machine-readable manifest with the full decorator list and source paths; AGENTS.md is the human-readable companion. Parse one, read the other.