For module developers · schema 5.0

Build a module for the festival.

A module is one manifest, a sandboxed UI, and a permissioned bridge to the desktop. Build a small app, publish it to the Module Store, and it runs in every user's window. No prior experience assumed.

19guides & references
29capabilities
100%sandboxed & safe

Ship your first module in four steps

Full walkthrough
01
01Scaffold
hanabi module init "My Module"

Starter manifest, a UI shell and a sample input.

02
02Validate
hanabi module validate ./my-module

The same rules the backend runs on upload.

03
03Package
hanabi module pack ./my-module

A safety-scanned, upload-ready zip.

04
04Publish
Developer Portal → New module

Upload, admin review, then the Module Store.

Capability bridge

The SDK, in four calls

Capability API

Your UI reaches the desktop only through declared, scoped capabilities — the SDK turns that protocol into plain await calls. Tap one:

module.ts
const hanabi = createHanabiClient();
const ctx = await hanabi.ready();
// → { user, theme, accent, windowId }
{ "user": "kana", "theme": "dark", "accent": "#ff5c8a" }
Platform pulse

What's new

Full changelog

The platform ships continuously. Here's the latest, plus where the roadmap stands.

Roadmap Foundations Capability bridge Worker sandbox Module Store Streaming You are here

One manifest. A sandboxed UI. A permissioned bridge.

Your UI runs in an opaque-origin iframe and reaches the platform only through the capability bridge — every call declared, granted, and scoped. The SDK turns that protocol into plain await calls.

files.readfiles.writedata.storejobs.createnotifications
ts
import { createHanabiClient } from '@hanabi/module-sdk';

const hanabi = createHanabiClient();
const ctx    = await hanabi.ready();               // read context

const { files } = await hanabi.pickFile(['xlsx']); // files.read
const file = await hanabi.readFile(files[0].id);   // file.bytesB64

await hanabi.writeFile('result.csv', out);         // files.write