Docs · developer guide

Start with
one file.

Everything you need to compile an app, mount a UI and run it on a host. The platform is a preview: the limits section is part of the documentation, not a footnote.

MBC v28Restricted TypeScriptRust runtimemacOS · Web · ESP32-S3

Quickstart

The platform checkout is a Rust workspace plus a small Node toolchain. You need macOS on Apple Silicon, Xcode Command Line Tools, stable Rust, Node.js, CMake 3.24+ and Git. For the Web host, add thewasm32-unknown-unknown target, wasm-pack and Playwright Chromium.

# 1 · dependencies
npm install

# 2 · compile every app/*/app.ts to MBC
npm run build:app

# 3 · build + open the native Home
npm run demo

# 4 · or run the browser host
npm run dev:web

The first native build downloads and compiles SDL 3.4.10 and LVGL 9.5.0 intotarget/native-deps. Later builds reuse the cache. The compiler never runs on the device.

Try the smallest loop.
Edit apps/counter/app.ts, run npm run build:app, then npm run demo. The launcher, Counter, Settings and momo are all MBC apps loaded by the same runtime.

Project map

The workspace separates the contract, the hosts and the products. Dependencies only point one way.

PathWhat lives there
crates/micro-irMBC model, codec, CRC-32, validation and icon catalog
crates/micro-vmTyped stack machine, host-call interface, instruction budgets
crates/micro-coreEvents, state, reactive bindings, UI tree, render patches
crates/micro-compilerSWC parse, allow-list diagnostics, lowering, microc CLI
crates/micro-host-*SDL, ESP32 and Web host adapters
apps/App sources: shell, counter, settings, momo
sdk/index.d.tsEditor declarations for the accepted language and host API
products/micro-web-playerBrowser product: device shell + generated Wasm
firmware/micro-os-esp32ESP-IDF component build and partition layout
native/CMake FetchContent and the shared C bridge
scripts/App build, Web copy, macOS bundle, ESP flash

Manifest

Every app starts with app({ … }). The manifest carries identity, the launcher icon and the capability allow-list that the compiler and runtime both enforce.

app({
  id: "notes",
  name: "Notes",
  icon: "edit",
  capabilities: ["kv", "storage"],
});

const draft = state("");

ui.mount(
  ui.column([
    ui.text("Notes", { size: 24, lineHeight: 32 }),
    ui.input(bind(() => draft.value), {
      placeholder: "write something",
      onChange: (text) => { draft.value = text; },
    }),
  ]),
);

Omitting capabilities — or declaring an empty list — denies every host call. The compiler rejects a call outside the manifest at the call site (MTS002). The manifest is stored in the MBC metadata section.

Language

The accepted surface is an allow-list, not full TypeScript. It is designed to be lowered to a small typed stack machine and validated before execution.

Supported

  • const / let; number, string, boolean, null
  • Arithmetic, equality, comparisons, assignment and ++/--
  • Template literals, blocks, if/else, while
  • Arrow handlers and bindings
  • state, bind, ui.mount, ui.place, and the widget catalog

Rejected

  • JSX, classes, general functions, async / await, promises
  • Exceptions, runtime imports, arbitrary objects / arrays
  • Spread, destructuring, computed properties
  • Browser / Node globals and dynamic UI creation
  • Unsupported literal glyphs (the compiler fails rather than shipping a box)

Layout is explicit

Columns and rows are containers; children get a position with ui.place. Anchors can pin an edge or stretch between two. There is no hidden layout pass whose result depends on host font metrics.

ui.place(
  ui.button("Add", {
    onClick: () => { count.value++; },
  }),
  { left: 24, top: 120, width: 160, height: 44 },
);

Host API

Host calls are the only way an app touches the outside world. Reads work in bindings and handlers; writes and async requests are handlers-only. Every category must be declared in the manifest.

CapabilityCallsNotes
clockclock.nowSNTP wall clock on device
kvkv.get / set / removePer-app namespaced state
configconfig.get / setHuman-editable app config
storagestorage.*Sandboxed TF-card files
netnet.http / wifi / lookupWordsAsync, callback-delivered
audioaudio.*URL playback + speech rate
jsonjson.getText / getNumberPath queries over responses
devicedevice.*Board identity, light, GPIO
osos.launch / goBack / setTitleShell and chrome control

net.* is asynchronous and delivers results through a callback. clock.now() is sampled per call and is not a reactive source: a binding that reads it only re-evaluates when one of its state dependencies changes.

Storage

Three separate contracts, so apps never write host-specific files themselves.

APIUseWeb / macOS / ESP32 backing
kvApp state: counters, review stages, cacheslocalStorage / ~/.micros/kv/<app>.json / NVS namespace
configHuman-editable config read at startuplocalStorage / ~/.micros/<app>/config.json / NVS micro_config
storageApp-private filesper-app localStorage / ~/.micros/sdcard/… / TF card /sdcard/micros/apps/<app>/

Paths are relative and sandboxed. storage exposes no host path and no cross-app handle. On a board without a card, storage.available() is false.

Limits

These are current boundaries, not a roadmap promise.

  • Static UI. No runtime widget creation, no dynamic list, no source-level debugging.
  • One foreground app. No background apps, services, timers or IPC.
  • Bounded handlers. 10,000 instructions per handler; all app work is on the host UI thread.
  • No MMU isolation. Bytecode executes in one address space, sandboxed by the VM and host API.
  • Unsigned artifacts. MBC has a CRC, not a signature; there is no install consent UI.
  • No OTA. Single factory app partition; no A/B slot or rollback.
  • Shell is an app. An unreadable shell.mbc aborts boot instead of falling back to native UI.
The short version.
Micro OS is an application layer for constrained screens, not a general-purpose OS and not a browser.

FAQ

Does it run JavaScript?

No. There is no JavaScript engine on any host. Apps are compiled ahead of time to MBC and executed by a Rust VM. The browser host runs that VM through WebAssembly; JavaScript only boots the page and pumps frames.

Can I use npm packages or a framework?

No. The language is an allow-list with no runtime imports. The UI is the ui catalog and state is state / bind. This is deliberate: the compiler can validate the whole program.

Is it a Linux distribution?

No. It is not a kernel. On ESP32 the kernel is ESP-IDF/FreeRTOS; on macOS the process belongs to SDL3/AppKit; in the browser the page owns the thread. Micro OS owns the app contract and host boundary.

Are apps signed?

Not yet. MBC carries a CRC-32 for corruption, not authentication. Capabilities are enforced, but the manifest is unauthenticated and there is no installer grant flow.

Can I run it on a phone?

Through the browser, yes — the Web Player is responsive and supports desktop and mobile browsers. Native iOS and Android hosts do not exist yet.

Where is the source?

The platform source lives at github.com/dereking/micros. This site is built separately with Astro and deployed on Cloudflare Pages.