HUB.KI DocsCustom apps
HUB.KI Docs
Custom apps

Introduction

What a custom app is and how it runs inside HUB.KI.

View as Markdown

A custom app is a single, self-contained HTML document that HUB.KI embeds in a sandboxed iframe. Your app talks to the platform through a small message bridge — enough to store data, know the current user, react to their theme and language, publish and receive events, run AI agents, and share content.

Apps are ordinary web pages. Bring any framework, or none.

How it works

The platform serves your artifact into a sandboxed iframe and exchanges JSON-RPC 2.0 messages with it over postMessage. The @hub-ki/app-sdk package wraps that exchange in plain async functions. Through the bridge your app can:

  • read and write its own private workspace (per user)
  • keep app state in a key/value store (per user, per version)
  • read the signed-in user's identity and the shared workspace documents (with permission)
  • get an access token to call HUB.KI APIs from its own backend (with permission)
  • publish and receive events in real time, and run AI agents (with permission)
  • show toasts, set the tab title, and open a share dialog

See the SDK reference for the full client API.

Everything a custom app can do is gated by the scopes it declares, so the platform — and the user's organization — stays in control.

Anatomy

An app is a folder with two required files:

my-app/
├── manifest.json   # metadata, scopes, versioning
└── app.html        # the single-file artifact

Optionally add an icon image (icon.svg, icon.png, …) referenced from the manifest.

Constraints

  • Single file. The iframe loads exactly one HTML document of at most 10 MB. Inline all CSS and JavaScript — external URLs resolved relative to the artifact will not load.
  • Sandboxed. The app runs with allow-scripts allow-forms and no same-origin access, so cookies and localStorage are unavailable. Persist state through the app's key/value store (the localStorage replacement) or the workspace.
  • Locked-down content policy. See below — it decides what may be inlined.
  • SDK major version 1. Declare sdkVersion in the manifest; the host currently supports major version 1.

Content Security Policy

The platform serves every app with this policy:

default-src 'none';
script-src 'unsafe-inline';
style-src 'unsafe-inline';
img-src data: blob:;
worker-src blob:;
connect-src 'none';
base-uri 'none';
form-action 'none';
sandbox allow-scripts allow-forms

What that means in practice:

You want to…Works?
Inline <script> and <style>Yes. Scripts and styles loaded from a URL do not.
Show imagesOnly as data: or blob: URLs. Inline SVG markup also works.
Use a web fontNo — fonts are not allowed from any source, including data: URLs. Use system fonts or draw glyphs as SVG.
Play audio or videoNo — media is not allowed from any source.
Call eval / new FunctionNo. Bundlers and libraries that rely on it fail at runtime.
Run WebAssemblyOnly with the capability:wasm scope, which adds 'wasm-unsafe-eval'.
Start a Web WorkerYes, from a blob: URL.
Submit a <form>No navigation — handle submit in JavaScript and call preventDefault().
fetch your backendOnly origins declared in connectOrigins and approved by the organization admin.

Ready to build one? Start with the Quick start.