Skip to main content

Architecture

A Neutron instance is one Internet Computer canister and the browser page it serves. Everything else is an internal division of labour inside those two places.

The canister side

The canister runs a single WebAssembly module produced by compiling one generated Motoko actor. That actor is not written by hand — it is emitted by the Neutron assembler from the manifests of the kernel plus every installed app.

Four things live inside that actor:

The generated wrapper. Ordinary app query and update functions become actor methods with a compiler-written prologue that asserts owner authorization and dispatches into the app's module; update wrappers also meter instruction usage. Internal functions, declared dependency exports, and scheduled handlers use compiler-generated private paths. Public-ingress declarations add protocol-specific dispatch, and paid-cycle handlers are route-only. Apps never write actor methods themselves.

Trusted system code. The kernel package and compiler-generated actor and wrapper use the privileged Motoko surface — cycles, timers, raw stable memory, certification, management-canister calls, actor construction, and lifecycle hooks. Ordinary app source cannot use that surface.

App modules. Plain Motoko modules — not actor classes. Each exposes an Init class whose methods the wrapper calls. An app with backend resources receives one structural environment record containing public installation identity, its own memory, its declared backend dependencies, and the capability leaves it explicitly selected; an app with none receives Init() with no argument.

Managed memory. Persistent state is declared in the manifest and lives in compiler-generated stable roots that are namespaced per app. No app can name, reach, migrate, or delete another app's root.

The browser side

Opening the canister in a browser loads the kernel frontend from /. It is a React tiling workspace shell — the distro's UI, and the part a distro is most likely to make its own.

App frontends never hold the owner's identity. Tiles, trays, and ordinary backgrounds use sandbox="allow-scripts" with credentialless, so their security origin is opaque. A separately approved dedicated background instead uses allow-same-origin on an installation-bound host: its ephemeral mode remains credentialless, while its persistent mode does not. Tile and tray URLs for such an app may use the unprefixed canister host, but their sandbox still makes them opaque. Each frame's operational channel into the kernel broker is a private MessagePort transferred into the exact registered window.

Every operation mediated by the kernel or another app endpoint goes through that port: signed canister calls, cross-app tools, brokered clipboard writes, connection credentials, and key derivation. The kernel attests the caller from the registered port, never from anything the app claims about itself. Direct browser facilities remain governed by the iframe sandbox, origin policy, CORS, and browser limits rather than by that broker.

How the pieces relate

ConcernWhere it lives
Who may call ordinary app methodsKernel authorization set, checked in the generated wrapper; declared public-ingress routes apply their own caller policy
What an app may reachThe manifest's canonical capability plan sets the bound; active scope, live grants or reservations, lease epochs, and broker checks determine current reach
Whether app code is safe to compileStatic Motoko policy in neutron-security, run at packaging and at compile
What the user is told before approvingKernel-attested disclosure derived from the capability plan
What runs where in the browserKernel-owned frame contexts and endpoint ids
How the canister changesThe install journal and self-upgrade path

Three properties worth internalising

There is no app-to-app canister boundary. Two installed apps share one Wasm module, one heap, one cycle balance. Isolation relies on the compiler's closed projection and generated scoping, static policy, app-scoped handles, and runtime broker registry and lease checks — not on a platform canister boundary. This is a real trade: it buys direct typed inter-app calls without an inter-canister hop, and it costs you the ability to rely on platform canister isolation between installed apps.

The user's browser is part of the trusted computing base for owner-facing operations. Browser installation performs package validation, compilation, install review, and consent in the kernel frontend. A compromised owner browser can exercise that owner's authority. Operator provisioning has a separate verified compile and deployment path.

Every upgrade is a whole-canister upgrade. Installing, updating, or removing an app rebuilds and replaces the entire actor. This is why managed memory migrations, stable-signature checks, and the install journal exist: they reject incompatible state shapes and prevent partial metadata promotion. They cannot prove that an app author's type-correct migration preserves the intended meaning of its data.

Next