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
| Concern | Where it lives |
|---|---|
| Who may call ordinary app methods | Kernel authorization set, checked in the generated wrapper; declared public-ingress routes apply their own caller policy |
| What an app may reach | The 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 compile | Static Motoko policy in neutron-security, run at packaging and at compile |
| What the user is told before approving | Kernel-attested disclosure derived from the capability plan |
| What runs where in the browser | Kernel-owned frame contexts and endpoint ids |
| How the canister changes | The 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
- Ownership model — why one canister means one human
- The kernel — the OS as a replaceable package
- Lifecycle — the ordered story of an install